Graphviz 12.0.1~dev.20240715.2254
Loading...
Searching...
No Matches
neatoinit.c
Go to the documentation of this file.
1
8/*************************************************************************
9 * Copyright (c) 2011 AT&T Intellectual Property
10 * All rights reserved. This program and the accompanying materials
11 * are made available under the terms of the Eclipse Public License v1.0
12 * which accompanies this distribution, and is available at
13 * https://www.eclipse.org/legal/epl-v10.html
14 *
15 * Contributors: Details at https://graphviz.org
16 *************************************************************************/
17
18
19#include "config.h"
20
21#include <time.h>
22#ifndef _WIN32
23#include <unistd.h>
24#endif
25#include <neatogen/neato.h>
26#include <pack/pack.h>
27#include <neatogen/stress.h>
28#ifdef DIGCOLA
29#include <neatogen/digcola.h>
30#endif
31#include <neatogen/kkutils.h>
32#include <common/pointset.h>
33#include <neatogen/sgd.h>
34#include <cgraph/alloc.h>
35#include <cgraph/bitarray.h>
36#include <cgraph/cgraph.h>
37#include <cgraph/gv_ctype.h>
38#include <cgraph/prisize_t.h>
39#include <cgraph/startswith.h>
40#include <cgraph/strcasecmp.h>
41#include <cgraph/streq.h>
42#include <float.h>
43#include <stdbool.h>
44#include <stddef.h>
45
46#ifndef HAVE_SRAND48
47#define srand48 srand
48#endif
49
51static int Pack; /* If >= 0, layout components separately and pack together
52 * The value of Pack gives margins around graphs.
53 */
54static char *cc_pfx = "_neato_cc";
55
57{
58 agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), true); //node custom data
60 ND_pos(n) = gv_calloc(GD_ndim(agraphof(n)), sizeof(double));
62}
63
64static void neato_init_edge(edge_t * e)
65{
66 agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), true); //node custom data
68 ED_factor(e) = late_double(e, E_weight, 1.0, 1.0);
69}
70
71bool user_pos(attrsym_t *posptr, attrsym_t *pinptr, node_t *np, int nG) {
72 double *pvec;
73 char *p, c;
74 double z;
75
76 if (posptr == NULL)
77 return false;
78 pvec = ND_pos(np);
79 p = agxget(np, posptr);
80 if (p[0]) {
81 c = '\0';
82 if (Ndim >= 3 && sscanf(p, "%lf,%lf,%lf%c", pvec, pvec+1, pvec+2, &c) >= 3){
83 ND_pinned(np) = P_SET;
84 if (PSinputscale > 0.0) {
85 int i;
86 for (i = 0; i < Ndim; i++)
87 pvec[i] = pvec[i] / PSinputscale;
88 }
89 if (Ndim > 3)
90 jitter_d(np, nG, 3);
91 if (c == '!' || (pinptr && mapbool(agxget(np, pinptr))))
92 ND_pinned(np) = P_PIN;
93 return true;
94 }
95 else if (sscanf(p, "%lf,%lf%c", pvec, pvec + 1, &c) >= 2) {
96 ND_pinned(np) = P_SET;
97 if (PSinputscale > 0.0) {
98 int i;
99 for (i = 0; i < Ndim; i++)
100 pvec[i] /= PSinputscale;
101 }
102 if (Ndim > 2) {
103 if (N_z && (p = agxget(np, N_z)) && sscanf(p,"%lf",&z) == 1) {
104 if (PSinputscale > 0.0) {
105 pvec[2] = z / PSinputscale;
106 }
107 else
108 pvec[2] = z;
109 jitter_d(np, nG, 3);
110 }
111 else
112 jitter3d(np, nG);
113 }
114 if (c == '!' || (pinptr && mapbool(agxget(np, pinptr))))
115 ND_pinned(np) = P_PIN;
116 return true;
117 } else
118 agerrorf("node %s, position %s, expected two doubles\n",
119 agnameof(np), p);
120 }
121 return false;
122}
123
125{
126 node_t *n;
127 edge_t *e;
128 int nG = agnnodes(g);
129 attrsym_t *N_pin;
130
131 N_pos = agfindnodeattr(g, "pos");
132 N_pin = agfindnodeattr(g, "pin");
133
134 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
136 user_pos(N_pos, N_pin, n, nG); /* set user position if given */
137 }
138 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
139 for (e = agfstout(g, n); e; e = agnxtout(g, e))
141 }
142}
143
145{
146 if (Nop || Pack < 0) {
148 }
149 free(GD_clust(g));
150}
151
153{
154 node_t *n;
155 edge_t *e;
156
157 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
158 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
160 }
162 }
164}
165
166static int numFields(const char *pos) {
167 int cnt = 0;
168 char c;
169
170 do {
171 while (gv_isspace(*pos))
172 pos++; /* skip white space */
173 if ((c = *pos)) { /* skip token */
174 cnt++;
175 while ((c = *pos) && !gv_isspace(c) && c != ';')
176 pos++;
177 }
178 } while (gv_isspace(c));
179 return cnt;
180}
181
182static void set_label(void* obj, textlabel_t * l, char *name)
183{
184 double x, y;
185 char *lp;
186 lp = agget(obj, name);
187 if (lp && sscanf(lp, "%lf,%lf", &x, &y) == 2) {
188 l->pos = (pointf){x, y};
189 l->set = true;
190 }
191}
192
193#ifdef IPSEPCOLA
194static cluster_data cluster_map(graph_t *mastergraph, graph_t *g) {
195 graph_t *subg;
196 node_t *n;
197 /* array of arrays of node indices in each cluster */
198 int **cs,*cn;
199 int i,j,nclusters=0;
200 bitarray_t assigned = bitarray_new(agnnodes(g));
201 cluster_data cdata = {0};
202
203 cdata.ntoplevel = agnnodes(g);
204 for (subg = agfstsubg(mastergraph); subg; subg = agnxtsubg(subg)) {
205 if (startswith(agnameof(subg), "cluster")) {
206 nclusters++;
207 }
208 }
209 cdata.nvars=0;
210 cdata.nclusters = nclusters;
211 cs = cdata.clusters = gv_calloc(nclusters, sizeof(int*));
212 cn = cdata.clustersizes = gv_calloc(nclusters, sizeof(int));
213 for (subg = agfstsubg(mastergraph); subg; subg = agnxtsubg(subg)) {
214 /* clusters are processed by separate calls to ordered_edges */
215 if (startswith(agnameof(subg), "cluster")) {
216 int *c;
217
218 *cn = agnnodes(subg);
219 cdata.nvars += *cn;
220 c = *cs++ = gv_calloc(*cn++, sizeof(int));
221 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
222 node_t *gn;
223 int ind = 0;
224 for (gn = agfstnode(g); gn; gn = agnxtnode(g, gn)) {
225 if(AGSEQ(gn)==AGSEQ(n)) break;
226 ind++;
227 }
228 *c++=ind;
229 bitarray_set(&assigned, ind, true);
230 cdata.ntoplevel--;
231 }
232 }
233 }
234 cdata.bb = gv_calloc(cdata.nclusters, sizeof(boxf));
235 cdata.toplevel = gv_calloc(cdata.ntoplevel, sizeof(int));
236 for(i=j=0;i<agnnodes(g);i++) {
237 if(!bitarray_get(assigned, i)) {
238 cdata.toplevel[j++] = i;
239 }
240 }
241 assert(cdata.ntoplevel == agnnodes(g) - cdata.nvars);
242 bitarray_reset(&assigned);
243 return cdata;
244}
245
246static void freeClusterData(cluster_data c) {
247 if (c.nclusters > 0) {
248 free(c.clusters[0]);
249 free(c.clusters);
250 free(c.clustersizes);
251 free(c.toplevel);
252 free(c.bb);
253 }
254}
255#endif
256
257/* user_spline:
258 * Attempt to use already existing pos info for spline
259 * Return 1 if successful, 0 otherwise.
260 * Assume E_pos != NULL and ED_spl(e) == NULL.
261 */
262static int user_spline(attrsym_t * E_pos, edge_t * e)
263{
264 char *pos;
265 int i, n, npts, nc;
266 pointf *pp;
267 double x, y;
268 int sflag = 0, eflag = 0;
269 pointf sp = { 0, 0 }, ep = { 0, 0};
270 bezier *newspl;
271 int more = 1;
272 static bool warned;
273
274 pos = agxget(e, E_pos);
275 if (*pos == '\0')
276 return 0;
277
278 uint32_t stype, etype;
279 arrow_flags(e, &stype, &etype);
280 do {
281 /* check for s head */
282 i = sscanf(pos, "s,%lf,%lf%n", &x, &y, &nc);
283 if (i == 2) {
284 sflag = 1;
285 pos = pos + nc;
286 sp.x = x;
287 sp.y = y;
288 }
289
290 /* check for e head */
291 i = sscanf(pos, " e,%lf,%lf%n", &x, &y, &nc);
292 if (i == 2) {
293 eflag = 1;
294 pos = pos + nc;
295 ep.x = x;
296 ep.y = y;
297 }
298
299 npts = numFields(pos); // count potential points
300 n = npts;
301 if (n < 4 || n % 3 != 1) {
303 if (!warned) {
304 warned = true;
305 agwarningf("pos attribute for edge (%s,%s) doesn't have 3n+1 points\n", agnameof(agtail(e)), agnameof(aghead(e)));
306 }
307 return 0;
308 }
309 pointf *ps = gv_calloc(n, sizeof(pointf));
310 pp = ps;
311 while (n) {
312 i = sscanf(pos, "%lf,%lf%n", &x, &y, &nc);
313 if (i < 2) {
314 if (!warned) {
315 warned = true;
316 agwarningf("syntax error in pos attribute for edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
317 }
318 free(ps);
320 return 0;
321 }
322 pos += nc;
323 pp->x = x;
324 pp->y = y;
325 pp++;
326 n--;
327 }
328 while (gv_isspace(*pos)) pos++;
329 if (*pos == '\0')
330 more = 0;
331 else
332 pos++;
333
334 /* parsed successfully; create spline */
335 assert(npts >= 0);
336 newspl = new_spline(e, (size_t)npts);
337 if (sflag) {
338 newspl->sflag = stype;
339 newspl->sp = sp;
340 }
341 if (eflag) {
342 newspl->eflag = etype;
343 newspl->ep = ep;
344 }
345 for (i = 0; i < npts; i++) {
346 newspl->list[i] = ps[i];
347 }
348 free(ps);
349 } while (more);
350
351 if (ED_label(e))
352 set_label(e, ED_label(e), "lp");
353 if (ED_xlabel(e))
354 set_label(e, ED_xlabel(e), "xlp");
355 if (ED_head_label(e))
356 set_label(e, ED_head_label(e), "head_lp");
357 if (ED_tail_label(e))
358 set_label(e, ED_tail_label(e), "tail_lp");
359
360 return 1;
361}
362
363/* Nop can be:
364 * 0 - do full layout
365 * 1 - assume initial node positions, do (optional) adjust and all splines
366 * 2 - assume final node and edges positions, do nothing except compute
367 * missing splines
368 */
369
370 /* Indicates the amount of edges with position information */
372
373/* nop_init_edges:
374 * Check edges for position info.
375 * If position info exists, check for edge label positions.
376 * Return number of edges with position info.
377 */
379{
380 node_t *n;
381 edge_t *e;
382 int nedges = 0;
383 attrsym_t *E_pos;
384
385 if (agnedges(g) == 0)
386 return AllEdges;
387
388 E_pos = agfindedgeattr(g, "pos");
389 if (!E_pos || Nop < 2)
390 return NoEdges;
391
392 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
393 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
394 if (user_spline(E_pos, e)) {
395 nedges++;
396 }
397 }
398 }
399 if (nedges) {
400 if (nedges == agnedges(g))
401 return AllEdges;
402 else
403 return SomeEdges;
404 } else
405 return NoEdges;
406}
407
408/* freeEdgeInfo:
409 */
410static void freeEdgeInfo (Agraph_t * g)
411{
412 node_t *n;
413 edge_t *e;
414
415 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
416 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
422 }
423 }
424}
425
426/* chkBB:
427 * Scans for a correct bb attribute. If available, sets it
428 * in the graph and returns 1.
429 */
430#define BS "%lf,%lf,%lf,%lf"
431
432static int chkBB(Agraph_t * g, attrsym_t * G_bb, boxf* bbp)
433{
434 char *s;
435 boxf bb;
436
437 s = agxget(g, G_bb);
438 if (sscanf(s, BS, &bb.LL.x, &bb.LL.y, &bb.UR.x, &bb.UR.y) == 4) {
439 if (bb.LL.y > bb.UR.y) {
440 /* If the LL.y coordinate is bigger than the UR.y coordinate,
441 * we assume the input was produced using -y, so we normalize
442 * the bb.
443 */
444 double tmp = bb.LL.y;
445 bb.LL.y = bb.UR.y;
446 bb.UR.y = tmp;
447 }
448 *bbp = bb;
449 return 1;
450 } else
451 return 0;
452}
453
454static void add_cluster(Agraph_t * g, Agraph_t * subg)
455{
456 int cno;
457 cno = ++(GD_n_cluster(g));
458 GD_clust(g) = gv_recalloc(GD_clust(g), GD_n_cluster(g), cno + 1,
459 sizeof(graph_t*));
460 GD_clust(g)[cno] = subg;
461 do_graph_label(subg);
462}
463
464
465static void nop_init_graphs(Agraph_t *, attrsym_t *, attrsym_t *);
466
467/* dfs:
468 * Process subgraph subg of parent graph g
469 * If subg is a cluster, add its bounding box, if any; attach to
470 * cluster array of parent, and recursively initialize subg.
471 * If not a cluster, recursively call this function on the subgraphs
472 * of subg, using parentg as the parent graph.
473 */
474static void
475dfs(Agraph_t * subg, Agraph_t * parentg, attrsym_t * G_lp, attrsym_t * G_bb)
476{
477 boxf bb;
478
479 if (startswith(agnameof(subg), "cluster") && chkBB(subg, G_bb, &bb)) {
480 agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), true);
481 GD_bb(subg) = bb;
482 add_cluster(parentg, subg);
483 nop_init_graphs(subg, G_lp, G_bb);
484 } else {
485 graph_t *sg;
486 for (sg = agfstsubg(subg); sg; sg = agnxtsubg(sg)) {
487 dfs(sg, parentg, G_lp, G_bb);
488 }
489 }
490}
491
492/* nop_init_graphs:
493 * Read in clusters and graph label info.
494 * A subgraph is a cluster if its name starts with "cluster" and
495 * it has a valid bb.
496 */
497static void
499{
500 graph_t *subg;
501 char *s;
502 double x, y;
503
504 if (GD_label(g) && G_lp) {
505 s = agxget(g, G_lp);
506 if (sscanf(s, "%lf,%lf", &x, &y) == 2) {
507 GD_label(g)->pos = (pointf){x, y};
508 GD_label(g)->set = true;
509 }
510 }
511
512 if (!G_bb)
513 return;
514 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
515 dfs(subg, g, G_lp, G_bb);
516 }
517}
518
519/* init_nop:
520 * This assumes all nodes have been positioned.
521 * It also assumes none of the relevant fields in A*info_t have been set.
522 * The input may provide additional position information for
523 * clusters, edges and labels. If certain position information
524 * is missing, init_nop will use a standard neato technique to
525 * supply it.
526 *
527 * If adjust is false, init_nop does nothing but initialize all
528 * of the basic graph information. No tweaking of positions or
529 * filling in edge splines is done.
530 *
531 * Returns 0 on normal success, 1 if layout has a background, and -1
532 * on failure.
533 */
535{
536 int i;
537 node_t *np;
538 pos_edge posEdges; /* How many edges have spline info */
539 attrsym_t *G_lp = agfindgraphattr(g, "lp");
540 attrsym_t *G_bb = agfindgraphattr(g, "bb");
541 int didAdjust = 0; /* Have nodes been moved? */
542 int haveBackground;
543 bool translate = !mapbool(agget(g, "notranslate"));
544
545 /* If G_bb not defined, define it */
546 if (!G_bb)
547 G_bb = agattr(g, AGRAPH, "bb", "");
548
549 scan_graph(g); /* mainly to set up GD_neato_nlist */
550 for (i = 0; (np = GD_neato_nlist(g)[i]); i++) {
551 if (!hasPos(np) && !startswith(agnameof(np), "cluster")) {
552 agerrorf("node %s in graph %s has no position\n",
553 agnameof(np), agnameof(g));
554 return -1;
555 }
556 if (ND_xlabel(np))
557 set_label(np, ND_xlabel(np), "xlp");
558 }
559 nop_init_graphs(g, G_lp, G_bb);
560 posEdges = nop_init_edges(g);
561
562 if (GD_drawing(g)->xdots) {
563 haveBackground = 1;
564 GD_drawing(g)->ratio_kind = R_NONE; /* Turn off any aspect change if background present */
565 }
566 else
567 haveBackground = 0;
568
569 if (adjust && Nop == 1 && !haveBackground)
570 didAdjust = adjustNodes(g);
571
572 if (didAdjust) {
573 if (GD_label(g)) GD_label(g)->set = false;
574/* FIX:
575 * - if nodes are moved, clusters are no longer valid.
576 */
577 }
578
579 compute_bb(g);
580
581 /* Adjust bounding box for any background */
582 if (haveBackground)
583 GD_bb(g) = xdotBB (g);
584
585 /* At this point, all bounding boxes should be correctly defined.
586 */
587
588 if (!adjust) {
589 node_t *n;
591 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
592 ND_coord(n).x = POINTS_PER_INCH * ND_pos(n)[0];
593 ND_coord(n).y = POINTS_PER_INCH * ND_pos(n)[1];
594 }
595 }
596 else {
597 bool didShift;
598 if (translate && !haveBackground && (GD_bb(g).LL.x != 0||GD_bb(g).LL.y != 0))
599 neato_translate (g);
600 didShift = neato_set_aspect(g);
601 /* if we have some edge positions and we either shifted or adjusted, free edge positions */
602 if (posEdges != NoEdges && (didShift || didAdjust)) {
603 freeEdgeInfo (g);
604 posEdges = NoEdges;
605 }
606 if (posEdges != AllEdges)
607 spline_edges0(g, false); /* add edges */
608 else
610 }
611
612 return haveBackground;
613}
614
615static void neato_init_graph (Agraph_t * g)
616{
617 int outdim;
618
620 outdim = late_int(g, agfindgraphattr(g, "dimen"), 2, 2);
621 GD_ndim(agroot(g)) = late_int(g, agfindgraphattr(g, "dim"), outdim, 2);
622 Ndim = GD_ndim(g->root) = MIN(GD_ndim(g->root), MAXDIM);
623 GD_odim(g->root) = MIN(outdim, Ndim);
625}
626
627static int neatoModel(graph_t * g)
628{
629 char *p = agget(g, "model");
630
631 if (!p || streq(p, "")) /* if p is NULL or "" */
632 return MODEL_SHORTPATH;
633 if (streq(p, "circuit"))
634 return MODEL_CIRCUIT;
635 if (streq(p, "subset"))
636 return MODEL_SUBSET;
637 if (streq(p, "shortpath"))
638 return MODEL_SHORTPATH;
639 if (streq(p, "mds")) {
640 if (agattr(g, AGEDGE, "len", 0))
641 return MODEL_MDS;
642 else {
644 "edges in graph %s have no len attribute. Hence, the mds model\n", agnameof(g));
645 agerr(AGPREV, "is inappropriate. Reverting to the shortest path model.\n");
646 return MODEL_SHORTPATH;
647 }
648 }
650 "Unknown value %s for attribute \"model\" in graph %s - ignored\n",
651 p, agnameof(g));
652 return MODEL_SHORTPATH;
653}
654
655/* neatoMode:
656 */
657static int neatoMode(graph_t * g)
658{
659 char *str;
660 int mode = MODE_MAJOR; /* default mode */
661
662 str = agget(g, "mode");
663 if (str && !streq(str, "")) {
664 if (streq(str, "KK"))
665 mode = MODE_KK;
666 else if (streq(str, "major"))
668 else if (streq(str, "sgd"))
669 mode = MODE_SGD;
670#ifdef DIGCOLA
671 else if (streq(str, "hier"))
672 mode = MODE_HIER;
673#ifdef IPSEPCOLA
674 else if (streq(str, "ipsep"))
676#endif
677#endif
678 else
680 "Illegal value %s for attribute \"mode\" in graph %s - ignored\n",
681 str, agnameof(g));
682 }
683
684 return mode;
685}
686
687/* checkEdge:
688 *
689 */
690static int checkEdge(PointMap * pm, edge_t * ep, int idx)
691{
692 int i = ND_id(agtail(ep));
693 int j = ND_id(aghead(ep));
694 int tmp;
695
696 if (i > j) {
697 tmp = i;
698 i = j;
699 j = tmp;
700 }
701 return insertPM(pm, i, j, idx);
702}
703
704#ifdef DIGCOLA
705/* dfsCycle:
706 * dfs for breaking cycles in vtxdata
707 */
708static void
709dfsCycle (vtx_data* graph, int i,int mode, node_t* nodes[])
710{
711 node_t *np, *hp;
712 int j;
713 /* if mode is IPSEP make it an in-edge
714 * at both ends, so that an edge constraint won't be generated!
715 */
716 double x = mode==MODE_IPSEP?-1.0:1.0;
717
718 np = nodes[i];
719 ND_mark(np) = true;
720 ND_onstack(np) = true;
721 for (size_t e = 1; e < graph[i].nedges; e++) {
722 if (graph[i].edists[e] == 1.0) continue; /* in edge */
723 j = graph[i].edges[e];
724 hp = nodes[j];
725 if (ND_onstack(hp)) { /* back edge: reverse it */
726 graph[i].edists[e] = x;
727 size_t f;
728 for (f = 1; f < graph[j].nedges && graph[j].edges[f] != i; f++) ;
729 assert (f < graph[j].nedges);
730 graph[j].edists[f] = -1.0;
731 }
732 else if (!ND_mark(hp)) dfsCycle(graph, j, mode, nodes);
733
734 }
735 ND_onstack(np) = false;
736}
737
738/* acyclic:
739 * Do a dfs of the vtx_data, looking for cycles, reversing edges.
740 */
741static void
742acyclic (vtx_data* graph, int nv, int mode, node_t* nodes[])
743{
744 int i;
745 node_t* np;
746
747 for (i = 0; i < nv; i++) {
748 np = nodes[i];
749 ND_mark(np) = false;
750 ND_onstack(np) = false;
751 }
752 for (i = 0; i < nv; i++) {
753 if (ND_mark(nodes[i])) continue;
754 dfsCycle (graph, i, mode, nodes);
755 }
756
757}
758#endif
759
760/* makeGraphData:
761 * Create sparse graph representation via arrays.
762 * Each node is represented by a vtx_data.
763 * The index of each neighbor is stored in the edges array;
764 * the corresponding edge lengths and weights go on ewgts and eweights.
765 * We do not allocate the latter 2 if the graph does not use them.
766 * By convention, graph[i].edges[0] == i.
767 * The values graph[i].ewgts[0] and graph[i].eweights[0] are left undefined.
768 *
769 * In constructing graph from g, we neglect loops. We track multiedges (ignoring
770 * direction). Edge weights are additive; the final edge length is the max.
771 *
772 * If direction is used, we set the edists field, -1 for tail, +1 for head.
773 * graph[i].edists[0] is left undefined. If multiedges exist, the direction
774 * of the first one encountered is used. Finally, a pass is made to guarantee
775 * the graph is acyclic.
776 *
777 */
778static vtx_data *makeGraphData(graph_t * g, int nv, int *nedges, int mode, int model, node_t*** nodedata)
779{
780 int ne = agnedges(g); /* upper bound */
781 float *ewgts = NULL;
782 node_t *np;
783 edge_t *ep;
784 float *eweights = NULL;
785#ifdef DIGCOLA
786 float *edists = NULL;
787#endif
788 PointMap *ps = newPM();
789 int i, idx;
790
791 /* lengths and weights unused in reweight model */
792 bool haveLen = false;
793 bool haveWt = false;
794 if (model != MODEL_SUBSET) {
795 haveLen = agattr(g, AGEDGE, "len", 0) != NULL;
796 haveWt = E_weight != 0;
797 }
798 bool haveDir = mode == MODE_HIER || mode == MODE_IPSEP;
799
800 vtx_data *graph = gv_calloc(nv, sizeof(vtx_data));
801 node_t** nodes = gv_calloc(nv, sizeof(node_t*));
802 const size_t edges_size = (size_t)(2 * ne + nv);
803 int *edges = gv_calloc(edges_size, sizeof(int)); // reserve space for self loops
804 if (haveLen || haveDir)
805 ewgts = gv_calloc(edges_size, sizeof(float));
806 if (haveWt)
807 eweights = gv_calloc(edges_size, sizeof(float));
808#ifdef DIGCOLA
809 if (haveDir)
810 edists = gv_calloc(edges_size, sizeof(float));
811#endif
812
813 i = 0;
814 ne = 0;
815 for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
816 int j = 1; /* index of neighbors */
817 clearPM(ps);
818 assert(ND_id(np) == i);
819 nodes[i] = np;
820 graph[i].edges = edges++; /* reserve space for the self loop */
821 if (haveLen || haveDir)
822 graph[i].ewgts = ewgts++;
823 else
824 graph[i].ewgts = NULL;
825 if (haveWt)
826 graph[i].eweights = eweights++;
827 else
828 graph[i].eweights = NULL;
829#ifdef DIGCOLA
830 if (haveDir) {
831 graph[i].edists = edists++;
832 }
833 else
834 graph[i].edists = NULL;
835#endif
836 size_t i_nedges = 1; // one for the self
837
838 for (ep = agfstedge(g, np); ep; ep = agnxtedge(g, ep, np)) {
839 if (aghead(ep) == agtail(ep))
840 continue; /* ignore loops */
841 idx = checkEdge(ps, ep, j);
842 if (idx != j) { /* seen before */
843 if (haveWt)
844 graph[i].eweights[idx] += ED_factor(ep);
845 if (haveLen) {
846 graph[i].ewgts[idx] = fmax(graph[i].ewgts[idx], ED_dist(ep));
847 }
848 } else {
849 node_t *vp = agtail(ep) == np ? aghead(ep) : agtail(ep);
850 ne++;
851 j++;
852
853 *edges++ = ND_id(vp);
854 if (haveWt)
855 *eweights++ = ED_factor(ep);
856 if (haveLen)
857 *ewgts++ = ED_dist(ep);
858 else if (haveDir)
859 *ewgts++ = 1.0;
860#ifdef DIGCOLA
861 if (haveDir) {
862 char *s = agget(ep,"dir");
863 if(s && startswith(s, "none")) {
864 *edists++ = 0;
865 } else {
866 *edists++ = np == aghead(ep) ? 1.0 : -1.0;
867 }
868 }
869#endif
870 i_nedges++;
871 }
872 }
873
874 graph[i].nedges = i_nedges;
875 graph[i].edges[0] = i;
876 i++;
877 }
878#ifdef DIGCOLA
879 if (haveDir) {
880 /* Make graph acyclic */
881 acyclic (graph, nv, mode, nodes);
882 }
883#endif
884
885 ne /= 2; /* every edge is counted twice */
886
887 /* If necessary, release extra memory. */
888 if (ne != agnedges(g)) {
889 edges = gv_recalloc(graph[0].edges, edges_size, 2 * ne + nv, sizeof(int));
890 if (haveLen)
891 ewgts = gv_recalloc(graph[0].ewgts, edges_size, 2 * ne + nv, sizeof(float));
892 if (haveWt)
893 eweights = gv_recalloc(graph[0].eweights, edges_size, 2 * ne + nv, sizeof(float));
894
895 for (i = 0; i < nv; i++) {
896 const size_t sz = graph[i].nedges;
897 graph[i].edges = edges;
898 edges += sz;
899 if (haveLen) {
900 graph[i].ewgts = ewgts;
901 ewgts += sz;
902 }
903 if (haveWt) {
904 graph[i].eweights = eweights;
905 eweights += sz;
906 }
907 }
908 }
909
910 *nedges = ne;
911 if (nodedata)
912 *nodedata = nodes;
913 else
914 free (nodes);
915 freePM(ps);
916 return graph;
917}
918
919static void initRegular(graph_t * G, int nG)
920{
921 double a, da;
922 node_t *np;
923
924 a = 0.0;
925 da = 2 * M_PI / nG;
926 for (np = agfstnode(G); np; np = agnxtnode(G, np)) {
927 ND_pos(np)[0] = nG * Spring_coeff * cos(a);
928 ND_pos(np)[1] = nG * Spring_coeff * sin(a);
929 ND_pinned(np) = P_SET;
930 a = a + da;
931 if (Ndim > 2)
932 jitter3d(np, nG);
933 }
934}
935
936#define SLEN(s) (sizeof(s)-1)
937#define SMART "self"
938#define REGULAR "regular"
939#define RANDOM "random"
940
941/* setSeed:
942 * Analyze "start" attribute. If unset, return dflt.
943 * If it begins with self, regular, or random, return set init to same,
944 * else set init to dflt.
945 * If init is random, look for value integer suffix to use a seed; if not
946 * found, use time to set seed and store seed in graph.
947 * Return seed in seedp.
948 * Return init.
949 */
950int
951setSeed (graph_t * G, int dflt, long* seedp)
952{
953 char smallbuf[32];
954 char *p = agget(G, "start");
955 int init = dflt;
956
957 if (!p || *p == '\0') return dflt;
958 if (gv_isalpha(*p)) {
959 if (startswith(p, SMART)) {
960 init = INIT_SELF;
961 p += SLEN(SMART);
962 } else if (startswith(p, REGULAR)) {
964 p += SLEN(REGULAR);
965 } else if (startswith(p, RANDOM)) {
967 p += SLEN(RANDOM);
968 }
969 else init = dflt;
970 }
971 else if (gv_isdigit(*p)) {
973 }
974
975 if (init == INIT_RANDOM) {
976 long seed;
977 /* Check for seed value */
978 if (!gv_isdigit(*p) || sscanf(p, "%ld", &seed) < 1) {
979#if defined(_WIN32)
980 seed = (unsigned) time(NULL);
981#else
982 seed = (unsigned) getpid() ^ (unsigned) time(NULL);
983#endif
984 snprintf(smallbuf, sizeof(smallbuf), "%ld", seed);
985 agset(G, "start", smallbuf);
986 }
987 *seedp = seed;
988 }
989 return init;
990}
991
992/* checkExp:
993 * Allow various weights for the scale factor in used to calculate stress.
994 * At present, only 1 or 2 are allowed, with 2 the default.
995 */
996#define exp_name "stresswt"
997
998static int checkExp (graph_t * G)
999{
1000 int exp = late_int(G, agfindgraphattr(G, exp_name), 2, 0);
1001 if (exp == 0 || exp > 2) {
1002 agwarningf("%s attribute value must be 1 or 2 - ignoring\n", exp_name);
1003 exp = 2;
1004 }
1005 return exp;
1006}
1007
1008/* checkStart:
1009 * Analyzes start attribute, setting seed.
1010 * If set,
1011 * If start is regular, places nodes and returns INIT_REGULAR.
1012 * If start is self, returns INIT_SELF.
1013 * If start is random, returns INIT_RANDOM
1014 * Set RNG seed
1015 * else return default
1016 *
1017 */
1018int checkStart(graph_t * G, int nG, int dflt)
1019{
1020 long seed;
1021 int init;
1022
1023 seed = 1;
1024 init = setSeed (G, dflt, &seed);
1025 if (N_pos && init != INIT_RANDOM) {
1026 agwarningf("node positions are ignored unless start=random\n");
1027 }
1028 if (init == INIT_REGULAR) initRegular(G, nG);
1029 srand48(seed);
1030 return init;
1031}
1032
1033#ifdef DEBUG_COLA
1034void dumpData(graph_t * g, vtx_data * gp, int nv, int ne)
1035{
1036 node_t *v;
1037 int i;
1038
1039 fprintf(stderr, "#nodes %d #edges %d\n", nv, ne);
1040 for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
1041 fprintf(stderr, "\"%s\" %d\n", agnameof(v), ND_id(v));
1042 }
1043 for (i = 0; i < nv; i++) {
1044 const size_t n = gp[i].nedges;
1045 fprintf(stderr, "[%d] %" PRISIZE_T "\n", i, n);
1046 for (size_t j = 0; j < n; j++) {
1047 fprintf(stderr, " %3d", gp[i].edges[j]);
1048 }
1049 fputs("\n", stderr);
1050 if (gp[i].ewgts) {
1051 fputs(" ewgts", stderr);
1052 for (size_t j = 0; j < n; j++) {
1053 fprintf(stderr, " %3f", gp[i].ewgts[j]);
1054 }
1055 fputs("\n", stderr);
1056 }
1057 if (gp[i].eweights) {
1058 fputs(" eweights", stderr);
1059 for (size_t j = 0; j < n; j++) {
1060 fprintf(stderr, " %3f", gp[i].eweights[j]);
1061 }
1062 fputs("\n", stderr);
1063 }
1064 if (gp[i].edists) {
1065 fputs(" edists", stderr);
1066 for (size_t j = 0; j < n; j++) {
1067 fprintf(stderr, " %3f", gp[i].edists[j]);
1068 }
1069 fputs("\n", stderr);
1070 }
1071 fputs("\n", stderr);
1072
1073 }
1074}
1075void dumpClusterData (cluster_data* dp)
1076{
1077 int i, j, sz;
1078
1079 fprintf (stderr, "nvars %d nclusters %d ntoplevel %d\n", dp->nvars, dp->nclusters, dp->ntoplevel);
1080 fprintf (stderr, "Clusters:\n");
1081 for (i = 0; i < dp->nclusters; i++) {
1082 sz = dp->clustersizes[i];
1083 fprintf (stderr, " [%d] %d vars\n", i, sz);
1084 for (j = 0; j < sz; j++)
1085 fprintf (stderr, " %d", dp->clusters[i][j]);
1086 fprintf (stderr, "\n");
1087 }
1088
1089
1090 fprintf (stderr, "Toplevel:\n");
1091 for (i = 0; i < dp->ntoplevel; i++)
1092 fprintf (stderr, " %d\n", dp->toplevel[i]);
1093
1094 fprintf (stderr, "Boxes:\n");
1095 for (i = 0; i < dp->nclusters; i++) {
1096 boxf bb = dp->bb[i];
1097 fprintf (stderr, " (%f,%f) (%f,%f)\n", bb.LL.x, bb.LL.y, bb.UR.x, bb.UR.y);
1098 }
1099}
1100void dumpOpts (ipsep_options* opp, int nv)
1101{
1102 int i;
1103
1104 fprintf (stderr, "diredges %d edge_gap %f noverlap %d gap (%f,%f)\n", opp->diredges, opp->edge_gap, opp->noverlap, opp->gap.x, opp->gap.y);
1105 for (i = 0; i < nv; i++)
1106 fprintf (stderr, " (%f,%f)\n", opp->nsize[i].x, opp->nsize[i].y);
1107 if (opp->clusters)
1108 dumpClusterData (opp->clusters);
1109}
1110#endif
1111
1112/* majorization:
1113 * Solve stress using majorization.
1114 * Old neato attributes to incorporate:
1115 * weight
1116 * mode will be MODE_MAJOR, MODE_HIER or MODE_IPSEP
1117 */
1118static void
1119majorization(graph_t *mg, graph_t * g, int nv, int mode, int model, int dim, adjust_data* am)
1120{
1121 int ne;
1122 int rv = 0;
1123 node_t *v;
1124 vtx_data *gp;
1125 node_t** nodes;
1126#ifdef DIGCOLA
1127#ifdef IPSEPCOLA
1128 expand_t margin;
1129#endif
1130#endif
1131 int init = checkStart(g, nv, mode == MODE_HIER ? INIT_SELF : INIT_RANDOM);
1132 int opts = checkExp (g);
1133
1134 if (init == INIT_SELF)
1136
1137 double **coords = gv_calloc(dim, sizeof(double *));
1138 coords[0] = gv_calloc(nv * dim, sizeof(double));
1139 for (int i = 1; i < Ndim; i++) {
1140 coords[i] = coords[0] + i * nv;
1141 }
1142 if (Verbose) {
1143 fprintf(stderr, "model %d smart_init %d stresswt %d iterations %d tol %f\n",
1145 fprintf(stderr, "convert graph: ");
1146 start_timer();
1147 fprintf(stderr, "majorization\n");
1148 }
1149 gp = makeGraphData(g, nv, &ne, mode, model, &nodes);
1150
1151 if (Verbose) {
1152 fprintf(stderr, "%d nodes %.2f sec\n", nv, elapsed_sec());
1153 }
1154
1155#ifdef DIGCOLA
1156 if (mode != MODE_MAJOR) {
1157 double lgap = late_double(g, agfindgraphattr(g, "levelsgap"), 0.0, -DBL_MAX);
1158 if (mode == MODE_HIER) {
1159 rv = stress_majorization_with_hierarchy(gp, nv, coords, nodes, Ndim,
1160 opts, model, MaxIter, lgap);
1161 }
1162#ifdef IPSEPCOLA
1163 else {
1164 char* str;
1165 ipsep_options opt;
1166 cluster_data cs = cluster_map(mg,g);
1167 pointf *nsize = gv_calloc(nv, sizeof(pointf));
1168 opt.edge_gap = lgap;
1169 opt.nsize = nsize;
1170 opt.clusters = cs;
1171 str = agget(g, "diredgeconstraints");
1172 if (mapbool(str)) {
1173 opt.diredges = 1;
1174 if(Verbose)
1175 fprintf(stderr,"Generating Edge Constraints...\n");
1176 } else if (str && !strncasecmp(str,"hier",4)) {
1177 opt.diredges = 2;
1178 if(Verbose)
1179 fprintf(stderr,"Generating DiG-CoLa Edge Constraints...\n");
1180 }
1181 else opt.diredges = 0;
1182 if (am->mode == AM_IPSEP) {
1183 opt.noverlap = 1;
1184 if(Verbose)
1185 fprintf(stderr,"Generating Non-overlap Constraints...\n");
1186 } else if (am->mode == AM_VPSC) {
1187 opt.noverlap = 2;
1188 if(Verbose)
1189 fprintf(stderr,"Removing overlaps as postprocess...\n");
1190 }
1191 else opt.noverlap = 0;
1192 margin = sepFactor (g);
1193 /* Multiply by 2 since opt.gap is the gap size, not the margin */
1194 if (margin.doAdd) {
1195 opt.gap.x = 2.0*PS2INCH(margin.x);
1196 opt.gap.y = 2.0*PS2INCH(margin.y);
1197 }
1198 else opt.gap.x = opt.gap.y = 2.0*PS2INCH(DFLT_MARGIN);
1199 if(Verbose)
1200 fprintf(stderr,"gap=%f,%f\n",opt.gap.x,opt.gap.y);
1201 {
1202 size_t i = 0;
1203 for (v = agfstnode(g); v; v = agnxtnode(g, v),i++) {
1204 nsize[i].x = ND_width(v);
1205 nsize[i].y = ND_height(v);
1206 }
1207 }
1208
1209#ifdef DEBUG_COLA
1210 fprintf (stderr, "nv %d ne %d Ndim %d model %d MaxIter %d\n", nv, ne, Ndim, model, MaxIter);
1211 fprintf (stderr, "Nodes:\n");
1212 for (int i = 0; i < nv; i++) {
1213 fprintf (stderr, " %s (%f,%f)\n", nodes[i]->name, coords[0][i], coords[1][i]);
1214 }
1215 fprintf (stderr, "\n");
1216 dumpData(g, gp, nv, ne);
1217 fprintf (stderr, "\n");
1218 dumpOpts (&opt, nv);
1219#endif
1220 rv = stress_majorization_cola(gp, nv, coords, nodes, Ndim, model, MaxIter, &opt);
1221 freeClusterData(cs);
1222 free (nsize);
1223 }
1224#endif
1225 }
1226 else
1227#endif
1228 rv = stress_majorization_kD_mkernel(gp, nv, coords, nodes, Ndim, opts, model, MaxIter);
1229
1230 if (rv < 0) {
1231 agerr(AGPREV, "layout aborted\n");
1232 }
1233 else for (v = agfstnode(g); v; v = agnxtnode(g, v)) { /* store positions back in nodes */
1234 int idx = ND_id(v);
1235 for (int i = 0; i < Ndim; i++) {
1236 ND_pos(v)[i] = coords[i][idx];
1237 }
1238 }
1239 freeGraphData(gp);
1240 free(coords[0]);
1241 free(coords);
1242 free(nodes);
1243}
1244
1245static void subset_model(Agraph_t * G, int nG)
1246{
1247 int i, j, ne;
1248 vtx_data *gp;
1249
1250 gp = makeGraphData(G, nG, &ne, MODE_KK, MODEL_SUBSET, NULL);
1252 for (i = 0; i < nG; i++) {
1253 for (j = 0; j < nG; j++) {
1254 GD_dist(G)[i][j] = Dij[i][j];
1255 }
1256 }
1257 free(Dij[0]);
1258 free(Dij);
1259 freeGraphData(gp);
1260}
1261
1262/* mds_model:
1263 * Assume the matrix already contains shortest path values.
1264 * Use the actual lengths provided the input for edges.
1265 */
1266static void mds_model(graph_t * g)
1267{
1268 long i, j;
1269 node_t *v;
1270 edge_t *e;
1271
1272 for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
1273 for (e = agfstout(g, v); e; e = agnxtout(g, e)) {
1274 i = AGSEQ(agtail(e));
1275 j = AGSEQ(aghead(e));
1276 if (i == j)
1277 continue;
1278 GD_dist(g)[i][j] = GD_dist(g)[j][i] = ED_dist(e);
1279 }
1280 }
1281}
1282
1283/* kkNeato:
1284 * Solve using gradient descent a la Kamada-Kawai.
1285 */
1286static void kkNeato(Agraph_t * g, int nG, int model)
1287{
1288 if (model == MODEL_SUBSET) {
1289 subset_model(g, nG);
1290 } else if (model == MODEL_CIRCUIT) {
1291 if (!circuit_model(g, nG)) {
1292 agwarningf(
1293 "graph %s is disconnected. Hence, the circuit model\n",
1294 agnameof(g));
1295 agerr(AGPREV,
1296 "is undefined. Reverting to the shortest path model.\n");
1297 agerr(AGPREV,
1298 "Alternatively, consider running neato using -Gpack=true or decomposing\n");
1299 agerr(AGPREV, "the graph into connected components.\n");
1300 shortest_path(g, nG);
1301 }
1302 } else if (model == MODEL_MDS) {
1303 shortest_path(g, nG);
1304 mds_model(g);
1305 } else
1306 shortest_path(g, nG);
1307 initial_positions(g, nG);
1308 diffeq_model(g, nG);
1309 if (Verbose) {
1310 fprintf(stderr, "Solving model %d iterations %d tol %f\n",
1311 model, MaxIter, Epsilon);
1312 start_timer();
1313 }
1314 solve_model(g, nG);
1315}
1316
1317/* neatoLayout:
1318 * Use stress optimization to layout a single component
1319 */
1320static void
1321neatoLayout(Agraph_t * mg, Agraph_t * g, int layoutMode, int layoutModel,
1322 adjust_data* am)
1323{
1324 int nG;
1325 char *str;
1326
1327 if ((str = agget(g, "maxiter")))
1328 MaxIter = atoi(str);
1329 else if (layoutMode == MODE_MAJOR)
1331 else if (layoutMode == MODE_SGD)
1332 MaxIter = 30;
1333 else
1334 MaxIter = 100 * agnnodes(g);
1335
1336 nG = scan_graph_mode(g, layoutMode);
1337 if (nG < 2 || MaxIter < 0)
1338 return;
1339 if (layoutMode == MODE_KK)
1340 kkNeato(g, nG, layoutModel);
1341 else if (layoutMode == MODE_SGD)
1342 sgd(g, layoutModel);
1343 else
1344 majorization(mg, g, nG, layoutMode, layoutModel, Ndim, am);
1345}
1346
1347/* addZ;
1348 * If dimension == 3 and z attribute is declared,
1349 * attach z value to nodes if not defined.
1350 */
1351static void addZ (Agraph_t* g)
1352{
1353 node_t* n;
1354 char buf[BUFSIZ];
1355
1356 if (Ndim >= 3 && N_z) {
1357 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
1358 snprintf(buf, sizeof(buf), "%lf", POINTS_PER_INCH * ND_pos(n)[2]);
1359 agxset(n, N_z, buf);
1360 }
1361 }
1362}
1363
1364#ifdef IPSEPCOLA
1365static void
1366addCluster (graph_t* g)
1367{
1368 graph_t *subg;
1369 for (subg = agfstsubg(agroot(g)); subg; subg = agnxtsubg(subg)) {
1370 if (startswith(agnameof(subg), "cluster")) {
1371 agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), true);
1372 add_cluster(g, subg);
1373 compute_bb(subg);
1374 }
1375 }
1376}
1377#endif
1378
1379/* doEdges:
1380 * Simple wrapper to compute graph's bb, then route edges after
1381 * a possible aspect ratio adjustment.
1382 */
1383static void doEdges(Agraph_t* g)
1384{
1385 compute_bb(g);
1386 spline_edges0(g, true);
1387}
1388
1389/* neato_layout:
1390 */
1392{
1393 int layoutMode;
1394 int model;
1396 pack_info pinfo;
1397 adjust_data am;
1398 double save_scale = PSinputscale;
1399
1400 if (Nop) {
1401 int ret;
1404 addZ (g);
1405 ret = init_nop(g, 1);
1406 if (ret < 0) {
1407 agerr(AGPREV, "as required by the -n flag\n");
1408 return;
1409 }
1410 else gv_postprocess(g, 0);
1411 } else {
1412 bool noTranslate = mapbool(agget(g, "notranslate"));
1415 layoutMode = neatoMode(g);
1416 graphAdjustMode (g, &am, 0);
1417 model = neatoModel(g);
1418 mode = getPackModeInfo (g, l_undef, &pinfo);
1419 Pack = getPack(g, -1, CL_OFFSET);
1420 /* pack if just packmode defined. */
1421 if (mode == l_undef) {
1422 /* If the user has not indicated packing but we are
1423 * using the new neato, turn packing on.
1424 */
1425 if (Pack < 0 && layoutMode)
1426 Pack = CL_OFFSET;
1427 pinfo.mode = l_node;
1428 } else if (Pack < 0)
1429 Pack = CL_OFFSET;
1430 if (Pack >= 0) {
1431 graph_t *gc;
1432 graph_t **cc;
1433 size_t n_cc;
1434 bool pin;
1435
1436 cc = pccomps(g, &n_cc, cc_pfx, &pin);
1437
1438 if (n_cc > 1) {
1439 bool *bp;
1440 for (size_t i = 0; i < n_cc; i++) {
1441 gc = cc[i];
1442 (void)graphviz_node_induce(gc, NULL);
1443 neatoLayout(g, gc, layoutMode, model, &am);
1444 removeOverlapWith(gc, &am);
1446 if (noTranslate) doEdges(gc);
1447 else spline_edges(gc);
1448 }
1449 if (pin) {
1450 bp = gv_calloc(n_cc, sizeof(bool));
1451 bp[0] = true;
1452 } else
1453 bp = NULL;
1454 pinfo.margin = (unsigned)Pack;
1455 pinfo.fixed = bp;
1456 pinfo.doSplines = true;
1457 packGraphs(n_cc, cc, g, &pinfo);
1458 free(bp);
1459 }
1460 else {
1461 neatoLayout(g, g, layoutMode, model, &am);
1462 removeOverlapWith(g, &am);
1463 if (noTranslate) doEdges(g);
1464 else spline_edges(g);
1465 }
1466 compute_bb(g);
1467 addZ (g);
1468
1469 /* cleanup and remove component subgraphs */
1470 for (size_t i = 0; i < n_cc; i++) {
1471 gc = cc[i];
1472 free_scan_graph(gc);
1473 agdelrec (gc, "Agraphinfo_t");
1474 agdelete(g, gc);
1475 }
1476 free (cc);
1477#ifdef IPSEPCOLA
1478 addCluster (g);
1479#endif
1480 } else {
1481 neatoLayout(g, g, layoutMode, model, &am);
1482 removeOverlapWith(g, &am);
1483 addZ (g);
1484 if (noTranslate) doEdges(g);
1485 else spline_edges(g);
1486 }
1487 gv_postprocess(g, !noTranslate);
1488 }
1489 PSinputscale = save_scale;
1490}
1491
expand_t sepFactor(graph_t *g)
Definition adjust.c:1074
int adjustNodes(graph_t *G)
Definition adjust.c:1027
void graphAdjustMode(graph_t *G, adjust_data *dp, char *dflt)
Definition adjust.c:885
int removeOverlapWith(graph_t *G, adjust_data *am)
Definition adjust.c:921
#define DFLT_MARGIN
Definition adjust.h:21
@ AM_VPSC
Definition adjust.h:28
@ AM_IPSEP
Definition adjust.h:28
Memory allocation wrappers that exit on failure.
static void * gv_recalloc(void *ptr, size_t old_nmemb, size_t new_nmemb, size_t size)
Definition alloc.h:73
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define Epsilon
Definition arcball.h:210
#define MIN(a, b)
Definition arith.h:28
#define M_PI
Definition arith.h:41
void arrow_flags(Agedge_t *e, uint32_t *sflag, uint32_t *eflag)
Definition arrows.c:217
API for compacted arrays of booleans.
static bitarray_t bitarray_new(size_t size_bits)
create an array of the given element length
Definition bitarray.h:47
static bool bitarray_get(bitarray_t self, size_t index)
get the value of the given element
Definition bitarray.h:65
static void bitarray_set(bitarray_t *self, size_t index, bool value)
set or clear the value of the given element
Definition bitarray.h:80
static void bitarray_reset(bitarray_t *self)
free underlying resources and leave a bit array empty
Definition bitarray.h:99
abstract graph C library, Cgraph API
int circuit_model(graph_t *g, int nG)
Definition circuit.c:38
static int doEdges
Definition ccomps.c:74
bool mapbool(const char *p)
Definition utils.c:336
void setEdgeType(graph_t *g, int defaultValue)
Definition utils.c:1443
int late_int(void *obj, attrsym_t *attr, int defaultValue, int minimum)
Definition utils.c:33
void common_init_node(node_t *n)
Definition utils.c:422
double late_double(void *obj, attrsym_t *attr, double defaultValue, double minimum)
Definition utils.c:48
void common_init_edge(edge_t *e)
Definition utils.c:505
double get_inputscale(graph_t *g)
Definition utils.c:71
void compute_bb(graph_t *g)
Definition utils.c:629
void gv_nodesize(node_t *n, bool flip)
Definition utils.c:1556
#define P_PIN
Definition const.h:263
#define P_SET
Definition const.h:261
#define CL_OFFSET
Definition const.h:151
#define MAXDIM
Definition const.h:169
#define EDGETYPE_LINE
Definition const.h:249
#define Spring_coeff
Definition const.h:167
#define GVSPLINES
Definition const.h:173
mode
Definition cvtgxl.c:33
void freeGraphData(vtx_data *graph)
Definition delaunay.c:861
static void init(int argc, char *argv[], double *angle, double *accuracy, int *check_edges_with_same_endpoint, int *seed, char **color_scheme, int *lightness)
static char adjust[]
Definition emit.c:2792
boxf xdotBB(Agraph_t *g)
Definition emit.c:2857
static long seed
Definition exeval.c:1035
#define G
Definition gdefs.h:7
#define PS2INCH(a_points)
Definition geom.h:70
struct pointf_s pointf
#define POINTS_PER_INCH
Definition geom.h:64
Agsym_t * E_weight
Definition globals.h:91
int State
Definition globals.h:65
int MaxIter
Definition globals.h:63
int Nop
Definition globals.h:57
Agsym_t * N_z
Definition globals.h:88
double PSinputscale
Definition globals.h:58
unsigned short Ndim
Definition globals.h:64
static int Verbose
Definition gml2gv.c:22
void free(void *)
node NULL
Definition grammar.y:149
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:199
int agnedges(Agraph_t *g)
Definition graph.c:164
int agnnodes(Agraph_t *g)
Definition graph.c:158
size_t graphviz_node_induce(Agraph_t *g, Agraph_t *edgeset)
Definition node_induce.c:9
Agsym_t * agattr(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up attributes of a graph
Definition attr.c:341
int agset(void *obj, char *name, const char *value)
Definition attr.c:469
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:481
char * agget(void *obj, char *name)
Definition attr.c:442
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:458
#define ED_dist(e)
Definition types.h:602
#define ED_xlabel(e)
Definition types.h:590
#define ED_head_label(e)
Definition types.h:587
#define agfindedgeattr(g, a)
Definition types.h:617
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:23
#define agtail(e)
Definition cgraph.h:889
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:93
#define ED_tail_label(e)
Definition types.h:596
#define ED_factor(e)
Definition types.h:585
#define aghead(e)
Definition cgraph.h:890
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:38
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:84
#define ED_label(e)
Definition types.h:589
void agwarningf(const char *fmt,...)
Definition agerror.c:173
void agerrorf(const char *fmt,...)
Definition agerror.c:165
int agerr(agerrlevel_t level, const char *fmt,...)
Definition agerror.c:155
@ AGPREV
Definition cgraph.h:858
#define agfindgraphattr(g, a)
Definition types.h:613
#define GD_drawing(g)
Definition types.h:353
#define GD_clust(g)
Definition types.h:360
#define GD_bb(g)
Definition types.h:354
#define GD_n_cluster(g)
Definition types.h:389
#define GD_ndim(g)
Definition types.h:390
#define GD_label(g)
Definition types.h:374
#define GD_dist(g)
Definition types.h:357
#define GD_flip(g)
Definition types.h:378
#define GD_neato_nlist(g)
Definition types.h:392
#define GD_odim(g)
Definition types.h:391
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
#define ND_pinned(n)
Definition types.h:519
#define agfindnodeattr(g, a)
Definition types.h:615
#define ND_height(n)
Definition types.h:498
#define ND_width(n)
Definition types.h:536
#define ND_xlabel(n)
Definition types.h:503
#define ND_pos(n)
Definition types.h:520
#define ND_coord(n)
Definition types.h:490
Agraph_t * agraphof(void *obj)
Definition obj.c:184
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:158
int agdelete(Agraph_t *g, void *obj)
deletes object. Equivalent to agclose, agdelnode, and agdeledge for obj being a graph,...
Definition obj.c:19
Agraph_t * agroot(void *obj)
Definition obj.c:167
#define AGSEQ(obj)
Definition cgraph.h:225
@ AGEDGE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
void * agbindrec(void *obj, const char *name, unsigned int recsize, int move_to_front)
attaches a new record of the given size to the object
Definition rec.c:88
int agdelrec(void *obj, const char *name)
deletes a named record from one object
Definition rec.c:136
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:77
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:82
Agraph_t * graph(char *name)
Definition gv.cpp:31
replacements for ctype.h functions
static bool gv_isdigit(int c)
Definition gv_ctype.h:41
static bool gv_isalpha(int c)
Definition gv_ctype.h:29
static bool gv_isspace(int c)
Definition gv_ctype.h:55
static opts_t opts
Definition gvgen.c:394
static int z
agxbuf * str
Definition htmlparse.c:97
void do_graph_label(graph_t *sg)
Set characteristics of graph label if it exists.
Definition input.c:836
DistType ** compute_apsp_artificial_weights(vtx_data *graph, int n)
Definition kkutils.c:93
void free_label(textlabel_t *p)
Definition labels.c:199
#define ND_onstack(n)
Definition acyclic.c:29
#define ND_mark(n)
Definition acyclic.c:28
void acyclic(graph_t *g)
Definition acyclic.c:56
Agraph_t ** pccomps(Agraph_t *g, size_t *ncc, char *pfx, bool *pinned)
Definition ccomps.c:136
static int * ps
Definition lu.c:51
#define hasPos(n)
Definition macros.h:18
#define ND_id(n)
Definition mm2gv.c:39
#define MODE_HIER
Definition neato.h:22
#define INIT_SELF
Definition neato.h:27
#define MODE_MAJOR
Definition neato.h:21
#define MODE_IPSEP
Definition neato.h:23
#define MODE_SGD
Definition neato.h:24
#define MODE_KK
Definition neato.h:20
#define INIT_RANDOM
Definition neato.h:29
#define MODEL_SUBSET
Definition neato.h:17
#define MODEL_MDS
Definition neato.h:18
#define MODEL_CIRCUIT
Definition neato.h:16
#define INIT_REGULAR
Definition neato.h:28
#define MODEL_SHORTPATH
Definition neato.h:15
static void add_cluster(Agraph_t *g, Agraph_t *subg)
Definition neatoinit.c:454
static void kkNeato(Agraph_t *g, int nG, int model)
Definition neatoinit.c:1286
pos_edge
Definition neatoinit.c:371
@ SomeEdges
Definition neatoinit.c:371
@ NoEdges
Definition neatoinit.c:371
@ AllEdges
Definition neatoinit.c:371
#define srand48
Definition neatoinit.c:47
static void neato_init_graph(Agraph_t *g)
Definition neatoinit.c:615
bool user_pos(attrsym_t *posptr, attrsym_t *pinptr, node_t *np, int nG)
Definition neatoinit.c:71
static vtx_data * makeGraphData(graph_t *g, int nv, int *nedges, int mode, int model, node_t ***nodedata)
Definition neatoinit.c:778
static int checkEdge(PointMap *pm, edge_t *ep, int idx)
Definition neatoinit.c:690
#define BS
Definition neatoinit.c:430
static int numFields(const char *pos)
Definition neatoinit.c:166
#define RANDOM
Definition neatoinit.c:939
int init_nop(Agraph_t *g, int adjust)
Definition neatoinit.c:534
static void neato_init_edge(edge_t *e)
Definition neatoinit.c:64
static void majorization(graph_t *mg, graph_t *g, int nv, int mode, int model, int dim, adjust_data *am)
Definition neatoinit.c:1119
static void initRegular(graph_t *G, int nG)
Definition neatoinit.c:919
static void mds_model(graph_t *g)
Definition neatoinit.c:1266
static void neatoLayout(Agraph_t *mg, Agraph_t *g, int layoutMode, int layoutModel, adjust_data *am)
Definition neatoinit.c:1321
static void neato_cleanup_graph(graph_t *g)
Definition neatoinit.c:144
#define REGULAR
Definition neatoinit.c:938
static void dfs(Agraph_t *subg, Agraph_t *parentg, attrsym_t *G_lp, attrsym_t *G_bb)
Definition neatoinit.c:475
static pos_edge nop_init_edges(Agraph_t *g)
Definition neatoinit.c:378
static void nop_init_graphs(Agraph_t *, attrsym_t *, attrsym_t *)
Definition neatoinit.c:498
static int neatoModel(graph_t *g)
Definition neatoinit.c:627
static void freeEdgeInfo(Agraph_t *g)
Definition neatoinit.c:410
#define SMART
Definition neatoinit.c:937
static int Pack
Definition neatoinit.c:51
static attrsym_t * N_pos
Definition neatoinit.c:50
void neato_cleanup(graph_t *g)
Definition neatoinit.c:152
static int checkExp(graph_t *G)
Definition neatoinit.c:998
#define SLEN(s)
Definition neatoinit.c:936
int checkStart(graph_t *G, int nG, int dflt)
Definition neatoinit.c:1018
static void set_label(void *obj, textlabel_t *l, char *name)
Definition neatoinit.c:182
void neato_layout(Agraph_t *g)
Definition neatoinit.c:1391
int setSeed(graph_t *G, int dflt, long *seedp)
Definition neatoinit.c:951
#define exp_name
Definition neatoinit.c:996
static int user_spline(attrsym_t *E_pos, edge_t *e)
Definition neatoinit.c:262
static int chkBB(Agraph_t *g, attrsym_t *G_bb, boxf *bbp)
Definition neatoinit.c:432
static int neatoMode(graph_t *g)
Definition neatoinit.c:657
static void addZ(Agraph_t *g)
Definition neatoinit.c:1351
void neato_init_node(node_t *n)
Definition neatoinit.c:56
static char * cc_pfx
Definition neatoinit.c:54
static void subset_model(Agraph_t *G, int nG)
Definition neatoinit.c:1245
static void neato_init_node_edge(graph_t *g)
Definition neatoinit.c:124
NEATOPROCS_API void spline_edges(Agraph_t *)
NEATOPROCS_API void neato_translate(Agraph_t *g)
NEATOPROCS_API void spline_edges0(Agraph_t *, bool)
NEATOPROCS_API void free_scan_graph(graph_t *)
Definition stuff.c:301
NEATOPROCS_API void solve_model(graph_t *, int)
Definition stuff.c:432
NEATOPROCS_API void initial_positions(graph_t *, int)
Definition stuff.c:333
NEATOPROCS_API void jitter_d(Agnode_t *, int, int)
Definition stuff.c:313
NEATOPROCS_API void diffeq_model(graph_t *, int)
Definition stuff.c:357
NEATOPROCS_API bool neato_set_aspect(graph_t *g)
NEATOPROCS_API void jitter3d(Agnode_t *, int)
Definition stuff.c:320
NEATOPROCS_API int scan_graph(graph_t *)
Definition stuff.c:296
NEATOPROCS_API void shortest_path(graph_t *, int)
Definition stuff.c:654
NEATOPROCS_API int scan_graph_mode(graph_t *G, int mode)
Definition stuff.c:216
pack_mode getPackModeInfo(Agraph_t *g, pack_mode dflt, pack_info *pinfo)
Definition pack.c:1220
int getPack(Agraph_t *g, int not_def, int dflt)
Definition pack.c:1236
int packGraphs(size_t ng, Agraph_t **gs, Agraph_t *root, pack_info *info)
Definition pack.c:1055
support for connected components
pack_mode
Definition pack.h:55
@ l_undef
Definition pack.h:55
@ l_node
Definition pack.h:55
void clearPM(PointMap *ps)
Definition pointset.c:139
int insertPM(PointMap *pm, int x, int y, int value)
Definition pointset.c:149
PointMap * newPM(void)
Definition pointset.c:134
void freePM(PointMap *ps)
Definition pointset.c:144
point containers PointSet and PointMap
void gv_postprocess(Agraph_t *g, int allowTranslation)
Definition postproc.c:601
#define PRISIZE_T
PRIu64 alike for printing size_t
Definition prisize_t.h:27
bezier * new_spline(edge_t *e, size_t sz)
Definition splines.c:215
void gv_cleanup_edge(Agedge_t *e)
Definition utils.c:1533
void gv_free_splines(edge_t *e)
Definition utils.c:1523
void gv_cleanup_node(Agnode_t *n)
Definition utils.c:1545
static int nedges
total no. of edges used in routing
Definition routespl.c:31
void sgd(graph_t *G, int model)
Definition sgd.c:147
int DistType
Definition sparsegraph.h:37
static bool startswith(const char *s, const char *prefix)
does the string s begin with the string prefix?
Definition startswith.h:11
platform abstraction for case-insensitive string functions
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11
int stress_majorization_kD_mkernel(vtx_data *graph, int n, double **d_coords, node_t **nodes, int dim, int opts, int model, int maxi)
Definition stress.c:801
#define opt_smart_init
Definition stress.h:28
#define opt_exp_flag
Definition stress.h:29
#define DFLT_ITERATIONS
Definition stress.h:21
graph or subgraph
Definition cgraph.h:425
Agraph_t * root
subgraphs - ancestors
Definition cgraph.h:434
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:639
Definition cdt.h:104
adjust_mode mode
Definition adjust.h:32
Definition types.h:89
pointf sp
Definition types.h:94
pointf * list
Definition types.h:90
uint32_t eflag
Definition types.h:93
pointf ep
Definition types.h:95
uint32_t sflag
Definition types.h:92
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
double x
Definition adjust.h:39
double y
Definition adjust.h:39
bool doAdd
Definition adjust.h:40
pack_mode mode
Definition pack.h:72
bool doSplines
use splines in constructing graph shape
Definition pack.h:71
bool * fixed
Definition pack.h:73
unsigned int margin
Definition pack.h:70
double x
Definition geom.h:29
double y
Definition geom.h:29
pointf pos
Definition types.h:114
bool set
Definition types.h:123
unsigned nedges
double elapsed_sec(void)
Definition timing.c:48
void start_timer(void)
Definition timing.c:43
@ R_NONE
Definition types.h:215
Definition grammar.c:93