diff --git a/cameo/cameo.c b/cameo/cameo.c index 5d5843c..9c2fcf6 100644 --- a/cameo/cameo.c +++ b/cameo/cameo.c @@ -32,6 +32,7 @@ int main(int argc, char **argv) char *in = NULL, *out = NULL; double r; struct path *paths; + int left; switch (argc) { case 4: @@ -50,14 +51,13 @@ int main(int argc, char **argv) /* * To do: - * - auto-detect orientation * - handle multiple paths - * - instead of reversing the path, reverse the handedness */ paths = gnuplot_read(in, r); assert(!paths->next); /* we don't handle this yet */ - paths = path_reverse(paths); - paths = path_offset(paths, 1); +// paths = path_reverse(paths); + left = path_tool_is_left(paths); + paths = path_offset(paths, left, 1); gnuplot_write(out, paths); return 0; } diff --git a/cameo/path.c b/cameo/path.c index 7446087..88f4289 100644 --- a/cameo/path.c +++ b/cameo/path.c @@ -99,7 +99,7 @@ struct path *path_reverse(const struct path *path) static struct point *offset_point(const struct point *a, const struct point *b, - const struct point *c, double off) + const struct point *c, double off, int left) { double ax, ay, bx, by; double aa, bb; @@ -113,8 +113,13 @@ static struct point *offset_point(const struct point *a, const struct point *b, aa = hypot(ax, ay); bb = hypot(bx, by); - nx = -(ay/aa+by/bb); - ny = ax/aa+bx/bb; + if (left) { + nx = -(ay/aa+by/bb); + ny = ax/aa+bx/bb; + } else { + nx = ay/aa+by/bb; + ny = -(ax/aa+bx/bb); + } nx *= off; ny *= off; @@ -143,6 +148,53 @@ static int left_turn(const struct point *a, const struct point *b, } +/* + * Angle in counter-clockwise direction to turn at point B when coming from A + * in order to face towards C. + */ + +static double angle(const struct point *a, const struct point *b, + const struct point *c) +{ + double ax, ay, bx, by; + double aa, bb; + double angle; + + ax = b->x-a->x; + ay = b->y-a->y; + bx = c->x-b->x; + by = c->y-b->y; + + aa = hypot(ax, ay); + bb = hypot(bx, by); + + angle = acos((ax*bx+ay*by)/aa/bb)/M_PI*180.0; + + return (ax*by-ay*bx) >= 0 ? angle : -angle; +} + + +/* + * If we predominantly turn to the right, then the tool must be on the + * left-hand side. Otherwise, it's on the right. + */ + +int path_tool_is_left(const struct path *path) +{ + const struct point *prev, *p, *next; + double a = 0; + + assert(path_is_closed(path)); + prev = path->first; + for (p = path->first->next; p; p = p->next) { + next = p->next ? p->next : path->first->next; + a += angle(prev, p, next); + prev = p; + } + return a < 0; +} + + /* * http://www.makecnc.com/bones.jpg */ @@ -176,7 +228,7 @@ static struct point *dog_point(const struct point *edge, * 6 o'clock to 12 o'clock, the tool would be at 9 o'clock. */ -struct path *path_offset(const struct path *path, int notch) +struct path *path_offset(const struct path *path, int left, int notch) { struct path *new; const struct point *prev, *p, *next; @@ -188,8 +240,8 @@ struct path *path_offset(const struct path *path, int notch) prev = path->first; for (p = path->first->next; p; p = p->next) { next = p->next ? p->next : path->first->next; - n = offset_point(prev, p, next, path->r_tool); - dog = notch && left_turn(prev, p, next); + n = offset_point(prev, p, next, path->r_tool, left); + dog = notch && left_turn(prev, p, next) == left; if (dog) n2 = clone_point(n); path_add_point(new, n); diff --git a/cameo/path.h b/cameo/path.h index 9b0dd3d..6458c37 100644 --- a/cameo/path.h +++ b/cameo/path.h @@ -30,7 +30,9 @@ struct path { struct path *path_new(double r_tool); void path_add(struct path *path, double x, double y, double z); struct path *path_reverse(const struct path *path); -struct path *path_offset(const struct path *path, int notch); +int path_direction(const struct path *path); +int path_tool_is_left(const struct path *path); +struct path *path_offset(const struct path *path, int left, int notch); void path_free(struct path *path); #endif /* !PATH_H */