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