Skip to content

Commit 39a09fe

Browse files
committed
Add class to split a polygon into triangles
1 parent 874209f commit 39a09fe

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed

Runtime/Triangulator.cs

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
using System.Collections.Generic;
2+
using UnityEngine;
3+
4+
namespace Zigurous.Graphics
5+
{
6+
/// <summary>
7+
/// Splits a polygon into triangles.
8+
/// </summary>
9+
public static class Triangulator
10+
{
11+
/// <summary>
12+
/// Splits a polygon into triangles. Supports concave polygons but not
13+
/// polygons with holes.
14+
/// </summary>
15+
/// <param name="points">The points that form a polygon.</param>
16+
/// <returns>The indices of the triangles.</returns>
17+
public static int[] Triangulate(Vector2[] points)
18+
{
19+
int n = points.Length;
20+
21+
if (n < 3) {
22+
return new int[0];
23+
}
24+
25+
int[] V = new int[n];
26+
27+
if (Area(points) > 0f)
28+
{
29+
for (int v = 0; v < n; v++) {
30+
V[v] = v;
31+
}
32+
}
33+
else
34+
{
35+
for (int v = 0; v < n; v++) {
36+
V[v] = (n - 1) - v;
37+
}
38+
}
39+
40+
List<int> indices = new List<int>();
41+
42+
int nv = n;
43+
int count = 2 * nv;
44+
45+
for (int m = 0, v = nv - 1; nv > 2;)
46+
{
47+
if ((count--) <= 0) {
48+
return indices.ToArray();
49+
}
50+
51+
int u = v;
52+
53+
if (nv <= u) {
54+
u = 0;
55+
}
56+
57+
v = u + 1;
58+
59+
if (nv <= v) {
60+
v = 0;
61+
}
62+
63+
int w = v + 1;
64+
65+
if (nv <= w) {
66+
w = 0;
67+
}
68+
69+
if (Snip(points, u, v, w, nv, V))
70+
{
71+
int a, b, c, s, t;
72+
73+
a = V[u];
74+
b = V[v];
75+
c = V[w];
76+
77+
indices.Add(a);
78+
indices.Add(b);
79+
indices.Add(c);
80+
81+
m++;
82+
83+
for (s = v, t = v + 1; t < nv; s++, t++) {
84+
V[s] = V[t];
85+
}
86+
87+
nv--;
88+
count = 2 * nv;
89+
}
90+
}
91+
92+
indices.Reverse();
93+
return indices.ToArray();
94+
}
95+
96+
private static float Area(Vector2[] points)
97+
{
98+
int n = points.Length;
99+
float A = 0f;
100+
101+
for (int p = n - 1, q = 0; q < n; p = q++)
102+
{
103+
Vector2 pval = points[p];
104+
Vector2 qval = points[q];
105+
A += pval.x * qval.y - qval.x * pval.y;
106+
}
107+
108+
return (A * 0.5f);
109+
}
110+
111+
private static bool Snip(Vector2[] points, int u, int v, int w, int n, int[] V)
112+
{
113+
Vector2 A = points[V[u]];
114+
Vector2 B = points[V[v]];
115+
Vector2 C = points[V[w]];
116+
117+
if (Mathf.Epsilon > (((B.x - A.x) * (C.y - A.y)) - ((B.y - A.y) * (C.x - A.x)))) {
118+
return false;
119+
}
120+
121+
for (int p = 0; p < n; p++)
122+
{
123+
if ((p == u) || (p == v) || (p == w)) {
124+
continue;
125+
}
126+
127+
Vector2 P = points[V[p]];
128+
129+
if (InsideTriangle(A, B, C, P)) {
130+
return false;
131+
}
132+
}
133+
134+
return true;
135+
}
136+
137+
private static bool InsideTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
138+
{
139+
float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
140+
float cCROSSap, bCROSScp, aCROSSbp;
141+
142+
ax = C.x - B.x; ay = C.y - B.y;
143+
bx = A.x - C.x; by = A.y - C.y;
144+
cx = B.x - A.x; cy = B.y - A.y;
145+
apx = P.x - A.x; apy = P.y - A.y;
146+
bpx = P.x - B.x; bpy = P.y - B.y;
147+
cpx = P.x - C.x; cpy = P.y - C.y;
148+
149+
aCROSSbp = ax * bpy - ay * bpx;
150+
cCROSSap = cx * apy - cy * apx;
151+
bCROSScp = bx * cpy - by * cpx;
152+
153+
return ((aCROSSbp >= 0f) && (bCROSScp >= 0f) && (cCROSSap >= 0f));
154+
}
155+
156+
}
157+
158+
}

Runtime/Triangulator.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)