/* * p2d_attrib.c - Determine various polygon attributes * * Written 2012, 2015 by Werner Almesberger * Copyright 2012, 2015 Werner Almesberger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. */ #include #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 cs, 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); cs = (ax * bx + ay * by) / aa / bb; if (cs <= -1) angle = 180; else if (cs >= 1) angle = 0; else angle = acos(cs) / 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); assert(!isnan(a)); /* require -std=c99 or -std=gnu99 */ 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; }