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