/* * p2d_attrib.c - Determine various polygon attributes * * Written 2012, 2015 by Werner Almesberger * Copyright 2012, 2015 Werner Almesberger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include "poly2d.h" /* * Angle in counter-clockwise direction to turn at point B when coming from A * in order to face towards C. */ static double angle_3(const struct v2d *a, const struct v2d *b, const struct v2d *c) { double ax, ay, bx, by; double aa, bb; double cross, angle; ax = b->x - a->x; ay = b->y - a->y; bx = c->x - b->x; by = c->y - b->y; cross = ax * by - ay * bx; if (!cross) return 0; aa = hypot(ax, ay); bb = hypot(bx, by); angle = acos((ax * bx + ay * by) / aa / bb) / M_PI * 180.0; return cross >= 0 ? angle : -angle; } /* * If we predominantly turn to the right, then the path must be clockwise. */ bool p2d_is_cw(const struct p2d *p) { const struct v2d *v; double a = 0; assert(p2d_vertices(p) >= 3); assert(p2d_is_closed(p)); assert(p2d_no_intersect(p)); v = p->v; do { a += angle_3(v, v->next, v->next->next); v = v->next; } while (v != p->v); return a < 0; } bool p2d_is_closed(const struct p2d *p) { return p->v == p->last || p->last->next; } /* * Known bug: if the polygon intersects on a vertex, the intersection may * go unnoticed. */ bool p2d_no_intersect(const struct p2d *p) { const struct v2d *v, *u; v = p->v; while (v) { u = v->next; if (!u || u == p->v) return 1; u = u->next; if (!u || u == p->v) return 1; while (u && u->next && u->next != v) { if (v2d_intersect(v, v->next, u, u->next, NULL, NULL) > 0) return 0; u = u->next; if (u == p->v) break; } v = v->next; if (v == p->v) break; } return 1; } unsigned p2d_vertices(const struct p2d *p) { const struct v2d *v; unsigned n = 0; v = p->v; while (v) { n++; v = v->next; if (v == p->v) break; } return n; }