40static void printboxes(
size_t boxn,
boxf *boxes) {
43 for (
size_t bi = 0; bi < boxn; bi++) {
44 ll = boxes[bi].
LL, ur = boxes[bi].
UR;
46 agxbprint(&buf,
"%.0f %.0f %.0f %.0f pathbox", ll.
x, ll.
y, ur.
x, ur.
y);
52static void psprintpolypts(
Ppoint_t *p,
int sz) {
55 fprintf(stderr,
"%%!\n");
56 fprintf(stderr,
"%% constraint poly\n");
57 fprintf(stderr,
"newpath\n");
58 for (i = 0; i < sz; i++)
59 fprintf(stderr,
"%f %f %s\n", p[i].x, p[i].y, i == 0 ?
"moveto" :
"lineto");
60 fprintf(stderr,
"closepath stroke\n");
62static void psprintpoint(
point p) {
63 fprintf(stderr,
"gsave\n");
65 "newpath %d %d moveto %d %d 2 0 360 arc closepath fill stroke\n", p.
x,
67 fprintf(stderr,
"/Times-Roman findfont 4 scalefont setfont\n");
68 fprintf(stderr,
"%d %d moveto (\\(%d,%d\\)) show\n", p.
x + 5, p.
y + 5, p.
x,
70 fprintf(stderr,
"grestore\n");
72static void psprintpointf(
pointf p) {
73 fprintf(stderr,
"gsave\n");
76 "newpath %.5g %.5g moveto %.5g %.5g 2 0 360 arc closepath fill stroke\n",
78 fprintf(stderr,
"/Times-Roman findfont 4 scalefont setfont\n");
79 fprintf(stderr,
"%.5g %.5g moveto (\\(%.5g,%.5g\\)) show\n", p.
x + 5, p.
y + 5,
81 fprintf(stderr,
"grestore\n");
89 for (
size_t i = 0; i < spl.
pn; i++) {
92 i == 0 ?
"moveto" : (i % 3 == 0 ?
"curveto" :
""));
102 for (
size_t i = 0; i < pl.
pn; i++) {
105 i == 0 ?
"moveto" :
"lineto");
111static void psprintpoly(
Ppoly_t p) {
116 for (
size_t bi = 0; bi < p.
pn; bi++) {
119 if (fabs(tail.x -
head.x) < 1 && fabs(tail.y -
head.y) < 1)
124 agxbprint(&buf,
"%s%.0f %.0f %.0f %.0f makevec", pfx, tail.x, tail.y,
131static void psprintboxes(
size_t boxn,
boxf *boxes) {
136 for (
size_t bi = 0; bi < boxn; bi++) {
137 ll = boxes[bi].
LL, ur = boxes[bi].
UR;
139 agxbprint(&buf,
"newpath\n%.0f %.0f moveto", ll.
x, ll.
y);
152static void psprintinit(
int begin) {
159static bool debugleveln(
edge_t *realedge,
int i) {
185 for (
size_t i = 0; i <
poly.pn; i++) {
186 edges[i].
a =
poly.ps[i];
196 pointf *ps = calloc(spl.
pn,
sizeof(ps[0]));
201 for (
size_t i = 0; i < spl.
pn; i++) {
235 const double num_div =
delta * (double)boxn;
237 for (
size_t splinepi = 0; splinepi + 3 < pn; splinepi += 3) {
238 for (
double si = 0; si <= num_div; si++) {
240 sp[0] = pps[splinepi];
241 sp[1] = pps[splinepi + 1];
242 sp[2] = pps[splinepi + 2];
243 sp[3] = pps[splinepi + 3];
244 sp[0].
x += t * (sp[1].
x - sp[0].
x);
245 sp[0].
y += t * (sp[1].
y - sp[0].
y);
246 sp[1].
x += t * (sp[2].
x - sp[1].
x);
247 sp[1].
y += t * (sp[2].
y - sp[1].
y);
248 sp[2].
x += t * (sp[3].
x - sp[2].
x);
249 sp[2].
y += t * (sp[3].
y - sp[2].
y);
250 sp[0].
x += t * (sp[1].
x - sp[0].
x);
251 sp[0].
y += t * (sp[1].
y - sp[0].
y);
252 sp[1].
x += t * (sp[2].
x - sp[1].
x);
253 sp[1].
y += t * (sp[2].
y - sp[1].
y);
254 sp[0].
x += t * (sp[1].
x - sp[0].
x);
255 sp[0].
y += t * (sp[1].
y - sp[0].
y);
256 for (
size_t bi = 0; bi < boxn; bi++) {
260 if (sp[0].y <= boxes[bi].UR.y +
FUDGE &&
262 boxes[bi].
LL.
x = fmin(boxes[bi].LL.x, sp[0].
x);
263 boxes[bi].
UR.
x = fmax(boxes[bi].UR.x, sp[0].
x);
309 agerrorf(
"in routesplines, cannot find NORMAL edge\n");
314 const size_t boxn = pp->
nbox;
320 if (debugleveln(realedge, 1))
321 printboxes(boxn, boxes);
322 if (debugleveln(realedge, 3)) {
324 psprintboxes(boxn, boxes);
331 if (boxn > 1 && boxes[0].LL.y > boxes[1].
LL.
y) {
333 for (
size_t bi = 0; bi < boxn; bi++) {
334 double v = boxes[bi].
UR.
y;
335 boxes[bi].
UR.
y = -1 * boxes[bi].
LL.
y;
346 for (bi = 0, pi = 0; bi < boxn; bi++) {
349 prev = boxes[bi].
LL.
y > boxes[bi - 1].
LL.
y ? -1 : 1;
351 next = boxes[bi + 1].
LL.
y > boxes[bi].
LL.
y ? 1 : -1;
353 if (next == -1 ||
prev == 1) {
354 polypoints[pi].
x = boxes[bi].
LL.
x;
355 polypoints[pi++].
y = boxes[bi].
UR.
y;
356 polypoints[pi].
x = boxes[bi].
LL.
x;
357 polypoints[pi++].
y = boxes[bi].
LL.
y;
359 polypoints[pi].
x = boxes[bi].
UR.
x;
360 polypoints[pi++].
y = boxes[bi].
LL.
y;
361 polypoints[pi].
x = boxes[bi].
UR.
x;
362 polypoints[pi++].
y = boxes[bi].
UR.
y;
364 }
else if (
prev == 0) {
365 polypoints[pi].
x = boxes[bi].
LL.
x;
366 polypoints[pi++].
y = boxes[bi].
UR.
y;
367 polypoints[pi].
x = boxes[bi].
LL.
x;
368 polypoints[pi++].
y = boxes[bi].
LL.
y;
370 if (!(
prev == -1 && next == -1)) {
372 agerrorf(
"in routesplines, illegal values of prev %d and next %d, "
374 prev, next, __LINE__);
379 for (bi = boxn - 1; bi !=
SIZE_MAX; bi--) {
382 prev = boxes[bi].
LL.
y > boxes[bi + 1].
LL.
y ? -1 : 1;
384 next = boxes[bi - 1].
LL.
y > boxes[bi].
LL.
y ? 1 : -1;
386 if (next == -1 ||
prev == 1) {
387 polypoints[pi].
x = boxes[bi].
LL.
x;
388 polypoints[pi++].
y = boxes[bi].
UR.
y;
389 polypoints[pi].
x = boxes[bi].
LL.
x;
390 polypoints[pi++].
y = boxes[bi].
LL.
y;
392 polypoints[pi].
x = boxes[bi].
UR.
x;
393 polypoints[pi++].
y = boxes[bi].
LL.
y;
394 polypoints[pi].
x = boxes[bi].
UR.
x;
395 polypoints[pi++].
y = boxes[bi].
UR.
y;
397 }
else if (
prev == 0) {
398 polypoints[pi].
x = boxes[bi].
UR.
x;
399 polypoints[pi++].
y = boxes[bi].
LL.
y;
400 polypoints[pi].
x = boxes[bi].
UR.
x;
401 polypoints[pi++].
y = boxes[bi].
UR.
y;
403 if (!(
prev == -1 && next == -1)) {
406 agerrorf(
"in routesplines, illegal values of prev %d and next %d, "
408 prev, next, __LINE__);
411 polypoints[pi].
x = boxes[bi].
UR.
x;
412 polypoints[pi++].
y = boxes[bi].
LL.
y;
413 polypoints[pi].
x = boxes[bi].
UR.
x;
414 polypoints[pi++].
y = boxes[bi].
UR.
y;
415 polypoints[pi].
x = boxes[bi].
LL.
x;
416 polypoints[pi++].
y = boxes[bi].
UR.
y;
417 polypoints[pi].
x = boxes[bi].
LL.
x;
418 polypoints[pi++].
y = boxes[bi].
LL.
y;
423 agerrorf(
"in routesplines, edge is a loop at %s\n",
429 for (
size_t bi = 0; bi < boxn; bi++) {
430 double v = boxes[bi].
UR.
y;
431 boxes[bi].
UR.
y = -1 * boxes[bi].
LL.
y;
434 for (
size_t i = 0; i < pi; i++)
435 polypoints[i].y *= -1;
438 static const double INITIAL_LLX = DBL_MAX;
439 static const double INITIAL_URX = -DBL_MAX;
440 for (
size_t bi = 0; bi < boxn; bi++) {
441 boxes[bi].
LL.
x = INITIAL_LLX;
442 boxes[bi].
UR.
x = INITIAL_URX;
449 agerrorf(
"in routesplines, Pshortestpath failed\n");
453 if (debugleveln(realedge, 3)) {
463 for (
size_t edgei = 0; edgei <
poly.pn; edgei++) {
464 edges[edgei].
a = polypoints[edgei];
465 edges[edgei].
b = polypoints[(edgei + 1) %
poly.pn];
480 agerrorf(
"in routesplines, Proutespline failed\n");
485 if (debugleveln(realedge, 3)) {
491 pointf *ps = calloc(spl.
pn,
sizeof(ps[0]));
499 for (
size_t splinepi = 0; splinepi < spl.
pn; splinepi++) {
500 ps[splinepi] = spl.
ps[splinepi];
505 bool is_horizontal = spl.
pn > 0;
506 for (
size_t i = 0; i < spl.
pn; ++i) {
507 if (fabs(ps[0].y - ps[i].y) >
FUDGE) {
508 is_horizontal =
false;
513 GV_INFO(
"spline [%.03f, %.03f] -- [%.03f, %.03f] is horizontal;"
514 " will be trivially bounded",
515 ps[0].x, ps[0].y, ps[spl.
pn - 1].
x, ps[spl.
pn - 1].
y);
519 bool is_vertical = spl.
pn > 0;
520 for (
size_t i = 0; i < spl.
pn; ++i) {
521 if (fabs(ps[0].x - ps[i].x) >
FUDGE) {
527 GV_INFO(
"spline [%.03f, %.03f] -- [%.03f, %.03f] is vertical;"
528 " will be trivially bounded",
529 ps[0].x, ps[0].y, ps[spl.
pn - 1].
x, ps[spl.
pn - 1].
y);
534 if (is_horizontal || is_vertical) {
535 for (
size_t i = 0; i < boxn; ++i) {
536 boxes[i].
LL.
x = ps[0].
x;
537 boxes[i].
UR.
x = ps[0].
x;
545 for (loopcnt = 0; unbounded && loopcnt <
LOOP_TRIES; loopcnt++) {
554 for (bi = 0; bi < boxn; bi++) {
574 agwarningf(
"Unable to reclaim box space in spline routing for edge \"%s\" "
575 "-> \"%s\". Something is probably seriously wrong.\n",
588 printboxes(boxn, boxes);
603static double overlap(
double i0,
double i1,
double j0,
double j1) {
610 if (i0 <= j0 && i1 >= j1)
613 if (j0 <= i0 && j1 >= i1)
616 if (j0 <= i0 && i0 <= j1)
618 assert(j0 <= i1 && i1 <= j1);
633 int errs, l, r, d, u;
637 for (
size_t bi = 0; bi < boxn; bi++) {
638 if (fabs(boxes[bi].LL.y - boxes[bi].
UR.
y) < .01)
640 if (fabs(boxes[bi].LL.x - boxes[bi].
UR.
x) < .01)
642 boxes[i] = boxes[bi];
648 agerrorf(
"in checkpath, all bounding boxes are below threshold\n");
655 agerrorf(
"in checkpath, box 0 has LL coord > UR coord\n");
659 for (
size_t bi = 0; bi + 1 < boxn; bi++) {
660 ba = &boxes[bi], bb = &boxes[bi + 1];
661 if (bb->LL.x > bb->UR.x || bb->LL.y > bb->UR.y) {
667 l = ba->
UR.
x < bb->LL.x ? 1 : 0;
668 r = ba->
LL.
x > bb->UR.x ? 1 : 0;
669 d = ba->
UR.
y < bb->LL.y ? 1 : 0;
670 u = ba->
LL.
y > bb->UR.y ? 1 : 0;
671 errs = l + r + d + u;
683 xy = ba->
UR.
x, ba->
UR.
x = bb->LL.x, bb->LL.x = xy, l = 0;
685 xy = ba->
LL.
x, ba->
LL.
x = bb->UR.x, bb->UR.x = xy, r = 0;
687 xy = ba->
UR.
y, ba->
UR.
y = bb->LL.y, bb->LL.y = xy, d = 0;
689 xy = ba->
LL.
y, ba->
LL.
y = bb->UR.y, bb->UR.y = xy, u = 0;
690 for (
int j = 0; j < errs - 1; j++) {
692 xy = (ba->
UR.
x + bb->LL.x) / 2.0 + 0.5, ba->
UR.
x = bb->LL.x = xy,
695 xy = (ba->
LL.
x + bb->UR.x) / 2.0 + 0.5, ba->
LL.
x = bb->UR.x = xy,
698 xy = (ba->
UR.
y + bb->LL.y) / 2.0 + 0.5, ba->
UR.
y = bb->LL.y = xy,
701 xy = (ba->
LL.
y + bb->UR.y) / 2.0 + 0.5, ba->
LL.
y = bb->UR.y = xy,
706 double xoverlap =
overlap(ba->
LL.
x, ba->
UR.
x, bb->LL.x, bb->UR.x);
707 double yoverlap =
overlap(ba->
LL.
y, ba->
UR.
y, bb->LL.y, bb->UR.y);
708 if (xoverlap > 0 && yoverlap > 0) {
709 if (xoverlap < yoverlap) {
710 if (ba->
UR.
x - ba->
LL.
x > bb->UR.x - bb->LL.x) {
712 if (ba->
UR.
x < bb->UR.x)
718 if (ba->
UR.
x < bb->UR.x)
724 if (ba->
UR.
y - ba->
LL.
y > bb->UR.y - bb->LL.y) {
726 if (ba->
UR.
y < bb->UR.y)
732 if (ba->
UR.
y < bb->UR.y)
750 if (thepath->
end.
p.
x < boxes[boxn - 1].
LL.
x ||
751 thepath->
end.
p.
x > boxes[boxn - 1].
UR.
x ||
752 thepath->
end.
p.
y < boxes[boxn - 1].
LL.
y ||
753 thepath->
end.
p.
y > boxes[boxn - 1].
UR.
y) {
754 thepath->
end.
p.
x = fmax(thepath->
end.
p.
x, boxes[boxn - 1].
LL.
x);
755 thepath->
end.
p.
x = fmin(thepath->
end.
p.
x, boxes[boxn - 1].
UR.
x);
756 thepath->
end.
p.
y = fmax(thepath->
end.
p.
y, boxes[boxn - 1].
LL.
y);
757 thepath->
end.
p.
y = fmin(thepath->
end.
p.
y, boxes[boxn - 1].
UR.
y);
764 for (
size_t bi = 0; bi < pp->
nbox; bi++)
765 fprintf(stderr,
"%" PRISIZE_T " (%.5g, %.5g), (%.5g, %.5g)\n", bi,
768 fprintf(stderr,
"start port: (%.5g, %.5g), tangent angle: %.5g, %s\n",
771 fprintf(stderr,
"end port: (%.5g, %.5g), tangent angle: %.5g, %s\n",
786static void nodes_delete(nodes_t *pvec) {
793typedef LIST(nodes_t *) cycles_t;
795static bool cycle_contains_edge(nodes_t *cycle,
edge_t *
edge) {
799 const size_t cycle_len =
LIST_SIZE(cycle);
801 for (
size_t i = 0; i < cycle_len; ++i) {
802 const node_t *c_start =
LIST_GET(cycle, i == 0 ? cycle_len - 1 : i - 1);
805 if (c_start == start && c_end == end)
813 const size_t cycle_len =
LIST_SIZE(cycle);
816 bool all_items_match;
818 for (
size_t c = 0; c <
LIST_SIZE(cycles); ++c) {
819 nodes_t *cur_cycle =
LIST_GET(cycles, c);
820 const size_t cur_cycle_len =
LIST_SIZE(cur_cycle);
823 if (cur_cycle_len == cycle_len) {
824 all_items_match =
true;
825 for (i = 0; i < cur_cycle_len; ++i) {
828 all_items_match =
false;
848 nodes_t *cycle =
gv_alloc(
sizeof(nodes_t));
857 dfs(g, n, visited, end, cycles);
870 cycles_t alloced_cycles = {.dtor = nodes_delete};
876 nodes_t *cycle =
gv_alloc(
sizeof(nodes_t));
881 dfs(g, n, cycle, n, &cycles);
890 nodes_t *shortest =
NULL;
892 for (
size_t c = 0; c <
LIST_SIZE(cycles); ++c) {
893 nodes_t *cycle =
LIST_GET(cycles, c);
896 if (cycle_len < min_size)
900 if (cycle_contains_edge(cycle,
edge)) {
922 for (
size_t idx = 0; idx <
LIST_SIZE(cycle); ++idx) {
938 const double dist =
DIST(spl[3], spl[0]);
939 const double r =
dist / 5.0;
940 const double vX = centroid.
x - midpt.
x;
941 const double vY = centroid.
y - midpt.
y;
942 const double magV = hypot(vX, vY);
946 const pointf a = {.
x = midpt.
x - vX / magV * r,
947 .y = midpt.
y - vY / magV * r};
949 spl[1].
x = spl[2].
x = a.
x;
950 spl[1].
y = spl[2].
y = a.
y;
964 for (
size_t i = 0; i < e_cnt; i++) {
968 assert(e_cnt <= INT_MAX);
999 pointf perp = {.
x = dumb[0].
y - dumb[3].
y, .y = dumb[3].
x - dumb[0].
x};
1002 assert(e_cnt - 1 <= INT_MAX);
1003 int dx = xstep * (int)(e_cnt - 1) / 2;
1004 dumb[1].
x = dumb[0].
x +
dx *
perp.
x / l_perp;
1005 dumb[1].
y = dumb[0].
y +
dx *
perp.
y / l_perp;
1006 dumb[2].
x = dumb[3].
x +
dx *
perp.
x / l_perp;
1007 dumb[2].
y = dumb[3].
y +
dx *
perp.
y / l_perp;
1012 for (
size_t i = 0; i < e_cnt; i++) {
1013 edge_t *e0 = edge_list[i];
1016 for (
size_t j = 0; j < 4; j++) {
1017 dumber[j] = dumb[j];
1020 for (
size_t j = 0; j < 4; j++) {
1021 dumber[3 - j] = dumb[j];
1025 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_zero(double v)
is a value precisely 0.0?
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)
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