From 931369e63435de740a13d856a16c7ae0284c5579 Mon Sep 17 00:00:00 2001 From: Emden Gansner Date: Wed, 20 Mar 2013 12:01:14 -0400 Subject: [PATCH] Extend normalize attribute to allow arbitrary angle; fix function so that it still works if the first node does not have any outedges. --- doc/info/attrs.html | 7 +++-- doc/infosrc/attrs | 7 +++-- lib/neatogen/adjust.c | 60 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/doc/info/attrs.html b/doc/info/attrs.html index 083cda936..93f78e6cc 100644 --- a/doc/info/attrs.html +++ b/doc/info/attrs.html @@ -326,7 +326,7 @@ This field indicates which graph component uses the attribute. GCNEbool false normalize -Gbool +Gdouble
bool falsenot dot nslimit
nslimit1 @@ -1291,7 +1291,10 @@ This field indicates which graph component uses the attribute.
normalize
If set, normalize coordinates of final layout so that the first point is at the origin, and then rotate the - layout so that the first edge is horizontal. + layout so that the angle of the first edge is specified by the value of normalize in degrees. + If normalize is not a number, it is evaluated as a bool, with true + corresponding to 0 degrees. NOTE: Since the attribute is evaluated first as a number, + 0 and 1 cannot be used for false and true.
nslimit ,
nslimit1 diff --git a/doc/infosrc/attrs b/doc/infosrc/attrs index faabe1ca2..699f16872 100644 --- a/doc/infosrc/attrs +++ b/doc/infosrc/attrs @@ -728,10 +728,13 @@ in the context of itself. For example, if the attribute is set, the first label line is long, and the second is shorter and left-justified, the second will align with the left-most character in the first line, regardless of how large the node might be. -:normalize:G:bool:false; notdot +:normalize:G:double/bool:false; notdot If set, normalize coordinates of final layout so that the first point is at the origin, and then rotate the -layout so that the first edge is horizontal. +layout so that the angle of the first edge is specified by the value of normalize in degrees. +If normalize is not a number, it is evaluated as a bool, with true +corresponding to 0 degrees. NOTE: Since the attribute is evaluated first as a number, +0 and 1 cannot be used for false and true. :nslimit/nslimit1:G:double; dot Used to set number of iterations in network simplex applications. nslimit is used in diff --git a/lib/neatogen/adjust.c b/lib/neatogen/adjust.c index 372d1f6fb..8577dc678 100644 --- a/lib/neatogen/adjust.c +++ b/lib/neatogen/adjust.c @@ -894,21 +894,50 @@ vpscAdjust(graph_t* G) } #endif +/* angleSet: + * Return true if "normalize" is defined and valid; return angle in phi. + * Read angle as degrees, convert to radians. + * Guarantee -PI < phi <= PI. + */ +static int +angleSet (graph_t* g, double* phi) +{ + double ang; + char* p; + char* a = agget(g, "normalize"); + + if (!a || (*a == '\0')) + return 0; + ang = strtod (a, &p); + if (p == a) { /* no number */ + if (mapbool(a)) + ang = 0.0; + else + return 0; + } + while (ang > 180) ang -= 360; + while (ang <= -180) ang += 360; + + *phi = RADIANS(ang); + return 1; +} + /* normalize: * If normalize is set, move first node to origin, then - * rotate graph so that first edge is horizontal. + * rotate graph so that the angle of the first edge is given + * by the degrees from normalize. * FIX: Generalize to allow rotation determined by graph shape. */ int normalize(graph_t * g) { node_t *v; edge_t *e; - - double theta; - pointf p; + double phi; + double cosv, sinv; + pointf p, orig; int ret; - if (!mapbool(agget(g, "normalize"))) + if (!angleSet(g, &phi)) return 0; v = agfstnode(g); @@ -928,16 +957,23 @@ int normalize(graph_t * g) if (e == NULL) return ret; - theta = -atan2(ND_pos(aghead(e))[1] - ND_pos(agtail(e))[1], + /* rotation necessary; pos => ccw */ + phi -= atan2(ND_pos(aghead(e))[1] - ND_pos(agtail(e))[1], ND_pos(aghead(e))[0] - ND_pos(agtail(e))[0]); - for (v = agfstnode(g); v; v = agnxtnode(g, v)) { - p.x = ND_pos(v)[0]; - p.y = ND_pos(v)[1]; - ND_pos(v)[0] = p.x * cos(theta) - p.y * sin(theta); - ND_pos(v)[1] = p.x * sin(theta) + p.y * cos(theta); + if (phi) { + orig.x = ND_pos(agtail(e))[0]; + orig.y = ND_pos(agtail(e))[1]; + cosv = cos(phi); + sinv = sin(phi); + for (v = agfstnode(g); v; v = agnxtnode(g, v)) { + p.x = ND_pos(v)[0] - orig.x; + p.y = ND_pos(v)[1] - orig.y; + ND_pos(v)[0] = p.x * cosv - p.y * sinv + orig.x; + ND_pos(v)[1] = p.x * sinv + p.y * cosv + orig.y; + } + return 1; } - if (theta) return 1; else return ret; } -- 2.40.0