41static void printboxes(
size_t boxn,
boxf *boxes) {
44 for (
size_t bi = 0; bi < boxn; bi++) {
45 ll = boxes[bi].
LL, ur = boxes[bi].
UR;
47 agxbprint(&buf,
"%.0f %.0f %.0f %.0f pathbox", ll.
x, ll.
y, ur.
x, ur.
y);
53static void psprintpolypts(
Ppoint_t *p,
int sz) {
56 fprintf(stderr,
"%%!\n");
57 fprintf(stderr,
"%% constraint poly\n");
58 fprintf(stderr,
"newpath\n");
59 for (i = 0; i < sz; i++)
60 fprintf(stderr,
"%f %f %s\n", p[i].x, p[i].y, i == 0 ?
"moveto" :
"lineto");
61 fprintf(stderr,
"closepath stroke\n");
63static void psprintpoint(
point p) {
64 fprintf(stderr,
"gsave\n");
66 "newpath %d %d moveto %d %d 2 0 360 arc closepath fill stroke\n", p.
x,
68 fprintf(stderr,
"/Times-Roman findfont 4 scalefont setfont\n");
69 fprintf(stderr,
"%d %d moveto (\\(%d,%d\\)) show\n", p.
x + 5, p.
y + 5, p.
x,
71 fprintf(stderr,
"grestore\n");
73static void psprintpointf(
pointf p) {
74 fprintf(stderr,
"gsave\n");
77 "newpath %.5g %.5g moveto %.5g %.5g 2 0 360 arc closepath fill stroke\n",
79 fprintf(stderr,
"/Times-Roman findfont 4 scalefont setfont\n");
80 fprintf(stderr,
"%.5g %.5g moveto (\\(%.5g,%.5g\\)) show\n", p.
x + 5, p.
y + 5,
82 fprintf(stderr,
"grestore\n");
90 for (
size_t i = 0; i < spl.
pn; i++) {
93 i == 0 ?
"moveto" : (i % 3 == 0 ?
"curveto" :
""));
103 for (
size_t i = 0; i < pl.
pn; i++) {
106 i == 0 ?
"moveto" :
"lineto");
112static void psprintpoly(
Ppoly_t p) {
117 for (
size_t bi = 0; bi < p.
pn; bi++) {
120 if (fabs(tail.x -
head.x) < 1 && fabs(tail.y -
head.y) < 1)
125 agxbprint(&buf,
"%s%.0f %.0f %.0f %.0f makevec", pfx, tail.x, tail.y,
132static void psprintboxes(
size_t boxn,
boxf *boxes) {
137 for (
size_t bi = 0; bi < boxn; bi++) {
138 ll = boxes[bi].
LL, ur = boxes[bi].
UR;
140 agxbprint(&buf,
"newpath\n%.0f %.0f moveto", ll.
x, ll.
y);
153static void psprintinit(
int begin) {
160static bool debugleveln(
edge_t *realedge,
int i) {
186 for (
size_t i = 0; i <
poly.pn; i++) {
187 edges[i].
a =
poly.ps[i];
197 pointf *ps = calloc(spl.
pn,
sizeof(ps[0]));
202 for (
size_t i = 0; i < spl.
pn; i++) {
236 const double num_div =
delta * (double)boxn;
238 for (
size_t splinepi = 0; splinepi + 3 < pn; splinepi += 3) {
239 for (
double si = 0; si <= num_div; si++) {
241 sp[0] = pps[splinepi];
242 sp[1] = pps[splinepi + 1];
243 sp[2] = pps[splinepi + 2];
244 sp[3] = pps[splinepi + 3];
245 sp[0].
x += t * (sp[1].
x - sp[0].
x);
246 sp[0].
y += t * (sp[1].
y - sp[0].
y);
247 sp[1].
x += t * (sp[2].
x - sp[1].
x);
248 sp[1].
y += t * (sp[2].
y - sp[1].
y);
249 sp[2].
x += t * (sp[3].
x - sp[2].
x);
250 sp[2].
y += t * (sp[3].
y - sp[2].
y);
251 sp[0].
x += t * (sp[1].
x - sp[0].
x);
252 sp[0].
y += t * (sp[1].
y - sp[0].
y);
253 sp[1].
x += t * (sp[2].
x - sp[1].
x);
254 sp[1].
y += t * (sp[2].
y - sp[1].
y);
255 sp[0].
x += t * (sp[1].
x - sp[0].
x);
256 sp[0].
y += t * (sp[1].
y - sp[0].
y);
257 for (
size_t bi = 0; bi < boxn; bi++) {
261 if (sp[0].y <= boxes[bi].UR.y +
FUDGE &&
263 boxes[bi].
LL.
x = fmin(boxes[bi].LL.x, sp[0].
x);
264 boxes[bi].
UR.
x = fmax(boxes[bi].UR.x, sp[0].
x);
310 agerrorf(
"in routesplines, cannot find NORMAL edge\n");
315 const size_t boxn = pp->
nbox;
321 if (debugleveln(realedge, 1))
322 printboxes(boxn, boxes);
323 if (debugleveln(realedge, 3)) {
325 psprintboxes(boxn, boxes);
332 if (boxn > 1 && boxes[0].LL.y > boxes[1].
LL.
y) {
334 for (
size_t bi = 0; bi < boxn; bi++) {
335 double v = boxes[bi].
UR.
y;
336 boxes[bi].
UR.
y = -1 * boxes[bi].
LL.
y;
347 for (bi = 0, pi = 0; bi < boxn; bi++) {
350 prev = boxes[bi].
LL.
y > boxes[bi - 1].
LL.
y ? -1 : 1;
352 next = boxes[bi + 1].
LL.
y > boxes[bi].
LL.
y ? 1 : -1;
354 if (next == -1 ||
prev == 1) {
355 polypoints[pi].
x = boxes[bi].
LL.
x;
356 polypoints[pi++].
y = boxes[bi].
UR.
y;
357 polypoints[pi].
x = boxes[bi].
LL.
x;
358 polypoints[pi++].
y = boxes[bi].
LL.
y;
360 polypoints[pi].
x = boxes[bi].
UR.
x;
361 polypoints[pi++].
y = boxes[bi].
LL.
y;
362 polypoints[pi].
x = boxes[bi].
UR.
x;
363 polypoints[pi++].
y = boxes[bi].
UR.
y;
365 }
else if (
prev == 0) {
366 polypoints[pi].
x = boxes[bi].
LL.
x;
367 polypoints[pi++].
y = boxes[bi].
UR.
y;
368 polypoints[pi].
x = boxes[bi].
LL.
x;
369 polypoints[pi++].
y = boxes[bi].
LL.
y;
371 if (!(
prev == -1 && next == -1)) {
373 agerrorf(
"in routesplines, illegal values of prev %d and next %d, "
375 prev, next, __LINE__);
380 for (bi = boxn - 1; bi !=
SIZE_MAX; bi--) {
383 prev = boxes[bi].
LL.
y > boxes[bi + 1].
LL.
y ? -1 : 1;
385 next = boxes[bi - 1].
LL.
y > boxes[bi].
LL.
y ? 1 : -1;
387 if (next == -1 ||
prev == 1) {
388 polypoints[pi].
x = boxes[bi].
LL.
x;
389 polypoints[pi++].
y = boxes[bi].
UR.
y;
390 polypoints[pi].
x = boxes[bi].
LL.
x;
391 polypoints[pi++].
y = boxes[bi].
LL.
y;
393 polypoints[pi].
x = boxes[bi].
UR.
x;
394 polypoints[pi++].
y = boxes[bi].
LL.
y;
395 polypoints[pi].
x = boxes[bi].
UR.
x;
396 polypoints[pi++].
y = boxes[bi].
UR.
y;
398 }
else if (
prev == 0) {
399 polypoints[pi].
x = boxes[bi].
UR.
x;
400 polypoints[pi++].
y = boxes[bi].
LL.
y;
401 polypoints[pi].
x = boxes[bi].
UR.
x;
402 polypoints[pi++].
y = boxes[bi].
UR.
y;
404 if (!(
prev == -1 && next == -1)) {
407 agerrorf(
"in routesplines, illegal values of prev %d and next %d, "
409 prev, next, __LINE__);
412 polypoints[pi].
x = boxes[bi].
UR.
x;
413 polypoints[pi++].
y = boxes[bi].
LL.
y;
414 polypoints[pi].
x = boxes[bi].
UR.
x;
415 polypoints[pi++].
y = boxes[bi].
UR.
y;
416 polypoints[pi].
x = boxes[bi].
LL.
x;
417 polypoints[pi++].
y = boxes[bi].
UR.
y;
418 polypoints[pi].
x = boxes[bi].
LL.
x;
419 polypoints[pi++].
y = boxes[bi].
LL.
y;
424 agerrorf(
"in routesplines, edge is a loop at %s\n",
430 for (
size_t bi = 0; bi < boxn; bi++) {
431 double v = boxes[bi].
UR.
y;
432 boxes[bi].
UR.
y = -1 * boxes[bi].
LL.
y;
435 for (
size_t i = 0; i < pi; i++)
436 polypoints[i].y *= -1;
439 static const double INITIAL_LLX = DBL_MAX;
440 static const double INITIAL_URX = -DBL_MAX;
441 for (
size_t bi = 0; bi < boxn; bi++) {
442 boxes[bi].
LL.
x = INITIAL_LLX;
443 boxes[bi].
UR.
x = INITIAL_URX;
450 agerrorf(
"in routesplines, Pshortestpath failed\n");
454 if (debugleveln(realedge, 3)) {
464 for (
size_t edgei = 0; edgei <
poly.pn; edgei++) {
465 edges[edgei].
a = polypoints[edgei];
466 edges[edgei].
b = polypoints[(edgei + 1) %
poly.pn];
481 agerrorf(
"in routesplines, Proutespline failed\n");
486 if (debugleveln(realedge, 3)) {
492 pointf *ps = calloc(spl.
pn,
sizeof(ps[0]));
500 for (
size_t splinepi = 0; splinepi < spl.
pn; splinepi++) {
501 ps[splinepi] = spl.
ps[splinepi];
506 bool is_horizontal = spl.
pn > 0;
507 for (
size_t i = 0; i < spl.
pn; ++i) {
508 if (fabs(ps[0].y - ps[i].y) >
FUDGE) {
509 is_horizontal =
false;
514 GV_INFO(
"spline [%.03f, %.03f] -- [%.03f, %.03f] is horizontal;"
515 " will be trivially bounded",
516 ps[0].x, ps[0].y, ps[spl.
pn - 1].
x, ps[spl.
pn - 1].
y);
520 bool is_vertical = spl.
pn > 0;
521 for (
size_t i = 0; i < spl.
pn; ++i) {
522 if (fabs(ps[0].x - ps[i].x) >
FUDGE) {
528 GV_INFO(
"spline [%.03f, %.03f] -- [%.03f, %.03f] is vertical;"
529 " will be trivially bounded",
530 ps[0].x, ps[0].y, ps[spl.
pn - 1].
x, ps[spl.
pn - 1].
y);
535 if (is_horizontal || is_vertical) {
536 for (
size_t i = 0; i < boxn; ++i) {
537 boxes[i].
LL.
x = ps[0].
x;
538 boxes[i].
UR.
x = ps[0].
x;
546 for (loopcnt = 0; unbounded && loopcnt <
LOOP_TRIES; loopcnt++) {
555 for (bi = 0; bi < boxn; bi++) {
575 agwarningf(
"Unable to reclaim box space in spline routing for edge \"%s\" "
576 "-> \"%s\". Something is probably seriously wrong.\n",
589 printboxes(boxn, boxes);
604static double overlap(
double i0,
double i1,
double j0,
double j1) {
611 if (i0 <= j0 && i1 >= j1)
614 if (j0 <= i0 && j1 >= i1)
617 if (j0 <= i0 && i0 <= j1)
619 assert(j0 <= i1 && i1 <= j1);
634 int errs, l, r, d, u;
638 for (
size_t bi = 0; bi < boxn; bi++) {
639 if (fabs(boxes[bi].LL.y - boxes[bi].
UR.
y) < .01)
641 if (fabs(boxes[bi].LL.x - boxes[bi].
UR.
x) < .01)
643 boxes[i] = boxes[bi];
649 agerrorf(
"in checkpath, all bounding boxes are below threshold\n");
656 agerrorf(
"in checkpath, box 0 has LL coord > UR coord\n");
660 for (
size_t bi = 0; bi + 1 < boxn; bi++) {
661 ba = &boxes[bi], bb = &boxes[bi + 1];
662 if (bb->LL.x > bb->UR.x || bb->LL.y > bb->UR.y) {
668 l = ba->
UR.
x < bb->LL.x ? 1 : 0;
669 r = ba->
LL.
x > bb->UR.x ? 1 : 0;
670 d = ba->
UR.
y < bb->LL.y ? 1 : 0;
671 u = ba->
LL.
y > bb->UR.y ? 1 : 0;
672 errs = l + r + d + u;
684 xy = ba->
UR.
x, ba->
UR.
x = bb->LL.x, bb->LL.x = xy, l = 0;
686 xy = ba->
LL.
x, ba->
LL.
x = bb->UR.x, bb->UR.x = xy, r = 0;
688 xy = ba->
UR.
y, ba->
UR.
y = bb->LL.y, bb->LL.y = xy, d = 0;
690 xy = ba->
LL.
y, ba->
LL.
y = bb->UR.y, bb->UR.y = xy, u = 0;
691 for (
int j = 0; j < errs - 1; j++) {
693 xy = (ba->
UR.
x + bb->LL.x) / 2.0 + 0.5, ba->
UR.
x = bb->LL.x = xy,
696 xy = (ba->
LL.
x + bb->UR.x) / 2.0 + 0.5, ba->
LL.
x = bb->UR.x = xy,
699 xy = (ba->
UR.
y + bb->LL.y) / 2.0 + 0.5, ba->
UR.
y = bb->LL.y = xy,
702 xy = (ba->
LL.
y + bb->UR.y) / 2.0 + 0.5, ba->
LL.
y = bb->UR.y = xy,
707 double xoverlap =
overlap(ba->
LL.
x, ba->
UR.
x, bb->LL.x, bb->UR.x);
708 double yoverlap =
overlap(ba->
LL.
y, ba->
UR.
y, bb->LL.y, bb->UR.y);
709 if (xoverlap > 0 && yoverlap > 0) {
710 if (xoverlap < yoverlap) {
711 if (ba->
UR.
x - ba->
LL.
x > bb->UR.x - bb->LL.x) {
713 if (ba->
UR.
x < bb->UR.x)
719 if (ba->
UR.
x < bb->UR.x)
725 if (ba->
UR.
y - ba->
LL.
y > bb->UR.y - bb->LL.y) {
727 if (ba->
UR.
y < bb->UR.y)
733 if (ba->
UR.
y < bb->UR.y)
751 if (thepath->
end.
p.
x < boxes[boxn - 1].
LL.
x ||
752 thepath->
end.
p.
x > boxes[boxn - 1].
UR.
x ||
753 thepath->
end.
p.
y < boxes[boxn - 1].
LL.
y ||
754 thepath->
end.
p.
y > boxes[boxn - 1].
UR.
y) {
755 thepath->
end.
p.
x = fmax(thepath->
end.
p.
x, boxes[boxn - 1].
LL.
x);
756 thepath->
end.
p.
x = fmin(thepath->
end.
p.
x, boxes[boxn - 1].
UR.
x);
757 thepath->
end.
p.
y = fmax(thepath->
end.
p.
y, boxes[boxn - 1].
LL.
y);
758 thepath->
end.
p.
y = fmin(thepath->
end.
p.
y, boxes[boxn - 1].
UR.
y);
765 for (
size_t bi = 0; bi < pp->
nbox; bi++)
766 fprintf(stderr,
"%" PRISIZE_T " (%.5g, %.5g), (%.5g, %.5g)\n", bi,
769 fprintf(stderr,
"start port: (%.5g, %.5g), tangent angle: %.5g, %s\n",
772 fprintf(stderr,
"end port: (%.5g, %.5g), tangent angle: %.5g, %s\n",
787static void nodes_delete(nodes_t *pvec) {
794typedef LIST(nodes_t *) cycles_t;
796static bool cycle_contains_edge(nodes_t *cycle,
edge_t *
edge) {
800 const size_t cycle_len =
LIST_SIZE(cycle);
802 for (
size_t i = 0; i < cycle_len; ++i) {
803 const node_t *c_start =
LIST_GET(cycle, i == 0 ? cycle_len - 1 : i - 1);
806 if (c_start == start && c_end == end)
814 const size_t cycle_len =
LIST_SIZE(cycle);
817 bool all_items_match;
819 for (
size_t c = 0; c <
LIST_SIZE(cycles); ++c) {
820 nodes_t *cur_cycle =
LIST_GET(cycles, c);
821 const size_t cur_cycle_len =
LIST_SIZE(cur_cycle);
824 if (cur_cycle_len == cycle_len) {
825 all_items_match =
true;
826 for (i = 0; i < cur_cycle_len; ++i) {
829 all_items_match =
false;
849 nodes_t *cycle =
gv_alloc(
sizeof(nodes_t));
858 dfs(g, n, visited, end, cycles);
871 cycles_t alloced_cycles = {.dtor = nodes_delete};
877 nodes_t *cycle =
gv_alloc(
sizeof(nodes_t));
882 dfs(g, n, cycle, n, &cycles);
891 nodes_t *shortest =
NULL;
893 for (
size_t c = 0; c <
LIST_SIZE(cycles); ++c) {
894 nodes_t *cycle =
LIST_GET(cycles, c);
897 if (cycle_len < min_size)
901 if (cycle_contains_edge(cycle,
edge)) {
923 for (
size_t idx = 0; idx <
LIST_SIZE(cycle); ++idx) {
939 const double dist =
DIST(spl[3], spl[0]);
940 const double r =
dist / 5.0;
941 const double vX = centroid.
x - midpt.
x;
942 const double vY = centroid.
y - midpt.
y;
943 const double magV = hypot(vX, vY);
948 const pointf a = {.
x = midpt.
x - vX / magV * r,
949 .y = midpt.
y - vY / magV * r};
965 for (
size_t i = 0; i < e_cnt; i++) {
969 assert(e_cnt <= INT_MAX);
1000 pointf perp = {.
x = dumb[0].
y - dumb[3].
y, .y = dumb[3].
x - dumb[0].
x};
1003 assert(e_cnt - 1 <= INT_MAX);
1004 int dx = xstep * (int)(e_cnt - 1) / 2;
1005 dumb[1].
x = dumb[0].
x +
dx *
perp.
x / l_perp;
1006 dumb[1].
y = dumb[0].
y +
dx *
perp.
y / l_perp;
1007 dumb[2].
x = dumb[3].
x +
dx *
perp.
x / l_perp;
1008 dumb[2].
y = dumb[3].
y +
dx *
perp.
y / l_perp;
1013 for (
size_t i = 0; i < e_cnt; i++) {
1014 edge_t *e0 = edge_list[i];
1017 for (
size_t j = 0; j < 4; j++) {
1018 dumber[j] = dumb[j];
1021 for (
size_t j = 0; j < 4; j++) {
1022 dumber[3 - j] = dumb[j];
1026 Ppoint_t pts[] = {dumber[0], dumber[1], dumber[2], dumber[3]};
Dynamically expanding string buffers.
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
static char * agxbdisown(agxbuf *xb)
Memory allocation wrappers that exit on failure.
static char * gv_strdup(const char *original)
static void * gv_calloc(size_t nmemb, size_t size)
static void * gv_alloc(size_t size)
helpers for verbose/debug printing
static void del(Dict_t *d, Dtlink_t **set, Agedge_t *e)
static double dist(int dim, double *x, double *y)
#define APPROXEQPT(p, q, tol)
geometric functions (e.g. on points and boxes)
static WUR pointf perp(pointf p)
static WUR pointf mid_pointf(pointf p, pointf q)
static WUR pointf add_pointf(pointf p, pointf q)
static int cnt(Dict_t *d, Dtlink_t **set)
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
void agwarningf(const char *fmt,...)
void agerrorf(const char *fmt,...)
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Agnode_t * agfstnode(Agraph_t *g)
Agraph_t * agraphof(void *obj)
char * agnameof(void *)
returns a string descriptor for the object.
Arithmetic helper functions.
static bool is_exactly_equal(double a, double b)
are two values precisely the same?
type-generic dynamically expanding list
#define LIST_APPEND(list,...)
#define LIST_COPY(list_type, src)
#define LIST_DROP_BACK(list)
#define LIST_CONTAINS(list, needle)
#define LIST_IS_EMPTY(list)
#define LIST_GET(list, index)
arithmetic overflow helpers
static bool fdiv_overflow(double n, double d, double *res)
finds and smooths shortest paths
void make_polyline(Ppolyline_t line, Ppolyline_t *sline)
int Proutespline(Pedge_t *barriers, size_t n_barriers, Ppolyline_t input_route, Pvector_t endpoint_slopes[2], Ppolyline_t *output_route)
int Pshortestpath(Ppoly_t *boundary, Ppoint_t endpoints[2], Ppolyline_t *output_route)
void clip_and_install(edge_t *fe, node_t *hn, pointf *ps, size_t pn, splineInfo *info)
void addEdgeLabels(edge_t *e)
static bool is_cycle_unique(cycles_t *cycles, nodes_t *cycle)
static void printpath(path *pp)
static pointf get_centroid(Agraph_t *g)
static void dfs(graph_t *g, node_t *search, nodes_t *visited, node_t *end, cycles_t *cycles)
int routesplinesinit(void)
static int nedges
total no. of edges used in routing
pointf * simpleSplineRoute(pointf tp, pointf hp, Ppoly_t poly, size_t *n_spl_pts, int polyline)
Given a simple (ccw) polygon, route an edge from tp to hp.
static nodes_t * find_shortest_cycle_with_edge(cycles_t *cycles, edge_t *edge, size_t min_size)
static cycles_t find_all_cycles(graph_t *g)
static size_t nboxes
total no. of boxes used in routing
static void limitBoxes(boxf *boxes, size_t boxn, const pointf *pps, size_t pn, double delta)
static int checkpath(size_t, boxf *, path *)
static pointf get_cycle_centroid(graph_t *g, edge_t *edge)
static double overlap(double i0, double i1, double j0, double j1)
void routesplinesterm(void)
void makeStraightEdges(graph_t *g, edge_t **edge_list, size_t e_cnt, int et, splineInfo *sinfo)
void makeStraightEdge(graph_t *g, edge_t *e, int et, splineInfo *sinfo)
pointf * routesplines(path *pp, size_t *npoints)
pointf * routepolylines(path *pp, size_t *npoints)
static pointf * routesplines_(path *pp, size_t *npoints, int polyline)
Agraph_t * root
subgraphs - ancestors
size_t nbox
number of subdivisions