Graphviz 14.1.1~dev.20251209.0353
Loading...
Searching...
No Matches
ortho.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/* TODO:
13 * In dot, prefer bottom or top routing
14 * In general, prefer closest side to closest side routing.
15 * Edge labels
16 * Ports/compass points
17 * ordering attribute
18 * Weights on edges in nodes
19 * Edge concentrators?
20 */
21
22#include "config.h"
23
24#define DEBUG
25#include <assert.h>
26#include <float.h>
27#include <math.h>
28#include <stdbool.h>
29#include <stddef.h>
30#include <ortho/maze.h>
31#include <ortho/fPQ.h>
32#include <ortho/ortho.h>
33#include <common/geomprocs.h>
34#include <common/globals.h>
35#include <common/render.h>
36#include <common/pointset.h>
37#include <util/alloc.h>
38#include <util/exit.h>
39#include <util/gv_math.h>
40#include <util/list.h>
41#include <util/unused.h>
42
43typedef struct {
44 int d;
46} epair_t;
47
48static UNUSED void emitSearchGraph(FILE *fp, sgraph *sg);
49static UNUSED void emitGraph(FILE *fp, maze *mp, size_t n_edges,
50 route *route_list, epair_t[]);
51#ifdef DEBUG
53#endif
54
55#define CELL(n) ((cell*)ND_alg(n))
56
57static double MID(double a, double b) {
58 return (a + b) / 2.0;
59}
60
61/* cellOf:
62 * Given 2 snodes sharing a cell, return the cell.
63 */
64static cell*
66{
67 cell* cp = p->cells[0];
68 if (cp == q->cells[0] || cp == q->cells[1]) return cp;
69 return p->cells[1];
70}
71
72static pointf midPt(const cell *cp) {
73 return mid_pointf(cp->bb.LL, cp->bb.UR);
74}
75
76/* sidePt:
77 * Given a cell and an snode on one of its sides, return the
78 * midpoint of the side.
79 */
80static pointf sidePt(const snode ptr, const cell* cp) {
81 if (cp == ptr.cells[1]) {
82 if (ptr.isVert) {
83 return (pointf){.x = cp->bb.LL.x, .y = MID(cp->bb.LL.y, cp->bb.UR.y)};
84 }
85 return (pointf){.x = MID(cp->bb.LL.x, cp->bb.UR.x), .y = cp->bb.LL.y};
86 }
87 if (ptr.isVert) {
88 return (pointf){.x = cp->bb.UR.x, .y = MID(cp->bb.LL.y, cp->bb.UR.y)};
89 }
90 return (pointf){.x = MID(cp->bb.LL.x, cp->bb.UR.x), .y = cp->bb.UR.y};
91}
92
93/* setSet:
94 * Initialize and normalize segments.
95 * p1 stores smaller value
96 * Assume b1 != b2
97 */
98static void
99setSeg (segment* sp, bool dir, double fix, double b1, double b2, int l1, int l2)
100{
101 sp->isVert = dir;
102 sp->comm_coord = fix;
103 if (b1 < b2) {
104 sp->p.p1 = b1;
105 sp->p.p2 = b2;
106 sp->l1 = l1;
107 sp->l2 = l2;
108 }
109 else {
110 sp->p.p2 = b1;
111 sp->p.p1 = b2;
112 sp->l2 = l1;
113 sp->l1 = l2;
114 }
115}
116
117/* Convert route in shortest path graph to route
118 * of segments. This records the first and last cells,
119 * plus cells where the path bends.
120 * Note that the shortest path will always have at least 4 nodes:
121 * the two dummy nodes representing the center of the two real nodes,
122 * and the two nodes on the boundary of the two real nodes.
123 */
124static route
126{
127 snode* ptr;
128 snode* next;
129 snode* prev; /* node in shortest path just previous to next */
130 cell* cp;
131 cell* ncp;
132 segment seg;
133 double fix, b1, b2;
134 int l1, l2;
135 pointf bp1, prevbp = {0.0,0.0}; /* bend points */
136
137 LIST(segment) rte = {0};
138
139 seg.prev = seg.next = 0;
140 ptr = prev = N_DAD(fst);
141 next = N_DAD(ptr);
142 if (IsNode(ptr->cells[0]))
143 cp = ptr->cells[1];
144 else
145 cp = ptr->cells[0];
146 bp1 = sidePt(*ptr, cp);
147 while (N_DAD(next)!=NULL) {
148 ncp = cellOf (prev, next);
149 updateWts (g, ncp, N_EDGE(ptr));
150
151 /* add seg if path bends or at end */
152 if (ptr->isVert != next->isVert || N_DAD(next) == lst) {
153 const pointf bp2 = ptr->isVert != next->isVert ? midPt (ncp) : sidePt(*next, ncp);
154 if (ptr->isVert) { /* horizontal segment */
155 if (ptr == N_DAD(fst)) l1 = B_NODE;
156 else if (prevbp.y > bp1.y) l1 = B_UP;
157 else l1 = B_DOWN;
158 if (ptr->isVert != next->isVert) {
159 if (next->cells[0] == ncp) l2 = B_UP;
160 else l2 = B_DOWN;
161 }
162 else l2 = B_NODE;
163 fix = cp->bb.LL.y;
164 b1 = cp->bb.LL.x;
165 b2 = ncp->bb.LL.x;
166 }
167 else { /* vertical segment */
168 if (ptr == N_DAD(fst)) l1 = B_NODE;
169 else if (prevbp.x > bp1.x) l1 = B_RIGHT;
170 else l1 = B_LEFT;
171 if (ptr->isVert != next->isVert) {
172 if (next->cells[0] == ncp) l2 = B_RIGHT;
173 else l2 = B_LEFT;
174 }
175 else l2 = B_NODE;
176 fix = cp->bb.LL.x;
177 b1 = cp->bb.LL.y;
178 b2 = ncp->bb.LL.y;
179 }
180 setSeg (&seg, !ptr->isVert, fix, b1, b2, l1, l2);
181 LIST_APPEND(&rte, seg);
182 cp = ncp;
183 prevbp = bp1;
184 bp1 = bp2;
185 if (ptr->isVert != next->isVert && N_DAD(next) == lst) {
186 l2 = B_NODE;
187 if (next->isVert) { /* horizontal segment */
188 if (prevbp.y > bp1.y) l1 = B_UP;
189 else l1 = B_DOWN;
190 fix = cp->bb.LL.y;
191 b1 = cp->bb.LL.x;
192 b2 = ncp->bb.LL.x;
193 }
194 else {
195 if (prevbp.x > bp1.x) l1 = B_RIGHT;
196 else l1 = B_LEFT;
197 fix = cp->bb.LL.x;
198 b1 = cp->bb.LL.y;
199 b2 = ncp->bb.LL.y;
200 }
201 setSeg (&seg, !next->isVert, fix, b1, b2, l1, l2);
202 LIST_APPEND(&rte, seg);
203 }
204 ptr = next;
205 }
206 prev = next;
207 next = N_DAD(next);
208 }
209
210 route ret = {0};
211 LIST_DETACH(&rte, &ret.segs, &ret.n);
212 for (size_t i = 0; i < ret.n; i++) {
213 if (i > 0)
214 ret.segs[i].prev = ret.segs + (i - 1);
215 if (i < ret.n - 1)
216 ret.segs[i].next = ret.segs + (i + 1);
217 }
218
219 return ret;
220}
221
222typedef struct {
224 double v;
226} chanItem;
227
228static void freeChannel(void *chan) {
229 channel *cp = chan;
230 free_graph (cp->G);
231 LIST_FREE(&cp->seg_list);
232 free (cp);
233}
234
235static void freeChanItem(void *item) {
236 chanItem *cp = item;
237 dtclose (cp->chans);
238 free (cp);
239}
240
241/* chancmpid:
242 * Compare intervals. Two intervals are equal if one contains
243 * the other. Otherwise, the one with the smaller p1 value is
244 * less.
245 * This combines two separate functions into one. Channels are
246 * disjoint, so we really only need to key on p1.
247 * When searching for a channel containing a segment, we rely on
248 * interval containment to return the correct channel.
249 */
250static int chancmpid(void *k1, void *k2) {
251 const paird *key1 = k1;
252 const paird *key2 = k2;
253 if (key1->p1 > key2->p1) {
254 if (key1->p2 <= key2->p2) return 0;
255 return 1;
256 }
257 if (key1->p1 < key2->p1) {
258 if (key1->p2 >= key2->p2) return 0;
259 return -1;
260 }
261 return 0;
262}
263
264static int dcmpid(void *k1, void *k2) {
265 const double *key1 = k1;
266 const double *key2 = k2;
267 return fcmp(*key1, *key2);
268}
269
271 offsetof(channel,p),
272 sizeof(paird),
273 offsetof(channel,link),
274 0,
276 chancmpid,
277};
278
280 offsetof(chanItem,v),
281 sizeof(double),
282 offsetof(chanItem,link),
283 0,
285 dcmpid,
286};
287
288static void
289addChan (Dt_t* chdict, channel* cp, double j)
290{
291 chanItem* subd = dtmatch (chdict, &j);
292
293 if (!subd) {
294 subd = gv_alloc(sizeof(chanItem));
295 subd->v = j;
296 subd->chans = dtopen (&chanDisc, Dtoset);
297 dtinsert (chdict, subd);
298 }
299 if (dtinsert(subd->chans, cp) != cp) {
300 free(cp);
301 }
302}
303
304static Dt_t*
306{
307 snode* np;
308 Dt_t* hchans = dtopen (&chanItemDisc, Dtoset);
309
310 for (size_t i = 0; i < mp->ncells; i++) {
311 channel* chp;
312 cell* cp = mp->cells+i;
313 cell* nextcp;
314 if (IsHScan(cp)) continue;
315
316 /* move left */
317 while ((np = cp->sides[M_LEFT]) && (nextcp = np->cells[0]) &&
318 !IsNode(nextcp)) {
319 cp = nextcp;
320 }
321
322 chp = gv_alloc(sizeof(channel));
323 chp->cp = cp;
324 chp->p.p1 = cp->bb.LL.x;
325
326 /* move right */
327 cp->flags |= MZ_HSCAN;
328 while ((np = cp->sides[M_RIGHT]) && (nextcp = np->cells[1]) &&
329 !IsNode(nextcp)) {
330 cp = nextcp;
331 cp->flags |= MZ_HSCAN;
332 }
333
334 chp->p.p2 = cp->bb.UR.x;
335 addChan (hchans, chp, chp->cp->bb.LL.y);
336 }
337 return hchans;
338}
339
340static Dt_t*
342{
343 snode* np;
344 Dt_t* vchans = dtopen (&chanItemDisc, Dtoset);
345
346 for (size_t i = 0; i < mp->ncells; i++) {
347 channel* chp;
348 cell* cp = mp->cells+i;
349 cell* nextcp;
350 if (IsVScan(cp)) continue;
351
352 /* move down */
353 while ((np = cp->sides[M_BOTTOM]) && (nextcp = np->cells[0]) &&
354 !IsNode(nextcp)) {
355 cp = nextcp;
356 }
357
358 chp = gv_alloc(sizeof(channel));
359 chp->cp = cp;
360 chp->p.p1 = cp->bb.LL.y;
361
362 /* move up */
363 cp->flags |= MZ_VSCAN;
364 while ((np = cp->sides[M_TOP]) && (nextcp = np->cells[1]) &&
365 !IsNode(nextcp)) {
366 cp = nextcp;
367 cp->flags |= MZ_VSCAN;
368 }
369
370 chp->p.p2 = cp->bb.UR.y;
371 addChan (vchans, chp, chp->cp->bb.LL.x);
372 }
373 return vchans;
374}
375
376static void
378{
379 seg->ind_no = LIST_SIZE(&chan->seg_list);
380 LIST_APPEND(&chan->seg_list, seg);
381}
382
383static channel*
384chanSearch (Dt_t* chans, segment* seg)
385{
386 channel* cp;
387 chanItem* chani = dtmatch (chans, &seg->comm_coord);
388 assert (chani);
389 cp = dtmatch (chani->chans, &seg->p);
390 assert (cp);
391 return cp;
392}
393
394static void
395assignSegs (size_t nrtes, route* route_list, maze* mp)
396{
397 channel* chan;
398
399 for (size_t i=0;i<nrtes;i++) {
400 route rte = route_list[i];
401 for (size_t j=0;j<rte.n;j++) {
402 segment* seg = rte.segs+j;
403 if (seg->isVert)
404 chan = chanSearch(mp->vchans, seg);
405 else
406 chan = chanSearch(mp->hchans, seg);
407 insertChan (chan, seg);
408 }
409 }
410}
411
412/* addLoop:
413 * Add two temporary nodes to sgraph corresponding to two ends of a loop at cell cp, i
414 * represented by dp and sp.
415 */
416static void
417addLoop (sgraph* sg, cell* cp, snode* dp, snode* sp)
418{
419 for (size_t i = 0; i < cp->nsides; i++) {
420 snode* onp = cp->sides[i];
421
422 if (onp->isVert) continue;
423 const bool onTop = onp->cells[0] == cp;
424 if (onTop)
425 createSEdge (sg, sp, onp, 0); /* FIX weight */
426 else
427 createSEdge (sg, dp, onp, 0); /* FIX weight */
428 }
429 sg->nnodes += 2;
430}
431
432/* addNodeEdges:
433 * Add temporary node to sgraph corresponding to cell cp, represented
434 * by np.
435 */
436static void
438{
439 for (size_t i = 0; i < cp->nsides; i++) {
440 snode* onp = cp->sides[i];
441
442 createSEdge (sg, np, onp, 0); /* FIX weight */
443 }
444 sg->nnodes++;
445#ifdef DEBUG
446 np->cells[0] = np->cells[1] = cp;
447#endif
448}
449
450static char* bendToStr (bend b)
451{
452 char* s = NULL;
453 switch (b) {
454 case B_NODE :
455 s = "B_NODE";
456 break;
457 case B_UP :
458 s = "B_UP";
459 break;
460 case B_LEFT :
461 s = "B_LEFT";
462 break;
463 case B_DOWN :
464 s = "B_DOWN";
465 break;
466 default:
467 assert(b == B_RIGHT);
468 s = "B_RIGHT";
469 break;
470 }
471 return s;
472}
473
474static void putSeg (FILE* fp, segment* seg)
475{
476 if (seg->isVert)
477 fprintf (fp, "((%f,%f),(%f,%f)) %s %s", seg->comm_coord, seg->p.p1,
478 seg->comm_coord, seg->p.p2, bendToStr (seg->l1), bendToStr (seg->l2));
479 else
480 fprintf (fp, "((%f,%f),(%f,%f)) %s %s", seg->p.p1,seg->comm_coord,
481 seg->p.p2, seg->comm_coord, bendToStr (seg->l1), bendToStr (seg->l2));
482}
483
484static UNUSED void dumpChanG(channel *cp, double v) {
485 if (LIST_SIZE(&cp->seg_list) < 2) return;
486 fprintf (stderr, "channel %.0f (%f,%f)\n", v, cp->p.p1, cp->p.p2);
487 for (size_t k = 0; k < LIST_SIZE(&cp->seg_list); ++k) {
488 const adj_list_t adj = cp->G->vertices[k].adj_list;
489 if (LIST_IS_EMPTY(&adj)) continue;
490 putSeg(stderr, LIST_GET(&cp->seg_list, k));
491 fputs (" ->\n", stderr);
492 for (size_t i = 0; i < LIST_SIZE(&adj); ++i) {
493 fputs (" ", stderr);
494 putSeg(stderr, LIST_GET(&cp->seg_list, LIST_GET(&adj, i)));
495 fputs ("\n", stderr);
496 }
497 }
498}
499
500static void
502{
503 Dt_t* lp;
504 Dtlink_t* l1;
505 Dtlink_t* l2;
506 channel* cp;
507
508 for (l1 = dtflatten (chans); l1; l1 = dtlink(chans,l1)) {
509 lp = ((chanItem*)l1)->chans;
510 for (l2 = dtflatten (lp); l2; l2 = dtlink(lp,l2)) {
511 cp = (channel*)l2;
512 if (!LIST_IS_EMPTY(&cp->seg_list)) {
513#ifdef DEBUG
514 if (odb_flags & ODB_CHANG) dumpChanG (cp, ((chanItem*)l1)->v);
515#endif
516 top_sort (cp->G);
517 for (size_t k = 0; k < LIST_SIZE(&cp->seg_list); ++k)
518 LIST_GET(&cp->seg_list, k)->track_no = cp->G->vertices[k].topsort_order+1;
519 }
520 }
521 }
522}
523
524static void
526{
527 Dt_t* lp;
528 Dtlink_t* l1;
529 Dtlink_t* l2;
530 channel* cp;
531
532 for (l1 = dtflatten (chans); l1; l1 = dtlink(chans,l1)) {
533 lp = ((chanItem*)l1)->chans;
534 for (l2 = dtflatten (lp); l2; l2 = dtlink(lp,l2)) {
535 cp = (channel*)l2;
536 cp->G = make_graph(LIST_SIZE(&cp->seg_list));
537 }
538 }
539}
540
541static int
542eqEndSeg (bend S1l2, bend S2l2, bend T1, bend T2)
543{
544 if ((S1l2==T2 && S2l2!=T2) || (S1l2==B_NODE && S2l2==T1))
545 return 0;
546 else
547 return -1;
548}
549
550static int
552{
553 if(S1->p.p2<S2->p.p2) {
554 if (S1->l2 == T1 && S2->l1 == T2) return -1;
555 if (S1->l2 == T2 && S2->l1 == T1) return 1;
556 return 0;
557 }
558 if (S1->p.p2 > S2->p.p2) {
559 if (S2->l1 == T2 && S2->l2 == T2) return -1;
560 if (S2->l1 == T1 && S2->l2 == T1) return 1;
561 return 0;
562 }
563 if (S2->l1 == T2) return eqEndSeg (S1->l2, S2->l2, T1, T2);
564 return -1 * eqEndSeg(S2->l2, S1->l2, T1, T2);
565}
566
567static int
568ellSeg (bend S1l1, bend S1l2, bend T)
569{
570 if (S1l1 == T) {
571 if (S1l2== T) return -1;
572 return 0;
573 }
574 return 1;
575}
576
577static int
578segCmp (segment* S1, segment* S2, bend T1, bend T2)
579{
580 /* no overlap */
581 if (S1->p.p2 < S2->p.p1 || S1->p.p1 > S2->p.p2) return 0;
582 /* left endpoint of S2 inside S1 */
583 if(S1->p.p1<S2->p.p1&&S2->p.p1<S1->p.p2)
584 return overlapSeg (S1, S2, T1, T2);
585 /* left endpoint of S1 inside S2 */
586 if (S2->p.p1 < S1->p.p1 && S1->p.p1 < S2->p.p2)
587 return -1*overlapSeg (S2, S1, T1, T2);
588 if (S1->p.p1 == S2->p.p1) {
589 if (S1->p.p2 < S2->p.p2) {
590 if(S1->l2==T1)
591 return eqEndSeg (S2->l1, S1->l1, T1, T2);
592 return -1 * eqEndSeg(S2->l1, S1->l1, T1, T2);
593 }
594 if (S1->p.p2 > S2->p.p2) {
595 if (S2->l2 == T2)
596 return eqEndSeg(S1->l1, S2->l1, T1, T2);
597 return -1 * eqEndSeg(S1->l1, S2->l1, T1, T2);
598 }
599 if (S1->l1 == S2->l1 && S1->l2 == S2->l2)
600 return 0;
601 if (S2->l1 == S2->l2) {
602 if (S2->l1 == T1) return 1;
603 if (S2->l1 == T2) return -1;
604 if (S1->l1 != T1 && S1->l2 != T1) return 1;
605 if (S1->l1 != T2 && S1->l2 != T2) return -1;
606 return 0;
607 }
608 if (S2->l1 == T1 && S2->l2 == T2) {
609 if (S1->l1 != T1 && S1->l2 == T2) return 1;
610 if (S1->l1 == T1 && S1->l2 != T2) return -1;
611 return 0;
612 }
613 if (S2->l2 == T1 && S2->l1 == T2) {
614 if (S1->l2 != T1 && S1->l1 == T2) return 1;
615 if (S1->l2 == T1 && S1->l1 != T2) return -1;
616 return 0;
617 }
618 if (S2->l1 == B_NODE && S2->l2 == T1) {
619 return ellSeg (S1->l1, S1->l2, T1);
620 }
621 if (S2->l1 == B_NODE && S2->l2 == T2) {
622 return -1*ellSeg (S1->l1, S1->l2, T2);
623 }
624 if (S2->l1 == T1 && S2->l2 == B_NODE) {
625 return ellSeg (S1->l2, S1->l1, T1);
626 }
627 /* ((S2->l1==T2)&&(S2->l2==B_NODE)) */
628 return -1 * ellSeg(S1->l2, S1->l1, T2);
629 }
630 if (S1->p.p2 == S2->p.p1) {
631 if (S1->l2 == S2->l1) return 0;
632 if (S1->l2 == T2) return 1;
633 return -1;
634 }
635 /* S1->p.p1==S2->p.p2 */
636 if (S1->l1 == S2->l2) return 0;
637 if (S1->l1 == T2) return 1;
638 return -1;
639}
640
641/* Function seg_cmp returns
642 * -1 if S1 HAS TO BE to the right/below S2 to avoid a crossing,
643 * 0 if a crossing is unavoidable or there is no crossing at all or
644 * the segments are parallel,
645 * 1 if S1 HAS TO BE to the left/above S2 to avoid a crossing
646 * -2 if S1 and S2 are incomparable
647 *
648 * Note: This definition means horizontal segments have track numbers
649 * increasing as y decreases, while vertical segments have track numbers
650 * increasing as x increases. It would be good to make this consistent,
651 * with horizontal track numbers increasing with y. This can be done by
652 * switching B_DOWN and B_UP in the first call to segCmp. At present,
653 * though, I'm not sure what assumptions are made in handling parallel
654 * segments, so we leave the code alone for the time being.
655 */
656static int
658{
659 if(S1->isVert!=S2->isVert||S1->comm_coord!=S2->comm_coord) {
660 agerrorf("incomparable segments !! -- Aborting\n");
661 return -2;
662 }
663 if(S1->isVert)
664 return segCmp (S1, S2, B_RIGHT, B_LEFT);
665 else
666 return segCmp (S1, S2, B_DOWN, B_UP);
667}
668
669static int
671{
672 seg_list_t *seg_list = &cp->seg_list;
673 const size_t size = LIST_SIZE(&cp->seg_list);
674 rawgraph* G = cp->G;
675
676 for (size_t x = 0; x + 1 < size; ++x) {
677 for (size_t y = x + 1; y < size; ++y) {
678 const int cmp = seg_cmp(LIST_GET(seg_list, x), LIST_GET(seg_list, y));
679 if (cmp == -2) {
680 return -1;
681 } else if (cmp > 0) {
682 insert_edge(G,x,y);
683 } else if (cmp == -1) {
684 insert_edge(G,y,x);
685 }
686 }
687 }
688
689 return 0;
690}
691
692static int
694{
695 for (Dtlink_t *l1 = dtflatten(chans); l1; l1 = dtlink(chans, l1)) {
696 Dt_t *const lp = ((chanItem*)l1)->chans;
697 for (Dtlink_t *l2 = dtflatten(lp); l2; l2 = dtlink(lp, l2)) {
698 channel *const cp = (channel*)l2;
699 if (!LIST_IS_EMPTY(&cp->seg_list))
700 if (add_edges_in_G(cp)) {
701 return -1;
702 }
703 }
704 }
705
706 return 0;
707}
708
709static segment*
710next_seg(segment* seg, int dir)
711{
712 assert(seg);
713 if (!dir)
714 return seg->prev;
715 else
716 return seg->next;
717}
718
719/* propagate_prec propagates the precedence relationship along
720 * a series of parallel segments on 2 edges
721 */
722static int
723propagate_prec(segment* seg, int prec, int hops, int dir)
724{
725 int x;
726 int ans=prec;
727 segment* next;
728 segment* current;
729
730 current = seg;
731 for(x=1;x<=hops;x++) {
732 next = next_seg(current, dir);
733 if(!current->isVert) {
734 if(next->comm_coord==current->p.p1) {
735 if(current->l1==B_UP) ans *= -1;
736 }
737 else {
738 if(current->l2==B_DOWN) ans *= -1;
739 }
740 }
741 else {
742 if(next->comm_coord==current->p.p1) {
743 if(current->l1==B_RIGHT) ans *= -1;
744 }
745 else {
746 if(current->l2==B_LEFT) ans *= -1;
747 }
748 }
749 current = next;
750 }
751 return ans;
752}
753
754static bool
756{
757 assert (s1->comm_coord==s2->comm_coord);
758 return s1->p.p1 == s2->p.p1 &&
759 s1->p.p2 == s2->p.p2 &&
760 s1->l1 == s2->l1 &&
761 s1->l2 == s2->l2;
762}
763
764/* decide_point returns (through ret) the number of hops needed in the given
765 * directions along the 2 edges to get to a deciding point (or NODES) and also
766 * puts into prec the appropriate dependency (follows same convention as
767 * seg_cmp)
768 */
769static int
770decide_point(pair *ret, segment* si, segment* sj, int dir1, int dir2)
771{
772 int prec = 0, ans = 0, temp;
773 segment* np1;
774 segment *np2 = NULL;
775
776 while ((np1 = next_seg(si,dir1)) && (np2 = next_seg(sj,dir2)) &&
777 is_parallel(np1, np2)) {
778 ans++;
779 si = np1;
780 sj = np2;
781 }
782 if (!np1)
783 prec = 0;
784 else if (!np2)
785 assert(0); /* FIXME */
786 else {
787 temp = seg_cmp(np1, np2);
788 if (temp == -2) {
789 return -1;
790 }
791 prec = propagate_prec(np1, temp, ans+1, 1-dir1);
792 }
793
794 ret->a = ans;
795 ret->b = prec;
796 return 0;
797}
798
799/* sets the edges for a series of parallel segments along two edges starting
800 * from segment i, segment j. It is assumed that the edge should be from
801 * segment i to segment j - the dependency is appropriately propagated
802 */
803static void
804set_parallel_edges (segment* seg1, segment* seg2, int dir1, int dir2, int hops,
805 maze* mp)
806{
807 int x;
808 channel* chan;
809 channel* nchan;
810 segment* prev1;
811 segment* prev2;
812
813 if (seg1->isVert)
814 chan = chanSearch(mp->vchans, seg1);
815 else
816 chan = chanSearch(mp->hchans, seg1);
817 insert_edge(chan->G, seg1->ind_no, seg2->ind_no);
818
819 for (x=1;x<=hops;x++) {
820 prev1 = next_seg(seg1, dir1);
821 prev2 = next_seg(seg2, dir2);
822 if(!seg1->isVert) {
823 nchan = chanSearch(mp->vchans, prev1);
824 if(prev1->comm_coord==seg1->p.p1) {
825 if(seg1->l1==B_UP) {
826 if(edge_exists(chan->G, seg1->ind_no, seg2->ind_no))
827 insert_edge(nchan->G, prev2->ind_no, prev1->ind_no);
828 else
829 insert_edge(nchan->G, prev1->ind_no, prev2->ind_no);
830 }
831 else {
832 if(edge_exists(chan->G, seg1->ind_no, seg2->ind_no))
833 insert_edge(nchan->G, prev1->ind_no, prev2->ind_no);
834 else
835 insert_edge(nchan->G, prev2->ind_no, prev1->ind_no);
836 }
837 }
838 else {
839 if(seg1->l2==B_UP) {
840 if(edge_exists(chan->G, seg1->ind_no, seg2->ind_no))
841 insert_edge(nchan->G,prev1->ind_no, prev2->ind_no);
842 else
843 insert_edge(nchan->G,prev2->ind_no, prev1->ind_no);
844 }
845 else {
846 if(edge_exists(chan->G, seg1->ind_no, seg2->ind_no))
847 insert_edge(nchan->G, prev2->ind_no, prev1->ind_no);
848 else
849 insert_edge(nchan->G, prev1->ind_no, prev2->ind_no);
850 }
851 }
852 }
853 else {
854 nchan = chanSearch(mp->hchans, prev1);
855 if(prev1->comm_coord==seg1->p.p1) {
856 if(seg1->l1==B_LEFT) {
857 if(edge_exists(chan->G, seg1->ind_no, seg2->ind_no))
858 insert_edge(nchan->G, prev1->ind_no, prev2->ind_no);
859 else
860 insert_edge(nchan->G, prev2->ind_no, prev1->ind_no);
861 }
862 else {
863 if(edge_exists(chan->G, seg1->ind_no, seg2->ind_no))
864 insert_edge(nchan->G, prev2->ind_no, prev1->ind_no);
865 else
866 insert_edge(nchan->G, prev1->ind_no, prev2->ind_no);
867 }
868 }
869 else {
870 if(seg1->l2==B_LEFT) {
871 if(edge_exists(chan->G, seg1->ind_no, seg2->ind_no))
872 insert_edge(nchan->G, prev2->ind_no, prev1->ind_no);
873 else
874 insert_edge(nchan->G, prev1->ind_no, prev2->ind_no);
875 }
876 else {
877 if(edge_exists(chan->G, seg1->ind_no, seg2->ind_no))
878 insert_edge(nchan->G, prev1->ind_no, prev2->ind_no);
879 else
880 insert_edge(nchan->G, prev2->ind_no, prev1->ind_no);
881 }
882 }
883 }
884 chan = nchan;
885 seg1 = prev1;
886 seg2 = prev2;
887 }
888}
889
890/* removes the edge between segments after the resolution of a conflict
891 */
892static void
893removeEdge(segment* seg1, segment* seg2, int dir, maze* mp)
894{
895 segment* ptr1;
896 segment* ptr2;
897 channel* chan;
898
899 ptr1 = seg1;
900 ptr2 = seg2;
901 while(is_parallel(ptr1, ptr2)) {
902 ptr1 = next_seg(ptr1, 1);
903 ptr2 = next_seg(ptr2, dir);
904 }
905 if(ptr1->isVert)
906 chan = chanSearch(mp->vchans, ptr1);
907 else
908 chan = chanSearch(mp->hchans, ptr1);
909 remove_redge (chan->G, ptr1->ind_no, ptr2->ind_no);
910}
911
912static int
914{
915 /* dir[1,2] are used to figure out whether we should use prev
916 * pointers or next pointers -- 0 : decrease, 1 : increase
917 */
918 int dir;
919 /* number of hops along the route to get to the deciding points */
920 pair hops;
921 /* precedences of the deciding points : same convention as
922 * seg_cmp function
923 */
924 int prec1, prec2;
925 pair p;
926 rawgraph* G = cp->G;
927 seg_list_t *segs = &cp->seg_list;
928
929 for(size_t i = 0; i + 1 < LIST_SIZE(&cp->seg_list); ++i) {
930 for(size_t j = i + 1; j < LIST_SIZE(&cp->seg_list); ++j) {
931 if (!edge_exists(G,i,j) && !edge_exists(G,j,i)) {
932 if (is_parallel(LIST_GET(segs, i), LIST_GET(segs, j))) {
933 /* get_directions */
934 if (LIST_GET(segs, i)->prev == 0) {
935 if (LIST_GET(segs, j)->prev == 0)
936 dir = 0;
937 else
938 dir = 1;
939 }
940 else if (LIST_GET(segs, j)->prev == 0) {
941 dir = 1;
942 }
943 else {
944 if (LIST_GET(segs, i)->prev->comm_coord ==
945 LIST_GET(segs, j)->prev->comm_coord)
946 dir = 0;
947 else
948 dir = 1;
949 }
950
951 if (decide_point(&p, LIST_GET(segs, i), LIST_GET(segs, j), 0, dir)
952 != 0) {
953 return -1;
954 }
955 hops.a = p.a;
956 prec1 = p.b;
957 if (decide_point(&p, LIST_GET(segs, i), LIST_GET(segs, j), 1,
958 1 - dir) != 0) {
959 return -1;
960 }
961 hops.b = p.a;
962 prec2 = p.b;
963
964 if (prec1 == -1) {
965 set_parallel_edges(LIST_GET(segs, j), LIST_GET(segs, i), dir, 0,
966 hops.a, mp);
967 set_parallel_edges(LIST_GET(segs, j), LIST_GET(segs, i), 1 - dir, 1,
968 hops.b, mp);
969 if(prec2==1)
970 removeEdge(LIST_GET(segs, i), LIST_GET(segs, j), 1 - dir, mp);
971 } else if (prec1 == 0) {
972 if (prec2 == -1) {
973 set_parallel_edges(LIST_GET(segs, j), LIST_GET(segs, i), dir, 0,
974 hops.a, mp);
975 set_parallel_edges(LIST_GET(segs, j), LIST_GET(segs, i), 1 - dir,
976 1, hops.b, mp);
977 } else if (prec2 == 0) {
978 set_parallel_edges(LIST_GET(segs, i), LIST_GET(segs, j), 0, dir,
979 hops.a, mp);
980 set_parallel_edges(LIST_GET(segs, i), LIST_GET(segs, j), 1,
981 1 - dir, hops.b, mp);
982 } else if (prec2 == 1) {
983 set_parallel_edges(LIST_GET(segs, i), LIST_GET(segs, j), 0, dir,
984 hops.a, mp);
985 set_parallel_edges(LIST_GET(segs, i), LIST_GET(segs, j), 1,
986 1 - dir, hops.b, mp);
987 }
988 } else if (prec1 == 1) {
989 set_parallel_edges(LIST_GET(segs, i), LIST_GET(segs, j), 0, dir,
990 hops.a, mp);
991 set_parallel_edges(LIST_GET(segs, i), LIST_GET(segs, j), 1, 1 - dir,
992 hops.b, mp);
993 if(prec2==-1)
994 removeEdge(LIST_GET(segs, i), LIST_GET(segs, j), 1 - dir, mp);
995 }
996 }
997 }
998 }
999 }
1000
1001 return 0;
1002}
1003
1004static int
1005add_p_edges (Dt_t* chans, maze* mp)
1006{
1007 for (Dtlink_t *l1 = dtflatten(chans); l1; l1 = dtlink(chans, l1)) {
1008 Dt_t *const lp = ((chanItem*)l1)->chans;
1009 for (Dtlink_t *l2 = dtflatten(lp); l2; l2 = dtlink(lp, l2)) {
1010 if (addPEdges((channel*)l2, mp) != 0) {
1011 return -1;
1012 }
1013 }
1014 }
1015
1016 return 0;
1017}
1018
1019static int
1021{
1022 /* Create the graphs for each channel */
1023 create_graphs(mp->hchans);
1024 create_graphs(mp->vchans);
1025
1026 /* add edges between non-parallel segments */
1027 if (add_np_edges(mp->hchans) != 0) {
1028 return -1;
1029 }
1030 if (add_np_edges(mp->vchans) != 0) {
1031 return -1;
1032 }
1033
1034 /* add edges between parallel segments + remove appropriate edges */
1035 if (add_p_edges(mp->hchans, mp) != 0) {
1036 return -1;
1037 }
1038 if (add_p_edges(mp->vchans, mp) != 0) {
1039 return -1;
1040 }
1041
1042 /* Assign the tracks after a top sort */
1043 assignTrackNo (mp->hchans);
1044 assignTrackNo (mp->vchans);
1045
1046 return 0;
1047}
1048
1049static double
1051{
1052 channel* chp = chanSearch(m->vchans, seg);
1053 const double f = seg->track_no / ((double)LIST_SIZE(&chp->seg_list) + 1);
1054 const pointf interp = interpolate_pointf(f, chp->cp->bb.LL, chp->cp->bb.UR);
1055 return interp.x;
1056}
1057
1058static double htrack(segment *seg, maze *m) {
1059 channel* chp = chanSearch(m->hchans, seg);
1060 double f = 1.0 - seg->track_no / ((double)LIST_SIZE(&chp->seg_list) + 1);
1061 double lo = chp->cp->bb.LL.y;
1062 double hi = chp->cp->bb.UR.y;
1063 return round(lo + f * (hi - lo));
1064}
1065
1066static void attachOrthoEdges(maze *mp, size_t n_edges, route* route_list,
1067 splineInfo *sinfo, epair_t es[], bool doLbls) {
1068 LIST(pointf) ispline = {0};
1069 textlabel_t* lbl;
1070
1071 for (size_t irte = 0; irte < n_edges; irte++) {
1072 Agedge_t *const e = es[irte].e;
1073 const pointf p1 = add_pointf(ND_coord(agtail(e)), ED_tail_port(e).p);
1074 const pointf q1 = add_pointf(ND_coord(aghead(e)), ED_head_port(e).p);
1075
1076 route rte = route_list[irte];
1077 size_t npts = 1 + 3*rte.n;
1078 LIST_RESERVE(&ispline, npts);
1079
1080 segment *seg = rte.segs;
1081 if (seg == NULL) {
1082 continue;
1083 }
1084 pointf p;
1085 if (seg->isVert) {
1086 p = (pointf){.x = vtrack(seg, mp), .y = p1.y};
1087 }
1088 else {
1089 p = (pointf){.x = p1.x, .y = htrack(seg, mp)};
1090 }
1091 LIST_APPEND(&ispline, p);
1092 LIST_APPEND(&ispline, p);
1093
1094 for (size_t i = 1;i<rte.n;i++) {
1095 seg = rte.segs+i;
1096 if (seg->isVert)
1097 p.x = vtrack(seg, mp);
1098 else
1099 p.y = htrack(seg, mp);
1100 LIST_APPEND(&ispline, p);
1101 LIST_APPEND(&ispline, p);
1102 LIST_APPEND(&ispline, p);
1103 }
1104
1105 if (seg->isVert) {
1106 p = (pointf){.x = vtrack(seg, mp), .y = q1.y};
1107 }
1108 else {
1109 p = (pointf){.x = q1.x, .y = htrack(seg, mp)};
1110 }
1111 LIST_APPEND(&ispline, p);
1112 LIST_APPEND(&ispline, p);
1113 if (Verbose > 1)
1114 fprintf(stderr, "ortho %s %s\n", agnameof(agtail(e)),agnameof(aghead(e)));
1115 clip_and_install(e, aghead(e), LIST_FRONT(&ispline), LIST_SIZE(&ispline),
1116 sinfo);
1117 if (doLbls && (lbl = ED_label(e)) && !lbl->set)
1118 addEdgeLabels(e);
1119 LIST_CLEAR(&ispline);
1120 }
1121 LIST_FREE(&ispline);
1122}
1123
1124static int
1126{
1127 pointf p = ND_coord(agtail(e));
1128 pointf q = ND_coord(aghead(e));
1129 return (int)DIST2(p,q);
1130}
1131
1132static int edgecmp(const void *x, const void *y) {
1133 const epair_t *e0 = x;
1134 const epair_t *e1 = y;
1135 if (e0->d > e1->d) {
1136 return 1;
1137 }
1138 if (e0->d < e1->d) {
1139 return -1;
1140 }
1141 return 0;
1142}
1143
1144static bool spline_merge(node_t * n)
1145{
1146 (void)n;
1147 return false;
1148}
1149
1150static bool swap_ends_p(edge_t * e)
1151{
1152 (void)e;
1153 return false;
1154}
1155
1156static splineInfo sinfo = { swap_ends_p, spline_merge, true, true };
1157
1158/* orthoEdges:
1159 * For edges without position information, construct an orthogonal routing.
1160 * If useLbls is true, use edge label info when available to guide routing,
1161 * and set label pos for those edges for which this info is not available.
1162 */
1163void orthoEdges(Agraph_t *g, bool useLbls) {
1164 epair_t* es = gv_calloc(agnedges(g), sizeof(epair_t));
1165 PointSet* ps = NULL;
1166 textlabel_t* lbl;
1167
1168 if (Concentrate)
1169 ps = newPS();
1170
1171#ifdef DEBUG
1172 {
1173 char* s = agget(g, "odb");
1174 char c;
1175 odb_flags = 0;
1176 if (s && *s != '\0') {
1177 while ((c = *s++)) {
1178 switch (c) {
1179 case 'c' :
1180 odb_flags |= ODB_CHANG; // emit channel graph
1181 break;
1182 case 'i' :
1183 odb_flags |= (ODB_SGRAPH|ODB_IGRAPH); // emit search graphs
1184 break;
1185 case 'm' :
1186 odb_flags |= ODB_MAZE; // emit maze
1187 break;
1188 case 'r' :
1189 odb_flags |= ODB_ROUTE; // emit routes in maze
1190 break;
1191 case 's' :
1192 odb_flags |= ODB_SGRAPH; // emit search graph
1193 break;
1194 default:
1195 break;
1196 }
1197 }
1198 }
1199 }
1200#endif
1201 if (useLbls) {
1202 agwarningf("Orthogonal edges do not currently handle edge labels. Try using xlabels.\n");
1203 useLbls = false;
1204 }
1205 maze *const mp = mkMaze(g);
1206 sgraph *const sg = mp->sg;
1207#ifdef DEBUG
1208 if (odb_flags & ODB_SGRAPH) emitSearchGraph (stderr, sg);
1209#endif
1210
1211 /* store edges to be routed in es, along with their lengths */
1212 size_t n_edges = 0;
1213 for (Agnode_t *n = agfstnode (g); n; n = agnxtnode(g, n)) {
1214 for (Agedge_t *e = agfstout(g, n); e; e = agnxtout(g,e)) {
1215 if (Nop == 2 && ED_spl(e)) continue;
1216 if (Concentrate) {
1217 int ti = AGSEQ(agtail(e));
1218 int hi = AGSEQ(aghead(e));
1219 if (ti <= hi) {
1220 if (isInPS (ps,ti,hi)) continue;
1221 addPS(ps,ti,hi);
1222 }
1223 else {
1224 if (isInPS (ps,hi,ti)) continue;
1225 addPS(ps,hi,ti);
1226 }
1227 }
1228 es[n_edges].e = e;
1229 es[n_edges].d = edgeLen (e);
1230 n_edges++;
1231 }
1232 }
1233
1234 route *const route_list = gv_calloc(n_edges, sizeof(route));
1235
1236 qsort(es, n_edges, sizeof(epair_t), edgecmp);
1237
1238 const int gstart = sg->nnodes;
1239 PQgen (sg->nnodes+2);
1240 snode *const sn = &sg->nodes[gstart];
1241 snode *const dn = &sg->nodes[gstart+1];
1242 for (size_t i = 0; i < n_edges; i++) {
1243#ifdef DEBUG
1244 if (i > 0 && (odb_flags & ODB_IGRAPH)) emitSearchGraph (stderr, sg);
1245#endif
1246 Agedge_t *const e = es[i].e;
1247 cell *const start = CELL(agtail(e));
1248 cell *const dest = CELL(aghead(e));
1249
1250 if (useLbls && (lbl = ED_label(e)) && lbl->set) {
1251 }
1252 else {
1253 if (start == dest)
1254 addLoop (sg, start, dn, sn);
1255 else {
1256 addNodeEdges (sg, dest, dn);
1257 addNodeEdges (sg, start, sn);
1258 }
1259 if (shortPath (sg, dn, sn)) goto orthofinish;
1260 }
1261
1262 route_list[i] = convertSPtoRoute(sg, sn, dn);
1263 reset (sg);
1264 }
1265 PQfree ();
1266
1267 mp->hchans = extractHChans (mp);
1268 mp->vchans = extractVChans (mp);
1269 assignSegs (n_edges, route_list, mp);
1270 if (assignTracks(mp) != 0)
1271 goto orthofinish;
1272#ifdef DEBUG
1273 if (odb_flags & ODB_ROUTE) emitGraph (stderr, mp, n_edges, route_list, es);
1274#endif
1275 attachOrthoEdges(mp, n_edges, route_list, &sinfo, es, useLbls);
1276
1277orthofinish:
1278 if (Concentrate)
1279 freePS (ps);
1280
1281 for (size_t i=0; i < n_edges; i++)
1282 free (route_list[i].segs);
1283 free (route_list);
1284 freeMaze (mp);
1285 free (es);
1286}
1287
1288#include <common/arith.h>
1289#define TRANS 10
1290
1291static char* prolog2 =
1292"%%!PS-Adobe-2.0\n\
1293%%%%BoundingBox: (atend)\n\
1294/point {\n\
1295 /Y exch def\n\
1296 /X exch def\n\
1297 newpath\n\
1298 X Y 3 0 360 arc fill\n\
1299} def\n\
1300/cell {\n\
1301 /Y exch def\n\
1302 /X exch def\n\
1303 /y exch def\n\
1304 /x exch def\n\
1305 newpath\n\
1306 x y moveto\n\
1307 x Y lineto\n\
1308 X Y lineto\n\
1309 X y lineto\n\
1310 closepath stroke\n\
1311} def\n\
1312/node {\n\
1313 /u exch def\n\
1314 /r exch def\n\
1315 /d exch def\n\
1316 /l exch def\n\
1317 newpath l d moveto\n\
1318 r d lineto r u lineto l u lineto\n\
1319 closepath fill\n\
1320} def\n\
1321\n";
1322
1323static char* epilog2 =
1324"showpage\n\
1325%%%%Trailer\n\
1326%%%%BoundingBox: %.f %.f %.f %.f\n";
1327
1328static pointf coordOf(cell *cp, snode *np) {
1329 if (cp->sides[M_TOP] == np) {
1330 return (pointf){.x = (cp->bb.LL.x + cp->bb.UR.x) / 2, .y = cp->bb.UR.y};
1331 }
1332 if (cp->sides[M_BOTTOM] == np) {
1333 return (pointf){.x = (cp->bb.LL.x + cp->bb.UR.x) / 2, .y = cp->bb.LL.y};
1334 }
1335 if (cp->sides[M_LEFT] == np) {
1336 return (pointf){.x = cp->bb.LL.x, .y = (cp->bb.LL.y + cp->bb.UR.y) / 2};
1337 }
1338 if (cp->sides[M_RIGHT] == np) {
1339 return (pointf){.x = cp->bb.UR.x, .y = (cp->bb.LL.y + cp->bb.UR.y) / 2};
1340 }
1341 agerrorf("Node not adjacent to cell -- Aborting\n");
1342 graphviz_exit(EXIT_FAILURE);
1343}
1344
1345static boxf
1346emitEdge (FILE* fp, Agedge_t* e, route rte, maze* m, boxf bb)
1347{
1348 double x, y;
1349 boxf n = CELL(agtail(e))->bb;
1350 segment* seg = rte.segs;
1351 if (seg->isVert) {
1352 x = vtrack(seg, m);
1353 y = (n.UR.y + n.LL.y)/2;
1354 }
1355 else {
1356 y = htrack(seg, m);
1357 x = (n.UR.x + n.LL.x)/2;
1358 }
1359 bb.LL.x = fmin(bb.LL.x, x);
1360 bb.LL.y = fmin(bb.LL.y, y);
1361 bb.UR.x = fmax(bb.UR.x, x);
1362 bb.UR.y = fmax(bb.UR.y, y);
1363 fprintf(fp, "newpath %.0f %.0f moveto\n", x, y);
1364
1365 for (size_t i = 1;i<rte.n;i++) {
1366 seg = rte.segs+i;
1367 if (seg->isVert) {
1368 x = vtrack(seg, m);
1369 }
1370 else {
1371 y = htrack(seg, m);
1372 }
1373 bb.LL.x = fmin(bb.LL.x, x);
1374 bb.LL.y = fmin(bb.LL.y, y);
1375 bb.UR.x = fmax(bb.UR.x, x);
1376 bb.UR.y = fmax(bb.UR.y, y);
1377 fprintf(fp, "%.0f %.0f lineto\n", x, y);
1378 }
1379
1380 n = CELL(aghead(e))->bb;
1381 if (seg->isVert) {
1382 x = vtrack(seg, m);
1383 y = (n.UR.y + n.LL.y)/2;
1384 }
1385 else {
1386 y = htrack(seg, m);
1387 x = (n.LL.x + n.UR.x)/2;
1388 }
1389 bb.LL.x = fmin(bb.LL.x, x);
1390 bb.LL.y = fmin(bb.LL.y, y);
1391 bb.UR.x = fmax(bb.UR.x, x);
1392 bb.UR.y = fmax(bb.UR.y, y);
1393 fprintf(fp, "%.0f %.0f lineto stroke\n", x, y);
1394
1395 return bb;
1396}
1397
1408static UNUSED void emitSearchGraph(FILE *fp, sgraph *sg) {
1409 pointf p;
1410 fputs ("graph G {\n", fp);
1411 fputs (" node[shape=point]\n", fp);
1412 fputs (" layout=neato\n", fp);
1413 for (int i = 0; i < sg->nnodes; i++) {
1414 snode *const np = sg->nodes+i;
1415 cell *cp = np->cells[0];
1416 if (cp == np->cells[1]) {
1417 p = midPt(cp);
1418 }
1419 else {
1420 if (IsNode(cp)) cp = np->cells[1];
1421 p = coordOf (cp, np);
1422 }
1423 fprintf (fp, " %d [pos=\"%.0f,%.0f!\"]\n", i, p.x, p.y);
1424 }
1425 for (int i = 0; i < sg->nedges; i++) {
1426 sedge *const ep = sg->edges+i;
1427 fprintf (fp, " %d -- %d[label=\"%f\"]\n", ep->v1, ep->v2, ep->weight);
1428 }
1429 fputs ("}\n", fp);
1430}
1431
1432static UNUSED void emitGraph(FILE *fp, maze *mp, size_t n_edges,
1433 route *route_list, epair_t es[]) {
1434 boxf absbb = {.LL = {.x = DBL_MAX, .y = DBL_MAX},
1435 .UR = {.x = -DBL_MAX, .y = -DBL_MAX}};
1436
1437 fprintf (fp, "%s", prolog2);
1438 fprintf (fp, "%d %d translate\n", TRANS, TRANS);
1439
1440 fputs ("0 0 1 setrgbcolor\n", fp);
1441 for (size_t i = 0; i < mp->ngcells; i++) {
1442 const boxf bb = mp->gcells[i].bb;
1443 fprintf (fp, "%f %f %f %f node\n", bb.LL.x, bb.LL.y, bb.UR.x, bb.UR.y);
1444 }
1445
1446 for (size_t i = 0; i < n_edges; i++) {
1447 absbb = emitEdge (fp, es[i].e, route_list[i], mp, absbb);
1448 }
1449
1450 fputs ("0.8 0.8 0.8 setrgbcolor\n", fp);
1451 for (size_t i = 0; i < mp->ncells; i++) {
1452 const boxf bb = mp->cells[i].bb;
1453 fprintf (fp, "%f %f %f %f cell\n", bb.LL.x, bb.LL.y, bb.UR.x, bb.UR.y);
1454 absbb.LL.x = fmin(absbb.LL.x, bb.LL.x);
1455 absbb.LL.y = fmin(absbb.LL.y, bb.LL.y);
1456 absbb.UR.x = fmax(absbb.UR.x, bb.UR.x);
1457 absbb.UR.y = fmax(absbb.UR.y, bb.UR.y);
1458 }
1459
1460 const boxf bbox = {
1461 .LL = {.x = absbb.LL.x + TRANS,
1462 .y = absbb.LL.y + TRANS},
1463 .UR = {.x = absbb.UR.x + TRANS,
1464 .y = absbb.UR.y + TRANS}};
1465 fprintf (fp, epilog2, bbox.LL.x, bbox.LL.y, bbox.UR.x, bbox.UR.y);
1466}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static void * gv_alloc(size_t size)
Definition alloc.h:47
CDT_API Dtlink_t * dtflatten(Dt_t *)
Definition dtflatten.c:10
#define dtmatch(d, o)
Definition cdt.h:185
#define dtlink(d, e)
Definition cdt.h:176
#define dtinsert(d, o)
Definition cdt.h:186
CDT_API int dtclose(Dt_t *)
Definition dtclose.c:8
CDT_API Dtmethod_t * Dtoset
ordered set (self-adjusting tree)
Definition dttree.c:304
CDT_API Dt_t * dtopen(Dtdisc_t *, Dtmethod_t *)
Definition dtopen.c:9
static NORETURN void graphviz_exit(int status)
Definition exit.h:23
void PQgen(int sz)
Definition fPQ.c:25
void PQfree(void)
Definition fPQ.c:36
static int cmp(const void *key, const void *candidate)
#define G
Definition gdefs.h:7
struct pointf_s pointf
#define DIST2(p, q)
Definition geom.h:55
geometric functions (e.g. on points and boxes)
static WUR pointf mid_pointf(pointf p, pointf q)
Definition geomprocs.h:104
static WUR pointf add_pointf(pointf p, pointf q)
Definition geomprocs.h:88
static WUR pointf interpolate_pointf(double t, pointf p, pointf q)
Definition geomprocs.h:112
bool Concentrate
Definition globals.h:59
int Nop
Definition globals.h:55
static bool Verbose
Definition gml2gv.c:24
static void free_graph(gmlgraph *p)
Definition gmlparse.c:118
void free(void *)
node NULL
Definition grammar.y:181
int agnedges(Agraph_t *g)
Definition graph.c:161
char * agget(void *obj, char *name)
Definition attr.c:448
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:26
#define ED_spl(e)
Definition types.h:595
#define agtail(e)
Definition cgraph.h:977
#define aghead(e)
Definition cgraph.h:978
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:41
#define ED_head_port(e)
Definition types.h:588
#define ED_label(e)
Definition types.h:589
#define ED_tail_port(e)
Definition types.h:597
void agwarningf(const char *fmt,...)
Definition agerror.c:173
void agerrorf(const char *fmt,...)
Definition agerror.c:165
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:48
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:41
#define ND_coord(n)
Definition types.h:490
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:143
#define AGSEQ(obj)
Definition cgraph.h:225
Arithmetic helper functions.
static int fcmp(double a, double b)
comparator for doubles
Definition gv_math.h:15
$2 prev
Definition htmlparse.y:291
type-generic dynamically expanding list
#define LIST_DETACH(list, datap, sizep)
Definition list.h:443
#define LIST(type)
Definition list.h:55
#define LIST_SIZE(list)
Definition list.h:80
#define LIST_CLEAR(list)
Definition list.h:240
#define LIST_APPEND(list, item)
Definition list.h:120
#define LIST_FREE(list)
Definition list.h:370
#define LIST_RESERVE(list, capacity)
Definition list.h:257
#define LIST_FRONT(list)
Definition list.h:180
#define LIST_IS_EMPTY(list)
Definition list.h:90
#define LIST_GET(list, index)
Definition list.h:155
static int * ps
Definition lu.c:51
maze * mkMaze(graph_t *g)
creates maze and fills maze::gcells and maze::cells. A subroutine of orthoEdges.
Definition maze.c:452
void updateWts(sgraph *g, cell *cp, sedge *ep)
updates sedge::weight of cell edges
Definition maze.c:171
void freeMaze(maze *mp)
Definition maze.c:504
makes maze with mkMaze for routing orthogonal edges
@ M_TOP
Definition maze.h:21
@ M_RIGHT
Definition maze.h:21
@ M_BOTTOM
Definition maze.h:21
@ M_LEFT
Definition maze.h:21
#define MZ_VSCAN
Definition maze.h:24
#define IsHScan(cp)
cell already inserted in horizontal channel
Definition maze.h:34
#define IsVScan(cp)
cell already inserted in vertical channel
Definition maze.h:32
#define IsNode(cp)
cell corresponds to node
Definition maze.h:30
#define MZ_HSCAN
Definition maze.h:25
#define N_DAD(n)
static boxf bbox(Ppoly_t **obsp, int npoly, int *np)
NEATOPROCS_API void s1(graph_t *, node_t *)
Definition stuff.c:651
snode priority queue for shortPath in sgraph
#define N_EDGE(n)
Definition fPQ.h:24
static char * bendToStr(bend b)
Definition ortho.c:450
static int seg_cmp(segment *S1, segment *S2)
Definition ortho.c:657
static pointf sidePt(const snode ptr, const cell *cp)
Definition ortho.c:80
static route convertSPtoRoute(sgraph *g, snode *fst, snode *lst)
Definition ortho.c:125
static Dt_t * extractVChans(maze *mp)
Definition ortho.c:341
static int add_edges_in_G(channel *cp)
Definition ortho.c:670
static int decide_point(pair *ret, segment *si, segment *sj, int dir1, int dir2)
Definition ortho.c:770
static int add_p_edges(Dt_t *chans, maze *mp)
Definition ortho.c:1005
static int edgeLen(Agedge_t *e)
Definition ortho.c:1125
static void removeEdge(segment *seg1, segment *seg2, int dir, maze *mp)
Definition ortho.c:893
static void setSeg(segment *sp, bool dir, double fix, double b1, double b2, int l1, int l2)
Definition ortho.c:99
static int eqEndSeg(bend S1l2, bend S2l2, bend T1, bend T2)
Definition ortho.c:542
static double htrack(segment *seg, maze *m)
Definition ortho.c:1058
static pointf coordOf(cell *cp, snode *np)
Definition ortho.c:1328
static UNUSED void emitGraph(FILE *fp, maze *mp, size_t n_edges, route *route_list, epair_t[])
Definition ortho.c:1432
static void putSeg(FILE *fp, segment *seg)
Definition ortho.c:474
static UNUSED void emitSearchGraph(FILE *fp, sgraph *sg)
dumps in dot format snode::cells and edges of sgraph for debugging
Definition ortho.c:1408
static char * epilog2
Definition ortho.c:1323
static int segCmp(segment *S1, segment *S2, bend T1, bend T2)
Definition ortho.c:578
#define CELL(n)
Definition ortho.c:55
static bool swap_ends_p(edge_t *e)
Definition ortho.c:1150
static segment * next_seg(segment *seg, int dir)
Definition ortho.c:710
static void set_parallel_edges(segment *seg1, segment *seg2, int dir1, int dir2, int hops, maze *mp)
Definition ortho.c:804
static bool spline_merge(node_t *n)
Definition ortho.c:1144
static int addPEdges(channel *cp, maze *mp)
Definition ortho.c:913
static double MID(double a, double b)
Definition ortho.c:57
static UNUSED void dumpChanG(channel *cp, double v)
Definition ortho.c:484
static void assignSegs(size_t nrtes, route *route_list, maze *mp)
Definition ortho.c:395
static cell * cellOf(snode *p, snode *q)
Definition ortho.c:65
static void create_graphs(Dt_t *chans)
Definition ortho.c:525
static void addChan(Dt_t *chdict, channel *cp, double j)
Definition ortho.c:289
static pointf midPt(const cell *cp)
Definition ortho.c:72
static int add_np_edges(Dt_t *chans)
Definition ortho.c:693
static void insertChan(channel *chan, segment *seg)
Definition ortho.c:377
static double vtrack(segment *seg, maze *m)
Definition ortho.c:1050
static Dt_t * extractHChans(maze *mp)
Definition ortho.c:305
static int overlapSeg(segment *S1, segment *S2, bend T1, bend T2)
Definition ortho.c:551
static void freeChannel(void *chan)
Definition ortho.c:228
static void assignTrackNo(Dt_t *chans)
Definition ortho.c:501
static void attachOrthoEdges(maze *mp, size_t n_edges, route *route_list, splineInfo *sinfo, epair_t es[], bool doLbls)
Definition ortho.c:1066
void orthoEdges(Agraph_t *g, bool useLbls)
Definition ortho.c:1163
static int dcmpid(void *k1, void *k2)
Definition ortho.c:264
static int ellSeg(bend S1l1, bend S1l2, bend T)
Definition ortho.c:568
#define TRANS
Definition ortho.c:1289
static void freeChanItem(void *item)
Definition ortho.c:235
static int chancmpid(void *k1, void *k2)
Definition ortho.c:250
static void addNodeEdges(sgraph *sg, cell *cp, snode *np)
Definition ortho.c:437
static int assignTracks(maze *mp)
Definition ortho.c:1020
static splineInfo sinfo
Definition ortho.c:1156
static Dtdisc_t chanDisc
Definition ortho.c:270
static int propagate_prec(segment *seg, int prec, int hops, int dir)
Definition ortho.c:723
static channel * chanSearch(Dt_t *chans, segment *seg)
Definition ortho.c:384
static void addLoop(sgraph *sg, cell *cp, snode *dp, snode *sp)
Definition ortho.c:417
static int edgecmp(const void *x, const void *y)
Definition ortho.c:1132
int odb_flags
Definition ortho.c:52
static boxf emitEdge(FILE *fp, Agedge_t *e, route rte, maze *m, boxf bb)
Definition ortho.c:1346
static char * prolog2
Definition ortho.c:1291
static bool is_parallel(segment *s1, segment *s2)
Definition ortho.c:755
static Dtdisc_t chanItemDisc
Definition ortho.c:279
void addPS(PointSet *ps, double x, double y)
Definition pointset.c:86
PointSet * newPS(void)
Definition pointset.c:68
void freePS(PointSet *ps)
Definition pointset.c:73
int isInPS(PointSet *ps, double x, double y)
Definition pointset.c:99
point containers PointSet and PointMap
rawgraph * make_graph(size_t n)
makes a graph with n vertices, 0 edges
Definition rawgraph.c:20
void insert_edge(rawgraph *g, size_t v1, size_t v2)
inserts edge FROM v1 to v2
Definition rawgraph.c:39
void remove_redge(rawgraph *g, size_t v1, size_t v2)
removes any edge between v1 to v2 – irrespective of direction
Definition rawgraph.c:45
void top_sort(rawgraph *g)
Definition rawgraph.c:75
bool edge_exists(rawgraph *g, size_t v1, size_t v2)
tests if there is an edge FROM v1 TO v2
Definition rawgraph.c:50
void clip_and_install(edge_t *fe, node_t *hn, pointf *ps, size_t pn, splineInfo *info)
Definition splines.c:234
void addEdgeLabels(edge_t *e)
Definition splines.c:1305
sedge * createSEdge(sgraph *g, snode *v1, snode *v2, double wt)
Definition sgraph.c:80
int shortPath(sgraph *g, snode *from, snode *to)
Definition sgraph.c:139
void reset(sgraph *G)
Definition sgraph.c:29
graph or subgraph
Definition cgraph.h:424
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
int flags
Definition maze.h:43
size_t nsides
Definition maze.h:54
boxf bb
Definition maze.h:56
snode ** sides
up to four sides: M_RIGHT, M_TOP, M_LEFT, M_BOTTOM
Definition maze.h:55
Dt_t * chans
Definition ortho.c:225
double v
Definition ortho.c:224
Dtlink_t link
Definition ortho.c:223
struct cell * cp
Definition structures.h:60
seg_list_t seg_list
segment pointers
Definition structures.h:58
paird p
Definition structures.h:57
rawgraph * G
Definition structures.h:59
Definition cdt.h:98
int d
Definition ortho.c:44
Agedge_t * e
Definition ortho.c:45
Definition utils.c:750
available channels for orthogonal edges around nodes of graph_t
Definition maze.h:66
cell * cells
cells not corresponding to graph nodes
Definition maze.h:69
cell * gcells
cells corresponding to graph nodes
Definition maze.h:70
size_t ncells
Definition maze.h:67
Dt_t * vchans
set of vertical channels, created by extractVChans
Definition maze.h:73
size_t ngcells
Definition maze.h:68
Dt_t * hchans
set of horizontal channels, created by extractHChans.
Definition maze.h:72
sgraph * sg
search graph
Definition maze.h:71
int a
Definition structures.h:25
int b
Definition structures.h:25
double p1
Definition structures.h:21
double p2
Definition structures.h:21
double x
Definition geom.h:29
double y
Definition geom.h:29
vertex * vertices
Definition rawgraph.h:27
segment * segs
Definition structures.h:50
size_t n
Definition structures.h:49
Definition sgraph.h:42
double weight
Definition sgraph.h:43
int v2
Definition sgraph.h:48
int v1
Definition sgraph.h:48
paird p
Definition structures.h:40
double comm_coord
Definition structures.h:39
size_t ind_no
index number of this segment in its channel
Definition structures.h:42
struct segment * next
Definition structures.h:45
bend l2
Definition structures.h:41
bend l1
Definition structures.h:41
bool isVert
Definition structures.h:38
int track_no
Definition structures.h:43
struct segment * prev
Definition structures.h:44
int nedges
Definition sgraph.h:52
sedge * edges
Definition sgraph.h:55
int nnodes
Definition sgraph.h:52
snode * nodes
Definition sgraph.h:54
a node of search graph sgraph, is created as a border segment between two adjusted cells of type cell...
Definition sgraph.h:26
bool isVert
Definition sgraph.h:39
struct cell * cells[2]
[0] - left or botom, [1] - top or right adjusted cell
Definition sgraph.h:32
bool set
Definition types.h:123
bend
Definition structures.h:32
@ B_LEFT
Definition structures.h:32
@ B_RIGHT
Definition structures.h:32
@ B_DOWN
Definition structures.h:32
@ B_UP
Definition structures.h:32
@ B_NODE
Definition structures.h:32
int topsort_order
Definition rawgraph.h:21
adj_list_t adj_list
adjacency list
Definition rawgraph.h:22
static clock_t T
Definition timing.c:17
Definition grammar.c:90
abstraction for squashing compiler warnings for unused symbols
#define UNUSED
Definition unused.h:25