]> granicus.if.org Git - graphviz/commitdiff
Fix neato to avoid unnecessary translations. This will allow nodes that have a fixed...
authorEmden R. Gansner <erg@alum.mit.edu>
Wed, 26 Feb 2014 21:03:34 +0000 (16:03 -0500)
committerEmden R. Gansner <erg@alum.mit.edu>
Wed, 26 Feb 2014 21:03:34 +0000 (16:03 -0500)
to have the same position on output.

lib/common/postproc.c
lib/fdpgen/layout.c
lib/neatogen/neatoinit.c
lib/neatogen/neatoprocs.h
lib/neatogen/neatosplines.c
lib/osage/osageinit.c

index ffc911c339be0e7068c624cd6546da01c31e0e31..163bf30e4107c08ac257d2e28c467960614d69c2 100644 (file)
@@ -573,7 +573,7 @@ static void addXLabels(Agraph_t * gp)
     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.
@@ -668,6 +668,8 @@ void gv_postprocess(Agraph_t * g, int allowTranslation)
     }
 }
 
+/* dotneato_postprocess:
+ */
 void dotneato_postprocess(Agraph_t * g)
 {
     gv_postprocess(g, 1);
index 0409f27ffd0782bd9bb500bdba23f1dd1c7f7459..bba7a006436e2eef82b6842212bdbacd011f7287 100644 (file)
@@ -1083,8 +1083,6 @@ void fdpLayout(graph_t * g)
 
     /* 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);
@@ -1138,6 +1136,6 @@ void fdp_layout(graph_t * g)
 
     if (EDGE_TYPE(g) != ET_NONE) fdpSplines (g); 
 
-    dotneato_postprocess(g);
+    gv_postprocess(g, 0);
     PSinputscale = save_scale;
 }
index 91585519469aa4f1faa4a8e94943c9b1e8c9462a..f2bbb29ec16a78339cb5bf5b2e1e27faf38a9151 100644 (file)
@@ -400,6 +400,24 @@ static pos_edge nop_init_edges(Agraph_t * g)
        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.
@@ -492,107 +510,9 @@ nop_init_graphs(Agraph_t * g, attrsym_t * G_lp, attrsym_t * G_bb)
     }
 }
 
-/* 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
@@ -602,7 +522,7 @@ static void translate(Agraph_t * g, pos_edge posEdges)
  * 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)
@@ -649,23 +569,14 @@ 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;
@@ -675,12 +586,19 @@ int init_nop(Agraph_t * g, int adjust)
            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;
 }
 
@@ -1470,6 +1388,16 @@ addCluster (graph_t* g)
 }
 #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)
@@ -1491,7 +1419,7 @@ 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);
@@ -1527,7 +1455,7 @@ void neato_layout(Agraph_t * 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);
@@ -1544,7 +1472,7 @@ void neato_layout(Agraph_t * g)
            else {
                neatoLayout(g, g, layoutMode, model, &am);
                removeOverlapWith(g, &am);
-               spline_edges(g);
+               doEdges(g);
            }
            compute_bb(g);
            addZ (g);
@@ -1564,9 +1492,9 @@ void neato_layout(Agraph_t * 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;
 }
index 48a3c6c4d1d4fd27c310d8a84d48def6030da100..0a8dce67b0a4082f10218d80e892a5679a5fecfa 100644 (file)
@@ -66,11 +66,11 @@ extern "C" {
     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);
index ba6c376bf8162466a207151ca5812f096dcb27d9..80d4198e7c8894c234a2932dec7f0f6d651686de 100644 (file)
@@ -754,10 +754,10 @@ int spline_edges1(graph_t * g, int edgetype)
  * 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) {
@@ -805,7 +805,7 @@ void spline_edges(graph_t * g)
     }
        
     shiftClusters (g, GD_bb(g).LL);
-    spline_edges0(g);
+    spline_edges0(g, TRUE);
 }
 
 /* scaleEdge:
@@ -888,22 +888,120 @@ static void scaleBB(graph_t * g, double xf, double yf)
        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;
@@ -912,7 +1010,7 @@ static void _neato_set_aspect(graph_t * g)
        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 */
@@ -927,14 +1025,14 @@ static void _neato_set_aspect(graph_t * g)
            }
        } 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);
@@ -946,7 +1044,7 @@ static void _neato_set_aspect(graph_t * g)
                yf = 1.0;
            }
        } else
-           return;
+           return FALSE;
        if (GD_flip(g)) {
            double t = xf;
            xf = yf;
@@ -969,24 +1067,30 @@ static void _neato_set_aspect(graph_t * g)
            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;
 }
 
index 9b770a9be25a49d4f3b15e531aa7b6ff3b5511b1..ab03a248c40b8bd8af114ae00e3fda24c268dd9d 100644 (file)
@@ -364,7 +364,7 @@ void osage_layout(Agraph_t *g)
            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);