1 package org.newdawn.slick.geom;
2
3
4 import javax.annotation.Nonnull;
5 import javax.annotation.Nullable;
6
7
8
9
10
11
12 public class NeatTriangulator implements Triangulator
13 {
14
15
16
17 private static final long serialVersionUID = 1L;
18
19
20 private static final float EPSILON = 1E-006F;
21
22
23 private float pointsX[];
24
25 private float pointsY[];
26
27 private int numPoints;
28
29 private Edge edges[];
30
31 @Nullable
32 private int V[];
33
34 private int numEdges;
35
36 private Triangle triangles[];
37
38 private int numTriangles;
39
40 private float offset = EPSILON;
41
42
43
44
45 public NeatTriangulator()
46 {
47 pointsX = new float[100];
48 pointsY = new float[100];
49 numPoints = 0;
50 edges = new Edge[100];
51 numEdges = 0;
52 triangles = new Triangle[100];
53 numTriangles = 0;
54 }
55
56
57
58
59 public void clear()
60 {
61 numPoints = 0;
62 numEdges = 0;
63 numTriangles = 0;
64 }
65
66
67
68
69
70
71
72
73 private int findEdge(int i, int j)
74 {
75 int k;
76 int l;
77 if(i < j)
78 {
79 k = i;
80 l = j;
81 } else
82 {
83 k = j;
84 l = i;
85 }
86 for(int i1 = 0; i1 < numEdges; i1++)
87 if(edges[i1].v0 == k && edges[i1].v1 == l)
88 return i1;
89
90 return -1;
91 }
92
93
94
95
96
97
98
99
100 private void addEdge(int i, int j, int k)
101 {
102 int l1 = findEdge(i, j);
103 int j1;
104 int k1;
105 Edge edge;
106 if(l1 < 0)
107 {
108 if(numEdges == edges.length)
109 {
110 Edge aedge[] = new Edge[edges.length * 2];
111 System.arraycopy(edges, 0, aedge, 0, numEdges);
112 edges = aedge;
113 }
114 j1 = -1;
115 k1 = -1;
116 l1 = numEdges++;
117 edge = edges[l1] = new Edge();
118 } else
119 {
120 edge = edges[l1];
121 j1 = edge.t0;
122 k1 = edge.t1;
123 }
124 int l;
125 int i1;
126 if(i < j)
127 {
128 l = i;
129 i1 = j;
130 j1 = k;
131 } else
132 {
133 l = j;
134 i1 = i;
135 k1 = k;
136 }
137 edge.v0 = l;
138 edge.v1 = i1;
139 edge.t0 = j1;
140 edge.t1 = k1;
141 edge.suspect = true;
142 }
143
144
145
146
147
148
149
150
151
152 void markSuspect(int i, int j, boolean flag) throws InternalException
153 {
154 int k;
155 if(0 > (k = findEdge(i, j)))
156 {
157 throw new InternalException("Attempt to mark unknown edge");
158 } else
159 {
160 edges[k].suspect = flag;
161 }
162 }
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178 private static boolean insideTriangle(float f, float f1, float f2, float f3, float f4, float f5, float f6, float f7)
179 {
180 float f8 = f4 - f2;
181 float f9 = f5 - f3;
182 float f10 = f - f4;
183 float f11 = f1 - f5;
184 float f12 = f2 - f;
185 float f13 = f3 - f1;
186 float f14 = f6 - f;
187 float f15 = f7 - f1;
188 float f16 = f6 - f2;
189 float f17 = f7 - f3;
190 float f18 = f6 - f4;
191 float f19 = f7 - f5;
192 float f22 = f8 * f17 - f9 * f16;
193 float f20 = f12 * f15 - f13 * f14;
194 float f21 = f10 * f19 - f11 * f18;
195 return f22 >= 0.0D && f21 >= 0.0D && f20 >= 0.0D;
196 }
197
198
199
200
201
202
203
204
205
206
207
208 private boolean snip(int i, int j, int k, int l)
209 {
210 float f = pointsX[V[i]];
211 float f1 = pointsY[V[i]];
212 float f2 = pointsX[V[j]];
213 float f3 = pointsY[V[j]];
214 float f4 = pointsX[V[k]];
215 float f5 = pointsY[V[k]];
216 if(1E-006F > (f2 - f) * (f5 - f1) - (f3 - f1) * (f4 - f))
217 return false;
218 for(int i1 = 0; i1 < l; i1++)
219 if(i1 != i && i1 != j && i1 != k)
220 {
221 float f6 = pointsX[V[i1]];
222 float f7 = pointsY[V[i1]];
223 if(insideTriangle(f, f1, f2, f3, f4, f5, f6, f7))
224 return false;
225 }
226
227 return true;
228 }
229
230
231
232
233
234
235 private float area()
236 {
237 float f = 0.0F;
238 int i = numPoints - 1;
239 for(int j = 0; j < numPoints;)
240 {
241 f += pointsX[i] * pointsY[j] - pointsY[i] * pointsX[j];
242 i = j++;
243 }
244
245 return f * 0.5F;
246 }
247
248
249
250
251
252
253 void basicTriangulation() throws InternalException
254 {
255 int i = numPoints;
256 if(i < 3)
257 return;
258 numEdges = 0;
259 numTriangles = 0;
260 V = new int[i];
261
262 if(0.0D < area())
263 {
264 for(int k = 0; k < i; k++)
265 V[k] = k;
266
267 } else
268 {
269 for(int l = 0; l < i; l++)
270 V[l] = numPoints - 1 - l;
271
272 }
273 int k1 = 2 * i;
274 int i1 = i - 1;
275 while(i > 2)
276 {
277 if(0 >= k1--) {
278 throw new InternalException("Bad polygon");
279 }
280
281 int j = i1;
282 if(i <= j)
283 j = 0;
284 i1 = j + 1;
285 if(i <= i1)
286 i1 = 0;
287 int j1 = i1 + 1;
288 if(i <= j1)
289 j1 = 0;
290 if(snip(j, i1, j1, i))
291 {
292 int l1 = V[j];
293 int i2 = V[i1];
294 int j2 = V[j1];
295 if(numTriangles == triangles.length)
296 {
297 Triangle atriangle[] = new Triangle[triangles.length * 2];
298 System.arraycopy(triangles, 0, atriangle, 0, numTriangles);
299 triangles = atriangle;
300 }
301 triangles[numTriangles] = new Triangle(l1, i2, j2);
302 addEdge(l1, i2, numTriangles);
303 addEdge(i2, j2, numTriangles);
304 addEdge(j2, l1, numTriangles);
305 numTriangles++;
306 int k2 = i1;
307 for(int l2 = i1 + 1; l2 < i; l2++)
308 {
309 V[k2] = V[l2];
310 k2++;
311 }
312
313 i--;
314 k1 = 2 * i;
315 }
316 }
317 V = null;
318 }
319
320
321
322
323 public boolean triangulate()
324 {
325 try
326 {
327 basicTriangulation();
328
329 return true;
330 }
331 catch (InternalException e)
332 {
333 numEdges = 0;
334 }
335 return false;
336 }
337
338
339
340
341 public void addPolyPoint(float x, float y)
342 {
343 for (int i=0;i<numPoints;i++) {
344 if ((pointsX[i] == x) && (pointsY[i] == y)) {
345
346 y += offset;
347 offset += EPSILON;
348 }
349 }
350
351 if(numPoints == pointsX.length)
352 {
353 float af[] = new float[numPoints * 2];
354 System.arraycopy(pointsX, 0, af, 0, numPoints);
355 pointsX = af;
356 af = new float[numPoints * 2];
357 System.arraycopy(pointsY, 0, af, 0, numPoints);
358 pointsY = af;
359 }
360
361 pointsX[numPoints] = x;
362 pointsY[numPoints] = y;
363 numPoints++;
364 }
365
366
367
368
369
370
371 class Triangle
372 {
373
374 final int[] v;
375
376
377
378
379
380
381
382
383 Triangle(int i, int j, int k)
384 {
385 v = new int[3];
386 v[0] = i;
387 v[1] = j;
388 v[2] = k;
389 }
390 }
391
392
393
394
395
396
397 class Edge
398 {
399
400 int v0;
401
402 int v1;
403
404 int t0;
405
406 int t1;
407
408 boolean suspect;
409
410
411
412
413 Edge()
414 {
415 v0 = -1;
416 v1 = -1;
417 t0 = -1;
418 t1 = -1;
419 }
420 }
421
422
423
424
425
426
427 class InternalException extends Exception {
428
429
430
431 private static final long serialVersionUID = 1L;
432
433
434
435
436
437
438 public InternalException(String msg) {
439 super(msg);
440 }
441 }
442
443
444
445
446 public int getTriangleCount() {
447 return numTriangles;
448 }
449
450
451
452
453 @Nonnull
454 public float[] getTrianglePoint(int tri, int i) {
455 float xp = pointsX[triangles[tri].v[i]];
456 float yp = pointsY[triangles[tri].v[i]];
457
458 return new float[] {xp,yp};
459 }
460
461
462
463
464 public void startHole() {
465 }
466 }