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