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