rbpoly2tri 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+