Graphviz 12.0.1~dev.20240715.2254
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 <cgraph/alloc.h>
13#include <limits.h>
14#include <stdbool.h>
15#include <stdio.h>
16#include <math.h>
17#include <stdlib.h>
18#include <pathplan/pathutil.h>
19#include <pathplan/tri.h>
20
21static int triangulate(Ppoint_t ** pointp, int pointn,
22 void (*fn) (void *, Ppoint_t *), void *vc);
23
24int ccw(Ppoint_t p1, Ppoint_t p2, Ppoint_t p3) {
25 double d = (p1.y - p2.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p1.x - p2.x);
26 return d > 0 ? ISCW : (d < 0 ? ISCCW : ISON);
27}
28
29static Ppoint_t point_indexer(void *base, int index) {
30 Ppoint_t **b = base;
31 return *b[index];
32}
33
34/* Ptriangulate:
35 * Return 0 on success; non-zero on error.
36 */
37int Ptriangulate(Ppoly_t * polygon, void (*fn) (void *, Ppoint_t *),
38 void *vc)
39{
40 Ppoint_t **pointp;
41
42 const size_t pointn = polygon->pn;
43
44 pointp = gv_calloc(pointn, sizeof(Ppoint_t*));
45
46 for (size_t i = 0; i < pointn; i++)
47 pointp[i] = &(polygon->ps[i]);
48
49 assert(pointn <= INT_MAX);
50 if (triangulate(pointp, (int)pointn, fn, vc) != 0) {
51 free(pointp);
52 return 1;
53 }
54
55 free(pointp);
56 return 0;
57}
58
59/* triangulate:
60 * Triangulates the given polygon.
61 * Returns non-zero if no diagonal exists.
62 */
63static int
64triangulate(Ppoint_t ** pointp, int pointn,
65 void (*fn) (void *, Ppoint_t *), void *vc)
66{
67 int i, ip1, ip2, j;
68 Ppoint_t A[3];
69 if (pointn > 3) {
70 for (i = 0; i < pointn; i++) {
71 ip1 = (i + 1) % pointn;
72 ip2 = (i + 2) % pointn;
73 if (isdiagonal(i, ip2, pointp, pointn, point_indexer)) {
74 A[0] = *pointp[i];
75 A[1] = *pointp[ip1];
76 A[2] = *pointp[ip2];
77 fn(vc, A);
78 j = 0;
79 for (i = 0; i < pointn; i++)
80 if (i != ip1)
81 pointp[j++] = pointp[i];
82 return triangulate(pointp, pointn - 1, fn, vc);
83 }
84 }
85 return -1;
86 } else {
87 A[0] = *pointp[0];
88 A[1] = *pointp[1];
89 A[2] = *pointp[2];
90 fn(vc, A);
91 }
92 return 0;
93}
94
95bool isdiagonal(int i, int ip2, void *pointp, int pointn, indexer_t indexer) {
96 int ip1, im1, j, jp1, res;
97
98 /* neighborhood test */
99 ip1 = (i + 1) % pointn;
100 im1 = (i + pointn - 1) % pointn;
101 /* If P[i] is a convex vertex [ i+1 left of (i-1,i) ]. */
102 if (ccw(indexer(pointp, im1), indexer(pointp, i), indexer(pointp, ip1)) == ISCCW)
103 res = ccw(indexer(pointp, i), indexer(pointp, ip2), indexer(pointp, im1)) == ISCCW &&
104 ccw(indexer(pointp, ip2), indexer(pointp, i), indexer(pointp, ip1)) == ISCCW;
105 /* Assume (i - 1, i, i + 1) not collinear. */
106 else
107 res = ccw(indexer(pointp, i), indexer(pointp, ip2), indexer(pointp, ip1)) == ISCW;
108 if (!res) {
109 return false;
110 }
111
112 /* check against all other edges */
113 for (j = 0; j < pointn; j++) {
114 jp1 = (j + 1) % pointn;
115 if (!(j == i || jp1 == i || j == ip2 || jp1 == ip2))
116 if (intersects
117 (indexer(pointp, i), indexer(pointp, ip2), indexer(pointp, j), indexer(pointp, jp1))) {
118 return false;
119 }
120 }
121 return true;
122}
123
125 int ccw1, ccw2, ccw3, ccw4;
126
127 if (ccw(pa, pb, pc) == ISON || ccw(pa, pb, pd) == ISON ||
128 ccw(pc, pd, pa) == ISON || ccw(pc, pd, pb) == ISON) {
129 if (between(pa, pb, pc) || between(pa, pb, pd) ||
130 between(pc, pd, pa) || between(pc, pd, pb))
131 return true;
132 } else {
133 ccw1 = ccw(pa, pb, pc) == ISCCW ? 1 : 0;
134 ccw2 = ccw(pa, pb, pd) == ISCCW ? 1 : 0;
135 ccw3 = ccw(pc, pd, pa) == ISCCW ? 1 : 0;
136 ccw4 = ccw(pc, pd, pb) == ISCCW ? 1 : 0;
137 return (ccw1 ^ ccw2) && (ccw3 ^ ccw4);
138 }
139 return false;
140}
141
143 const Ppoint_t pba = {.x = pb.x - pa.x, .y = pb.y - pa.y};
144 const Ppoint_t pca = {.x = pc.x - pa.x, .y = pc.y - pa.y};
145 if (ccw(pa, pb, pc) != ISON)
146 return false;
147 return pca.x * pba.x + pca.y * pba.y >= 0 &&
148 pca.x * pca.x + pca.y * pca.y <= pba.x * pba.x + pba.y * pba.y;
149}
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
Ppoint_t(* indexer_t)(void *base, int index)
Definition tri.h:53
@ ISON
co-linear
Definition tri.h:41
@ ISCW
clockwise
Definition tri.h:40
@ ISCCW
counter-clockwise
Definition tri.h:39
bool intersects(Ppoint_t pa, Ppoint_t pb, Ppoint_t pc, Ppoint_t pd)
line to line intersection
Definition triang.c:124
bool between(Ppoint_t pa, Ppoint_t pb, Ppoint_t pc)
is pb between pa and pc?
Definition triang.c:142
static int triangulate(Ppoint_t **pointp, int pointn, void(*fn)(void *, Ppoint_t *), void *vc)
Definition triang.c:64
int Ptriangulate(Ppoly_t *polygon, void(*fn)(void *, Ppoint_t *), void *vc)
Definition triang.c:37
int ccw(Ppoint_t p1, Ppoint_t p2, Ppoint_t p3)
are the given points counter-clockwise, clockwise, or co-linear?
Definition triang.c:24
static Ppoint_t point_indexer(void *base, int index)
Definition triang.c:29
bool isdiagonal(int i, int ip2, void *pointp, int pointn, indexer_t indexer)
is (i, i + 2) a diagonal?
Definition triang.c:95