46
47
void neato_init_node(node_t * n)
50
agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE); //node custom data
51
#endif /* WITH_CGRAPH */
48
52
common_init_node(n);
49
ND_pos(n) = N_NEW(GD_ndim(n->graph), double);
50
gv_nodesize(n, GD_flip(n->graph));
53
ND_pos(n) = N_NEW(GD_ndim(agraphof(n)), double);
54
gv_nodesize(n, GD_flip(agraphof(n)));
53
57
static void neato_init_edge(edge_t * e)
60
agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE); //node custom data
61
#endif /* WITH_CGRAPH */
55
62
common_init_edge(e);
65
#endif /* WITH_CGRAPH */
57
66
ED_factor(e) = late_double(e, E_weight, 1.0, 1.0);
92
108
pvec[i] = pvec[i] / PSinputscale;
95
if (N_z && (p = agxget(np, N_z->index)) &&
96
(sscanf(p,"%lf",&z) == 1)) {
112
if (N_z && (p = agxget(np, N_z->index)) && (sscanf(p,"%lf",&z) == 1)) {
114
if (N_z && (p = agxget(np, N_z)) && (sscanf(p,"%lf",&z) == 1)) {
97
116
if (PSinputscale > 0.0) {
98
117
pvec[2] = z / PSinputscale;
202
229
cluster_data *cdata = GNEW(cluster_data);
204
231
cdata->ntoplevel = agnnodes(g);
205
233
mm = mastergraph->meta_node;
207
235
for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
209
237
subg = agusergraph(mn);
210
if (!strncmp(subg->name, "cluster", 7)) {
239
for (subg = agfstsubg(mastergraph); subg; subg = agnxtsubg(subg)) {
241
if (!strncmp(agnameof(subg), "cluster", 7)) {
215
246
cdata->nclusters = nclusters;
216
247
cs = cdata->clusters = N_GNEW(nclusters,int*);
217
248
cn = cdata->clustersizes = N_GNEW(nclusters,int);
218
250
/* fprintf(stderr,"search %d clusters...\n",nclusters); */
219
251
for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
221
253
subg = agusergraph(mn);
255
for (subg = agfstsubg(mastergraph); subg; subg = agnxtsubg(subg)) {
222
257
/* clusters are processed by separate calls to ordered_edges */
223
if (!strncmp(subg->name, "cluster", 7)) {
258
if (!strncmp(agnameof(subg), "cluster", 7)) {
226
261
*cn = agnnodes(subg);
233
268
for (gn = agfstnode(g); gn; gn = agnxtnode(g, gn)) {
234
if(gn->id==n->id) break;
269
if(AGID(gn)==AGID(n)) break;
237
/* fprintf(stderr," node=%s, id=%d, ind=%d\n",n->name,n->id,ind); */
272
/* fprintf(stderr," node=%s, id=%d, ind=%d\n",agnameof(n),n->id,ind); */
239
274
assigned[ind]=TRUE;
240
275
cdata->ntoplevel--;
406
444
* Scans for a correct bb attribute. If available, sets it
407
445
* in the graph and returns 1.
409
#define BS "%d,%d,%d,%d"
447
#define BS "%lf,%lf,%lf,%lf"
411
449
static int chkBB(Agraph_t * g, attrsym_t * G_bb)
416
455
s = agxget(g, G_bb->index);
417
459
if (sscanf(s, BS, &bb.LL.x, &bb.LL.y, &bb.UR.x, &bb.UR.y) == 4) {
418
460
if (bb.LL.y > bb.UR.y) {
419
461
/* If the LL.y coordinate is bigger than the UR.y coordinate,
420
462
* we assume the input was produced using -y, so we normalize
465
double tmp = bb.LL.y;
424
466
bb.LL.y = bb.UR.y;
448
491
dfs(node_t * mn, Agraph_t * g, attrsym_t * G_lp, attrsym_t * G_bb)
492
#else /* WITH_CGRAPH */
493
dfs(Agraph_t * subg, Agraph_t * g, attrsym_t * G_lp, attrsym_t * G_bb)
494
#endif /* WITH_CGRAPH */
452
subg = agusergraph(mn);
453
if (!strncmp(subg->name, "cluster", 7) && chkBB(subg, G_bb)) {
498
graph_t *subg = agusergraph(mn);
500
if (!strncmp(agnameof(subg), "cluster", 7) && chkBB(subg, G_bb)) {
454
501
add_cluster(g, subg);
455
502
nop_init_graphs(subg, G_lp, G_bb);
457
505
graph_t *mg = g->meta_node->graph;
459
507
for (me = agfstout(mg, mn); me; me = agnxtout(mg, me)) {
460
508
dfs(me->head, g, G_lp, G_bb);
511
for (mg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
512
dfs(mg, g, G_lp, G_bb);
471
524
nop_init_graphs(Agraph_t * g, attrsym_t * G_lp, attrsym_t * G_bb)
478
535
if (GD_label(g) && G_lp) {
479
537
s = agxget(g, G_lp->index);
480
if (sscanf(s, "%d,%d", &p.x, &p.y) == 2) {
541
if (sscanf(s, "%lf,%lf", &x, &y) == 2) {
542
GD_label(g)->pos = pointfof(x, y);
481
543
GD_label(g)->set = TRUE;
488
550
mg = g->meta_node->graph;
489
551
for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
490
552
dfs(me->head, g, G_lp, G_bb);
553
#else /* WITH_CGRAPH */
554
for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
555
dfs(subg, g, G_lp, G_bb);
556
#endif /* WITH_CGRAPH */
523
589
if (ED_label(e) && ED_label(e)->set) {
524
ED_label(e)->p.x -= offset.x;
525
ED_label(e)->p.y -= offset.y;
590
ED_label(e)->pos.x -= offset.x;
591
ED_label(e)->pos.y -= offset.y;
527
593
if (ED_head_label(e) && ED_head_label(e)->set) {
528
ED_head_label(e)->p.x -= offset.x;
529
ED_head_label(e)->p.y -= offset.y;
594
ED_head_label(e)->pos.x -= offset.x;
595
ED_head_label(e)->pos.y -= offset.y;
531
597
if (ED_tail_label(e) && ED_tail_label(e)->set) {
532
ED_tail_label(e)->p.x -= offset.x;
533
ED_tail_label(e)->p.y -= offset.y;
598
ED_tail_label(e)->pos.x -= offset.x;
599
ED_tail_label(e)->pos.y -= offset.y;
539
static void translateG(Agraph_t * g, point offset)
605
static void translateG(Agraph_t * g, pointf offset)
584
654
* clusters, edges and labels. If certain position information
585
655
* is missing, init_nop will use a standard neato technique to
658
* If adjust is false, init_nop does nothing but initialize all
659
* of the basic graph information. No tweaking of positions or
660
* filling in edge splines is done.
662
* Returns 0 on normal success, 1 if postprocess should be avoided, and -1
588
665
int init_nop(Agraph_t * g, int adjust)
592
669
pos_edge posEdges; /* How many edges have spline info */
593
attrsym_t *G_lp = agfindattr(g, "lp");
594
attrsym_t *G_bb = agfindattr(g, "bb");
670
attrsym_t *G_lp = agfindgraphattr(g, "lp");
671
attrsym_t *G_bb = agfindgraphattr(g, "bb");
672
int didAdjust = 0; /* Have nodes been moved? */
596
675
/* If G_bb not defined, define it */
598
678
G_bb = agraphattr(g, "bb", "");
679
#else /* WITH_CGRAPH */
680
G_bb = agattr(g, AGRAPH, "bb", "");
681
#endif /* WITH_CGRAPH */
600
683
scan_graph(g); /* mainly to set up GD_neato_nlist */
601
684
for (i = 0; (np = GD_neato_nlist(g)[i]); i++) {
602
if (!hasPos(np) && strncmp(np->name, "cluster", 7)) {
685
if (!hasPos(np) && strncmp(agnameof(np), "cluster", 7)) {
603
686
agerr(AGERR, "node %s in graph %s has no position\n",
687
agnameof(np), agnameof(g));
608
691
nop_init_graphs(g, G_lp, G_bb);
609
692
posEdges = nop_init_edges(g);
611
if (adjust && Nop == 1)
694
if (adjust && (Nop == 1))
695
didAdjust = adjustNodes(g);
698
if (GD_label(g)) GD_label(g)->set = FALSE;
700
* - if nodes are moved, clusters are no longer valid.
614
704
/* If g does not have a good "bb" attribute or we adjusted the nodes,
617
if (!chkBB(g, G_bb) || (adjust && Nop == 1))
707
if (!chkBB(g, G_bb) || didAdjust)
710
/* Adjust bounding box for any background */
711
if (GD_drawing(g)->xdots) {
713
GD_bb(g) = xdotBB (g);
620
718
/* At this point, all bounding boxes should be correctly defined.
621
719
* If necessary, we translate the graph to the origin.
623
if (adjust && (GD_bb(g).LL.x || GD_bb(g).LL.y))
721
if (adjust && !haveBackground && (ROUND(abs(GD_bb(g).LL.x)) || ROUND(abs(GD_bb(g).LL.y))))
624
722
translate(g, posEdges);
628
726
State = GVSPLINES;
629
727
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
630
ND_coord_i(n).x = POINTS(ND_pos(n)[0]);
631
ND_coord_i(n).y = POINTS(ND_pos(n)[1]);
728
ND_coord(n).x = POINTS_PER_INCH * (ND_pos(n)[0]);
729
ND_coord(n).y = POINTS_PER_INCH * (ND_pos(n)[1]);
634
732
else if (posEdges != AllEdges)
637
735
State = GVSPLINES;
638
736
neato_set_aspect(g);
738
return haveBackground;
643
static void neato_init_graphn(Agraph_t * g, int dfltdim)
741
static void neato_init_graph (Agraph_t * g)
645
745
setEdgeType (g, ET_LINE);
646
GD_ndim(g->root) = late_int(g, agfindattr(g, "dim"), dfltdim, 2);
746
outdim = late_int(g, agfindgraphattr(g, "dimen"), 2, 2);
747
GD_ndim(agroot(g)) = late_int(g, agfindgraphattr(g, "dim"), outdim, 2);
647
748
Ndim = GD_ndim(g->root) = MIN(GD_ndim(g->root), MAXDIM);
749
GD_odim(g->root) = MIN(outdim, Ndim);
648
750
neato_init_node_edge(g);
651
static void neato_init_graph(Agraph_t * g)
653
neato_init_graphn(g, 2);
656
753
static int neatoModel(graph_t * g)
658
755
char *p = agget(g, "model");
661
if (!p || (!(c = *p)))
758
if (!p || (!(c = *p))) /* if p is NULL or "" */
662
759
return MODEL_SHORTPATH;
663
760
if ((c == 'c') && streq(p, "circuit"))
664
761
return MODEL_CIRCUIT;
668
765
else if (streq(p, "shortpath"))
669
766
return MODEL_SHORTPATH;
768
if ((c == 'm') && streq(p, "mds")) {
770
if (agindex(g->root->proto->e, "len") >= 0)
771
#else /* WITH_CGRAPH */
772
if (agattr(g, AGEDGE, "len", 0))
773
#endif /* WITH_CGRAPH */
777
"edges in graph %s have no len attribute. Hence, the mds model\n", agnameof(g));
778
agerr(AGPREV, "is inappropriate. Reverting to the shortest path model.\n");
779
return MODEL_SHORTPATH;
672
783
"Unknown value %s for attribute \"model\" in graph %s - ignored\n",
674
785
return MODEL_SHORTPATH;
864
983
i_nedges = 1; /* one for the self */
866
985
for (ep = agfstedge(g, np); ep; ep = agnxtedge(g, ep, np)) {
867
if (ep->head == ep->tail)
986
if (aghead(ep) == agtail(ep))
868
987
continue; /* ignore loops */
869
988
idx = checkEdge(ps, ep, j);
870
989
if (idx != j) { /* seen before */
1055
1174
fprintf(stderr, "n %d e %d\n", nv, ne);
1056
1175
for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
1057
fprintf(stderr, "\"%s\" %d\n", v->name, ND_id(v));
1176
fprintf(stderr, "\"%s\" %d\n", agnameof(v), ND_id(v));
1059
1178
for (i = 0; i < nv; i++) {
1060
1179
n = gp[i].nedges;
1076
1195
/* majorization:
1077
1196
* Solve stress using majorization.
1078
1197
* Old neato attributes to incorporate:
1080
* model will be MODE_MAJOR, MODE_HIER or MODE_IPSEP
1199
* mode will be MODE_MAJOR, MODE_HIER or MODE_IPSEP
1083
majorization(graph_t *mg, graph_t * g, int nv, int mode, int model, int dim, int steps)
1202
majorization(graph_t *mg, graph_t * g, int nv, int mode, int model, int dim, int steps, adjust_data* am)
1085
1204
double **coords;
1103
1227
model, (init == INIT_SELF), MaxIter, Epsilon);
1104
1228
fprintf(stderr, "convert graph: ");
1231
fprintf(stderr, "majorization\n");
1232
// fprintf(stderr, "%i\n", count_nodes(g));
1234
#endif /* WITH_CGRAPH */
1107
1236
gp = makeGraphData(g, nv, &ne, mode, model, &nodes);
1114
1243
if (mode != MODE_MAJOR) {
1115
double lgap = late_double(g, agfindattr(g, "levelsgap"), 0.0, -MAXDOUBLE);
1244
double lgap = late_double(g, agfindgraphattr(g, "levelsgap"), 0.0, -MAXDOUBLE);
1116
1245
if (mode == MODE_HIER) {
1117
1246
stress_majorization_with_hierarchy(gp, nv, ne, coords, nodes, Ndim,
1118
1247
(init == INIT_SELF), model, MaxIter, lgap);
1135
1264
opt.diredges = 1;
1137
1266
fprintf(stderr,"Generating Edge Constraints...\n");
1138
} else if (str && !strncasecmp(str,"hier",4)) {
1267
} else if (str && !strncasecmp(str,"hier",4)) {
1139
1268
opt.diredges = 2;
1141
1270
fprintf(stderr,"Generating DiG-CoLa Edge Constraints...\n");
1143
1272
else opt.diredges = 0;
1144
am = graphAdjustMode (g);
1145
1273
if (am->mode == AM_IPSEP) {
1146
1274
opt.noverlap = 1;
1216
1345
freeGraphData(gp);
1349
* Assume the matrix already contains shortest path values.
1350
* Use the actual lengths provided the input for edges.
1352
static void mds_model(graph_t * g, int nG)
1358
for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
1359
for (e = agfstout(g, v); e; e = agnxtout(g, e)) {
1360
i = AGID(agtail(e));
1361
j = AGID(aghead(e));
1364
GD_dist(g)[i][j] = GD_dist(g)[j][i] = ED_dist(e);
1220
1370
* Solve using gradient descent a la Kamada-Kawai.
1266
1421
if ((nG < 2) || (MaxIter <=0))
1268
1423
if (layoutMode)
1269
majorization(mg, g, nG, layoutMode, layoutModel, Ndim, MaxIter);
1424
majorization(mg, g, nG, layoutMode, layoutModel, Ndim, MaxIter, am);
1271
1426
kkNeato(g, nG, layoutModel);
1275
1430
* If dimension == 3 and z attribute is declared,
1276
1431
* attach z value to nodes if not defined.
1433
static void addZ (Agraph_t* g)
1282
1436
char buf[BUFSIZ];
1284
1438
if ((Ndim >= 3) && N_z) {
1285
1439
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
1286
sprintf(buf, "%d", POINTS(ND_pos(n)[2]));
1440
sprintf(buf, "%lf", POINTS_PER_INCH * (ND_pos(n)[2]));
1287
1442
agxset(n, N_z->index, buf);
1443
#else /* WITH_CGRAPH */
1444
agxset(n, N_z, buf);
1445
#endif /* WITH_CGRAPH */
1452
addCluster (graph_t* g)
1461
for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
1463
subg = agusergraph(mn);
1465
for (subg = agfstsubg(agroot(g)); subg; subg = agnxtsubg(subg)) {
1467
if (!strncmp(agnameof(subg), "cluster", 7)) {
1468
add_cluster(g, subg);
1292
1475
/* neato_layout:
1294
1477
void neato_layout(Agraph_t * g)
1306
1491
ret = init_nop(g, 1);
1307
1492
PSinputscale = save;
1309
1494
agerr(AGPREV, "as required by the -n flag\n");
1497
else gv_postprocess(g, ret);
1313
1499
neato_init_graph(g);
1314
1500
layoutMode = neatoMode(g);
1501
graphAdjustMode (g, &am, 0);
1315
1502
model = neatoModel(g);
1316
mode = getPackMode(g, l_undef);
1503
mode = getPackModeInfo (g, l_undef, &pinfo);
1317
1504
Pack = getPack(g, -1, CL_OFFSET);
1318
1505
/* pack if just packmode defined. */
1319
1506
if (mode == l_undef) {
1338
1524
for (i = 0; i < n_cc; i++) {
1340
1526
nodeInduce(gc);
1341
neatoLayout(g, gc, layoutMode, model);
1527
neatoLayout(g, gc, layoutMode, model, &am);
1528
removeOverlapWith(gc, &am);
1529
setEdgeType (gc, ET_LINE);
1344
1532
if (n_cc > 1) {
1370
1556
#ifdef IPSEPCOLA
1377
for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
1379
subg = agusergraph(mn);
1380
if (!strncmp(subg->name, "cluster", 7)) {
1381
add_cluster(g,subg);
1388
neatoLayout(g, g, layoutMode, model);
1560
neatoLayout(g, g, layoutMode, model, &am);
1561
removeOverlapWith(g, &am);
1391
1563
spline_edges(g);
1565
dotneato_postprocess(g);
1394
dotneato_postprocess(g);