rbpoly2tri 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,820 @@
1
+ /*
2
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
3
+ * http://code.google.com/p/poly2tri/
4
+ *
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without modification,
8
+ * are permitted provided that the following conditions are met:
9
+ *
10
+ * * Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ * * Redistributions in binary form must reproduce the above copyright notice,
13
+ * this list of conditions and the following disclaimer in the documentation
14
+ * and/or other materials provided with the distribution.
15
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
16
+ * used to endorse or promote products derived from this software without specific
17
+ * prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+ */
31
+ #include "sweep.h"
32
+ #include "sweep_context.h"
33
+ #include "advancing_front.h"
34
+ #include "../common/utils.h"
35
+
36
+ namespace p2t {
37
+
38
+ // Triangulate simple polygon with holes
39
+ void Sweep::Triangulate(SweepContext& tcx)
40
+ {
41
+ tcx.InitTriangulation();
42
+ tcx.CreateAdvancingFront(nodes_);
43
+ // Sweep points; build mesh
44
+ SweepPoints(tcx);
45
+ // Clean up
46
+ FinalizationPolygon(tcx);
47
+ }
48
+
49
+ void Sweep::SweepPoints(SweepContext& tcx)
50
+ {
51
+ for (int i = 1; i < tcx.point_count(); i++) {
52
+ Point& point = *tcx.GetPoint(i);
53
+ Node* node = &PointEvent(tcx, point);
54
+ for (int i = 0; i < point.edge_list.size(); i++) {
55
+ EdgeEvent(tcx, point.edge_list[i], node);
56
+ }
57
+ }
58
+ }
59
+
60
+ void Sweep::FinalizationPolygon(SweepContext& tcx)
61
+ {
62
+ // Get an Internal triangle to start with
63
+ Triangle* t = tcx.front()->head()->next->triangle;
64
+ Point* p = tcx.front()->head()->next->point;
65
+ while (!t->GetConstrainedEdgeCW(*p)) {
66
+ t = t->NeighborCCW(*p);
67
+ }
68
+
69
+ // Collect interior triangles constrained by edges
70
+ tcx.MeshClean(*t);
71
+ }
72
+
73
+ /**
74
+ * Find closes node to the left of the new point and
75
+ * create a new triangle. If needed new holes and basins
76
+ * will be filled to.
77
+ *
78
+ * @param tcx
79
+ * @param point
80
+ * @return
81
+ */
82
+ Node& Sweep::PointEvent(SweepContext& tcx, Point& point)
83
+ {
84
+ Node& node = tcx.LocateNode(point);
85
+ Node& new_node = NewFrontTriangle(tcx, point, node);
86
+
87
+ // Only need to check +epsilon since point never have smaller
88
+ // x value than node due to how we fetch nodes from the front
89
+ if (point.x <= node.point->x + EPSILON) {
90
+ Fill(tcx, node);
91
+ }
92
+
93
+ //tcx.AddNode(new_node);
94
+
95
+ FillAdvancingFront(tcx, new_node);
96
+ return new_node;
97
+ }
98
+
99
+ void Sweep::EdgeEvent(SweepContext& tcx, Edge* edge, Node* node)
100
+ {
101
+ tcx.edge_event.constrained_edge = edge;
102
+ tcx.edge_event.right = (edge->p->x > edge->q->x);
103
+
104
+ if (IsEdgeSideOfTriangle(*node->triangle, *edge->p, *edge->q)) {
105
+ return;
106
+ }
107
+
108
+ // For now we will do all needed filling
109
+ // TODO: integrate with flip process might give some better performance
110
+ // but for now this avoid the issue with cases that needs both flips and fills
111
+ FillEdgeEvent(tcx, edge, node);
112
+ EdgeEvent(tcx, *edge->p, *edge->q, node->triangle, *edge->q);
113
+ }
114
+
115
+ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangle, Point& point)
116
+ {
117
+ if (IsEdgeSideOfTriangle(*triangle, ep, eq)) {
118
+ return;
119
+ }
120
+
121
+ Point* p1 = triangle->PointCCW(point);
122
+ Orientation o1 = Orient2d(eq, *p1, ep);
123
+ if (o1 == COLLINEAR) {
124
+ //throw new RuntimeException( "EdgeEvent - Collinear not supported" );
125
+ assert(false);
126
+ }
127
+
128
+ Point* p2 = triangle->PointCW(point);
129
+ Orientation o2 = Orient2d(eq, *p2, ep);
130
+ if (o2 == COLLINEAR) {
131
+ //throw new RuntimeException( "EdgeEvent - Collinear not supported" );
132
+ assert(false);
133
+ }
134
+
135
+ if (o1 == o2) {
136
+ // Need to decide if we are rotating CW or CCW to get to a triangle
137
+ // that will cross edge
138
+ if (o1 == CW) {
139
+ triangle = triangle->NeighborCCW(point);
140
+ } else{
141
+ triangle = triangle->NeighborCW(point);
142
+ }
143
+ EdgeEvent(tcx, ep, eq, triangle, point);
144
+ } else {
145
+ // This triangle crosses constraint so lets flippin start!
146
+ FlipEdgeEvent(tcx, ep, eq, triangle, point);
147
+ }
148
+ }
149
+
150
+ bool Sweep::IsEdgeSideOfTriangle(Triangle& triangle, Point& ep, Point& eq)
151
+ {
152
+ int index = triangle.EdgeIndex(&ep, &eq);
153
+
154
+ if (index != -1) {
155
+ triangle.MarkConstrainedEdge(index);
156
+ Triangle* t = triangle.GetNeighbor(index);
157
+ if (t) {
158
+ t->MarkConstrainedEdge(&ep, &eq);
159
+ }
160
+ return true;
161
+ }
162
+ return false;
163
+ }
164
+
165
+ Node& Sweep::NewFrontTriangle(SweepContext& tcx, Point& point, Node& node)
166
+ {
167
+ Triangle* triangle = new Triangle(point, *node.point, *node.next->point);
168
+
169
+ triangle->MarkNeighbor(*node.triangle);
170
+ tcx.AddToMap(triangle);
171
+
172
+ Node* new_node = new Node(point);
173
+ nodes_.push_back(new_node);
174
+
175
+ new_node->next = node.next;
176
+ new_node->prev = &node;
177
+ node.next->prev = new_node;
178
+ node.next = new_node;
179
+
180
+ if (!Legalize(tcx, *triangle)) {
181
+ tcx.MapTriangleToNodes(*triangle);
182
+ }
183
+
184
+ return *new_node;
185
+ }
186
+
187
+ /**
188
+ * Adds a triangle to the advancing front to fill a hole.
189
+ * @param tcx
190
+ * @param node - middle node, that is the bottom of the hole
191
+ */
192
+ void Sweep::Fill(SweepContext& tcx, Node& node)
193
+ {
194
+ Triangle* triangle = new Triangle(*node.prev->point, *node.point, *node.next->point);
195
+
196
+ // TODO: should copy the constrained_edge value from neighbor triangles
197
+ // for now constrained_edge values are copied during the legalize
198
+ triangle->MarkNeighbor(*node.prev->triangle);
199
+ triangle->MarkNeighbor(*node.triangle);
200
+
201
+ tcx.AddToMap(triangle);
202
+
203
+ // Update the advancing front
204
+ node.prev->next = node.next;
205
+ node.next->prev = node.prev;
206
+
207
+ // If it was legalized the triangle has already been mapped
208
+ if (!Legalize(tcx, *triangle)) {
209
+ tcx.MapTriangleToNodes(*triangle);
210
+ }
211
+
212
+ }
213
+
214
+ /**
215
+ * Fills holes in the Advancing Front
216
+ *
217
+ *
218
+ * @param tcx
219
+ * @param n
220
+ */
221
+ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n)
222
+ {
223
+
224
+ // Fill right holes
225
+ Node* node = n.next;
226
+
227
+ while (node->next) {
228
+ double angle = HoleAngle(*node);
229
+ if (angle > M_PI_2 || angle < -M_PI_2) break;
230
+ Fill(tcx, *node);
231
+ node = node->next;
232
+ }
233
+
234
+ // Fill left holes
235
+ node = n.prev;
236
+
237
+ while (node->prev) {
238
+ double angle = HoleAngle(*node);
239
+ if (angle > M_PI_2 || angle < -M_PI_2) break;
240
+ Fill(tcx, *node);
241
+ node = node->prev;
242
+ }
243
+
244
+ // Fill right basins
245
+ if (n.next && n.next->next) {
246
+ double angle = BasinAngle(n);
247
+ if (angle < PI_3div4) {
248
+ FillBasin(tcx, n);
249
+ }
250
+ }
251
+ }
252
+
253
+ double Sweep::BasinAngle(Node& node)
254
+ {
255
+ double ax = node.point->x - node.next->next->point->x;
256
+ double ay = node.point->y - node.next->next->point->y;
257
+ return atan2(ay, ax);
258
+ }
259
+
260
+ /**
261
+ *
262
+ * @param node - middle node
263
+ * @return the angle between 3 front nodes
264
+ */
265
+ double Sweep::HoleAngle(Node& node)
266
+ {
267
+ /* Complex plane
268
+ * ab = cosA +i*sinA
269
+ * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx)
270
+ * atan2(y,x) computes the principal value of the argument function
271
+ * applied to the complex number x+iy
272
+ * Where x = ax*bx + ay*by
273
+ * y = ax*by - ay*bx
274
+ */
275
+ double ax = node.next->point->x - node.point->x;
276
+ double ay = node.next->point->y - node.point->y;
277
+ double bx = node.prev->point->x - node.point->x;
278
+ double by = node.prev->point->y - node.point->y;
279
+ return atan2(ax * by - ay * bx, ax * bx + ay * by);
280
+ }
281
+
282
+ /**
283
+ * Returns true if triangle was legalized
284
+ */
285
+ bool Sweep::Legalize(SweepContext& tcx, Triangle& t)
286
+ {
287
+ // To legalize a triangle we start by finding if any of the three edges
288
+ // violate the Delaunay condition
289
+ for (int i = 0; i < 3; i++) {
290
+ if (t.delaunay_edge[i])
291
+ continue;
292
+
293
+ Triangle* ot = t.GetNeighbor(i);
294
+
295
+ if (ot) {
296
+ Point* p = t.GetPoint(i);
297
+ Point* op = ot->OppositePoint(t, *p);
298
+ int oi = ot->Index(op);
299
+
300
+ // If this is a Constrained Edge or a Delaunay Edge(only during recursive legalization)
301
+ // then we should not try to legalize
302
+ if (ot->constrained_edge[oi] || ot->delaunay_edge[oi]) {
303
+ t.constrained_edge[i] = ot->constrained_edge[oi];
304
+ continue;
305
+ }
306
+
307
+ bool inside = Incircle(*p, *t.PointCCW(*p), *t.PointCW(*p), *op);
308
+
309
+ if (inside) {
310
+ // Lets mark this shared edge as Delaunay
311
+ t.delaunay_edge[i] = true;
312
+ ot->delaunay_edge[oi] = true;
313
+
314
+ // Lets rotate shared edge one vertex CW to legalize it
315
+ RotateTrianglePair(t, *p, *ot, *op);
316
+
317
+ // We now got one valid Delaunay Edge shared by two triangles
318
+ // This gives us 4 new edges to check for Delaunay
319
+
320
+ // Make sure that triangle to node mapping is done only one time for a specific triangle
321
+ bool not_legalized = !Legalize(tcx, t);
322
+ if (not_legalized) {
323
+ tcx.MapTriangleToNodes(t);
324
+ }
325
+
326
+ not_legalized = !Legalize(tcx, *ot);
327
+ if (not_legalized)
328
+ tcx.MapTriangleToNodes(*ot);
329
+
330
+ // Reset the Delaunay edges, since they only are valid Delaunay edges
331
+ // until we add a new triangle or point.
332
+ // XXX: need to think about this. Can these edges be tried after we
333
+ // return to previous recursive level?
334
+ t.delaunay_edge[i] = false;
335
+ ot->delaunay_edge[oi] = false;
336
+
337
+ // If triangle have been legalized no need to check the other edges since
338
+ // the recursive legalization will handles those so we can end here.
339
+ return true;
340
+ }
341
+ }
342
+ }
343
+ return false;
344
+ }
345
+
346
+ /**
347
+ * <b>Requirement</b>:<br>
348
+ * 1. a,b and c form a triangle.<br>
349
+ * 2. a and d is know to be on opposite side of bc<br>
350
+ * <pre>
351
+ * a
352
+ * +
353
+ * / \
354
+ * / \
355
+ * b/ \c
356
+ * +-------+
357
+ * / d \
358
+ * / \
359
+ * </pre>
360
+ * <b>Fact</b>: d has to be in area B to have a chance to be inside the circle formed by
361
+ * a,b and c<br>
362
+ * d is outside B if orient2d(a,b,d) or orient2d(c,a,d) is CW<br>
363
+ * This preknowledge gives us a way to optimize the incircle test
364
+ * @param a - triangle point, opposite d
365
+ * @param b - triangle point
366
+ * @param c - triangle point
367
+ * @param d - point opposite a
368
+ * @return true if d is inside circle, false if on circle edge
369
+ */
370
+ bool Sweep::Incircle(Point& pa, Point& pb, Point& pc, Point& pd)
371
+ {
372
+ double adx = pa.x - pd.x;
373
+ double ady = pa.y - pd.y;
374
+ double bdx = pb.x - pd.x;
375
+ double bdy = pb.y - pd.y;
376
+
377
+ double adxbdy = adx * bdy;
378
+ double bdxady = bdx * ady;
379
+ double oabd = adxbdy - bdxady;
380
+
381
+ if (oabd <= 0)
382
+ return false;
383
+
384
+ double cdx = pc.x - pd.x;
385
+ double cdy = pc.y - pd.y;
386
+
387
+ double cdxady = cdx * ady;
388
+ double adxcdy = adx * cdy;
389
+ double ocad = cdxady - adxcdy;
390
+
391
+ if (ocad <= 0)
392
+ return false;
393
+
394
+ double bdxcdy = bdx * cdy;
395
+ double cdxbdy = cdx * bdy;
396
+
397
+ double alift = adx * adx + ady * ady;
398
+ double blift = bdx * bdx + bdy * bdy;
399
+ double clift = cdx * cdx + cdy * cdy;
400
+
401
+ double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd;
402
+
403
+ return det > 0;
404
+ }
405
+
406
+ /**
407
+ * Rotates a triangle pair one vertex CW
408
+ *<pre>
409
+ * n2 n2
410
+ * P +-----+ P +-----+
411
+ * | t /| |\ t |
412
+ * | / | | \ |
413
+ * n1| / |n3 n1| \ |n3
414
+ * | / | after CW | \ |
415
+ * |/ oT | | oT \|
416
+ * +-----+ oP +-----+
417
+ * n4 n4
418
+ * </pre>
419
+ */
420
+ void Sweep::RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op)
421
+ {
422
+ Triangle* n1, *n2, *n3, *n4;
423
+ n1 = t.NeighborCCW(p);
424
+ n2 = t.NeighborCW(p);
425
+ n3 = ot.NeighborCCW(op);
426
+ n4 = ot.NeighborCW(op);
427
+
428
+ bool ce1, ce2, ce3, ce4;
429
+ ce1 = t.GetConstrainedEdgeCCW(p);
430
+ ce2 = t.GetConstrainedEdgeCW(p);
431
+ ce3 = ot.GetConstrainedEdgeCCW(op);
432
+ ce4 = ot.GetConstrainedEdgeCW(op);
433
+
434
+ bool de1, de2, de3, de4;
435
+ de1 = t.GetDelunayEdgeCCW(p);
436
+ de2 = t.GetDelunayEdgeCW(p);
437
+ de3 = ot.GetDelunayEdgeCCW(op);
438
+ de4 = ot.GetDelunayEdgeCW(op);
439
+
440
+ t.Legalize(p, op);
441
+ ot.Legalize(op, p);
442
+
443
+ // Remap delaunay_edge
444
+ ot.SetDelunayEdgeCCW(p, de1);
445
+ t.SetDelunayEdgeCW(p, de2);
446
+ t.SetDelunayEdgeCCW(op, de3);
447
+ ot.SetDelunayEdgeCW(op, de4);
448
+
449
+ // Remap constrained_edge
450
+ ot.SetConstrainedEdgeCCW(p, ce1);
451
+ t.SetConstrainedEdgeCW(p, ce2);
452
+ t.SetConstrainedEdgeCCW(op, ce3);
453
+ ot.SetConstrainedEdgeCW(op, ce4);
454
+
455
+ // Remap neighbors
456
+ // XXX: might optimize the markNeighbor by keeping track of
457
+ // what side should be assigned to what neighbor after the
458
+ // rotation. Now mark neighbor does lots of testing to find
459
+ // the right side.
460
+ t.ClearNeighbors();
461
+ ot.ClearNeighbors();
462
+ if (n1) ot.MarkNeighbor(*n1);
463
+ if (n2) t.MarkNeighbor(*n2);
464
+ if (n3) t.MarkNeighbor(*n3);
465
+ if (n4) ot.MarkNeighbor(*n4);
466
+ t.MarkNeighbor(ot);
467
+ }
468
+
469
+ /**
470
+ * Fills a basin that has formed on the Advancing Front to the right
471
+ * of given node.<br>
472
+ * First we decide a left,bottom and right node that forms the
473
+ * boundaries of the basin. Then we do a reqursive fill.
474
+ *
475
+ * @param tcx
476
+ * @param node - starting node, this or next node will be left node
477
+ */
478
+ void Sweep::FillBasin(SweepContext& tcx, Node& node)
479
+ {
480
+ if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) {
481
+ tcx.basin.left_node = node.next->next;
482
+ } else {
483
+ tcx.basin.left_node = node.next;
484
+ }
485
+
486
+ // Find the bottom and right node
487
+ tcx.basin.bottom_node = tcx.basin.left_node;
488
+ while (tcx.basin.bottom_node->next
489
+ && tcx.basin.bottom_node->point->y >= tcx.basin.bottom_node->next->point->y) {
490
+ tcx.basin.bottom_node = tcx.basin.bottom_node->next;
491
+ }
492
+ if (tcx.basin.bottom_node == tcx.basin.left_node) {
493
+ // No valid basin
494
+ return;
495
+ }
496
+
497
+ tcx.basin.right_node = tcx.basin.bottom_node;
498
+ while (tcx.basin.right_node->next
499
+ && tcx.basin.right_node->point->y < tcx.basin.right_node->next->point->y) {
500
+ tcx.basin.right_node = tcx.basin.right_node->next;
501
+ }
502
+ if (tcx.basin.right_node == tcx.basin.bottom_node) {
503
+ // No valid basins
504
+ return;
505
+ }
506
+
507
+ tcx.basin.width = tcx.basin.right_node->point->x - tcx.basin.left_node->point->x;
508
+ tcx.basin.left_highest = tcx.basin.left_node->point->y > tcx.basin.right_node->point->y;
509
+
510
+ FillBasinReq(tcx, tcx.basin.bottom_node);
511
+ }
512
+
513
+ /**
514
+ * Recursive algorithm to fill a Basin with triangles
515
+ *
516
+ * @param tcx
517
+ * @param node - bottom_node
518
+ * @param cnt - counter used to alternate on even and odd numbers
519
+ */
520
+ void Sweep::FillBasinReq(SweepContext& tcx, Node* node)
521
+ {
522
+ // if shallow stop filling
523
+ if (IsShallow(tcx, *node)) {
524
+ return;
525
+ }
526
+
527
+ Fill(tcx, *node);
528
+
529
+ if (node->prev == tcx.basin.left_node && node->next == tcx.basin.right_node) {
530
+ return;
531
+ } else if (node->prev == tcx.basin.left_node) {
532
+ Orientation o = Orient2d(*node->point, *node->next->point, *node->next->next->point);
533
+ if (o == CW) {
534
+ return;
535
+ }
536
+ node = node->next;
537
+ } else if (node->next == tcx.basin.right_node) {
538
+ Orientation o = Orient2d(*node->point, *node->prev->point, *node->prev->prev->point);
539
+ if (o == CCW) {
540
+ return;
541
+ }
542
+ node = node->prev;
543
+ } else {
544
+ // Continue with the neighbor node with lowest Y value
545
+ if (node->prev->point->y < node->next->point->y) {
546
+ node = node->prev;
547
+ } else {
548
+ node = node->next;
549
+ }
550
+ }
551
+
552
+ FillBasinReq(tcx, node);
553
+ }
554
+
555
+ bool Sweep::IsShallow(SweepContext& tcx, Node& node)
556
+ {
557
+ double height;
558
+
559
+ if (tcx.basin.left_highest) {
560
+ height = tcx.basin.left_node->point->y - node.point->y;
561
+ } else {
562
+ height = tcx.basin.right_node->point->y - node.point->y;
563
+ }
564
+
565
+ // if shallow stop filling
566
+ if (tcx.basin.width > height) {
567
+ return true;
568
+ }
569
+ return false;
570
+ }
571
+
572
+ void Sweep::FillEdgeEvent(SweepContext& tcx, Edge* edge, Node* node)
573
+ {
574
+ if (tcx.edge_event.right) {
575
+ FillRightAboveEdgeEvent(tcx, edge, node);
576
+ } else {
577
+ FillLeftAboveEdgeEvent(tcx, edge, node);
578
+ }
579
+ }
580
+
581
+ void Sweep::FillRightAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node)
582
+ {
583
+ while (node->next->point->x < edge->p->x) {
584
+ // Check if next node is below the edge
585
+ if (Orient2d(*edge->q, *node->next->point, *edge->p) == CCW) {
586
+ FillRightBelowEdgeEvent(tcx, edge, *node);
587
+ } else {
588
+ node = node->next;
589
+ }
590
+ }
591
+ }
592
+
593
+ void Sweep::FillRightBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
594
+ {
595
+ if (node.point->x < edge->p->x) {
596
+ if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) {
597
+ // Concave
598
+ FillRightConcaveEdgeEvent(tcx, edge, node);
599
+ } else{
600
+ // Convex
601
+ FillRightConvexEdgeEvent(tcx, edge, node);
602
+ // Retry this one
603
+ FillRightBelowEdgeEvent(tcx, edge, node);
604
+ }
605
+ }
606
+ }
607
+
608
+ void Sweep::FillRightConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
609
+ {
610
+ Fill(tcx, *node.next);
611
+ if (node.next->point != edge->p) {
612
+ // Next above or below edge?
613
+ if (Orient2d(*edge->q, *node.next->point, *edge->p) == CCW) {
614
+ // Below
615
+ if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) {
616
+ // Next is concave
617
+ FillRightConcaveEdgeEvent(tcx, edge, node);
618
+ } else {
619
+ // Next is convex
620
+ }
621
+ }
622
+ }
623
+
624
+ }
625
+
626
+ void Sweep::FillRightConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
627
+ {
628
+ // Next concave or convex?
629
+ if (Orient2d(*node.next->point, *node.next->next->point, *node.next->next->next->point) == CCW) {
630
+ // Concave
631
+ FillRightConcaveEdgeEvent(tcx, edge, *node.next);
632
+ } else{
633
+ // Convex
634
+ // Next above or below edge?
635
+ if (Orient2d(*edge->q, *node.next->next->point, *edge->p) == CCW) {
636
+ // Below
637
+ FillRightConvexEdgeEvent(tcx, edge, *node.next);
638
+ } else{
639
+ // Above
640
+ }
641
+ }
642
+ }
643
+
644
+ void Sweep::FillLeftAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node)
645
+ {
646
+ while (node->prev->point->x > edge->p->x) {
647
+ // Check if next node is below the edge
648
+ if (Orient2d(*edge->q, *node->prev->point, *edge->p) == CW) {
649
+ FillLeftBelowEdgeEvent(tcx, edge, *node);
650
+ } else {
651
+ node = node->prev;
652
+ }
653
+ }
654
+ }
655
+
656
+ void Sweep::FillLeftBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
657
+ {
658
+ if (node.point->x > edge->p->x) {
659
+ if (Orient2d(*node.point, *node.prev->point, *node.prev->prev->point) == CW) {
660
+ // Concave
661
+ FillLeftConcaveEdgeEvent(tcx, edge, node);
662
+ } else {
663
+ // Convex
664
+ FillLeftConvexEdgeEvent(tcx, edge, node);
665
+ // Retry this one
666
+ FillLeftBelowEdgeEvent(tcx, edge, node);
667
+ }
668
+ }
669
+ }
670
+
671
+ void Sweep::FillLeftConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
672
+ {
673
+ // Next concave or convex?
674
+ if (Orient2d(*node.prev->point, *node.prev->prev->point, *node.prev->prev->prev->point) == CW) {
675
+ // Concave
676
+ FillLeftConcaveEdgeEvent(tcx, edge, *node.prev);
677
+ } else{
678
+ // Convex
679
+ // Next above or below edge?
680
+ if (Orient2d(*edge->q, *node.prev->prev->point, *edge->p) == CW) {
681
+ // Below
682
+ FillLeftConvexEdgeEvent(tcx, edge, *node.prev);
683
+ } else{
684
+ // Above
685
+ }
686
+ }
687
+ }
688
+
689
+ void Sweep::FillLeftConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
690
+ {
691
+ Fill(tcx, *node.prev);
692
+ if (node.prev->point != edge->p) {
693
+ // Next above or below edge?
694
+ if (Orient2d(*edge->q, *node.prev->point, *edge->p) == CW) {
695
+ // Below
696
+ if (Orient2d(*node.point, *node.prev->point, *node.prev->prev->point) == CW) {
697
+ // Next is concave
698
+ FillLeftConcaveEdgeEvent(tcx, edge, node);
699
+ } else{
700
+ // Next is convex
701
+ }
702
+ }
703
+ }
704
+
705
+ }
706
+
707
+ void Sweep::FlipEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* t, Point& p)
708
+ {
709
+ Triangle& ot = t->NeighborAcross(p);
710
+ Point& op = *ot.OppositePoint(*t, p);
711
+
712
+ if (&ot == NULL) {
713
+ // If we want to integrate the fillEdgeEvent do it here
714
+ // With current implementation we should never get here
715
+ //throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle");
716
+ assert(0);
717
+ }
718
+
719
+ if (InScanArea(p, *t->PointCCW(p), *t->PointCW(p), op)) {
720
+ // Lets rotate shared edge one vertex CW
721
+ RotateTrianglePair(*t, p, ot, op);
722
+ tcx.MapTriangleToNodes(*t);
723
+ tcx.MapTriangleToNodes(ot);
724
+
725
+ if (p == eq && op == ep) {
726
+ if (eq == *tcx.edge_event.constrained_edge->q && ep == *tcx.edge_event.constrained_edge->p) {
727
+ t->MarkConstrainedEdge(&ep, &eq);
728
+ ot.MarkConstrainedEdge(&ep, &eq);
729
+ Legalize(tcx, *t);
730
+ Legalize(tcx, ot);
731
+ } else {
732
+ // XXX: I think one of the triangles should be legalized here?
733
+ }
734
+ } else {
735
+ Orientation o = Orient2d(eq, op, ep);
736
+ t = &NextFlipTriangle(tcx, (int)o, *t, ot, p, op);
737
+ FlipEdgeEvent(tcx, ep, eq, t, p);
738
+ }
739
+ } else {
740
+ Point& newP = NextFlipPoint(ep, eq, ot, op);
741
+ FlipScanEdgeEvent(tcx, ep, eq, *t, ot, newP);
742
+ EdgeEvent(tcx, ep, eq, t, p);
743
+ }
744
+ }
745
+
746
+ Triangle& Sweep::NextFlipTriangle(SweepContext& tcx, int o, Triangle& t, Triangle& ot, Point& p, Point& op)
747
+ {
748
+ if (o == CCW) {
749
+ // ot is not crossing edge after flip
750
+ int edge_index = ot.EdgeIndex(&p, &op);
751
+ ot.delaunay_edge[edge_index] = true;
752
+ Legalize(tcx, ot);
753
+ ot.ClearDelunayEdges();
754
+ return t;
755
+ }
756
+
757
+ // t is not crossing edge after flip
758
+ int edge_index = t.EdgeIndex(&p, &op);
759
+
760
+ t.delaunay_edge[edge_index] = true;
761
+ Legalize(tcx, t);
762
+ t.ClearDelunayEdges();
763
+ return ot;
764
+ }
765
+
766
+ Point& Sweep::NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op)
767
+ {
768
+ Orientation o2d = Orient2d(eq, op, ep);
769
+ if (o2d == CW) {
770
+ // Right
771
+ return *ot.PointCCW(op);
772
+ } else if (o2d == CCW) {
773
+ // Left
774
+ return *ot.PointCW(op);
775
+ } else{
776
+ //throw new RuntimeException("[Unsupported] Opposing point on constrained edge");
777
+ assert(0);
778
+ }
779
+ }
780
+
781
+ void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle,
782
+ Triangle& t, Point& p)
783
+ {
784
+ Triangle& ot = t.NeighborAcross(p);
785
+ Point& op = *ot.OppositePoint(t, p);
786
+
787
+ if (&t.NeighborAcross(p) == NULL) {
788
+ // If we want to integrate the fillEdgeEvent do it here
789
+ // With current implementation we should never get here
790
+ //throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle");
791
+ assert(0);
792
+ }
793
+
794
+ if (InScanArea(eq, *flip_triangle.PointCCW(eq), *flip_triangle.PointCW(eq), op)) {
795
+ // flip with new edge op->eq
796
+ FlipEdgeEvent(tcx, eq, op, &ot, op);
797
+ // TODO: Actually I just figured out that it should be possible to
798
+ // improve this by getting the next ot and op before the the above
799
+ // flip and continue the flipScanEdgeEvent here
800
+ // set new ot and op here and loop back to inScanArea test
801
+ // also need to set a new flip_triangle first
802
+ // Turns out at first glance that this is somewhat complicated
803
+ // so it will have to wait.
804
+ } else{
805
+ Point& newP = NextFlipPoint(ep, eq, ot, op);
806
+ FlipScanEdgeEvent(tcx, ep, eq, flip_triangle, ot, newP);
807
+ }
808
+ }
809
+
810
+ Sweep::~Sweep() {
811
+
812
+ // Clean up memory
813
+ for(int i = 0; i < nodes_.size(); i++) {
814
+ delete nodes_[i];
815
+ }
816
+
817
+ }
818
+
819
+ }
820
+