Root/poly2d/p2d_attrib.c

1/*
2 * p2d_attrib.c - Determine various polygon attributes
3 *
4 * Written 2012, 2015 by Werner Almesberger
5 * Copyright 2012, 2015 Werner Almesberger
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 */
12
13
14#include <stdbool.h>
15#include <stdio.h>
16#include <math.h>
17#include <assert.h>
18
19#include "poly2d.h"
20
21
22/*
23 * Angle in counter-clockwise direction to turn at point B when coming from A
24 * in order to face towards C.
25 */
26
27static double angle_3(const struct v2d *a, const struct v2d *b,
28    const struct v2d *c)
29{
30    double ax, ay, bx, by;
31    double cs, aa, bb;
32    double cross, angle;
33
34    ax = b->x - a->x;
35    ay = b->y - a->y;
36    bx = c->x - b->x;
37    by = c->y - b->y;
38
39    cross = ax * by - ay * bx;
40    if (!cross)
41        return 0;
42
43    aa = hypot(ax, ay);
44    bb = hypot(bx, by);
45
46    cs = (ax * bx + ay * by) / aa / bb;
47    if (cs <= -1)
48        angle = 180;
49    else if (cs >= 1)
50        angle = 0;
51    else
52        angle = acos(cs) / M_PI * 180.0;
53    return cross >= 0 ? angle : -angle;
54}
55
56/*
57 * If we predominantly turn to the right, then the path must be clockwise.
58 */
59
60bool p2d_is_cw(const struct p2d *p)
61{
62    const struct v2d *v;
63    double a = 0;
64
65    assert(p2d_vertices(p) >= 3);
66    assert(p2d_is_closed(p));
67    assert(p2d_no_intersect(p));
68
69    v = p->v;
70    do {
71        a += angle_3(v, v->next, v->next->next);
72        v = v->next;
73    }
74    while (v != p->v);
75    assert(!isnan(a)); /* require -std=c99 or -std=gnu99 */
76    return a < 0;
77}
78
79
80bool p2d_is_closed(const struct p2d *p)
81{
82    return p->v == p->last || p->last->next;
83}
84
85
86/*
87 * Known bug: if the polygon intersects on a vertex, the intersection may
88 * go unnoticed.
89 */
90
91bool p2d_no_intersect(const struct p2d *p)
92{
93    const struct v2d *v, *u;
94
95    v = p->v;
96    while (v) {
97        u = v->next;
98        if (!u || u == p->v)
99            return 1;
100        u = u->next;
101        if (!u || u == p->v)
102            return 1;
103        while (u && u->next && u->next != v) {
104            if (v2d_intersect(v, v->next, u, u->next,
105                NULL, NULL) > 0)
106                return 0;
107            u = u->next;
108            if (u == p->v)
109                break;
110        }
111        v = v->next;
112        if (v == p->v)
113            break;
114    }
115    return 1;
116}
117
118
119unsigned p2d_vertices(const struct p2d *p)
120{
121    const struct v2d *v;
122    unsigned n = 0;
123
124    v = p->v;
125    while (v) {
126        n++;
127        v = v->next;
128        if (v == p->v)
129            break;
130    }
131    return n;
132}
133

Archive Download this file

Branches:
master



interactive