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)
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)
65 fprintf(stderr,
"gsave\n");
67 "newpath %d %d moveto %d %d 2 0 360 arc closepath fill stroke\n",
69 fprintf(stderr,
"/Times-Roman findfont 4 scalefont setfont\n");
70 fprintf(stderr,
"%d %d moveto (\\(%d,%d\\)) show\n", p.
x + 5, p.
y + 5,
72 fprintf(stderr,
"grestore\n");
74static void psprintpointf(
pointf p)
76 fprintf(stderr,
"gsave\n");
78 "newpath %.5g %.5g moveto %.5g %.5g 2 0 360 arc closepath fill stroke\n",
80 fprintf(stderr,
"/Times-Roman findfont 4 scalefont setfont\n");
81 fprintf(stderr,
"%.5g %.5g moveto (\\(%.5g,%.5g\\)) show\n", p.
x + 5, p.
y + 5,
83 fprintf(stderr,
"grestore\n");
92 for (
size_t i = 0; i < spl.
pn; i++) {
95 i == 0 ?
"moveto" : (i % 3 == 0 ?
"curveto" :
""));
106 for (
size_t i = 0; i < pl.
pn; i++) {
109 i == 0 ?
"moveto" :
"lineto");
115static void psprintpoly(
Ppoly_t p)
121 for (
size_t bi = 0; bi < p.
pn; bi++) {
124 if (fabs(tail.x -
head.x) < 1 && fabs(tail.y -
head.y) < 1) pfx =
"%%";
127 agxbprint(&buf,
"%s%.0f %.0f %.0f %.0f makevec", pfx, tail.x, tail.y,
head.x,
134static void psprintboxes(
size_t boxn,
boxf *boxes) {
139 for (
size_t bi = 0; bi < boxn; bi++) {
140 ll = boxes[bi].
LL, ur = boxes[bi].
UR;
142 agxbprint(&buf,
"newpath\n%.0f %.0f moveto", ll.
x, ll.
y);
155static void psprintinit (
int begin)
163static bool debugleveln(
edge_t* realedge,
int i)
191 for (
size_t i = 0; i <
poly.pn; i++) {
192 edges[i].
a =
poly.ps[i];
207 for (
size_t i = 0; i < spl.
pn; i++) {
242 const double num_div =
delta * (double)boxn;
244 for (
size_t splinepi = 0; splinepi + 3 < pn; splinepi += 3) {
245 for (
double si = 0; si <= num_div; si++) {
247 sp[0] = pps[splinepi];
248 sp[1] = pps[splinepi + 1];
249 sp[2] = pps[splinepi + 2];
250 sp[3] = pps[splinepi + 3];
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[2].
x += t * (sp[3].
x - sp[2].
x);
256 sp[2].
y += t * (sp[3].
y - sp[2].
y);
257 sp[0].
x += t * (sp[1].
x - sp[0].
x);
258 sp[0].
y += t * (sp[1].
y - sp[0].
y);
259 sp[1].
x += t * (sp[2].
x - sp[1].
x);
260 sp[1].
y += t * (sp[2].
y - sp[1].
y);
261 sp[0].
x += t * (sp[1].
x - sp[0].
x);
262 sp[0].
y += t * (sp[1].
y - sp[0].
y);
263 for (
size_t bi = 0; bi < boxn; bi++) {
267 if (sp[0].y <= boxes[bi].UR.y+
FUDGE && sp[0].
y >= boxes[bi].
LL.
y-
FUDGE) {
268 boxes[bi].
LL.
x = fmin(boxes[bi].LL.x, sp[0].
x);
269 boxes[bi].
UR.
x = fmax(boxes[bi].UR.x, sp[0].
x);
309 for (realedge = pp->
data;
313 agerrorf(
"in routesplines, cannot find NORMAL edge\n");
318 const size_t boxn = pp->
nbox;
324 if (debugleveln(realedge, 1))
325 printboxes(boxn, boxes);
326 if (debugleveln(realedge, 3)) {
328 psprintboxes(boxn, boxes);
335 if (boxn > 1 && boxes[0].LL.y > boxes[1].
LL.
y) {
337 for (
size_t bi = 0; bi < boxn; bi++) {
338 double v = boxes[bi].
UR.
y;
339 boxes[bi].
UR.
y = -1*boxes[bi].
LL.
y;
350 for (bi = 0, pi = 0; bi < boxn; bi++) {
353 prev = boxes[bi].
LL.
y > boxes[bi - 1].
LL.
y ? -1 : 1;
355 next = boxes[bi + 1].
LL.
y > boxes[bi].
LL.
y ? 1 : -1;
357 if (next == -1 ||
prev == 1) {
358 polypoints[pi].
x = boxes[bi].
LL.
x;
359 polypoints[pi++].
y = boxes[bi].
UR.
y;
360 polypoints[pi].
x = boxes[bi].
LL.
x;
361 polypoints[pi++].
y = boxes[bi].
LL.
y;
363 polypoints[pi].
x = boxes[bi].
UR.
x;
364 polypoints[pi++].
y = boxes[bi].
LL.
y;
365 polypoints[pi].
x = boxes[bi].
UR.
x;
366 polypoints[pi++].
y = boxes[bi].
UR.
y;
369 else if (
prev == 0) {
370 polypoints[pi].
x = boxes[bi].
LL.
x;
371 polypoints[pi++].
y = boxes[bi].
UR.
y;
372 polypoints[pi].
x = boxes[bi].
LL.
x;
373 polypoints[pi++].
y = boxes[bi].
LL.
y;
376 if (!(
prev == -1 && next == -1)) {
378 agerrorf(
"in routesplines, illegal values of prev %d and next %d, line %d\n",
prev, next, __LINE__);
383 for (bi = boxn - 1; bi !=
SIZE_MAX; bi--) {
386 prev = boxes[bi].
LL.
y > boxes[bi + 1].
LL.
y ? -1 : 1;
388 next = boxes[bi - 1].
LL.
y > boxes[bi].
LL.
y ? 1 : -1;
390 if (next == -1 ||
prev == 1 ) {
391 polypoints[pi].
x = boxes[bi].
LL.
x;
392 polypoints[pi++].
y = boxes[bi].
UR.
y;
393 polypoints[pi].
x = boxes[bi].
LL.
x;
394 polypoints[pi++].
y = boxes[bi].
LL.
y;
396 polypoints[pi].
x = boxes[bi].
UR.
x;
397 polypoints[pi++].
y = boxes[bi].
LL.
y;
398 polypoints[pi].
x = boxes[bi].
UR.
x;
399 polypoints[pi++].
y = boxes[bi].
UR.
y;
402 else if (
prev == 0) {
403 polypoints[pi].
x = boxes[bi].
UR.
x;
404 polypoints[pi++].
y = boxes[bi].
LL.
y;
405 polypoints[pi].
x = boxes[bi].
UR.
x;
406 polypoints[pi++].
y = boxes[bi].
UR.
y;
409 if (!(
prev == -1 && next == -1)) {
412 agerrorf(
"in routesplines, illegal values of prev %d and next %d, line %d\n",
prev, next, __LINE__);
415 polypoints[pi].
x = boxes[bi].
UR.
x;
416 polypoints[pi++].
y = boxes[bi].
LL.
y;
417 polypoints[pi].
x = boxes[bi].
UR.
x;
418 polypoints[pi++].
y = boxes[bi].
UR.
y;
419 polypoints[pi].
x = boxes[bi].
LL.
x;
420 polypoints[pi++].
y = boxes[bi].
UR.
y;
421 polypoints[pi].
x = boxes[bi].
LL.
x;
422 polypoints[pi++].
y = boxes[bi].
LL.
y;
433 for (
size_t bi = 0; bi < boxn; bi++) {
434 double v = boxes[bi].
UR.
y;
435 boxes[bi].
UR.
y = -1*boxes[bi].
LL.
y;
438 for (
size_t i = 0; i < pi; i++)
439 polypoints[i].y *= -1;
442 static const double INITIAL_LLX = DBL_MAX;
443 static const double INITIAL_URX = -DBL_MAX;
444 for (
size_t bi = 0; bi < boxn; bi++) {
445 boxes[bi].
LL.
x = INITIAL_LLX;
446 boxes[bi].
UR.
x = INITIAL_URX;
453 agerrorf(
"in routesplines, Pshortestpath failed\n");
457 if (debugleveln(realedge, 3)) {
468 for (
size_t edgei = 0; edgei <
poly.pn; edgei++) {
469 edges[edgei].
a = polypoints[edgei];
470 edges[edgei].
b = polypoints[(edgei + 1) %
poly.pn];
485 agerrorf(
"in routesplines, Proutespline failed\n");
490 if (debugleveln(realedge, 3)) {
504 for (
size_t splinepi = 0; splinepi < spl.
pn; splinepi++) {
505 ps[splinepi] = spl.
ps[splinepi];
510 bool is_horizontal = spl.
pn > 0;
511 for (
size_t i = 0; i < spl.
pn; ++i) {
513 is_horizontal =
false;
518 GV_INFO(
"spline [%.03f, %.03f] -- [%.03f, %.03f] is horizontal;"
519 " will be trivially bounded",
ps[0].x,
ps[0].y,
ps[spl.
pn - 1].x,
524 bool is_vertical = spl.
pn > 0;
525 for (
size_t i = 0; i < spl.
pn; ++i) {
532 GV_INFO(
"spline [%.03f, %.03f] -- [%.03f, %.03f] is vertical;"
533 " will be trivially bounded",
ps[0].x,
ps[0].y,
ps[spl.
pn - 1].x,
539 if (is_horizontal || is_vertical) {
540 for (
size_t i = 0; i < boxn; ++i) {
541 boxes[i].
LL.
x =
ps[0].x;
542 boxes[i].
UR.
x =
ps[0].x;
550 for (loopcnt = 0; unbounded && loopcnt <
LOOP_TRIES; loopcnt++) {
559 for (bi = 0; bi < boxn; bi++) {
591 printboxes(boxn, boxes);
606static double overlap(
double i0,
double i1,
double j0,
double j1) {
613 if (i0 <= j0 && i1 >= j1)
616 if (j0 <= i0 && j1 >= i1)
619 if (j0 <= i0 && i0 <= j1)
621 assert(j0 <= i1 && i1 <= j1);
637 int errs, l, r, d, u;
641 for (
size_t bi = 0; bi < boxn; bi++) {
642 if (fabs(boxes[bi].LL.y - boxes[bi].
UR.
y) < .01)
644 if (fabs(boxes[bi].LL.x - boxes[bi].
UR.
x) < .01)
646 boxes[i] = boxes[bi];
653 agerrorf(
"in checkpath, box 0 has LL coord > UR coord\n");
657 for (
size_t bi = 0; bi + 1 < boxn; bi++) {
658 ba = &boxes[bi], bb = &boxes[bi + 1];
659 if (bb->LL.x > bb->UR.x || bb->LL.y > bb->UR.y) {
665 l = ba->
UR.
x < bb->LL.x ? 1 : 0;
666 r = ba->
LL.
x > bb->UR.x ? 1 : 0;
667 d = ba->
UR.
y < bb->LL.y ? 1 : 0;
668 u = ba->
LL.
y > bb->UR.y ? 1 : 0;
669 errs = l + r + d + u;
672 " don't touch\n", bi, bi + 1);
679 xy = ba->
UR.
x, ba->
UR.
x = bb->LL.x, bb->LL.x = xy, l = 0;
681 xy = ba->
LL.
x, ba->
LL.
x = bb->UR.x, bb->UR.x = xy, r = 0;
683 xy = ba->
UR.
y, ba->
UR.
y = bb->LL.y, bb->LL.y = xy, d = 0;
685 xy = ba->
LL.
y, ba->
LL.
y = bb->UR.y, bb->UR.y = xy, u = 0;
686 for (
int j = 0; j < errs - 1; j++) {
688 xy = (ba->
UR.
x + bb->LL.x) / 2.0 + 0.5, ba->
UR.
x =
689 bb->LL.x = xy, l = 0;
691 xy = (ba->
LL.
x + bb->UR.x) / 2.0 + 0.5, ba->
LL.
x =
692 bb->UR.x = xy, r = 0;
694 xy = (ba->
UR.
y + bb->LL.y) / 2.0 + 0.5, ba->
UR.
y =
695 bb->LL.y = xy, d = 0;
697 xy = (ba->
LL.
y + bb->UR.y) / 2.0 + 0.5, ba->
LL.
y =
698 bb->UR.y = xy, u = 0;
702 double xoverlap =
overlap(ba->
LL.
x, ba->
UR.
x, bb->LL.x, bb->UR.x);
703 double yoverlap =
overlap(ba->
LL.
y, ba->
UR.
y, bb->LL.y, bb->UR.y);
704 if (xoverlap > 0 && yoverlap > 0) {
705 if (xoverlap < yoverlap) {
706 if (ba->
UR.
x - ba->
LL.
x > bb->UR.x - bb->LL.x) {
708 if (ba->
UR.
x < bb->UR.x)
714 if (ba->
UR.
x < bb->UR.x)
720 if (ba->
UR.
y - ba->
LL.
y > bb->UR.y - bb->LL.y) {
722 if (ba->
UR.
y < bb->UR.y)
728 if (ba->
UR.
y < bb->UR.y)
746 if (thepath->
end.
p.
x < boxes[boxn - 1].
LL.
x
747 || thepath->
end.
p.
x > boxes[boxn - 1].
UR.
x
748 || thepath->
end.
p.
y < boxes[boxn - 1].
LL.
y
749 || thepath->
end.
p.
y > boxes[boxn - 1].
UR.
y) {
750 thepath->
end.
p.
x = fmax(thepath->
end.
p.
x, boxes[boxn - 1].
LL.
x);
751 thepath->
end.
p.
x = fmin(thepath->
end.
p.
x, boxes[boxn - 1].
UR.
x);
752 thepath->
end.
p.
y = fmax(thepath->
end.
p.
y, boxes[boxn - 1].
LL.
y);
753 thepath->
end.
p.
y = fmin(thepath->
end.
p.
y, boxes[boxn - 1].
UR.
y);
761 for (
size_t bi = 0; bi < pp->
nbox; bi++)
762 fprintf(stderr,
"%" PRISIZE_T " (%.5g, %.5g), (%.5g, %.5g)\n", bi,
765 fprintf(stderr,
"start port: (%.5g, %.5g), tangent angle: %.5g, %s\n",
768 fprintf(stderr,
"end port: (%.5g, %.5g), tangent angle: %.5g, %s\n",
784static void nodes_delete(nodes_t *pvec) {
791typedef LIST(nodes_t *) cycles_t;
793static bool cycle_contains_edge(nodes_t *cycle,
edge_t *
edge) {
797 const size_t cycle_len =
LIST_SIZE(cycle);
799 for (
size_t i=0; i < cycle_len; ++i) {
800 const node_t *c_start =
LIST_GET(cycle, i == 0 ? cycle_len - 1 : i - 1);
803 if (c_start == start && c_end == end)
812 const size_t cycle_len =
LIST_SIZE(cycle);
815 bool all_items_match;
817 for (
size_t c = 0; c <
LIST_SIZE(cycles); ++c) {
818 nodes_t *cur_cycle =
LIST_GET(cycles, c);
819 const size_t cur_cycle_len =
LIST_SIZE(cur_cycle);
822 if (cur_cycle_len == cycle_len) {
823 all_items_match =
true;
824 for (i=0; i < cur_cycle_len; ++i) {
827 all_items_match =
false;
847 nodes_t *cycle =
gv_alloc(
sizeof(nodes_t));
856 dfs(g, n, visited, end, cycles);
869 cycles_t alloced_cycles = {.dtor = nodes_delete};
870 cycles_t cycles = {.dtor = nodes_delete};
873 nodes_t *cycle =
gv_alloc(
sizeof(nodes_t));
877 dfs(g, n, cycle, n, &cycles);
886 nodes_t *shortest =
NULL;
888 for (
size_t c = 0; c <
LIST_SIZE(cycles); ++c) {
889 nodes_t *cycle =
LIST_GET(cycles, c);
892 if (cycle_len < min_size)
896 if (cycle_contains_edge(cycle,
edge)) {
919 for (
size_t idx = 0; idx <
LIST_SIZE(cycle); ++idx) {
942 double vX = centroid.
x - midpt.
x;
943 double vY = centroid.
y - midpt.
y;
944 double magV = hypot(vX, vY);
945 if (magV == 0)
return;
946 a.
x = midpt.
x - vX / magV * r;
947 a.
y = midpt.
y - vY / magV * r;
950 spl[1].
x = spl[2].
x = a.
x;
951 spl[1].
y = spl[2].
y = a.
y;
966 for (
size_t i = 0; i < e_cnt; i++) {
970 assert(e_cnt <= INT_MAX);
1002 .
x = dumb[0].
y - dumb[3].
y,
1003 .y = dumb[3].
x - dumb[0].
x
1007 assert(e_cnt - 1 <= INT_MAX);
1008 int dx = xstep * (int)(e_cnt - 1) / 2;
1009 dumb[1].
x = dumb[0].
x +
dx *
perp.
x / l_perp;
1010 dumb[1].
y = dumb[0].
y +
dx *
perp.
y / l_perp;
1011 dumb[2].
x = dumb[3].
x +
dx *
perp.
x / l_perp;
1012 dumb[2].
y = dumb[3].
y +
dx *
perp.
y / l_perp;
1017 for (
size_t i = 0; i < e_cnt; i++) {
1018 edge_t *e0 = edge_list[i];
1021 for (
size_t j = 0; j < 4; j++) {
1022 dumber[j] = dumb[j];
1025 for (
size_t j = 0; j < 4; j++) {
1026 dumber[3 - j] = dumb[j];
1030 Ppoint_t pts[] = {dumber[0], dumber[1], dumber[2], dumber[3]};
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, item)
#define LIST_DROP_BACK(list)
#define LIST_CONTAINS(list, needle)
#define LIST_IS_EMPTY(list)
#define LIST_COPY(dst, src)
#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