Graphviz 14.0.5~dev.20251126.0104
Loading...
Searching...
No Matches
blockpath.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include <circogen/blockpath.h>
12#include <circogen/circular.h>
13#include <circogen/edgelist.h>
14#include <stddef.h>
15#include <stdbool.h>
16#include <stdint.h>
17#include <util/agxbuf.h>
18#include <util/alloc.h>
19#include <util/list.h>
20
21/* The code below lays out a single block on a circle.
22 */
23
24/* We use the unused fields order and to_orig in cloned nodes and edges */
25#define ORIGE(e) (ED_to_orig(e))
26
27/* clone_graph:
28 * Create two copies of the argument graph
29 * One is a subgraph, the other is an actual copy since we will be
30 * adding edges to it.
31 *
32 * @param state Context containing a counter to use for graph copy naming
33 */
34static Agraph_t *clone_graph(Agraph_t *ing, Agraph_t **xg, circ_state *state) {
35 Agraph_t *clone;
36 Agraph_t *xclone;
37 Agnode_t *n;
38 Agnode_t *xn;
39 Agnode_t *xh;
40 Agedge_t *e;
41 Agedge_t *xe;
42 agxbuf gname = {0};
43
44 agxbprint(&gname, "_clone_%d", state->graphCopyCount++);
45 clone = agsubg(ing, agxbuse(&gname), 1);
46 agbindrec(clone, "Agraphinfo_t", sizeof(Agraphinfo_t), true); //node custom data
47 agxbprint(&gname, "_clone_%d", state->graphCopyCount++);
48 xclone = agopen(agxbuse(&gname), ing->desc, NULL);
50 for (n = agfstnode(ing); n; n = agnxtnode(ing, n)) {
51 agsubnode(clone,n,1);
52 xn = agnode(xclone, agnameof(n),1);
53 agbindrec(xn, "Agnodeinfo_t", sizeof(Agnodeinfo_t), true); //node custom data
54 CLONE(n) = xn;
55 }
56
57 for (n = agfstnode(ing); n; n = agnxtnode(ing, n)) {
58 xn = CLONE(n);
59 for (e = agfstout(ing, n); e; e = agnxtout(ing, e)) {
60 agsubedge(clone,e,1);
61 xh = CLONE(aghead(e));
62 xe = agedge(xclone, xn, xh, NULL, 1);
63 agbindrec(xe, "Agedgeinfo_t", sizeof(Agedgeinfo_t), true); //node custom data
64 ORIGE(xe) = e;
65 DEGREE(xn) += 1;
66 DEGREE(xh) += 1;
67 }
68 }
69 *xg = xclone;
70 return clone;
71}
72
73typedef LIST(Agnode_t *) deglist_t;
74
76static int cmpDegree(const void *x, const void *y) {
77 Agnode_t *const *a = x;
78 Agnode_t *const *b = y;
79 if (DEGREE(*a) < DEGREE(*b)) {
80 return 1;
81 }
82 if (DEGREE(*a) > DEGREE(*b)) {
83 return -1;
84 }
85 return 0;
86}
87
89static deglist_t getList(Agraph_t *g) {
90 deglist_t dl = {0};
91 Agnode_t *n;
92
93 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
94 LIST_APPEND(&dl, n);
95 }
96 LIST_SORT(&dl, cmpDegree);
97 return dl;
98}
99
100static void find_pair_edges(Agraph_t * g, Agnode_t * n, Agraph_t * outg)
101{
102 int edge_cnt = 0;
103
104 const int node_degree = DEGREE(n);
105 LIST(Agnode_t *) neighbors_with = {0};
106 LIST(Agnode_t *) neighbors_without = {0};
107
108 for (Agedge_t *e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
109 Agnode_t *n1 = aghead(e);
110 if (n1 == n)
111 n1 = agtail(e);
112 bool has_pair_edge = false;
113 for (Agedge_t *ep = agfstedge(g, n); ep; ep = agnxtedge(g, ep, n)) {
114 if (ep == e)
115 continue;
116 Agnode_t *n2 = aghead(ep);
117 if (n2 == n)
118 n2 = agtail(ep);
119 Agedge_t *const ex = agfindedge(g, n1, n2);
120 if (ex) {
121 has_pair_edge = true;
122 if ((uintptr_t)n1 < (uintptr_t)n2) { // count edge only once
123 edge_cnt++;
124 if (ORIGE(ex)) {
125 agdelete(outg, ORIGE(ex));
126 ORIGE(ex) = 0; /* delete only once */
127 }
128 }
129 }
130 }
131 if (has_pair_edge) {
132 LIST_APPEND(&neighbors_with, n1);
133 } else {
134 LIST_APPEND(&neighbors_without, n1);
135 }
136 }
137
138 int diff = node_degree - 1 - edge_cnt;
139 if (diff > 0) {
140 if ((size_t)diff < LIST_SIZE(&neighbors_without)) {
141 for (size_t mark = 0; mark + 1 < LIST_SIZE(&neighbors_without); mark += 2) {
142 Agnode_t *const tp = LIST_GET(&neighbors_without, mark);
143 Agnode_t *const hp = LIST_GET(&neighbors_without, mark + 1);
144 agbindrec(agedge(g, tp, hp, NULL, 1), "Agedgeinfo_t", sizeof(Agedgeinfo_t), true); // edge custom data
145 DEGREE(tp)++;
146 DEGREE(hp)++;
147 diff--;
148 }
149
150 for (size_t mark = 2; diff > 0; ++mark, --diff) {
151 Agnode_t *const tp = LIST_GET(&neighbors_without, 0);
152 Agnode_t *const hp = LIST_GET(&neighbors_without, mark);
153 agbindrec(agedge(g, tp, hp, NULL, 1), "Agedgeinfo_t", sizeof(Agedgeinfo_t), true); // edge custom data
154 DEGREE(tp)++;
155 DEGREE(hp)++;
156 }
157 }
158
159 else if ((size_t)diff == LIST_SIZE(&neighbors_without)) {
160 Agnode_t *const tp =
161 LIST_IS_EMPTY(&neighbors_with) ? NULL : LIST_GET(&neighbors_with, 0);
162 for (size_t mark = 0; mark < LIST_SIZE(&neighbors_without); mark++) {
163 Agnode_t *const hp = LIST_GET(&neighbors_without, mark);
164 agbindrec(agedge(g, tp, hp, NULL, 1), "Agedgeinfo_t", sizeof(Agedgeinfo_t), true); //node custom data
165 if (tp != NULL) {
166 DEGREE(tp)++;
167 }
168 DEGREE(hp)++;
169 }
170 }
171 }
172
173 LIST_FREE(&neighbors_without);
174 LIST_FREE(&neighbors_with);
175}
176
181 int nodeCount;
182 Agraph_t *outg;
183 Agraph_t *g;
184 Agnode_t *currnode, *adjNode;
185 Agedge_t *e;
186
187 outg = clone_graph(ing, &g, state);
188 nodeCount = agnnodes(g);
189 deglist_t dl = getList(g);
190
191 for (int counter = 0; counter < nodeCount - 3; ++counter) {
192 currnode = LIST_IS_EMPTY(&dl) ? NULL : LIST_POP_BACK(&dl);
193
194 /* Remove all adjacent nodes since they have to be reinserted */
195 for (e = agfstedge(g, currnode); e; e = agnxtedge(g, e, currnode)) {
196 adjNode = aghead(e);
197 if (currnode == adjNode)
198 adjNode = agtail(e);
199 LIST_REMOVE(&dl, adjNode);
200 }
201
202 find_pair_edges(g, currnode, outg);
203
204 for (e = agfstedge(g, currnode); e; e = agnxtedge(g, e, currnode)) {
205 adjNode = aghead(e);
206 if (currnode == adjNode)
207 adjNode = agtail(e);
208
209 DEGREE(adjNode)--;
210 LIST_APPEND(&dl, adjNode);
211 }
212 LIST_SORT(&dl, cmpDegree);
213
214 agdelete(g, currnode);
215 }
216
217 agclose(g);
218 LIST_FREE(&dl);
219 return outg;
220}
221
222static void
224 Agnode_t * change)
225{
227
228 parent = TPARENT(ancestor);
229 if (parent == NULL)
230 return;
231
232 dist++;
233
234 /* check parent to see if it has other leaf paths at greater distance
235 than the context node.
236 set the path/distance of the leaf at this ancestor node */
237
238 if (DISTONE(parent) == 0) {
239 LEAFONE(parent) = n;
241 } else if (dist > DISTONE(parent)) {
242 if (LEAFONE(parent) != change) {
243 if (!DISTTWO(parent) || LEAFTWO(parent) != change)
244 change = LEAFONE(parent);
247 }
248 LEAFONE(parent) = n;
250 } else if (dist > DISTTWO(parent)) {
251 LEAFTWO(parent) = n;
253 return;
254 } else
255 return;
256
257 measure_distance(n, parent, dist, change);
258}
259
261static nodelist_t find_longest_path(Agraph_t *tree) {
262 Agnode_t *n;
263 Agedge_t *e;
264 Agnode_t *common = 0;
265 int maxlength = 0;
266 int length;
267
268 if (agnnodes(tree) == 1) {
269 nodelist_t beginPath = {0};
270 n = agfstnode(tree);
271 LIST_APPEND(&beginPath, n);
272 SET_ONPATH(n);
273 return beginPath;
274 }
275
276 for (n = agfstnode(tree); n; n = agnxtnode(tree, n)) {
277 int count = 0;
278 for (e = agfstedge(tree, n); e; e = agnxtedge(tree, e, n)) {
279 count++;
280 }
281 if (count == 1)
282 measure_distance(n, n, 0, NULL);
283 }
284
285 /* find the branch node rooted at the longest path */
286 for (n = agfstnode(tree); n; n = agnxtnode(tree, n)) {
287 length = DISTONE(n) + DISTTWO(n);
288 if (length > maxlength) {
289 common = n;
290 maxlength = length;
291 }
292 }
293
294 nodelist_t beginPath = {0};
295 for (n = LEAFONE(common); n != common; n = TPARENT(n)) {
296 LIST_APPEND(&beginPath, n);
297 SET_ONPATH(n);
298 }
299 LIST_APPEND(&beginPath, common);
300 SET_ONPATH(common);
301
302 if (DISTTWO(common)) { /* 2nd path might be empty */
303 nodelist_t endPath = {0};
304 for (n = LEAFTWO(common); n != common; n = TPARENT(n)) {
305 LIST_APPEND(&endPath, n);
306 SET_ONPATH(n);
307 }
308 reverseAppend(&beginPath, &endPath);
309 }
310
311 return beginPath;
312}
313
315static void dfs(Agraph_t * g, Agnode_t * n, Agraph_t * tree)
316{
317 Agedge_t *e;
319
320 SET_VISITED(n);
321 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
322 neighbor = aghead(e);
323 if (neighbor == n)
324 neighbor = agtail(e);
325
326 if (!VISITED(neighbor)) {
327 /* add the edge to the dfs tree */
328 agsubedge(tree,e,1);
329 TPARENT(neighbor) = n;
330 dfs(g, neighbor, tree);
331 }
332 }
333}
334
339 Agnode_t *n;
340 Agraph_t *tree;
341 agxbuf gname = {0};
342
343 agxbprint(&gname, "_span_%d", state->spanningTreeCount++);
344 tree = agsubg(g, agxbuse(&gname), 1);
345 agxbfree(&gname);
346 agbindrec(tree, "Agraphinfo_t", sizeof(Agraphinfo_t), true); //node custom data
347
348 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
349 agsubnode(tree,n,1);
350 DISTONE(n) = 0;
351 DISTTWO(n) = 0;
352 UNSET_VISITED(n);
353 }
354
355 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
356 if (!VISITED(n)) {
357 TPARENT(n) = NULL;
358 dfs(g, n, tree);
359 }
360 }
361
362 return tree;
363}
364
366static void block_graph(Agraph_t * g, block_t * sn)
367{
368 Agnode_t *n;
369 Agedge_t *e;
370 Agraph_t *subg = sn->sub_graph;
371
372 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
373 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
374 if (BLOCK(aghead(e)) == sn)
375 agsubedge(subg,e,1);
376 }
377 }
378}
379
380static int count_all_crossings(nodelist_t * list, Agraph_t * subg)
381{
382 edgelist *openEdgeList = init_edgelist();
383 Agnode_t *n;
384 Agedge_t *e;
385 int crossings = 0;
386 int order = 1;
387
388 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
389 for (e = agfstout(subg, n); e; e = agnxtout(subg, e)) {
390 EDGEORDER(e) = 0;
391 }
392 }
393
394 for (size_t item = 0; item < LIST_SIZE(list); ++item) {
395 n = LIST_GET(list, item);
396
397 for (e = agfstedge(subg, n); e; e = agnxtedge(subg, e, n)) {
398 if (EDGEORDER(e) > 0) {
399 edgelistitem *eitem;
400 Agedge_t *ep;
401
402 for (eitem = dtfirst(openEdgeList); eitem;
403 eitem = dtnext(openEdgeList, eitem)) {
404 ep = eitem->edge;
405 if (EDGEORDER(ep) > EDGEORDER(e)) {
406 if (aghead(ep) != n && agtail(ep) != n)
407 crossings++;
408 }
409 }
410 remove_edge(openEdgeList, e);
411 }
412 }
413
414 for (e = agfstedge(subg, n); e; e = agnxtedge(subg, e, n)) {
415 if (EDGEORDER(e) == 0) {
416 EDGEORDER(e) = order;
417 add_edge(openEdgeList, e);
418 }
419 }
420 order++;
421 }
422
423 free_edgelist(openEdgeList);
424 return crossings;
425}
426
427#define CROSS_ITER 10
428
429/* Attempt to reduce edge crossings by moving nodes.
430 * Original crossing count is in cnt; final count is returned there.
431 * list is the original list; return the best list found.
432 */
433static nodelist_t reduce(nodelist_t list, Agraph_t *subg, int *cnt) {
434 Agnode_t *curnode;
435 Agedge_t *e;
437 int crossings, j, newCrossings;
438
439 crossings = *cnt;
440 for (curnode = agfstnode(subg); curnode;
441 curnode = agnxtnode(subg, curnode)) {
442 /* move curnode next to its neighbors */
443 for (e = agfstedge(subg, curnode); e;
444 e = agnxtedge(subg, e, curnode)) {
445 neighbor = agtail(e);
446 if (neighbor == curnode)
447 neighbor = aghead(e);
448
449 for (j = 0; j < 2; j++) {
450 nodelist_t listCopy;
451 LIST_COPY(&listCopy, &list);
452 insertNodelist(&list, curnode, neighbor, j);
453 newCrossings = count_all_crossings(&list, subg);
454 if (newCrossings < crossings) {
455 crossings = newCrossings;
456 LIST_FREE(&listCopy);
457 if (crossings == 0) {
458 *cnt = 0;
459 return list;
460 }
461 } else {
462 LIST_FREE(&list);
463 list = listCopy;
464 }
465 }
466 }
467 }
468 *cnt = crossings;
469 return list;
470}
471
472static nodelist_t reduce_edge_crossings(nodelist_t list, Agraph_t *subg) {
473 int i, crossings, origCrossings;
474
475 crossings = count_all_crossings(&list, subg);
476 if (crossings == 0)
477 return list;
478
479 for (i = 0; i < CROSS_ITER; i++) {
480 origCrossings = crossings;
481 list = reduce(list, subg, &crossings);
482 /* return if no crossings or no improvement */
483 if (origCrossings == crossings || crossings == 0)
484 return list;
485 }
486 return list;
487}
488
490static double largest_nodesize(nodelist_t * list)
491{
492 double size = 0;
493
494 for (size_t item = 0; item < LIST_SIZE(list); ++item) {
495 Agnode_t *n = ORIGN(LIST_GET(list, item));
496 if (ND_width(n) > size)
497 size = ND_width(n);
498 if (ND_height(n) > size)
499 size = ND_height(n);
500 }
501 return size;
502}
503
505static void place_node(Agraph_t * g, Agnode_t * n, nodelist_t * list)
506{
507 Agedge_t *e;
508 bool placed = false;
509 nodelist_t neighbors = {0};
510
511 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
512 LIST_APPEND(&neighbors, aghead(e));
514 }
515 for (e = agfstin(g, n); e; e = agnxtin(g, e)) {
516 LIST_APPEND(&neighbors, agtail(e));
518 }
519
520 /* Look for 2 neighbors consecutive on list */
521 if (LIST_SIZE(&neighbors) >= 2) {
522 for (size_t one = 0; one < LIST_SIZE(list); ++one) {
523 const size_t two = (one + 1) % LIST_SIZE(list);
524
525 if (NEIGHBOR(LIST_GET(list, one)) && NEIGHBOR(LIST_GET(list, two))) {
526 appendNodelist(list, one + 1, n);
527 placed = true;
528 break;
529 }
530 }
531 }
532
533 /* Find any neighbor on list */
534 if (!placed && !LIST_IS_EMPTY(&neighbors)) {
535 for (size_t one = 0; one < LIST_SIZE(list); ++one) {
536 if (NEIGHBOR(LIST_GET(list, one))) {
537 appendNodelist(list, one + 1, n);
538 placed = true;
539 break;
540 }
541 }
542 }
543
544 if (!placed)
545 LIST_APPEND(list, n);
546
547 for (size_t one = 0; one < LIST_SIZE(&neighbors); ++one)
548 UNSET_NEIGHBOR(LIST_GET(&neighbors, one));
549 LIST_FREE(&neighbors);
550}
551
553static void place_residual_nodes(Agraph_t * g, nodelist_t * list)
554{
555 Agnode_t *n;
556
557 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
558 if (!ONPATH(n))
559 place_node(g, n, list);
560 }
561}
562
564nodelist_t layout_block(Agraph_t *g, block_t *sn, double min_dist,
565 circ_state *state) {
566 Agraph_t *copyG, *tree, *subg;
567 int k;
568 double theta, radius;
569
570 subg = sn->sub_graph;
571 block_graph(g, sn); /* add induced edges */
572
573 copyG = remove_pair_edges(subg, state);
574
575 tree = spanning_tree(copyG, state);
576 nodelist_t longest_path = find_longest_path(tree);
577 place_residual_nodes(subg, &longest_path);
578 /* at this point, longest_path is a list of all nodes in the block */
579
580 /* apply crossing reduction algorithms here */
581 longest_path = reduce_edge_crossings(longest_path, subg);
582
583 size_t N = LIST_SIZE(&longest_path);
584 const double largest_node = largest_nodesize(&longest_path);
585 /* N*(min_dist+largest_node) is roughly circumference of required circle */
586 if (N == 1)
587 radius = 0;
588 else
589 radius = (double)N * (min_dist + largest_node) / (2 * M_PI);
590
591 for (size_t item = 0; item < LIST_SIZE(&longest_path); ++item) {
592 Agnode_t *n = LIST_GET(&longest_path, item);
593 if (ISPARENT(n)) {
594 /* QUESTION: Why is only one parent realigned? */
595 realignNodelist(&longest_path, item);
596 break;
597 }
598 }
599
600 k = 0;
601 for (size_t item = 0; item < LIST_SIZE(&longest_path); ++item) {
602 Agnode_t *n = LIST_GET(&longest_path, item);
603 POSITION(n) = k;
604 PSI(n) = 0.0;
605 theta = k * (2.0 * M_PI / (double)N);
606
607 ND_pos(n)[0] = radius * cos(theta);
608 ND_pos(n)[1] = radius * sin(theta);
609
610 k++;
611 }
612
613 if (N == 1)
614 sn->radius = largest_node / 2;
615 else
616 sn->radius = radius;
617 sn->rad0 = sn->radius;
618
619 /* initialize parent pos */
620 sn->parent_pos = -1;
621
622 agclose(copyG);
623 return longest_path;
624}
625
626#ifdef DEBUG
627void prTree(Agraph_t * g)
628{
629 Agnode_t *n;
630
631 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
632 if (TPARENT(n)) {
633 fprintf(stderr, "%s ", agnameof(n));
634 fprintf(stderr, "-> %s\n", agnameof(TPARENT(n)));
635 }
636 }
637}
638#endif
Dynamically expanding string buffers.
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:97
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:252
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:325
Memory allocation wrappers that exit on failure.
#define M_PI
Definition arith.h:41
#define N(n)
Definition bcomps.c:58
static int count_all_crossings(nodelist_t *list, Agraph_t *subg)
Definition blockpath.c:380
static void place_node(Agraph_t *g, Agnode_t *n, nodelist_t *list)
Add n to list. By construction, n is not in list at start.
Definition blockpath.c:505
static nodelist_t find_longest_path(Agraph_t *tree)
Find and return longest path in tree.
Definition blockpath.c:261
static void block_graph(Agraph_t *g, block_t *sn)
Add induced edges.
Definition blockpath.c:366
static nodelist_t reduce(nodelist_t list, Agraph_t *subg, int *cnt)
Definition blockpath.c:433
static void place_residual_nodes(Agraph_t *g, nodelist_t *list)
Add nodes not in list to list.
Definition blockpath.c:553
static void dfs(Agraph_t *g, Agnode_t *n, Agraph_t *tree)
Simple depth first search, adding traversed edges to tree.
Definition blockpath.c:315
static double largest_nodesize(nodelist_t *list)
Return max dimension of nodes on list.
Definition blockpath.c:490
#define CROSS_ITER
Definition blockpath.c:427
static Agraph_t * spanning_tree(Agraph_t *g, circ_state *state)
Definition blockpath.c:338
static void find_pair_edges(Agraph_t *g, Agnode_t *n, Agraph_t *outg)
Definition blockpath.c:100
static void measure_distance(Agnode_t *n, Agnode_t *ancestor, int dist, Agnode_t *change)
Definition blockpath.c:223
static Agraph_t * clone_graph(Agraph_t *ing, Agraph_t **xg, circ_state *state)
Definition blockpath.c:34
static Agraph_t * remove_pair_edges(Agraph_t *ing, circ_state *state)
Definition blockpath.c:180
static deglist_t getList(Agraph_t *g)
Add nodes to deg_list, storing them by descending degree.
Definition blockpath.c:89
nodelist_t layout_block(Agraph_t *g, block_t *sn, double min_dist, circ_state *state)
Definition blockpath.c:564
static nodelist_t reduce_edge_crossings(nodelist_t list, Agraph_t *subg)
Definition blockpath.c:472
#define ORIGE(e)
Definition blockpath.c:25
#define dtnext(d, o)
Definition cdt.h:181
#define dtfirst(d)
Definition cdt.h:180
#define BLOCK(n)
Definition circular.h:85
#define DEGREE(n)
Definition circular.h:120
#define SET_ONPATH(n)
Definition circular.h:113
#define VISITED(n)
Definition circular.h:104
#define EDGEORDER(e)
Definition circular.h:78
#define LEAFONE(n)
Definition circular.h:91
#define UNSET_NEIGHBOR(n)
Definition circular.h:118
#define POSITION(n)
Definition circular.h:95
#define CLONE(n)
Definition circular.h:89
#define SET_VISITED(n)
Definition circular.h:110
#define UNSET_VISITED(n)
Definition circular.h:116
#define ORIGN(n)
Definition circular.h:82
#define ISPARENT(n)
Definition circular.h:106
#define NEIGHBOR(n)
Definition circular.h:108
#define DISTONE(n)
Definition circular.h:93
#define SET_NEIGHBOR(n)
Definition circular.h:114
#define PSI(n)
Definition circular.h:96
#define DISTTWO(n)
Definition circular.h:94
#define ONPATH(n)
Definition circular.h:107
#define TPARENT(n)
Definition circular.h:90
#define LEAFTWO(n)
Definition circular.h:92
#define parent(i)
Definition closest.c:73
static Extype_t length(Exid_t *rhs, Exdisc_t *disc)
Definition compile.c:1606
void add_edge(edgelist *list, Agedge_t *e)
Definition edgelist.c:57
edgelist * init_edgelist(void)
Definition edgelist.c:46
void free_edgelist(edgelist *list)
Definition edgelist.c:52
void remove_edge(edgelist *list, Agedge_t *e)
Definition edgelist.c:65
static void endPath(bezier_path_t *polypath)
Definition ellipse.c:194
static double dist(int dim, double *x, double *y)
static char * gname
Definition gml2gv.c:25
node NULL
Definition grammar.y:181
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:196
int agnnodes(Agraph_t *g)
Definition graph.c:155
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Definition edge.c:253
Agedge_t * agsubedge(Agraph_t *g, Agedge_t *e, int createflag)
Definition edge.c:348
Agedge_t * agnxtin(Agraph_t *g, Agedge_t *e)
Definition edge.c:71
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:26
#define agtail(e)
Definition cgraph.h:977
#define agfindedge(g, t, h)
Definition types.h:609
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:96
#define aghead(e)
Definition cgraph.h:978
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:41
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:87
Agedge_t * agfstin(Agraph_t *g, Agnode_t *n)
Definition edge.c:57
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:95
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
creates a new graph with the given name and kind
Definition graph.c:42
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Definition node.c:141
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:48
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:41
Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
Definition node.c:252
#define ND_height(n)
Definition types.h:498
#define ND_width(n)
Definition types.h:536
#define ND_pos(n)
Definition types.h:520
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:143
int agdelete(Agraph_t *g, void *obj)
deletes object. Equivalent to agclose, agdelnode, and agdeledge for obj being a graph,...
Definition obj.c:20
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:89
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Definition subg.c:53
@ tree
Definition gvgen.c:35
static void mark(const stk_t *stk, Agnode_t *n)
set a mark on n
Definition ccomps.c:36
type-generic dynamically expanding list
#define LIST(type)
Definition list.h:55
#define LIST_SIZE(list)
Definition list.h:80
#define LIST_APPEND(list, item)
Definition list.h:120
#define LIST_FREE(list)
Definition list.h:370
#define LIST_POP_BACK(list)
Definition list.h:407
#define LIST_SORT(list, cmp)
Definition list.h:338
#define LIST_IS_EMPTY(list)
Definition list.h:90
#define LIST_COPY(dst, src)
Definition list.h:286
#define LIST_REMOVE(list, item)
Definition list.h:218
#define LIST_GET(list, index)
Definition list.h:155
#define neighbor(t, i, edim, elist)
Definition make_map.h:41
void realignNodelist(nodelist_t *list, size_t np)
Make np new front of list, with current last hooked to current first.
Definition nodelist.c:36
void insertNodelist(nodelist_t *list, Agnode_t *cn, Agnode_t *neighbor, int pos)
Definition nodelist.c:46
void reverseAppend(nodelist_t *l1, nodelist_t *l2)
Create l1 @ (rev l2) Destroys and frees l2.
Definition nodelist.c:72
void appendNodelist(nodelist_t *list, size_t one, Agnode_t *n)
Add node after one.
Definition nodelist.c:19
#define node_degree(i)
graph or subgraph
Definition cgraph.h:424
Agdesc_t desc
Definition cgraph.h:426
Definition block.h:26
double radius
Definition block.h:30
Agraph_t * sub_graph
Definition block.h:29
double parent_pos
Definition block.h:34
double rad0
Definition block.h:31
int graphCopyCount
how many cloned graphs have we created?
Definition circular.h:20
int spanningTreeCount
how many spanning trees have we created?
Definition circular.h:21
Definition cdt.h:98
Agedge_t * edge
Definition edgelist.h:21
Definition utils.c:750