to have the same position on output.
free(lbls);
}
-/* dotneato_postprocess:
+/* gv_postprocess:
* Set graph and cluster label positions.
* Add space for root graph label and translate graph accordingly.
* Set final nodesize using ns.
}
}
+/* dotneato_postprocess:
+ */
void dotneato_postprocess(Agraph_t * g)
{
gv_postprocess(g, 1);
/* Set bbox info for g and all clusters. This is needed for
* spline drawing. We already know the graph bbox is at the origin.
- * (We pass the origin to spline_edges0. This really isn't true,
- * as the algorithm has done many translations.)
* On return from spline drawing, all bounding boxes should be correct.
*/
setBB(g);
if (EDGE_TYPE(g) != ET_NONE) fdpSplines (g);
- dotneato_postprocess(g);
+ gv_postprocess(g, 0);
PSinputscale = save_scale;
}
return NoEdges;
}
+/* freeEdgeInfo:
+ */
+static void freeEdgeInfo (Agraph_t * g)
+{
+ node_t *n;
+ edge_t *e;
+
+ for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+ for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
+ gv_free_splines(e);
+ free_label(ED_label(e));
+ free_label(ED_xlabel(e));
+ free_label(ED_head_label(e));
+ free_label(ED_tail_label(e));
+ }
+ }
+}
+
/* chkBB:
* Scans for a correct bb attribute. If available, sets it
* in the graph and returns 1.
}
}
-/* translateE:
- * Translate edge by offset.
- * Assume ED_spl(e) != NULL
- */
-static void translateE(edge_t * e, pointf offset)
-{
- int i, j;
- pointf *pt;
- bezier *bez;
-
- bez = ED_spl(e)->list;
- for (i = 0; i < ED_spl(e)->size; i++) {
- pt = bez->list;
- for (j = 0; j < bez->size; j++) {
- pt->x -= offset.x;
- pt->y -= offset.y;
- pt++;
- }
- if (bez->sflag) {
- bez->sp.x -= offset.x;
- bez->sp.y -= offset.y;
- }
- if (bez->eflag) {
- bez->ep.x -= offset.x;
- bez->ep.y -= offset.y;
- }
- bez++;
- }
-
- if (ED_label(e) && ED_label(e)->set) {
- ED_label(e)->pos.x -= offset.x;
- ED_label(e)->pos.y -= offset.y;
- }
- if (ED_xlabel(e) && ED_xlabel(e)->set) {
- ED_xlabel(e)->pos.x -= offset.x;
- ED_xlabel(e)->pos.y -= offset.y;
- }
- if (ED_head_label(e) && ED_head_label(e)->set) {
- ED_head_label(e)->pos.x -= offset.x;
- ED_head_label(e)->pos.y -= offset.y;
- }
- if (ED_tail_label(e) && ED_tail_label(e)->set) {
- ED_tail_label(e)->pos.x -= offset.x;
- ED_tail_label(e)->pos.y -= offset.y;
- }
-}
-
-/* translateG:
- */
-static void translateG(Agraph_t * g, pointf offset)
-{
- int i;
-
- GD_bb(g).UR.x -= offset.x;
- GD_bb(g).UR.y -= offset.y;
- GD_bb(g).LL.x -= offset.x;
- GD_bb(g).LL.y -= offset.y;
-
- if (GD_label(g) && GD_label(g)->set) {
- GD_label(g)->pos.x -= offset.x;
- GD_label(g)->pos.y -= offset.y;
- }
-
- for (i = 1; i <= GD_n_cluster(g); i++)
- translateG(GD_clust(g)[i], offset);
-}
-
-/* translate:
- */
-static void translate(Agraph_t * g, pos_edge posEdges)
-{
- node_t *n;
- edge_t *e;
- pointf offset;
- pointf ll;
-
- ll = GD_bb(g).LL;
-
- offset.x = PS2INCH(ll.x);
- offset.y = PS2INCH(ll.y);
- for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
- ND_pos(n)[0] -= offset.x;
- ND_pos(n)[1] -= offset.y;
- if (ND_xlabel(n) && ND_xlabel(n)->set) {
- ND_xlabel(n)->pos.x -= ll.x;
- ND_xlabel(n)->pos.y -= ll.y;
- }
- }
- if (posEdges != NoEdges) {
- for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
- for (e = agfstout(g, n); e; e = agnxtout(g, e))
- if (ED_spl(e))
- translateE(e, ll);
- }
- }
- translateG(g, ll);
-}
-
/* init_nop:
* This assumes all nodes have been positioned.
- * It also assumes none of the * relevant fields in A*info_t have been set.
+ * It also assumes none of the relevant fields in A*info_t have been set.
* The input may provide additional position information for
* clusters, edges and labels. If certain position information
* is missing, init_nop will use a standard neato technique to
* of the basic graph information. No tweaking of positions or
* filling in edge splines is done.
*
- * Returns 0 on normal success, 1 if postprocess should be avoided, and -1
+ * Returns 0 on normal success, 1 if layout has a background, and -1
* on failure.
*/
int init_nop(Agraph_t * g, int adjust)
*/
}
-#if 0
- /* If g does not have a good "bb" attribute or we adjusted the nodes,
- * compute it.
- */
- if (!chkBB(g, G_bb) || didAdjust)
-#endif
- compute_bb(g);
+ compute_bb(g);
/* Adjust bounding box for any background */
if (haveBackground)
GD_bb(g) = xdotBB (g);
/* At this point, all bounding boxes should be correctly defined.
- * If necessary, we translate the graph to the origin.
*/
- if (adjust && !haveBackground && (ROUND(abs(GD_bb(g).LL.x)) || ROUND(abs(GD_bb(g).LL.y))))
- translate(g, posEdges);
if (!adjust) {
node_t *n;
ND_coord(n).y = POINTS_PER_INCH * (ND_pos(n)[1]);
}
}
- else if (posEdges != AllEdges)
- spline_edges0(g);
else {
- State = GVSPLINES;
- neato_set_aspect(g);
+ boolean didShift = neato_set_aspect(g);
+ /* if we have some edge positions and we either shifted or adjusted, free edge positions */
+ if ((posEdges != NoEdges) && (didShift || didAdjust)) {
+ freeEdgeInfo (g);
+ posEdges = NoEdges;
+ }
+ if (posEdges != AllEdges)
+ spline_edges0(g, FALSE); /* add edges */
+ else
+ State = GVSPLINES;
}
+
return haveBackground;
}
}
#endif
+/* doEdges:
+ * Simple wrapper to compute graph's bb, then route edges after
+ * a possible aspect ratio adjustment.
+ */
+static void doEdges(Agraph_t* g)
+{
+ compute_bb(g);
+ spline_edges0(g, TRUE);
+}
+
/* neato_layout:
*/
void neato_layout(Agraph_t * g)
agerr(AGPREV, "as required by the -n flag\n");
return;
}
- else gv_postprocess(g, !ret);
+ else gv_postprocess(g, 0);
} else {
PSinputscale = get_inputscale (g);
neato_init_graph(g);
neatoLayout(g, gc, layoutMode, model, &am);
removeOverlapWith(gc, &am);
setEdgeType (gc, ET_LINE);
- spline_edges(gc);
+ doEdges(gc);
}
if (pin) {
bp = N_NEW(n_cc, boolean);
else {
neatoLayout(g, g, layoutMode, model, &am);
removeOverlapWith(g, &am);
- spline_edges(g);
+ doEdges(g);
}
compute_bb(g);
addZ (g);
neatoLayout(g, g, layoutMode, model, &am);
removeOverlapWith(g, &am);
addZ (g);
- spline_edges(g);
+ doEdges(g);
}
- dotneato_postprocess(g);
+ gv_postprocess(g, 0);
}
PSinputscale = save_scale;
}
extern void solve_model(graph_t *, int);
extern int solveCircuit(int nG, double **Gm, double **Gm_inv);
extern void spline_edges(Agraph_t *);
- extern void spline_edges0(Agraph_t *);
+ extern void spline_edges0(Agraph_t *, boolean);
extern int spline_edges1(graph_t * g, int);
extern int splineEdges(graph_t *,
int (*edgefn) (graph_t *, expand_t*, int), int);
- extern void neato_set_aspect(graph_t * g);
+ extern boolean neato_set_aspect(graph_t * g);
extern void toggle(int);
extern int user_pos(Agsym_t *, Agsym_t *, Agnode_t *, int);
extern double **new_array(int i, int j, double val);
* when output in dot or plain format.
*
*/
-void spline_edges0(graph_t * g)
+void spline_edges0(graph_t * g, boolean set_aspect)
{
int et = EDGE_TYPE (g);
- neato_set_aspect(g);
+ if (set_aspect) neato_set_aspect(g);
if (et == ET_NONE) return;
#ifndef ORTHO
if (et == ET_ORTHO) {
}
shiftClusters (g, GD_bb(g).LL);
- spline_edges0(g);
+ spline_edges0(g, TRUE);
}
/* scaleEdge:
scaleBB(GD_clust(g)[i], xf, yf);
}
+/* translateE:
+ * Translate edge by offset.
+ * Assume ED_spl(e) != NULL
+ */
+static void translateE(edge_t * e, pointf offset)
+{
+ int i, j;
+ pointf *pt;
+ bezier *bez;
+
+ bez = ED_spl(e)->list;
+ for (i = 0; i < ED_spl(e)->size; i++) {
+ pt = bez->list;
+ for (j = 0; j < bez->size; j++) {
+ pt->x -= offset.x;
+ pt->y -= offset.y;
+ pt++;
+ }
+ if (bez->sflag) {
+ bez->sp.x -= offset.x;
+ bez->sp.y -= offset.y;
+ }
+ if (bez->eflag) {
+ bez->ep.x -= offset.x;
+ bez->ep.y -= offset.y;
+ }
+ bez++;
+ }
+
+ if (ED_label(e) && ED_label(e)->set) {
+ ED_label(e)->pos.x -= offset.x;
+ ED_label(e)->pos.y -= offset.y;
+ }
+ if (ED_xlabel(e) && ED_xlabel(e)->set) {
+ ED_xlabel(e)->pos.x -= offset.x;
+ ED_xlabel(e)->pos.y -= offset.y;
+ }
+ if (ED_head_label(e) && ED_head_label(e)->set) {
+ ED_head_label(e)->pos.x -= offset.x;
+ ED_head_label(e)->pos.y -= offset.y;
+ }
+ if (ED_tail_label(e) && ED_tail_label(e)->set) {
+ ED_tail_label(e)->pos.x -= offset.x;
+ ED_tail_label(e)->pos.y -= offset.y;
+ }
+}
+
+/* translateG:
+ */
+static void translateG(Agraph_t * g, pointf offset)
+{
+ int i;
+
+ GD_bb(g).UR.x -= offset.x;
+ GD_bb(g).UR.y -= offset.y;
+ GD_bb(g).LL.x -= offset.x;
+ GD_bb(g).LL.y -= offset.y;
+
+ if (GD_label(g) && GD_label(g)->set) {
+ GD_label(g)->pos.x -= offset.x;
+ GD_label(g)->pos.y -= offset.y;
+ }
+
+ for (i = 1; i <= GD_n_cluster(g); i++)
+ translateG(GD_clust(g)[i], offset);
+}
+
+/* translate:
+ */
+static void translate(Agraph_t * g)
+{
+ node_t *n;
+ edge_t *e;
+ pointf offset;
+ pointf ll;
+
+ ll = GD_bb(g).LL;
+
+ offset.x = PS2INCH(ll.x);
+ offset.y = PS2INCH(ll.y);
+ for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+ ND_pos(n)[0] -= offset.x;
+ ND_pos(n)[1] -= offset.y;
+ if (ND_xlabel(n) && ND_xlabel(n)->set) {
+ ND_xlabel(n)->pos.x -= ll.x;
+ ND_xlabel(n)->pos.y -= ll.y;
+ }
+ }
+ for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+ for (e = agfstout(g, n); e; e = agnxtout(g, e))
+ if (ED_spl(e))
+ translateE(e, ll);
+ }
+ translateG(g, ll);
+}
+
/* _neato_set_aspect;
- * Assume all bounding boxes are correct and
- * that GD_bb(g).LL is at origin.
- * Also assume g is the root graph
+ * Assume all bounding boxes are correct.
+ * Return false if no transform is performed. This includes
+ * the possiblity that a translation was done.
*/
-static void _neato_set_aspect(graph_t * g)
+static boolean _neato_set_aspect(graph_t * g)
{
- /* int i; */
double xf, yf, actual, desired;
node_t *n;
+ if (g->root != g)
+ return FALSE;
+
/* compute_bb(g); */
if (GD_drawing(g)->ratio_kind) {
+ if (ROUND(abs(GD_bb(g).LL.x)) || ROUND(abs(GD_bb(g).LL.y)))
+ translate (g);
/* normalize */
- assert(ROUND(GD_bb(g).LL.x) == 0);
- assert(ROUND(GD_bb(g).LL.y) == 0);
if (GD_flip(g)) {
double t = GD_bb(g).UR.x;
GD_bb(g).UR.x = GD_bb(g).UR.y;
if (GD_drawing(g)->ratio_kind == R_FILL) {
/* fill is weird because both X and Y can stretch */
if (GD_drawing(g)->size.x <= 0)
- return;
+ return FALSE;
xf = (double) GD_drawing(g)->size.x / GD_bb(g).UR.x;
yf = (double) GD_drawing(g)->size.y / GD_bb(g).UR.y;
/* handle case where one or more dimensions is too big */
}
} else if (GD_drawing(g)->ratio_kind == R_EXPAND) {
if (GD_drawing(g)->size.x <= 0)
- return;
+ return FALSE;
xf = (double) GD_drawing(g)->size.x / GD_bb(g).UR.x;
yf = (double) GD_drawing(g)->size.y / GD_bb(g).UR.y;
if ((xf > 1.0) && (yf > 1.0)) {
double scale = MIN(xf, yf);
xf = yf = scale;
} else
- return;
+ return FALSE;
} else if (GD_drawing(g)->ratio_kind == R_VALUE) {
desired = GD_drawing(g)->ratio;
actual = (GD_bb(g).UR.y) / (GD_bb(g).UR.x);
yf = 1.0;
}
} else
- return;
+ return FALSE;
if (GD_flip(g)) {
double t = xf;
xf = yf;
ND_pos(n)[1] = ND_pos(n)[1] * yf;
}
scaleBB(g, xf, yf);
+ return TRUE;
}
+ else
+ return FALSE;
}
/* neato_set_aspect:
* Sets aspect ratio if necessary; real work done in _neato_set_aspect;
* This also copies the internal layout coordinates (ND_pos) to the
* external ones (ND_coord).
+ *
+ * Return true if some node moved.
*/
-void neato_set_aspect(graph_t * g)
+boolean neato_set_aspect(graph_t * g)
{
node_t *n;
+ boolean moved = FALSE;
/* setting aspect ratio only makes sense on root graph */
- if (g->root == g)
- _neato_set_aspect(g);
+ moved = _neato_set_aspect(g);
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
ND_coord(n).x = POINTS_PER_INCH * (ND_pos(n)[0]);
ND_coord(n).y = POINTS_PER_INCH * (ND_pos(n)[1]);
}
+ return moved;
}
ND_pos(n)[0] = PS2INCH(ND_coord(n).x);
ND_pos(n)[1] = PS2INCH(ND_coord(n).y);
}
- spline_edges0(g);
+ spline_edges0(g, TRUE);
}
else {
int et = EDGE_TYPE (g);