Graphviz 12.0.1~dev.20240715.2254
Loading...
Searching...
No Matches
pack.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
12/* Module for packing disconnected graphs together.
13 * Based on "Disconnected Graph Layout and the Polyomino Packing Approach",
14 * K. Freivalds et al., GD0'01, LNCS 2265, pp. 378-391.
15 */
16
17#include <math.h>
18#include <assert.h>
19#include <cgraph/alloc.h>
20#include <cgraph/prisize_t.h>
21#include <cgraph/sort.h>
22#include <cgraph/startswith.h>
23#include <cgraph/streq.h>
24#include <common/render.h>
25#include <pack/pack.h>
26#include <common/pointset.h>
27#include <stdbool.h>
28#include <stddef.h>
29
30#define C 100 /* Max. avg. polyomino size */
31
32#define MOVEPT(p) ((p).x += dx, (p).y += dy)
33/* Given cell size s, GRID(x:double,s:int) returns how many cells are required by size x */
34#define GRID(x,s) ((int)ceil((x)/(s)))
35/* Given grid cell size s, CVAL(v:int,s:int) returns index of cell containing point v */
36#define CVAL(v,s) ((v) >= 0 ? (v)/(s) : (((v)+1)/(s))-1)
37/* Given grid cell size s, CELL(p:point,s:int) sets p to cell containing point p */
38#define CELL(p,s) ((p).x = CVAL((p).x,s), (p).y = CVAL((p).y,(s)))
39
40typedef struct {
41 int perim; /* half size of bounding rectangle perimeter */
43 int nc; /* no. of cells */
44 size_t index;
45} ginfo;
46
47typedef struct {
48 double width, height;
49 size_t index;
50} ainfo;
51
52/* Compute grid step size. This is a root of the
53 * quadratic equation al^2 +bl + c, where a, b and
54 * c are defined below.
55 */
56static int computeStep(size_t ng, boxf *bbs, unsigned int margin) {
57 double l1, l2;
58 double a, b, c, d, r;
59 double W, H; /* width and height of graph, with margin */
60 int root;
61
62 a = C * (double)ng - 1;
63 c = 0;
64 b = 0;
65 for (size_t i = 0; i < ng; i++) {
66 boxf bb = bbs[i];
67 W = bb.UR.x - bb.LL.x + 2 * margin;
68 H = bb.UR.y - bb.LL.y + 2 * margin;
69 b -= (W + H);
70 c -= (W * H);
71 }
72 d = b * b - 4.0 * a * c;
73 if (d < 0) {
74 agerrorf("libpack: disc = %f ( < 0)\n", d);
75 return -1;
76 }
77 r = sqrt(d);
78 l1 = (-b + r) / (2 * a);
79 l2 = (-b - r) / (2 * a);
80 root = (int) l1;
81 if (root == 0) root = 1;
82 if (Verbose > 2) {
83 fprintf(stderr, "Packing: compute grid size\n");
84 fprintf(stderr, "a %f b %f c %f d %f r %f\n", a, b, c, d, r);
85 fprintf(stderr, "root %d (%f) %d (%f)\n", root, l1, (int) l2,
86 l2);
87 fprintf(stderr, " r1 %f r2 %f\n", a * l1 * l1 + b * l1 + c,
88 a * l2 * l2 + b * l2 + c);
89 }
90
91 return root;
92}
93
94/* Comparison function for polyominoes.
95 * Size is determined by perimeter.
96 */
97static int cmpf(const void *X, const void *Y)
98{
99 const ginfo *x = *(ginfo *const *) X;
100 const ginfo *y = *(ginfo *const *) Y;
101 /* flip order to get descending array */
102 if (y->perim < x->perim) {
103 return -1;
104 }
105 if (y->perim > x->perim) {
106 return 1;
107 }
108 return 0;
109}
110
112static int sgn(int x) {
113 return x > 0 ? 1 : -1;
114}
115
116/* Mark cells crossed by line from cell p to cell q.
117 * Bresenham's algorithm, from Graphics Gems I, pp. 99-100.
118 */
119static void fillLine(pointf p, pointf q, PointSet * ps)
120{
121 int x1 = ROUND(p.x);
122 int y1 = ROUND(p.y);
123 int x2 = ROUND(q.x);
124 int y2 = ROUND(q.y);
125 int d, x, y, ax, ay, sx, sy, dx, dy;
126
127 dx = x2 - x1;
128 ax = abs(dx) << 1;
129 sx = sgn(dx);
130 dy = y2 - y1;
131 ay = abs(dy) << 1;
132 sy = sgn(dy);
133
134 x = x1;
135 y = y1;
136 if (ax > ay) { /* x dominant */
137 d = ay - (ax >> 1);
138 for (;;) {
139 addPS(ps, x, y);
140 if (x == x2)
141 return;
142 if (d >= 0) {
143 y += sy;
144 d -= ax;
145 }
146 x += sx;
147 d += ay;
148 }
149 } else { /* y dominant */
150 d = ax - (ay >> 1);
151 for (;;) {
152 addPS(ps, x, y);
153 if (y == y2)
154 return;
155 if (d >= 0) {
156 x += sx;
157 d -= ay;
158 }
159 y += sy;
160 d += ax;
161 }
162 }
163}
164
165/* It appears that spline_edges always have the start point at the
166 * beginning and the end point at the end.
167 */
168static void fillEdge(Agedge_t *e, pointf p, PointSet *ps, double dx, double dy,
169 int ssize, bool doS) {
170 size_t k;
171 bezier bz;
172 pointf pt, hpt;
173 Agnode_t *h;
174
175 pt = p;
176
177 /* If doS is false or the edge has not splines, use line segment */
178 if (!doS || !ED_spl(e)) {
179 h = aghead(e);
180 hpt = coord(h);
181 MOVEPT(hpt);
182 CELL(hpt, ssize);
183 fillLine(pt, hpt, ps);
184 return;
185 }
186
187 for (size_t j = 0; j < ED_spl(e)->size; j++) {
188 bz = ED_spl(e)->list[j];
189 if (bz.sflag) {
190 pt = bz.sp;
191 hpt = bz.list[0];
192 k = 1;
193 } else {
194 pt = bz.list[0];
195 hpt = bz.list[1];
196 k = 2;
197 }
198 MOVEPT(pt);
199 CELL(pt, ssize);
200 MOVEPT(hpt);
201 CELL(hpt, ssize);
202 fillLine(pt, hpt, ps);
203
204 for (; k < bz.size; k++) {
205 pt = hpt;
206 hpt = bz.list[k];
207 MOVEPT(hpt);
208 CELL(hpt, ssize);
209 fillLine(pt, hpt, ps);
210 }
211
212 if (bz.eflag) {
213 pt = hpt;
214 hpt = bz.ep;
215 MOVEPT(hpt);
216 CELL(hpt, ssize);
217 fillLine(pt, hpt, ps);
218 }
219 }
220
221}
222
223/* Generate polyomino info from graph using the bounding box of
224 * the graph.
225 */
226static void genBox(boxf bb0, ginfo *info, int ssize, unsigned int margin,
227 pointf center, char *s) {
228 PointSet *ps;
229 int W, H;
230 pointf UR, LL;
231 boxf bb;
232 double x, y;
233
234 bb = bb0;
235 ps = newPS();
236
237 LL.x = center.x - margin;
238 LL.y = center.y - margin;
239 UR.x = center.x + bb.UR.x - bb.LL.x + margin;
240 UR.y = center.y + bb.UR.y - bb.LL.y + margin;
241 CELL(LL, ssize);
242 CELL(UR, ssize);
243
244 for (x = LL.x; x <= UR.x; x++)
245 for (y = LL.y; y <= UR.y; y++)
246 addPS(ps, x, y);
247
248 info->cells = pointsOf(ps);
249 info->nc = sizeOf(ps);
250 W = GRID(bb0.UR.x - bb0.LL.x + 2 * margin, ssize);
251 H = GRID(bb0.UR.y - bb0.LL.y + 2 * margin, ssize);
252 info->perim = W + H;
253
254 if (Verbose > 2) {
255 int i;
256 fprintf(stderr, "%s no. cells %d W %d H %d\n",
257 s, info->nc, W, H);
258 for (i = 0; i < info->nc; i++)
259 fprintf(stderr, " %.0f %.0f cell\n", info->cells[i].x,
260 info->cells[i].y);
261 }
262
263 freePS(ps);
264}
265
266/* Generate polyomino info from graph.
267 * We add all cells covered partially by the bounding box of the
268 * node. If doSplines is true and an edge has a spline, we use the
269 * polyline determined by the control point. Otherwise,
270 * we use each cell crossed by a straight edge between the head and tail.
271 * If mode = l_clust, we use the graph's GD_clust array to treat the
272 * top level clusters like large nodes.
273 * Returns 0 if okay.
274 */
275static int genPoly(Agraph_t *root, Agraph_t *g, ginfo *info, int ssize,
276 pack_info *pinfo, pointf center) {
277 PointSet *ps;
278 int W, H;
279 Agraph_t *eg; /* graph containing edges */
280 Agnode_t *n;
281 Agedge_t *e;
282 graph_t *subg;
283 unsigned int margin = pinfo->margin;
284 bool doSplines = pinfo->doSplines;
285
286 if (root)
287 eg = root;
288 else
289 eg = g;
290
291 ps = newPS();
292 const double dx = center.x - round(GD_bb(g).LL.x);
293 const double dy = center.y - round(GD_bb(g).LL.y);
294
295 if (pinfo->mode == l_clust) {
296 int i;
297
298 /* backup the alg data */
299 void **alg = gv_calloc(agnnodes(g), sizeof(void*));
300 for (i = 0, n = agfstnode(g); n; n = agnxtnode(g, n)) {
301 alg[i++] = ND_alg(n);
302 ND_alg(n) = 0;
303 }
304
305 /* do bbox of top clusters */
306 for (i = 1; i <= GD_n_cluster(g); i++) {
307 subg = GD_clust(g)[i];
308 boxf bb = GD_bb(subg);
309 if (bb.UR.x > bb.LL.x && bb.UR.y > bb.LL.y) {
310 MOVEPT(bb.LL);
311 MOVEPT(bb.UR);
312 bb.LL.x -= margin;
313 bb.LL.y -= margin;
314 bb.UR.x += margin;
315 bb.UR.y += margin;
316 CELL(bb.LL, ssize);
317 CELL(bb.UR, ssize);
318
319 for (double x = bb.LL.x; x <= bb.UR.x; x++)
320 for (double y = bb.LL.y; y <= bb.UR.y; y++)
321 addPS(ps, x, y);
322
323 /* note which nodes are in clusters */
324 for (n = agfstnode(subg); n; n = agnxtnode(subg, n))
325 ND_clust(n) = subg;
326 }
327 }
328
329 /* now do remaining nodes and edges */
330 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
331 pointf pt = coord(n);
332 MOVEPT(pt);
333 if (!ND_clust(n)) { /* n is not in a top-level cluster */
334 const pointf s2 = {.x = margin + ND_xsize(n) / 2,
335 .y = margin + ND_ysize(n) / 2};
336 pointf LL = sub_pointf(pt, s2);
337 pointf UR = add_pointf(pt, s2);
338 CELL(LL, ssize);
339 CELL(UR, ssize);
340
341 for (double x = LL.x; x <= UR.x; x++)
342 for (double y = LL.y; y <= UR.y; y++)
343 addPS(ps, x, y);
344
345 CELL(pt, ssize);
346 for (e = agfstout(eg, n); e; e = agnxtout(eg, e)) {
347 fillEdge(e, pt, ps, dx, dy, ssize, doSplines);
348 }
349 } else {
350 CELL(pt, ssize);
351 for (e = agfstout(eg, n); e; e = agnxtout(eg, e)) {
352 if (ND_clust(n) == ND_clust(aghead(e)))
353 continue;
354 fillEdge(e, pt, ps, dx, dy, ssize, doSplines);
355 }
356 }
357 }
358
359 /* restore the alg data */
360 for (i = 0, n = agfstnode(g); n; n = agnxtnode(g, n)) {
361 ND_alg(n)= alg[i++];
362 }
363 free(alg);
364
365 } else
366 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
367 pointf pt = coord(n);
368 MOVEPT(pt);
369 pointf s2 = {.x = margin + ND_xsize(n) / 2,
370 .y = margin + ND_ysize(n) / 2};
371 pointf LL = sub_pointf(pt, s2);
372 pointf UR = add_pointf(pt, s2);
373 CELL(LL, ssize);
374 CELL(UR, ssize);
375
376 for (double x = LL.x; x <= UR.x; x++)
377 for (double y = LL.y; y <= UR.y; y++)
378 addPS(ps, x, y);
379
380 CELL(pt, ssize);
381 for (e = agfstout(eg, n); e; e = agnxtout(eg, e)) {
382 fillEdge(e, pt, ps, dx, dy, ssize, doSplines);
383 }
384 }
385
386 info->cells = pointsOf(ps);
387 info->nc = sizeOf(ps);
388 W = GRID(GD_bb(g).UR.x - GD_bb(g).LL.x + 2 * margin, ssize);
389 H = GRID(GD_bb(g).UR.y - GD_bb(g).LL.y + 2 * margin, ssize);
390 info->perim = W + H;
391
392 if (Verbose > 2) {
393 int i;
394 fprintf(stderr, "%s no. cells %d W %d H %d\n",
395 agnameof(g), info->nc, W, H);
396 for (i = 0; i < info->nc; i++)
397 fprintf(stderr, " %.0f %.0f cell\n", info->cells[i].x,
398 info->cells[i].y);
399 }
400
401 freePS(ps);
402 return 0;
403}
404
405/* Check if polyomino fits at given point.
406 * If so, add cells to pointset, store point in place and return true.
407 */
408static int fits(int x, int y, ginfo *info, PointSet *ps, pointf *place,
409 int step, boxf *bbs) {
410 pointf *cells = info->cells;
411 int n = info->nc;
412 int i;
413
414 for (i = 0; i < n; i++) {
415 pointf cell = *cells;
416 cell.x += x;
417 cell.y += y;
418 if (inPS(ps, cell))
419 return 0;
420 cells++;
421 }
422
423 const pointf LL = bbs[info->index].LL;
424 place->x = step * x - LL.x;
425 place->y = step * y - LL.y;
426
427 cells = info->cells;
428 for (i = 0; i < n; i++) {
429 pointf cell = *cells;
430 cell.x += x;
431 cell.y += y;
432 insertPS(ps, cell);
433 cells++;
434 }
435
436 if (Verbose >= 2)
437 fprintf(stderr, "cc (%d cells) at (%d,%d) (%.0f,%.0f)\n", n, x, y,
438 place->x, place->y);
439 return 1;
440}
441
442/* Position fixed graph. Store final translation and
443 * fill polyomino set. Note that polyomino set for the
444 * graph is constructed where it will be.
445 */
446static void placeFixed(ginfo *info, PointSet *ps, pointf *place,
447 pointf center) {
448 pointf *cells = info->cells;
449 int n = info->nc;
450 int i;
451
452 place->x = -center.x;
453 place->y = -center.y;
454
455 for (i = 0; i < n; i++) {
456 insertPS(ps, *cells++);
457 }
458
459 if (Verbose >= 2)
460 fprintf(stderr, "cc (%d cells) at (%.0f,%.0f)\n", n, place->x,
461 place->y);
462}
463
464/* Search for points on concentric "circles" out
465 * from the origin. Check if polyomino can be placed
466 * with bounding box origin at point.
467 * First graph (i == 0) is centered on the origin if possible.
468 */
469static void placeGraph(size_t i, ginfo *info, PointSet *ps, pointf *place,
470 int step, unsigned int margin, boxf* bbs) {
471 int x, y;
472 int bnd;
473 boxf bb = bbs[info->index];
474
475 if (i == 0) {
476 const int W = GRID(bb.UR.x - bb.LL.x + 2 * margin, step);
477 const int H = GRID(bb.UR.y - bb.LL.y + 2 * margin, step);
478 if (fits(-W / 2, -H / 2, info, ps, place, step, bbs))
479 return;
480 }
481
482 if (fits(0, 0, info, ps, place, step, bbs))
483 return;
484 const double W = ceil(bb.UR.x - bb.LL.x);
485 const double H = ceil(bb.UR.y - bb.LL.y);
486 if (W >= H) {
487 for (bnd = 1;; bnd++) {
488 x = 0;
489 y = -bnd;
490 for (; x < bnd; x++)
491 if (fits(x, y, info, ps, place, step, bbs))
492 return;
493 for (; y < bnd; y++)
494 if (fits(x, y, info, ps, place, step, bbs))
495 return;
496 for (; x > -bnd; x--)
497 if (fits(x, y, info, ps, place, step, bbs))
498 return;
499 for (; y > -bnd; y--)
500 if (fits(x, y, info, ps, place, step, bbs))
501 return;
502 for (; x < 0; x++)
503 if (fits(x, y, info, ps, place, step, bbs))
504 return;
505 }
506 } else {
507 for (bnd = 1;; bnd++) {
508 y = 0;
509 x = -bnd;
510 for (; y > -bnd; y--)
511 if (fits(x, y, info, ps, place, step, bbs))
512 return;
513 for (; x < bnd; x++)
514 if (fits(x, y, info, ps, place, step, bbs))
515 return;
516 for (; y < bnd; y++)
517 if (fits(x, y, info, ps, place, step, bbs))
518 return;
519 for (; x > -bnd; x--)
520 if (fits(x, y, info, ps, place, step, bbs))
521 return;
522 for (; y > 0; y--)
523 if (fits(x, y, info, ps, place, step, bbs))
524 return;
525 }
526 }
527}
528
529#ifdef DEBUG
530void dumpp(ginfo * info, char *pfx)
531{
532 pointf *cells = info->cells;
533 int i, c_cnt = info->nc;
534
535 fprintf(stderr, "%s\n", pfx);
536 for (i = 0; i < c_cnt; i++) {
537 fprintf(stderr, "%.0f %.0f box\n", cells[i].x, cells[i].y);
538 }
539}
540#endif
541
543static int ucmpf(const void *X, const void *Y, void *user_values) {
544 const ainfo* x = *(ainfo *const *) X;
545 const ainfo* y = *(ainfo *const *) Y;
546 const packval_t *userVals = user_values;
547
548 const unsigned int dX = userVals[x->index];
549 const unsigned int dY = userVals[y->index];
550 if (dX > dY) return 1;
551 if (dX < dY) return -1;
552 return 0;
553}
554
556static int acmpf(const void *X, const void *Y)
557{
558 const ainfo* x = *(ainfo *const *) X;
559 const ainfo* y = *(ainfo *const *) Y;
560 double dX = x->height + x->width;
561 double dY = y->height + y->width;
562 if (dX < dY) return 1;
563 if (dX > dY) return -1;
564 return 0;
565}
566
567#define INC(m,c,r) \
568 if (m){ c++; if (c == nc) { c = 0; r++; } } \
569 else { r++; if (r == nr) { r = 0; c++; } }
570
571static pointf *arrayRects(size_t ng, boxf *gs, pack_info *pinfo) {
572 size_t nr = 0, nc;
573 size_t r, c;
574 ainfo *info;
575 double v, wd, ht;
576 pointf *places = gv_calloc(ng, sizeof(pointf));
577 boxf bb;
578 int sz, rowMajor;
579
580 /* set up no. of rows and columns */
581 sz = pinfo->sz;
582 if (pinfo->flags & PK_COL_MAJOR) {
583 rowMajor = 0;
584 if (sz > 0) {
585 nr = (size_t)sz;
586 nc = (ng + (nr-1))/nr;
587 }
588 else {
589 nr = ceil(sqrt(ng));
590 nc = (ng + (nr-1))/nr;
591 }
592 }
593 else {
594 rowMajor = 1;
595 if (sz > 0) {
596 nc = (size_t)sz;
597 nr = (ng + (nc-1))/nc;
598 }
599 else {
600 nc = ceil(sqrt(ng));
601 nr = (ng + (nc-1))/nc;
602 }
603 }
604 if (Verbose)
605 fprintf(stderr, "array packing: %s %" PRISIZE_T " rows %" PRISIZE_T
606 " columns\n", rowMajor ? "row major" : "column major", nr, nc);
607 double *widths = gv_calloc(nc + 1, sizeof(double));
608 double *heights = gv_calloc(nr + 1, sizeof(double));
609
610 ainfo *ip = info = gv_calloc(ng, sizeof(ainfo));
611 for (size_t i = 0; i < ng; i++, ip++) {
612 bb = gs[i];
613 ip->width = bb.UR.x - bb.LL.x + pinfo->margin;
614 ip->height = bb.UR.y - bb.LL.y + pinfo->margin;
615 ip->index = i;
616 }
617
618 ainfo **sinfo = gv_calloc(ng, sizeof(ainfo*));
619 for (size_t i = 0; i < ng; i++) {
620 sinfo[i] = info + i;
621 }
622
623 if (pinfo->vals) {
624 gv_sort(sinfo, ng, sizeof(ainfo *), ucmpf, pinfo->vals);
625 }
626 else if (!(pinfo->flags & PK_INPUT_ORDER)) {
627 qsort(sinfo, ng, sizeof(ainfo *), acmpf);
628 }
629
630 /* compute column widths and row heights */
631 r = c = 0;
632 for (size_t i = 0; i < ng; i++, ip++) {
633 ip = sinfo[i];
634 widths[c] = fmax(widths[c], ip->width);
635 heights[r] = fmax(heights[r], ip->height);
636 INC(rowMajor,c,r);
637 }
638
639 /* convert widths and heights to positions */
640 wd = 0;
641 for (size_t i = 0; i <= nc; i++) {
642 v = widths[i];
643 widths[i] = wd;
644 wd += v;
645 }
646
647 ht = 0;
648 for (size_t i = nr; 0 < i; i--) {
649 v = heights[i-1];
650 heights[i] = ht;
651 ht += v;
652 }
653 heights[0] = ht;
654
655 /* position rects */
656 r = c = 0;
657 for (size_t i = 0; i < ng; i++, ip++) {
658 ip = sinfo[i];
659 const size_t idx = ip->index;
660 bb = gs[idx];
661 if (pinfo->flags & PK_LEFT_ALIGN)
662 places[idx].x = widths[c];
663 else if (pinfo->flags & PK_RIGHT_ALIGN)
664 places[idx].x = widths[c+1] - (bb.UR.x - bb.LL.x);
665 else
666 places[idx].x = (widths[c] + widths[c+1] - bb.UR.x - bb.LL.x)/2.0;
667 if (pinfo->flags & PK_TOP_ALIGN)
668 places[idx].y = heights[r] - (bb.UR.y - bb.LL.y);
669 else if (pinfo->flags & PK_BOT_ALIGN)
670 places[idx].y = heights[r+1];
671 else
672 places[idx].y = (heights[r] + heights[r+1] - bb.UR.y - bb.LL.y)/2.0;
673 INC(rowMajor,c,r);
674 }
675
676 free (info);
677 free (sinfo);
678 free (widths);
679 free (heights);
680 return places;
681}
682
683static pointf *polyRects(size_t ng, boxf *gs, pack_info *pinfo) {
684 int stepSize;
685 Dict_t *ps;
686
687 /* calculate grid size */
688 stepSize = computeStep(ng, gs, pinfo->margin);
689 if (Verbose)
690 fprintf(stderr, "step size = %d\n", stepSize);
691 if (stepSize <= 0)
692 return 0;
693
694 /* generate polyomino cover for the rectangles */
695 ginfo *info = gv_calloc(ng, sizeof(ginfo));
696 for (size_t i = 0; i < ng; i++) {
697 info[i].index = i;
698 genBox(gs[i], info + i, stepSize, pinfo->margin, (pointf){0}, "");
699 }
700
701 /* sort */
702 ginfo **sinfo = gv_calloc(ng, sizeof(ginfo*));
703 for (size_t i = 0; i < ng; i++) {
704 sinfo[i] = info + i;
705 }
706 qsort(sinfo, ng, sizeof(ginfo *), cmpf);
707
708 ps = newPS();
709 pointf *places = gv_calloc(ng, sizeof(pointf));
710 for (size_t i = 0; i < ng; i++)
711 placeGraph(i, sinfo[i], ps, places + sinfo[i]->index,
712 stepSize, pinfo->margin, gs);
713
714 free(sinfo);
715 for (size_t i = 0; i < ng; i++)
716 free(info[i].cells);
717 free(info);
718 freePS(ps);
719
720 if (Verbose > 1)
721 for (size_t i = 0; i < ng; i++)
722 fprintf(stderr, "pos[%" PRISIZE_T "] %.0f %.0f\n", i, places[i].x,
723 places[i].y);
724
725 return places;
726}
727
728/* Given a collection of graphs, reposition them in the plane
729 * to not overlap but pack "nicely".
730 * ng is the number of graphs
731 * gs is a pointer to an array of graph pointers
732 * root gives the graph containing the edges; if null, the function
733 * looks in each graph in gs for its edges
734 * pinfo->margin gives the amount of extra space left around nodes in points
735 * If pinfo->doSplines is true, use edge splines, if computed,
736 * in calculating polyomino.
737 * pinfo->mode specifies the packing granularity and technique:
738 * l_node : pack at the node/cluster level
739 * l_graph : pack at the bounding box level
740 * Returns array of points to which graphs should be translated;
741 * the array needs to be freed;
742 * Returns NULL if problem occur or if ng == 0.
743 *
744 * Depends on graph fields GD_bb, node fields ND_pos(inches), ND_xsize and
745 * ND_ysize, and edge field ED_spl.
746 *
747 * FIX: fixed mode does not always work. The fixed ones get translated
748 * back to be centered on the origin.
749 * FIX: Check CELL and GRID macros for negative coordinates
750 * FIX: Check width and height computation
751 */
752static pointf *polyGraphs(size_t ng, Agraph_t **gs, Agraph_t *root,
753 pack_info *pinfo) {
754 int stepSize;
755 ginfo *info;
756 Dict_t *ps;
757 bool *fixed = pinfo->fixed;
758 int fixed_cnt = 0;
759 boxf fixed_bb = { {0, 0}, {0, 0} };
760
761 if (ng == 0)
762 return 0;
763
764 /* update bounding box info for each graph */
765 /* If fixed, compute bbox of fixed graphs */
766 for (size_t i = 0; i < ng; i++) {
767 Agraph_t *g = gs[i];
768 compute_bb(g);
769 if (fixed && fixed[i]) {
770 const boxf bb = GD_bb(g);
771 if (fixed_cnt) {
772 fixed_bb.LL.x = fmin(bb.LL.x, fixed_bb.LL.x);
773 fixed_bb.LL.y = fmin(bb.LL.y, fixed_bb.LL.y);
774 fixed_bb.UR.x = fmax(bb.UR.x, fixed_bb.UR.x);
775 fixed_bb.UR.y = fmax(bb.UR.y, fixed_bb.UR.y);
776 } else
777 fixed_bb = bb;
778 fixed_cnt++;
779 }
780 if (Verbose > 2) {
781 fprintf(stderr, "bb[%s] %.5g %.5g %.5g %.5g\n", agnameof(g),
782 GD_bb(g).LL.x, GD_bb(g).LL.y,
783 GD_bb(g).UR.x, GD_bb(g).UR.y);
784 }
785 }
786
787 /* calculate grid size */
788 boxf *bbs = gv_calloc(ng, sizeof(boxf));
789 for (size_t i = 0; i < ng; i++)
790 bbs[i] = GD_bb(gs[i]);
791 stepSize = computeStep(ng, bbs, pinfo->margin);
792 if (Verbose)
793 fprintf(stderr, "step size = %d\n", stepSize);
794 if (stepSize <= 0) {
795 free(bbs);
796 return 0;
797 }
798
799 /* generate polyomino cover for the graphs */
800 pointf center = {0};
801 if (fixed) {
802 center = mid_pointf(fixed_bb.LL, fixed_bb.UR);
803 }
804 info = gv_calloc(ng, sizeof(ginfo));
805 for (size_t i = 0; i < ng; i++) {
806 Agraph_t *g = gs[i];
807 info[i].index = i;
808 if (pinfo->mode == l_graph)
809 genBox(GD_bb(g), info + i, stepSize, pinfo->margin, center, agnameof(g));
810 else if (genPoly(root, gs[i], info + i, stepSize, pinfo, center)) {
811 free(bbs);
812 return 0;
813 }
814 }
815
816 /* sort */
817 ginfo **sinfo = gv_calloc(ng, sizeof(ginfo*));
818 for (size_t i = 0; i < ng; i++) {
819 sinfo[i] = info + i;
820 }
821 qsort(sinfo, ng, sizeof(ginfo *), cmpf);
822
823 ps = newPS();
824 pointf *places = gv_calloc(ng, sizeof(pointf));
825 if (fixed) {
826 for (size_t i = 0; i < ng; i++) {
827 if (fixed[i])
828 placeFixed(sinfo[i], ps, places + sinfo[i]->index, center);
829 }
830 for (size_t i = 0; i < ng; i++) {
831 if (!fixed[i])
832 placeGraph(i, sinfo[i], ps, places + sinfo[i]->index,
833 stepSize, pinfo->margin, bbs);
834 }
835 } else {
836 for (size_t i = 0; i < ng; i++)
837 placeGraph(i, sinfo[i], ps, places + sinfo[i]->index,
838 stepSize, pinfo->margin, bbs);
839 }
840
841 free(sinfo);
842 for (size_t i = 0; i < ng; i++)
843 free(info[i].cells);
844 free(info);
845 freePS(ps);
846 free (bbs);
847
848 if (Verbose > 1)
849 for (size_t i = 0; i < ng; i++)
850 fprintf(stderr, "pos[%" PRISIZE_T "] %.0f %.0f\n", i, places[i].x,
851 places[i].y);
852
853 return places;
854}
855
856pointf *putGraphs(size_t ng, Agraph_t **gs, Agraph_t *root, pack_info *pinfo) {
857 int v;
858 Agraph_t* g;
859 pointf* pts = NULL;
860 char* s;
861
862 if (ng == 0) return NULL;
863
864 if (pinfo->mode <= l_graph)
865 return polyGraphs (ng, gs, root, pinfo);
866
867 boxf *bbs = gv_calloc(ng, sizeof(boxf));
868
869 for (size_t i = 0; i < ng; i++) {
870 g = gs[i];
871 compute_bb(g);
872 bbs[i] = GD_bb(g);
873 }
874
875 if (pinfo->mode == l_array) {
876 if (pinfo->flags & PK_USER_VALS) {
877 pinfo->vals = gv_calloc(ng, sizeof(packval_t));
878 for (size_t i = 0; i < ng; i++) {
879 s = agget (gs[i], "sortv");
880 if (s && sscanf(s, "%d", &v) > 0 && v >= 0)
881 pinfo->vals[i] = v;
882 }
883
884 }
885 pts = arrayRects(ng, bbs, pinfo);
886 if (pinfo->flags & PK_USER_VALS)
887 free (pinfo->vals);
888 }
889
890 free (bbs);
891
892 return pts;
893}
894
895pointf *putRects(size_t ng, boxf *bbs, pack_info *pinfo) {
896 if (ng == 0) return NULL;
897 if (pinfo->mode == l_node || pinfo->mode == l_clust) return NULL;
898 if (pinfo->mode == l_graph)
899 return polyRects (ng, bbs, pinfo);
900 if (pinfo->mode == l_array)
901 return arrayRects(ng, bbs, pinfo);
902 return NULL;
903}
904
905/* Packs rectangles.
906 * ng - number of rectangles
907 * bbs - array of rectangles
908 * info - parameters used in packing
909 * This decides where to layout the rectangles and repositions
910 * the bounding boxes.
911 *
912 * Returns 0 on success.
913 */
914int packRects(size_t ng, boxf *bbs, pack_info *pinfo) {
915 boxf bb;
916
917 if (ng <= 1) return 0;
918
919 pointf *pp = putRects(ng, bbs, pinfo);
920 if (!pp)
921 return 1;
922
923 for (size_t i = 0; i < ng; i++) {
924 bb = bbs[i];
925 const pointf p = pp[i];
926 bb.LL = add_pointf(bb.LL, p);
927 bb.UR = add_pointf(bb.UR, p);
928 bbs[i] = bb;
929 }
930 free(pp);
931 return 0;
932}
933
935static void shiftEdge(Agedge_t *e, double dx, double dy) {
936 bezier bz;
937
938 if (ED_label(e))
939 MOVEPT(ED_label(e)->pos);
940 if (ED_xlabel(e))
941 MOVEPT(ED_xlabel(e)->pos);
942 if (ED_head_label(e))
943 MOVEPT(ED_head_label(e)->pos);
944 if (ED_tail_label(e))
945 MOVEPT(ED_tail_label(e)->pos);
946
947 if (ED_spl(e) == NULL)
948 return;
949
950 for (size_t j = 0; j < ED_spl(e)->size; j++) {
951 bz = ED_spl(e)->list[j];
952 for (size_t k = 0; k < bz.size; k++)
953 MOVEPT(bz.list[k]);
954 if (bz.sflag)
955 MOVEPT(ED_spl(e)->list[j].sp);
956 if (bz.eflag)
957 MOVEPT(ED_spl(e)->list[j].ep);
958 }
959}
960
961static void shiftGraph(Agraph_t *g, double dx, double dy) {
962 graph_t *subg;
963 boxf bb = GD_bb(g);
964 int i;
965
966 bb.LL.x += dx;
967 bb.UR.x += dx;
968 bb.LL.y += dy;
969 bb.UR.y += dy;
970 GD_bb(g) = bb;
971
972 if (GD_label(g) && GD_label(g)->set)
973 MOVEPT(GD_label(g)->pos);
974
975 for (i = 1; i <= GD_n_cluster(g); i++) {
976 subg = GD_clust(g)[i];
977 shiftGraph(subg, dx, dy);
978 }
979}
980
981/* The function takes ng graphs gs and a similar
982 * number of points pp and translates each graph so
983 * that the lower left corner of the bounding box of graph gs[i] is at
984 * point ps[i]. To do this, it assumes the bb field in
985 * Agraphinfo_t accurately reflects the current graph layout.
986 * The graph is repositioned by translating the pos and coord fields of
987 * each node appropriately.
988 *
989 * If doSplines is non-zero, the function also translates splines coordinates
990 * of each edge, if they have been calculated. In addition, edge labels are
991 * repositioned.
992 *
993 * If root is non-NULL, it is taken as the root graph of
994 * the graphs in gs and is used to find the edges. Otherwise, the function
995 * uses the edges found in each graph gs[i].
996 *
997 * It returns 0 on success.
998 *
999 * This function uses the bb field in Agraphinfo_t,
1000 * the pos and coord fields in nodehinfo_t and
1001 * the spl field in Aedgeinfo_t.
1002 */
1003int shiftGraphs(size_t ng, Agraph_t **gs, pointf *pp, Agraph_t *root,
1004 bool doSplines) {
1005 double fx, fy;
1006 Agraph_t *g;
1007 Agraph_t *eg;
1008 Agnode_t *n;
1009 Agedge_t *e;
1010
1011 if (ng == 0)
1012 return 0;
1013
1014 for (size_t i = 0; i < ng; i++) {
1015 g = gs[i];
1016 if (root)
1017 eg = root;
1018 else
1019 eg = g;
1020 const pointf p = pp[i];
1021 const double dx = p.x;
1022 const double dy = p.y;
1023 fx = PS2INCH(dx);
1024 fy = PS2INCH(dy);
1025
1026 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
1027 ND_pos(n)[0] += fx;
1028 ND_pos(n)[1] += fy;
1029 MOVEPT(ND_coord(n));
1030 if (ND_xlabel(n)) {
1031 MOVEPT(ND_xlabel(n)->pos);
1032 }
1033 if (doSplines) {
1034 for (e = agfstout(eg, n); e; e = agnxtout(eg, e))
1035 shiftEdge(e, dx, dy);
1036 }
1037 }
1038 shiftGraph(g, dx, dy);
1039 }
1040
1041 return 0;
1042}
1043
1044/* Packs graphs.
1045 * ng - number of graphs
1046 * gs - pointer to array of graphs
1047 * root - graph used to find edges
1048 * info - parameters used in packing
1049 * info->doSplines - if true, use already computed spline control points
1050 * This decides where to layout the graphs and repositions the graph's
1051 * position info.
1052 *
1053 * Returns 0 on success.
1054 */
1055int packGraphs(size_t ng, Agraph_t **gs, Agraph_t *root, pack_info *info) {
1056 int ret;
1057 pointf *pp = putGraphs(ng, gs, root, info);
1058
1059 if (!pp)
1060 return 1;
1061 ret = shiftGraphs(ng, gs, pp, root, info->doSplines);
1062 free(pp);
1063 return ret;
1064}
1065
1066/* Packs subgraphs of given root graph, then recalculates root's bounding box.
1067 * Note that it does not recompute subgraph bounding boxes.
1068 * Cluster bounding boxes are recomputed in shiftGraphs.
1069 */
1070int packSubgraphs(size_t ng, Agraph_t **gs, Agraph_t *root, pack_info *info) {
1071 int ret;
1072
1073 ret = packGraphs(ng, gs, root, info);
1074 if (ret == 0) {
1075 int j;
1076 boxf bb;
1077 graph_t* g;
1078
1079 compute_bb(root);
1080 bb = GD_bb(root);
1081 for (size_t i = 0; i < ng; i++) {
1082 g = gs[i];
1083 for (j = 1; j <= GD_n_cluster(g); j++) {
1084 EXPANDBB(bb,GD_bb(GD_clust(g)[j]));
1085 }
1086 }
1087 GD_bb(root) = bb;
1088 }
1089 return ret;
1090}
1091
1093int pack_graph(size_t ng, Agraph_t **gs, Agraph_t *root, bool *fixed) {
1094 int ret;
1096
1098 info.doSplines = true;
1099 info.fixed = fixed;
1100 ret = packSubgraphs(ng, gs, root, &info);
1101 if (ret == 0) dotneato_postprocess (root);
1102 return ret;
1103}
1104
1105static const char*chkFlags(const char *p, pack_info *pinfo) {
1106 int c, more;
1107
1108 if (*p != '_') return p;
1109 p++;
1110 more = 1;
1111 while (more && (c = *p)) {
1112 switch (c) {
1113 case 'c' :
1114 pinfo->flags |= PK_COL_MAJOR;
1115 p++;
1116 break;
1117 case 'i' :
1118 pinfo->flags |= PK_INPUT_ORDER;
1119 p++;
1120 break;
1121 case 'u' :
1122 pinfo->flags |= PK_USER_VALS;
1123 p++;
1124 break;
1125 case 't' :
1126 pinfo->flags |= PK_TOP_ALIGN;
1127 p++;
1128 break;
1129 case 'b' :
1130 pinfo->flags |= PK_BOT_ALIGN;
1131 p++;
1132 break;
1133 case 'l' :
1134 pinfo->flags |= PK_LEFT_ALIGN;
1135 p++;
1136 break;
1137 case 'r' :
1138 pinfo->flags |= PK_RIGHT_ALIGN;
1139 p++;
1140 break;
1141 default :
1142 more = 0;
1143 break;
1144 }
1145 }
1146 return p;
1147}
1148
1149static const char *mode2Str(pack_mode m) {
1150
1151 switch (m) {
1152 case l_clust:
1153 return "cluster";
1154 case l_node:
1155 return "node";
1156 case l_graph:
1157 return "graph";
1158 case l_array:
1159 return "array";
1160 case l_aspect:
1161 return "aspect";
1162 case l_undef:
1163 default:
1164 break;
1165 }
1166 return "undefined";
1167}
1168
1169/* Return pack_mode of graph using "packmode" attribute.
1170 * If not defined, return dflt
1171 */
1172pack_mode
1173parsePackModeInfo(const char* p, pack_mode dflt, pack_info* pinfo)
1174{
1175 float v;
1176 int i;
1177
1178 assert (pinfo);
1179 pinfo->flags = 0;
1180 pinfo->mode = dflt;
1181 pinfo->sz = 0;
1182 pinfo->vals = NULL;
1183 if (p) {
1184 if (startswith(p, "array")) {
1185 pinfo->mode = l_array;
1186 p += strlen("array");
1187 p = chkFlags (p, pinfo);
1188 if ((sscanf (p, "%d", &i)>0) && (i > 0))
1189 pinfo->sz = i;
1190 } else if (startswith(p, "aspect")) {
1191 pinfo->mode = l_aspect;
1192 if (sscanf(p + strlen("aspect"), "%f", &v) > 0 && v > 0)
1193 pinfo->aspect = v;
1194 else
1195 pinfo->aspect = 1;
1196 } else if (streq(p, "cluster")) {
1197 pinfo->mode = l_clust;
1198 } else if (streq(p, "graph")) {
1199 pinfo->mode = l_graph;
1200 } else if (streq(p, "node")) {
1201 pinfo->mode = l_node;
1202 }
1203 }
1204
1205 if (Verbose) {
1206 fprintf (stderr, "pack info:\n");
1207 fprintf (stderr, " mode %s\n", mode2Str(pinfo->mode));
1208 if (pinfo->mode == l_aspect)
1209 fprintf (stderr, " aspect %f\n", pinfo->aspect);
1210 fprintf (stderr, " size %d\n", pinfo->sz);
1211 fprintf (stderr, " flags %d\n", pinfo->flags);
1212 }
1213 return pinfo->mode;
1214}
1215
1216/* Return pack_mode of graph using "packmode" attribute.
1217 * If not defined, return dflt
1218 */
1219pack_mode
1221{
1222 return parsePackModeInfo (agget(g, "packmode"), dflt, pinfo);
1223}
1224
1225pack_mode
1227{
1229 return getPackModeInfo (g, dflt, &info);
1230}
1231
1232/* Return "pack" attribute of g.
1233 * If not defined or negative, return not_def.
1234 * If defined but not specified, return dflt.
1235 */
1236int getPack(Agraph_t * g, int not_def, int dflt)
1237{
1238 char *p;
1239 int i;
1240 int v = not_def;
1241
1242 if ((p = agget(g, "pack"))) {
1243 if (sscanf(p, "%d", &i) == 1 && i >= 0)
1244 v = i;
1245 else if (*p == 't' || *p == 'T')
1246 v = dflt;
1247 }
1248
1249 return v;
1250}
1251
1252pack_mode
1253getPackInfo(Agraph_t * g, pack_mode dflt, int dfltMargin, pack_info* pinfo)
1254{
1255 assert (pinfo);
1256
1257 pinfo->margin = getPack(g, dfltMargin, dfltMargin);
1258 if (Verbose) {
1259 fprintf (stderr, " margin %u\n", pinfo->margin);
1260 }
1261 pinfo->doSplines = false;
1262 pinfo->fixed = NULL;
1263 getPackModeInfo(g, dflt, pinfo);
1264
1265 return pinfo->mode;
1266}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define ROUND(f)
Definition arith.h:48
void compute_bb(graph_t *g)
Definition utils.c:629
#define CL_OFFSET
Definition const.h:151
static splineInfo sinfo
Definition dotsplines.c:130
static float dy
Definition draw.c:38
static float dx
Definition draw.c:37
#define Y(i)
Definition gdefs.h:3
#define X(prefix, name, str, type, subtype,...)
Definition gdefs.h:14
#define PS2INCH(a_points)
Definition geom.h:70
#define EXPANDBB(b0, b1)
Definition geom.h:57
static pointf mid_pointf(pointf p, pointf q)
Definition geomprocs.h:81
static pointf add_pointf(pointf p, pointf q)
Definition geomprocs.h:63
static pointf sub_pointf(pointf p, pointf q)
Definition geomprocs.h:72
static int Verbose
Definition gml2gv.c:22
void free(void *)
node NULL
Definition grammar.y:149
int agnnodes(Agraph_t *g)
Definition graph.c:158
char * agget(void *obj, char *name)
Definition attr.c:442
#define ED_xlabel(e)
Definition types.h:590
#define ED_head_label(e)
Definition types.h:587
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:23
#define ED_spl(e)
Definition types.h:595
#define ED_tail_label(e)
Definition types.h:596
#define aghead(e)
Definition cgraph.h:890
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:38
#define ED_label(e)
Definition types.h:589
void agerrorf(const char *fmt,...)
Definition agerror.c:165
#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_label(g)
Definition types.h:374
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_ysize(n)
Definition types.h:538
#define ND_clust(n)
Definition types.h:489
#define ND_alg(n)
Definition types.h:484
#define ND_xlabel(n)
Definition types.h:503
#define ND_pos(n)
Definition types.h:520
#define ND_coord(n)
Definition types.h:490
#define ND_xsize(n)
Definition types.h:537
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:158
static int * ps
Definition lu.c:51
static int genPoly(Agraph_t *root, Agraph_t *g, ginfo *info, int ssize, pack_info *pinfo, pointf center)
Definition pack.c:275
#define MOVEPT(p)
Definition pack.c:32
pack_mode getPackModeInfo(Agraph_t *g, pack_mode dflt, pack_info *pinfo)
Definition pack.c:1220
pack_mode parsePackModeInfo(const char *p, pack_mode dflt, pack_info *pinfo)
Definition pack.c:1173
static pointf * arrayRects(size_t ng, boxf *gs, pack_info *pinfo)
Definition pack.c:571
static int fits(int x, int y, ginfo *info, PointSet *ps, pointf *place, int step, boxf *bbs)
Definition pack.c:408
static const char * chkFlags(const char *p, pack_info *pinfo)
Definition pack.c:1105
static int ucmpf(const void *X, const void *Y, void *user_values)
Sort by user values.
Definition pack.c:543
static int sgn(int x)
sgn, as defined in Graphics Gems I, ยง11.8, pp. 99
Definition pack.c:112
pack_mode getPackMode(Agraph_t *g, pack_mode dflt)
Definition pack.c:1226
static const char * mode2Str(pack_mode m)
Definition pack.c:1149
#define CELL(p, s)
Definition pack.c:38
static int cmpf(const void *X, const void *Y)
Definition pack.c:97
static pointf * polyRects(size_t ng, boxf *gs, pack_info *pinfo)
Definition pack.c:683
static void shiftGraph(Agraph_t *g, double dx, double dy)
Definition pack.c:961
pointf * putRects(size_t ng, boxf *bbs, pack_info *pinfo)
Definition pack.c:895
int packSubgraphs(size_t ng, Agraph_t **gs, Agraph_t *root, pack_info *info)
Definition pack.c:1070
static void placeGraph(size_t i, ginfo *info, PointSet *ps, pointf *place, int step, unsigned int margin, boxf *bbs)
Definition pack.c:469
int pack_graph(size_t ng, Agraph_t **gs, Agraph_t *root, bool *fixed)
Pack subgraphs followed by postprocessing.
Definition pack.c:1093
int getPack(Agraph_t *g, int not_def, int dflt)
Definition pack.c:1236
int packRects(size_t ng, boxf *bbs, pack_info *pinfo)
Definition pack.c:914
static void placeFixed(ginfo *info, PointSet *ps, pointf *place, pointf center)
Definition pack.c:446
int packGraphs(size_t ng, Agraph_t **gs, Agraph_t *root, pack_info *info)
Definition pack.c:1055
static void fillLine(pointf p, pointf q, PointSet *ps)
Definition pack.c:119
static int computeStep(size_t ng, boxf *bbs, unsigned int margin)
Definition pack.c:56
static int acmpf(const void *X, const void *Y)
Sort by height + width.
Definition pack.c:556
static pointf * polyGraphs(size_t ng, Agraph_t **gs, Agraph_t *root, pack_info *pinfo)
Definition pack.c:752
static void fillEdge(Agedge_t *e, pointf p, PointSet *ps, double dx, double dy, int ssize, bool doS)
Definition pack.c:168
#define INC(m, c, r)
Definition pack.c:567
#define GRID(x, s)
Definition pack.c:34
int shiftGraphs(size_t ng, Agraph_t **gs, pointf *pp, Agraph_t *root, bool doSplines)
Definition pack.c:1003
#define C
Definition pack.c:30
pack_mode getPackInfo(Agraph_t *g, pack_mode dflt, int dfltMargin, pack_info *pinfo)
Definition pack.c:1253
static void genBox(boxf bb0, ginfo *info, int ssize, unsigned int margin, pointf center, char *s)
Definition pack.c:226
pointf * putGraphs(size_t ng, Agraph_t **gs, Agraph_t *root, pack_info *pinfo)
Definition pack.c:856
static void shiftEdge(Agedge_t *e, double dx, double dy)
Translate all of the edge components by the given offset.
Definition pack.c:935
support for connected components
#define PK_TOP_ALIGN
Definition pack.h:61
pack_mode
Definition pack.h:55
@ l_aspect
Definition pack.h:55
@ l_clust
Definition pack.h:55
@ l_undef
Definition pack.h:55
@ l_graph
Definition pack.h:55
@ l_array
Definition pack.h:55
@ l_node
Definition pack.h:55
unsigned int packval_t
Definition pack.h:65
#define PK_COL_MAJOR
Definition pack.h:57
#define PK_USER_VALS
Definition pack.h:58
#define PK_BOT_ALIGN
Definition pack.h:62
#define PK_LEFT_ALIGN
Definition pack.h:59
#define PK_INPUT_ORDER
Definition pack.h:63
#define PK_RIGHT_ALIGN
Definition pack.h:60
void addPS(PointSet *ps, double x, double y)
Definition pointset.c:71
void insertPS(PointSet *ps, pointf pt)
Definition pointset.c:63
PointSet * newPS(void)
Definition pointset.c:53
void freePS(PointSet *ps)
Definition pointset.c:58
pointf * pointsOf(PointSet *ps)
Definition pointset.c:93
int sizeOf(PointSet *ps)
Definition pointset.c:88
int inPS(PointSet *ps, pointf pt)
Definition pointset.c:78
point containers PointSet and PointMap
void dotneato_postprocess(Agraph_t *g)
Definition postproc.c:693
#define PRISIZE_T
PRIu64 alike for printing size_t
Definition prisize_t.h:27
pointf coord(node_t *n)
Definition utils.c:151
qsort with carried along context
static void gv_sort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *, void *), void *arg)
qsort with an extra state parameter, ala qsort_r
Definition sort.h:35
static bool startswith(const char *s, const char *prefix)
does the string s begin with the string prefix?
Definition startswith.h:11
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11
graph or subgraph
Definition cgraph.h:425
Definition cdt.h:104
Definition pack.c:47
double height
Definition pack.c:48
double width
Definition pack.c:48
size_t index
index in original array
Definition pack.c:49
Definition types.h:89
size_t size
Definition types.h:91
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
result of partitioning available space, part of maze
Definition grid.h:33
Definition pack.c:40
int perim
Definition pack.c:41
size_t index
index in original array
Definition pack.c:44
pointf * cells
cells in covering polyomino
Definition pack.c:42
int nc
Definition pack.c:43
float aspect
Definition pack.h:68
int flags
Definition pack.h:75
pack_mode mode
Definition pack.h:72
int sz
Definition pack.h:69
bool doSplines
use splines in constructing graph shape
Definition pack.h:71
bool * fixed
Definition pack.h:73
packval_t * vals
Definition pack.h:74
unsigned int margin
Definition pack.h:70
int y
Definition geom.h:27
int x
Definition geom.h:27
double x
Definition geom.h:29
double y
Definition geom.h:29
static point center(point vertex[], size_t n)
Definition grammar.c:93