diff --git a/cameo/above.fig b/cameo/above.fig new file mode 100644 index 0000000..7bcca80 --- /dev/null +++ b/cameo/above.fig @@ -0,0 +1,81 @@ +#FIG 3.2 Produced by xfig version 3.2.5b +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +5 1 1 2 14 7 68 -1 -1 6.000 0 0 0 0 5398.867 4722.104 8550 5535 8467 5807 7512 7197 +6 7605 5715 7965 5985 +2 1 0 1 4 7 50 -1 0 4.000 0 0 -1 1 0 2 + 1 1 1.00 30.00 30.00 + 7650 5760 7920 5760 +4 1 4 50 -1 18 15 0.0000 4 135 300 7785 5985 na\001 +-6 +1 3 0 2 0 7 50 -1 0 0.000 1 0.0000 5625 6750 45 45 5625 6750 5670 6750 +1 3 0 2 0 7 50 -1 0 0.000 1 0.0000 8100 6525 45 45 8100 6525 8145 6525 +1 3 0 2 0 7 50 -1 0 0.000 1 0.0000 8550 7425 45 45 8550 7425 8595 7425 +1 3 0 2 0 7 50 -1 0 0.000 1 0.0000 5400 4725 45 45 5400 4725 5445 4725 +1 3 0 2 0 7 50 -1 0 0.000 1 0.0000 9315 4365 45 45 9315 4365 9360 4365 +1 3 0 2 0 7 50 -1 0 0.000 1 0.0000 7053 5826 45 45 7053 5826 7098 5826 +2 1 1 2 0 7 45 -1 0 6.000 0 0 -1 1 0 2 + 0 0 2.00 150.00 180.00 + 8100 6525 5400 4725 +2 1 0 2 0 7 45 -1 0 0.000 0 0 -1 0 0 2 + 5625 6750 9315 4365 +2 1 0 2 1 7 55 -1 0 0.000 0 0 -1 1 0 2 + 0 0 2.00 150.00 180.00 + 5635 6763 8100 6525 +2 1 0 2 1 7 55 -1 0 0.000 0 0 -1 1 0 2 + 0 0 2.00 150.00 180.00 + 8100 6525 8550 7425 +2 1 0 2 4 7 60 -1 0 0.000 0 0 -1 1 0 2 + 0 0 2.00 150.00 180.00 + 8100 6525 7965 4995 +2 1 0 2 4 7 60 -1 0 0.000 0 0 -1 1 0 2 + 0 0 2.00 150.00 180.00 + 8100 6525 9450 5850 +2 1 1 2 1 7 55 -1 0 6.000 0 0 -1 0 0 2 + 8550 7425 8775 8550 +2 1 1 2 1 7 55 -1 0 6.000 0 0 -1 0 0 2 + 5625 6750 4275 7200 +2 3 0 0 1 7 70 -1 44 0.000 0 0 -1 0 0 6 + 4500 7155 5625 6750 8100 6525 8550 7425 8730 8325 4500 7155 +2 1 0 2 14 7 55 -1 0 0.000 0 0 -1 1 0 2 + 0 0 2.00 150.00 180.00 + 2925 4725 5400 4725 +2 1 0 1 4 7 50 -1 0 4.000 0 0 -1 1 0 2 + 1 1 1.00 30.00 30.00 + 8595 6435 8865 6435 +2 1 0 1 0 7 50 -1 0 4.000 0 0 -1 1 0 2 + 1 1 1.00 30.00 30.00 + 4185 4950 4500 4950 +2 1 0 1 0 7 50 -1 0 4.000 0 0 -1 1 0 2 + 1 1 1.00 30.00 30.00 + 4140 5400 4500 5400 +2 1 0 1 0 7 50 -1 0 4.000 0 0 -1 1 0 2 + 1 1 1.00 30.00 30.00 + 4365 5850 4680 5850 +2 1 0 2 4 7 60 -1 0 0.000 0 0 -1 1 0 2 + 0 0 2.00 150.00 180.00 + 7974 5013 9324 4338 +2 1 0 2 4 7 60 -1 0 0.000 0 0 -1 1 0 2 + 0 0 2.00 150.00 180.00 + 9450 5850 9315 4320 +4 0 0 50 -1 18 15 0.0000 4 180 180 5355 6660 A\001 +4 0 0 50 -1 18 15 0.0000 4 180 180 8685 7515 C\001 +4 1 4 50 -1 18 15 0.0000 4 180 300 8730 6660 nb\001 +4 0 0 50 -1 18 15 0.0000 4 180 180 8145 6345 B\001 +4 1 14 50 -1 18 15 0.0000 4 180 165 5400 4590 P\001 +4 1 0 50 -1 18 15 0.0000 4 195 195 6750 5445 Q\001 +4 0 0 50 -1 18 15 0.0000 4 195 1470 3150 5175 Q = A+u*AM\001 +4 0 0 50 -1 18 15 0.0000 4 195 1425 3150 5625 P = B+v*BQ\001 +4 0 0 50 -1 18 15 0.0000 4 195 1650 3150 6075 Q = B+1/v*BP\001 +4 0 0 50 -1 18 15 0.0000 4 180 1695 2925 4635 Tool direction\001 +4 0 0 50 -1 18 15 0.0000 4 240 1890 5715 7785 Polygon, inside\001 +4 0 0 50 -1 18 15 0.0000 4 180 975 3150 7020 v >= 0 ?\001 +4 0 0 50 -1 18 15 0.0000 4 225 1590 3150 6660 u in [0, 1] &&\001 +4 0 0 50 -1 18 15 0.0000 4 180 210 9225 4275 M\001 +4 0 0 50 -1 18 15 0.0000 4 240 2115 7155 4005 Midpoint, outside\001 diff --git a/cameo/area.c b/cameo/area.c index 7b88b53..a0b9fad 100644 --- a/cameo/area.c +++ b/cameo/area.c @@ -25,7 +25,7 @@ #include "area.h" -#define EPSILON 0.0001 +#define EPSILON 1e-6 static int bbox(const struct path *path, @@ -107,13 +107,14 @@ static int cramer2(double a, double b, double c, double d, double e, double f, /* * Solve - * ax+na*bx = cx+nb*dx - * ay+na*by = cy+nb*dy + * + * ax + na*bx = cx + nb*dx + * ay + na*by = cy + nb*dy * * which is * - * na*bx + nb*-dx = cx-ax - * na*by + nb*-dy = cy-ay + * na*bx + nb*-dx = cx - ax + * na*by + nb*-dy = cy - ay */ static int intersect(double ax, double ay, double bx, double by, @@ -123,6 +124,55 @@ static int intersect(double ax, double ay, double bx, double by, } +/* + * See above.fig. The equation we solve is + * + * Q = A+u*(AM) + * Q = B+v*(BP) + * + * equals + * + * ax + u*(mx-ax) = bx + v*(px-bx) + * ay + u*(my-ay) = by + v*(py-by) + * + * equals + * + * u*(mx-ax) + v*(bx-px) = bx - ax + * u*(my-ay) + v*(by-py) = by - ay + * + * For BC, the equation becomes + * + * Q = C+u*(CM) + * Q = B+v*(BP) + */ + +static int above(const struct point *a, const struct point *b, + const struct point *c, double px, double py) +{ + double ab, bc; + double mx, my; + double u, v; + + ab = hypot(a->x-b->x, a->y-b->y); + bc = hypot(b->x-c->x, b->y-c->y); + if (fabs(ab) < EPSILON || fabs(bc) < EPSILON) + return 0; + + mx = b->x-(b->y-a->y)/ab-(c->y-b->y)/bc; + my = b->y+(b->x-a->x)/ab+(c->x-b->x)/bc; + + if (cramer2(mx-a->x, b->x-px, my-a->y, b->y-py, b->x-a->x, b->y-a->y, + &u, &v)) + if (u >= 0 && u <= 1 && v >= 0) + return 1; + if (cramer2(mx-c->x, b->x-px, my-c->y, b->y-py, b->x-c->x, b->y-c->y, + &u, &v)) + if (u >= 0 && u <= 1 && v >= 0) + return 1; + return 0; +} + + /* * Solve * @@ -131,7 +181,7 @@ static int intersect(double ax, double ay, double bx, double by, * http://en.wikipedia.org/wiki/Quadratic_equation */ -static int touch(double ax, double ay, double bx, double by, +static int touch_solve(double ax, double ay, double bx, double by, double cx, double cy, double r, int enter, double *n) { double dx = cx-ax; @@ -153,9 +203,42 @@ static int touch(double ax, double ay, double bx, double by, } +/* + * The points A, B, and C are (if the path is left-handed): + * + * - A: the beginning of the segment leading into the corner + * - B: the corner point + * - C: the beginning of the segment leading out of the corner + * + * If the path is right-handed, we swap A and C, making it left-handed. + */ + +static int touch(double ax, double ay, double bx, double by, + const struct point *a, const struct point *b, const struct point *c, + double r, int enter, int left, double *n) +{ + double px, py; + + if (!touch_solve(ax, ay, bx, by, b->x, b->y, r, enter, n)) + return 0; + px = ax+*n*bx; + py = ay+*n*by; + return above(a, b, c, px, py) == left; +} + + +/* + * Here, the points A, B, C, and D are: + * + * - A: before the beginning of the current segment + * - B: the beginning + * - C: the end + * - D: the next point beyond the end + */ + static int hit_segment(double fx, double fy, double tx, double ty, - const struct point *a, const struct point *b, double r, int enter, - int left, double *n) + const struct point *a, const struct point *b, const struct point *c, + const struct point *d, double r, int enter, int left, double *n) { double dx, dy, nx, ny, nn; double px, py; @@ -164,8 +247,8 @@ static int hit_segment(double fx, double fy, double tx, double ty, tx -= fx; ty -= fy; - dx = b->x-a->x; - dy = b->y-a->y; + dx = c->x-b->x; + dy = c->y-b->y; if (left) { nx = dx; @@ -181,17 +264,17 @@ static int hit_segment(double fx, double fy, double tx, double ty, nn = hypot(nx, ny); - px = a->x-ny/nn*r; - py = a->y+nx/nn*r; + px = b->x-ny/nn*r; + py = b->y+nx/nn*r; if (!intersect(fx, fy, tx, ty, px, py, dx, dy, &na, &nb)) return 0; if (nb <= 0) { - if (!touch(fx, fy, tx, ty, a->x, a->y, r, enter, &na)) + if (!touch(fx, fy, tx, ty, a, b, c, r, enter, left, &na)) return 0; } if (nb >= 1) { - if (!touch(fx, fy, tx, ty, b->x, b->y, r, enter, &na)) + if (!touch(fx, fy, tx, ty, b, c, d, r, enter, left, &na)) return 0; } if (na <= 0 || na >= 1) @@ -204,21 +287,28 @@ static int hit_segment(double fx, double fy, double tx, double ty, static int hit_path(double fx, double fy, double tx, double ty, const struct path *path, int inside, int enter, double r, double *x) { - const struct point *p; + const struct point *p, *last, *next2; int left; double nx, tmp; int found = 0; + /* + * @@@ We don't wrap around the ends properly and create a zero-sized + * imaginary segment between path->first and path->last. + */ left = path_tool_is_left(path); if (inside) left = !left; + last = path->last; for (p = path->first; p != path->last; p = p->next) { - if (hit_segment(fx, fy, tx, ty, p, p->next, + next2 = p->next->next ? p->next->next : path->first; + if (hit_segment(fx, fy, tx, ty, last, p, p->next, next2, r, enter, left, &tmp)) { if (!found || nx > tmp) nx = tmp; found = 1; } + last = p; } if (found) *x = fx+nx*(tx-fx);