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