Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
triang.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include <assert.h>
12#include <stdbool.h>
13#include <stdio.h>
14#include <math.h>
15#include <stdlib.h>
16#include <pathplan/pathutil.h>
17#include <pathplan/tri.h>
18#include <util/alloc.h>
19
20static int triangulate(Ppoint_t **pointp, size_t pointn,
21 void (*fn)(void *, const Ppoint_t *), void *vc);
22
23int ccw(Ppoint_t p1, Ppoint_t p2, Ppoint_t p3) {
24 double d = (p1.y - p2.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p1.x - p2.x);
25 return d > 0 ? ISCW : (d < 0 ? ISCCW : ISON);
26}
27
28static Ppoint_t point_indexer(void *base, size_t index) {
29 Ppoint_t **b = base;
30 return *b[index];
31}
32
33/* Ptriangulate:
34 * Return 0 on success; non-zero on error.
35 */
36int Ptriangulate(Ppoly_t *polygon, void (*fn)(void *, const Ppoint_t *),
37 void *vc) {
38 Ppoint_t **pointp;
39
40 const size_t pointn = polygon->pn;
41
42 pointp = gv_calloc(pointn, sizeof(Ppoint_t*));
43
44 for (size_t i = 0; i < pointn; i++)
45 pointp[i] = &(polygon->ps[i]);
46
47 assert(pointn >= 3);
48 if (triangulate(pointp, pointn, fn, vc) != 0) {
49 free(pointp);
50 return 1;
51 }
52
53 free(pointp);
54 return 0;
55}
56
57/* triangulate:
58 * Triangulates the given polygon.
59 * Returns non-zero if no diagonal exists.
60 */
61static int triangulate(Ppoint_t **pointp, size_t pointn,
62 void (*fn)(void *, const Ppoint_t *), void *vc) {
63 assert(pointn >= 3);
64 Ppoint_t A[3];
65 if (pointn > 3) {
66 for (size_t i = 0; i < pointn; i++) {
67 const size_t ip1 = (i + 1) % pointn;
68 const size_t ip2 = (i + 2) % pointn;
69 if (isdiagonal(i, ip2, pointp, pointn, point_indexer)) {
70 A[0] = *pointp[i];
71 A[1] = *pointp[ip1];
72 A[2] = *pointp[ip2];
73 fn(vc, A);
74 size_t j = 0;
75 for (i = 0; i < pointn; i++)
76 if (i != ip1)
77 pointp[j++] = pointp[i];
78 return triangulate(pointp, pointn - 1, fn, vc);
79 }
80 }
81 return -1;
82 } else {
83 A[0] = *pointp[0];
84 A[1] = *pointp[1];
85 A[2] = *pointp[2];
86 fn(vc, A);
87 }
88 return 0;
89}
90
91bool isdiagonal(size_t i, size_t ip2, void *pointp, size_t pointn,
92 indexer_t indexer) {
93 int res;
94
95 /* neighborhood test */
96 const size_t ip1 = (i + 1) % pointn;
97 const size_t im1 = (i + pointn - 1) % pointn;
98 /* If P[i] is a convex vertex [ i+1 left of (i-1,i) ]. */
99 if (ccw(indexer(pointp, im1), indexer(pointp, i), indexer(pointp, ip1)) == ISCCW)
100 res = ccw(indexer(pointp, i), indexer(pointp, ip2), indexer(pointp, im1)) == ISCCW &&
101 ccw(indexer(pointp, ip2), indexer(pointp, i), indexer(pointp, ip1)) == ISCCW;
102 /* Assume (i - 1, i, i + 1) not collinear. */
103 else
104 res = ccw(indexer(pointp, i), indexer(pointp, ip2), indexer(pointp, ip1)) == ISCW;
105 if (!res) {
106 return false;
107 }
108
109 /* check against all other edges */
110 for (size_t j = 0; j < pointn; j++) {
111 const size_t jp1 = (j + 1) % pointn;
112 if (!(j == i || jp1 == i || j == ip2 || jp1 == ip2))
113 if (intersects
114 (indexer(pointp, i), indexer(pointp, ip2), indexer(pointp, j), indexer(pointp, jp1))) {
115 return false;
116 }
117 }
118 return true;
119}
120
122 int ccw1, ccw2, ccw3, ccw4;
123
124 if (ccw(pa, pb, pc) == ISON || ccw(pa, pb, pd) == ISON ||
125 ccw(pc, pd, pa) == ISON || ccw(pc, pd, pb) == ISON) {
126 if (between(pa, pb, pc) || between(pa, pb, pd) ||
127 between(pc, pd, pa) || between(pc, pd, pb))
128 return true;
129 } else {
130 ccw1 = ccw(pa, pb, pc) == ISCCW ? 1 : 0;
131 ccw2 = ccw(pa, pb, pd) == ISCCW ? 1 : 0;
132 ccw3 = ccw(pc, pd, pa) == ISCCW ? 1 : 0;
133 ccw4 = ccw(pc, pd, pb) == ISCCW ? 1 : 0;
134 return (ccw1 ^ ccw2) && (ccw3 ^ ccw4);
135 }
136 return false;
137}
138
140 const Ppoint_t pba = {.x = pb.x - pa.x, .y = pb.y - pa.y};
141 const Ppoint_t pca = {.x = pc.x - pa.x, .y = pc.y - pa.y};
142 if (ccw(pa, pb, pc) != ISON)
143 return false;
144 return pca.x * pba.x + pca.y * pba.y >= 0 &&
145 pca.x * pca.x + pca.y * pca.y <= pba.x * pba.x + pba.y * pba.y;
146}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define A(n, t)
Definition expr.h:76
void free(void *)
double x
Definition pathgeom.h:38
double y
Definition pathgeom.h:38
@ ISON
co-linear
Definition tri.h:43
@ ISCW
clockwise
Definition tri.h:42
@ ISCCW
counter-clockwise
Definition tri.h:41
Ppoint_t(* indexer_t)(void *base, size_t index)
Definition tri.h:55
bool intersects(Ppoint_t pa, Ppoint_t pb, Ppoint_t pc, Ppoint_t pd)
line to line intersection
Definition triang.c:121
bool isdiagonal(size_t i, size_t ip2, void *pointp, size_t pointn, indexer_t indexer)
is (i, i + 2) a diagonal?
Definition triang.c:91
bool between(Ppoint_t pa, Ppoint_t pb, Ppoint_t pc)
is pb between pa and pc?
Definition triang.c:139
static Ppoint_t point_indexer(void *base, size_t index)
Definition triang.c:28
int ccw(Ppoint_t p1, Ppoint_t p2, Ppoint_t p3)
are the given points counter-clockwise, clockwise, or co-linear?
Definition triang.c:23
static int triangulate(Ppoint_t **pointp, size_t pointn, void(*fn)(void *, const Ppoint_t *), void *vc)
Definition triang.c:61
int Ptriangulate(Ppoly_t *polygon, void(*fn)(void *, const Ppoint_t *), void *vc)
Definition triang.c:36