UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
BowyerWatsonTriangulator.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2#pragma once
3
4#include "Core/Types.h"
5#include "Math/SlopeUtils.h"
7#include "UI/Display.h"
8#ifdef CADKERNEL_DEV
9#include "UI/DefineForDebug.h"
10#endif
11
12namespace UE::CADKernel
13{
14
16{
17protected:
18 struct FTriangle
19 {
23
24 FTriangle(const int32& Index0, const int32& Index1, const int32& Index2, const TArray<TPair<int32, FVector2d>>& InVertices)
25 {
26 Set(Index0, Index1, Index2, InVertices);
27 }
28
29 void Set(const int32& Index0, const int32& Index1, const int32& Index2, const TArray<TPair<int32, FVector2d>>& InVertices)
30 {
32 VertexIndices[1] = Index1;
33 VertexIndices[2] = Index2;
35 Center = FVector(Triangle.CircumCircleCenterWithSquareRadius(SquareRadius), 0.);
36 }
37 };
38
39
40public:
41
48 : VerticesCount(InVertices.Num())
49 , Vertices(InVertices)
50 , EdgeVertexIndices(OutEdgeVertices)
51 {
52 Init();
53 }
54
56 {
57 FTimePoint StartTime = FChrono::Now();
58#ifdef DEBUG_BOWYERWATSON
59 F3DDebugSession DelaunayDebugSession(bDisplay, TEXT("Delaunay Algo"));
60#endif // DEBUG_DELAUNAY
61
62 Vertices.Sort([](const TPair<int32, FVector2d>& Vertex1, const TPair<int32, FVector2d>& Vertex2) {return (Vertex1.Value.X + Vertex1.Value.Y) > (Vertex2.Value.X + Vertex2.Value.Y); });
63
64#ifdef DEBUG_BOWYERWATSON
65 if (bDisplay)
66 {
67 F3DDebugSession _(TEXT("Vertices"));
68 for (const TPair<int32, FVector2d>& Vertex : Vertices)
69 {
70 //F3DDebugSession _(TEXT("Vertex"));
71 DisplayPoint2DWithScale(Vertex.Value , EVisuProperty::YellowPoint, Vertex.Key);
72 }
73 //Wait();
74 }
75#endif
76 // initialization of Bowyer & Watson algorithm with a bounding mesh of the vertex cloud
77 // i.e. 2 triangles defined by the corners of the offset vertices bounding box
78 MakeBoundingMesh();
79
80#ifdef DEBUG_BOWYERWATSON_STEP
82 Wait(bDisplay);
83
84 static int32 StopIndex = 206;
85#endif
86
87 EdgeVertexIndices.Reserve(TriangleSet.Num() * 6);
88
89 // insert each point in the mesh
90 // The points are sorted on the diagonal of the bbox and are inserted from one end to the other
91 int32 VertexIndex = 0;
92 for (int32 VIndex = 0; VIndex < VerticesCount; ++VIndex)
93 {
94 if (VIndex % 2 == 0)
95 {
96 VertexIndex = VIndex / 2;
97 }
98 else
99 {
100 VertexIndex = VerticesCount - 1 - VIndex / 2;
101 }
102
103 SelectedTriangleIndices.Reset(VerticesCount);
104 AdditionalTriangleIndices.Reset(VerticesCount);
105
106 const FVector2d& NewVertex = Vertices[VertexIndex].Value;
107
108#ifdef DEBUG_BOWYERWATSON_STEP
109 F3DDebugSession _(bDisplay, FString::Printf(TEXT("Step %d"), VIndex));
110 if (bDisplay)
111 {
112 F3DDebugSession _(TEXT("New Point"));
113 DisplayPoint(NewVertex * DisplayScale, EVisuProperty::YellowPoint, Vertices[VertexIndex].Key);
115 }
116#endif
117
118 bool bHaveDoubt = false;
119
120 // find all triangles whose circumcircles contain the new vertex
121 {
122 // The problem is for triangle with huge circumscribed circle radius (flat triangle)
123 // in this case, if distance between the new vertex and the circumscribed circle center nearly equals its radius
124 // - So the idea is to check that the new vertex is not outside the triangle and could generate a flatten triangle
125 // To check this, the slop between each side is evaluated (ComputeUnorientedSlope(NewVertex, Triangle.Vertex[a], Triangle.Vertex[b]))
126 // if the slop is nearly null this mean that the new vertex is outside the triangle and will generate a flat triangle
127
128 constexpr double IncreaseFactor = 1.001; // to process the case of new vertex on the circumscribed circle
129 constexpr double ReducingFactor = 0.999 / IncreaseFactor; // to remove the case of new vertex on the circumscribed circle
130 constexpr double LargeReducingFactor = 0.99; // to remove the case of new vertex on the circumscribed circle
131 // the case of 4 points nearly on the same circle is manage in a second time i.e. we check that the
132
133 for (int32 TriangleIndex = 0; TriangleIndex < TriangleSet.Num(); TriangleIndex++)
134 {
135 const FVector2d Center(TriangleSet[TriangleIndex].Center.X, TriangleSet[TriangleIndex].Center.Y);
136
137 const double SquareDistanceToCenter = FVector2d::DistSquared(Center, NewVertex);
138
139 const double SquareRadiusMax = TriangleSet[TriangleIndex].SquareRadius * IncreaseFactor;
142
144 {
145 SelectedTriangleIndices.Add(TriangleIndex);
147 {
148 bHaveDoubt = true;
149 }
150 }
151 else
152 {
154 {
155 if (DoesTriangleContainingNewVertex(NewVertex, TriangleIndex))
156 {
157 SelectedTriangleIndices.Add(TriangleIndex);
158 }
159 else
160 {
161 AdditionalTriangleIndices.Add(TriangleIndex);
162 }
163 }
164 }
165 }
166 }
167
168#ifdef DEBUG_BOWYERWATSON_STEP
169 if (bHaveDoubt && (VIndex >= StopIndex))
170 {
171 F3DDebugSession A(bDisplay, TEXT("HaveDoubt"));
173 }
174#endif
175 if (!bHaveDoubt)
176 {
177 bHaveDoubt = !DoSelectedTrianglesFormSinglePartition();
178 }
179
180 if (SelectedTriangleIndices.Num() == 0)
181 {
182 for (int32& TriangleIndex : AdditionalTriangleIndices)
183 {
184 if (DoesTriangleContainingNewVertex(NewVertex, TriangleIndex))
185 {
186 SelectedTriangleIndices.Add(TriangleIndex);
187 TriangleIndex = -1;
188 }
189 }
190 }
191 else if(bHaveDoubt)
192 {
194 TmpTriangleIndices = MoveTemp(SelectedTriangleIndices);
195 SelectedTriangleIndices.Reset(TmpTriangleIndices.Num());
196
197 AddTrianglesContainingNewVertexToSelectedTriangles(NewVertex, TmpTriangleIndices);
198
199 AddConnectedTrianglesToSelection(TmpTriangleIndices);
200
201 for (int32& TriangleIndex : TmpTriangleIndices)
202 {
203 if (TriangleIndex >= 0)
204 {
205 AdditionalTriangleIndices.Add(TriangleIndex);
206 }
207 }
208 }
209
210#ifdef DEBUG_BOWYERWATSON_STEP
211 if (VIndex == StopIndex)
212 {
214 Wait();
215 }
216#endif
217
218 if (AdditionalTriangleIndices.Num() > 0)
219 {
220 // Additional triangles are triangles that the new vertex is nearly coincident to the circle.
221 // in this case, to select the triangle, the analyze is made with the dual space of the Delaunay triangulation: the Voronoi diagram.
222 // https://docs.google.com/presentation/d/1Hr5jvLH8tm4KqXgmT-Di-2kFZYOT7MB246hhPKUk6Cw/edit?usp=sharing
223
224 // Boundary vertex of selected triangles
226 BoundaryVertex.Reserve(SelectedTriangleIndices.Num() + AdditionalTriangleIndices.Num() + 3);
227 for (int32 TriangleIndex : SelectedTriangleIndices)
228 {
229 for (int32 Index = 0; Index < 3; Index++)
230 {
231 const int32 StartVertex = TriangleSet[TriangleIndex].VertexIndices[Index];
232 BoundaryVertex.AddUnique(StartVertex);
233 }
234 }
235
238 {
239 FVector2d Vertex = Vertices[Index].Value;
240 double Slope = ComputeSlope(NewVertex, Vertex);
241 BoundaryVertexToSlope.Emplace(Index, Slope);
242 }
243
244 // Sort the vertex to make the boundary polygon
245 BoundaryVertexToSlope.Sort([](const TPair<int32, double>& Vertex1, const TPair<int32, double>& Vertex2) {return Vertex1.Value < Vertex2.Value; });
246
247 bool bTriangleHasBeenAdded = true;
249 {
250 bTriangleHasBeenAdded = false;
251 for (int32& TriangleIndex : AdditionalTriangleIndices)
252 {
253 if (TriangleIndex < 0)
254 {
255 continue;
256 }
257
258 FTriangle& CandidateTriangle = TriangleSet[TriangleIndex];
259
260 // if the CandidateTriangle is connected by an edge to the boundary polygon
263 for (int32 Index = 0; Index < 3; Index++)
264 {
265 int32 Candidate = CandidateTriangle.VertexIndices[Index];
267 {
269 }
270 else
271 {
273 }
274 }
275 if (ConnectedVertex != 2)
276 {
277 continue;
278 }
279
281
282#ifdef DEBUG_BOWYERWATSON_STEP_2
283 if (VIndex == StopIndex)
284 {
286 {
287 F3DDebugSession A(TEXT("New Sel triangle"));
288 DisplayTriangle(TriangleIndex, EVisuProperty::YellowCurve);
289 }
290 {
291 F3DDebugSession A(TEXT("Candidate Point"));
293 }
294 Wait();
295 }
296#endif
297
298 double NewVertexSlope = ComputeSlope(NewVertex, CandidateVertex);
299
300 int32 StartIndex = -1;
301 int32 EndIndex = 0;
303 {
305 {
306 EndIndex = ApexIndex;
307 break;
308 }
309 }
310
311 StartIndex = EndIndex == 0 ? BoundaryVertexToSlope.Num() - 1 : EndIndex - 1;
312
313 FVector2d StartPoint = Vertices[BoundaryVertexToSlope[StartIndex].Key].Value;
314 double SlopeNewStartPlusPi = ComputeSlope(NewVertex, StartPoint) + Slope::RightSlope;
316
317 FVector2d EndPoint = Vertices[BoundaryVertexToSlope[EndIndex].Key].Value;
318 double SlopeNewEndMinusPi = ComputeSlope(NewVertex, EndPoint) - Slope::RightSlope;
320
321#ifdef DEBUG_BOWYERWATSON_STEP_2
322 if (VIndex == StopIndex)
323 {
324 DisplayLocalVoronoiDiagram(CandidateVertex, NewVertex, StartPoint, EndPoint);
325 Wait();
326 }
327#endif
328
330 {
332 if (EndIndex == 0 && NewVertexSlope > BoundaryVertexToSlope.Last().Value)
333 {
335 }
336 else
337 {
339 }
341 SelectedTriangleIndices.Add(TriangleIndex);
342
343#ifdef DEBUG_BOWYERWATSON_STEP_2
344 if (VIndex == StopIndex)
345 {
347 Wait();
348 }
349#endif
350 }
351 TriangleIndex = -1;
352 }
353 }
354 }
355
356#ifdef DEBUG_BOWYERWATSON_STEP
357 if (VIndex >= StopIndex)
358 {
360 Wait();
361 }
362#endif
363
364 EdgeVertexIndices.Reset(VerticesCount);
365 FindBoundaryEdgesOfSelectedTriangles(EdgeVertexIndices);
366
367 // make the new triangles : Each new triangle is defined by an edge of the boundary and the new vertex
368#ifdef DEBUG_BOWYERWATSON_STEP
369 if (bDisplay && VIndex >= StopIndex)
370 {
371 F3DDebugSession _(TEXT("To remesh"));
372 for (int32 EdgeIndex = 0; EdgeIndex < EdgeVertexIndices.Num(); EdgeIndex += 2)
373 {
374 if (EdgeVertexIndices[EdgeIndex] < 0)
375 {
376 continue;
377 }
378 DisplaySegment(Vertices[EdgeVertexIndices[EdgeIndex]].Value * DisplayScale, Vertices[EdgeVertexIndices[EdgeIndex + 1]].Value * DisplayScale, 0, EVisuProperty::YellowCurve);
379 }
380 Wait();
381 }
382#endif
383 {
384#ifdef DEBUG_BOWYERWATSON_STEP
385 F3DDebugSession _(bDisplay && VIndex >= StopIndex, TEXT("New Triangles"));
386#endif
387
388 // The deleted triangles are replaced by the new ones
389 int32 EdgeIndex = 0;
390 for (int32 TriangleIndex : SelectedTriangleIndices)
391 {
392 while (EdgeVertexIndices[EdgeIndex] < 0)
393 {
394 EdgeIndex += 2;
395 }
396 TriangleSet[TriangleIndex].Set(EdgeVertexIndices[EdgeIndex + 1], EdgeVertexIndices[EdgeIndex], VertexIndex, Vertices);
397#ifdef DEBUG_BOWYERWATSON_STEP
398 if (bDisplay && VIndex >= StopIndex)
399 {
400 //F3DDebugSession A(TEXT("Triangle"));
401 DisplayTriangle(TriangleIndex, EVisuProperty::BlueCurve);
402 //Wait();
403 }
404#endif
405
406 EdgeIndex += 2;
407 }
408 // When all deleted triangles are replaced, the new triangles are added in the array
409 for (; EdgeIndex < EdgeVertexIndices.Num(); EdgeIndex += 2)
410 {
411 if (EdgeVertexIndices[EdgeIndex] < 0)
412 {
413 continue;
414 }
415 TriangleSet.Emplace(EdgeVertexIndices[EdgeIndex + 1], EdgeVertexIndices[EdgeIndex], VertexIndex, Vertices);
416#ifdef DEBUG_BOWYERWATSON_STEP
417 if (bDisplay && VIndex >= StopIndex)
418 {
419 //F3DDebugSession A(TEXT("Triangle"));
420 DisplayTriangle(TriangleSet.Num() - 1, EVisuProperty::BlueCurve);
421 //Wait();
422 }
423#endif
424 }
425 }
426
427#ifdef DEBUG_BOWYERWATSON_STEP
428 if (bDisplay)
429 {
432 }
433#endif
434 }
435
436#ifdef DEBUG_BOWYERWATSON
437 if (bDisplay)
438 {
439 // The final mesh
441 Wait(bDisplay);
442 }
443#endif
444
445 // Find all Edges and their type (inner edge or boundary edge)
446 EdgeVertexIndices.Reset(TriangleSet.Num() * 6);
447
448 for (int32 TriangleIndex = 0; TriangleIndex < TriangleSet.Num(); TriangleIndex++)
449 {
450 int32 Index = 0;
451 for (; Index < 3; Index++)
452 {
453 if (TriangleSet[TriangleIndex].VertexIndices[Index] >= VerticesCount)
454 {
455 // one of the point is a corner of the bounding mesh
456 // At least, only one edge is added and this edge is necessarily an outer edge
457 break;
458 }
459 }
460 bool bIsOuter = Index < 3;
461
462 int32 EndVertex = TriangleSet[TriangleIndex].VertexIndices[2];
463 for (Index = 0; Index < 3; Index++)
464 {
465 int32 StartVertex = TriangleSet[TriangleIndex].VertexIndices[Index];
466 if (StartVertex < VerticesCount && EndVertex < VerticesCount)
467 {
468 int32 Endex = 0;
469 for (; Endex < EdgeVertexIndices.Num(); Endex += 2)
470 {
471 // Does the edge exist
472 if (EdgeVertexIndices[Endex] == EndVertex && EdgeVertexIndices[Endex + 1] == StartVertex)
473 {
474 if (!bIsOuter)
475 {
476 EdgeInstanceCount[Endex / 2]++;
477 }
478 break;
479 }
480 }
481
482 if (Endex == EdgeVertexIndices.Num())
483 {
484 // No
485 EdgeVertexIndices.Add(StartVertex);
486 EdgeVertexIndices.Add(EndVertex);
487 EdgeInstanceCount.Add(bIsOuter ? 0 : 1);
488 }
489 }
490 EndVertex = StartVertex;
491 }
492 }
493#ifdef DEBUG_BOWYERWATSON
494 DisplayEdges();
495 //Wait();
496#endif
497
498 // the bounding mesh vertices are removed
499 Vertices.SetNum(VerticesCount);
500
501 for (int32& Indice : EdgeVertexIndices)
502 {
503 Indice = Vertices[Indice].Key;
504 }
505 }
506
508 {
509 int32 EdgeCount = 0;
510 for (int32 Index = 0; Index < EdgeVertexIndices.Num() / 2; ++Index)
511 {
512 if (EdgeInstanceCount[Index] < 2)
513 {
514 EdgeCount++;
515 }
516 }
517 return EdgeCount;
518 }
519
524 {
525 int32 EdgeCount = OuterEdgeCount();
526 OuterEdgeIndices.Reserve(EdgeCount);
527 for (int32 Index = 0, EdgeIndex = 0; Index < EdgeVertexIndices.Num(); ++EdgeIndex)
528 {
529 if (EdgeInstanceCount[EdgeIndex] < 2)
530 {
531 OuterEdgeIndices.Add(EdgeVertexIndices[Index++]);
532 OuterEdgeIndices.Add(EdgeVertexIndices[Index++]);
533 }
534 else
535 {
536 Index += 2;
537 }
538 }
539 }
540
542 {
543 int32 EdgeCount = OuterEdgeCount();
544 OuterVertexIndices.Reserve(EdgeCount);
545 for (int32 Index = 0, EdgeIndex = 0; Index < EdgeVertexIndices.Num(); ++EdgeIndex)
546 {
547 if (EdgeInstanceCount[EdgeIndex] < 2)
548 {
549 OuterVertexIndices.Add(EdgeVertexIndices[Index++]);
550 OuterVertexIndices.Add(EdgeVertexIndices[Index++]);
551 }
552 else
553 {
554 Index += 2;
555 }
556 }
557 }
558
560 {
561 TSet<int32> OuterVertices;
562 GetOuterVertices(OuterVertices);
563 return OuterVertices.Array();
564 }
565
566 void GetMesh(TArray<int32>& Triangles)
567 {
568 Triangles.Reset(TriangleSet.Num() * 3);
569 for (const FTriangle& Triangle : TriangleSet)
570 {
571 Triangles.Append(Triangle.VertexIndices, 3);
572 }
573 }
574
575#ifdef DEBUG_BOWYERWATSON
576 static bool bDisplay;
577#endif
578
579private:
580 int32 VerticesCount;
581
583
588 TArray<int32>& EdgeVertexIndices;
589
590 TArray<FTriangle> TriangleSet;
591
592 // It's use to mark all triangles whose circumcircles contain the next vertex
593 TArray<int32> SelectedTriangleIndices;
594 TArray<int32> AdditionalTriangleIndices;
595
600 TArray<int32> EdgeInstanceCount;
601
602 void MakeBoundingMesh()
603 {
605 for (const TPair<int32, FVector2d>& Vertex : Vertices)
606 {
607 VerticesBBox += Vertex.Value;
608 }
609
610 const double DiagonalLength = VerticesBBox.DiagonalLength();
611 VerticesBBox.Offset(DiagonalLength);
612
613 int32 VerticesId = Vertices.Num();
614 Vertices.Emplace(VerticesId++, VerticesBBox.GetCorner(3));
615 Vertices.Emplace(VerticesId++, VerticesBBox.GetCorner(2));
616 Vertices.Emplace(VerticesId++, VerticesBBox.GetCorner(0));
617 Vertices.Emplace(VerticesId++, VerticesBBox.GetCorner(1));
618
619 TriangleSet.Emplace(VerticesCount, VerticesCount + 1, VerticesCount + 2, Vertices);
620 TriangleSet.Emplace(VerticesCount + 2, VerticesCount + 3, VerticesCount, Vertices);
621 }
622
623 void Init()
624 {
625 VerticesCount = Vertices.Num();
626 Vertices.Reserve(VerticesCount + 4);
627 TriangleSet.Reserve(VerticesCount);
628 SelectedTriangleIndices.Reserve(VerticesCount);
629 AdditionalTriangleIndices.Reserve(VerticesCount);
630 EdgeVertexIndices.Reserve(4 * VerticesCount);
631 EdgeInstanceCount.Reserve(2 * VerticesCount);
632 }
633
634 // Find the boundary edges of the selected triangles:
635 // For all selected triangles,
636 // For each triangle edges
637 // if the edge is not in EdgeVertexIndices: Add the edge i.e. add its vertex indices
638 // else (the edge is in EdgeVertexIndices), remove the edge of EdgeVertexIndices
639 // As the triangles are oriented, the edge AB of a triangle is the edge BA of the adjacent triangle
640 void FindBoundaryEdgesOfSelectedTriangles(TArray<int32>& BoundaryEdgeVertexIndices)
641 {
642 BoundaryEdgeVertexIndices.Reset(SelectedTriangleIndices.Num() * 6);
643 for (int32 TriangleIndex : SelectedTriangleIndices)
644 {
645 int32 EndVertex = TriangleSet[TriangleIndex].VertexIndices[2];
646 for (int32 Index = 0; Index < 3; Index++)
647 {
648 int32 StartVertex = TriangleSet[TriangleIndex].VertexIndices[Index];
649 int32 Endex = 0;
650 // Does the edge exist
651 for (; Endex < BoundaryEdgeVertexIndices.Num(); Endex += 2)
652 {
653 if (BoundaryEdgeVertexIndices[Endex] == EndVertex && BoundaryEdgeVertexIndices[Endex + 1] == StartVertex)
654 {
657 break;
658 }
659 }
660 if (Endex == BoundaryEdgeVertexIndices.Num())
661 { // No
662 BoundaryEdgeVertexIndices.Add(StartVertex);
663 BoundaryEdgeVertexIndices.Add(EndVertex);
664 }
665 EndVertex = StartVertex;
666 }
667 }
668 }
669
670 bool DoSelectedTrianglesFormSinglePartition()
671 {
672 FindBoundaryEdgesOfSelectedTriangles(EdgeVertexIndices);
673
674 int32 StartIndex = -1;
675 int32 LastIndex = -1;
676 for (int32 EdgeIndex = 0; EdgeIndex < EdgeVertexIndices.Num(); EdgeIndex += 2)
677 {
678 if (EdgeVertexIndices[EdgeIndex] < 0)
679 {
680 continue;
681 }
682 StartIndex = EdgeVertexIndices[EdgeIndex];
683 LastIndex = EdgeVertexIndices[EdgeIndex + 1];
684 EdgeVertexIndices[EdgeIndex] = -1;
685 EdgeVertexIndices[EdgeIndex + 1] = -1;
686 break;
687 }
688
689 const int32 IndiceCount = EdgeVertexIndices.Num();
690 while (LastIndex != StartIndex)
691 {
692 int32 EdgeIndex = 0;
693 for (; EdgeIndex < IndiceCount; EdgeIndex += 2)
694 {
695 if (EdgeVertexIndices[EdgeIndex] == LastIndex)
696 {
697 LastIndex = EdgeVertexIndices[EdgeIndex + 1];
698 EdgeVertexIndices[EdgeIndex] = -1;
699 EdgeVertexIndices[EdgeIndex + 1] = -1;
700 }
701 }
702 if (EdgeIndex == IndiceCount)
703 {
704 return false;
705 }
706 }
707
708 // All edges are selected ?
709 bool bAllEdgesAreSelected = true;
710 for (int32 EdgeIndex = 0; EdgeIndex < EdgeVertexIndices.Num(); EdgeIndex += 2)
711 {
712 if (EdgeVertexIndices[EdgeIndex] > 0)
713 {
714 return false;
715 }
716 }
717
718 return true;
719 }
720
721 bool DoesTriangleContainingNewVertex(const FVector2d& NewVertex, int32 CandiadateTriangle)
722 {
723 const FVector2d& Point0 = Vertices[TriangleSet[CandiadateTriangle].VertexIndices[0]].Value;
724 const FVector2d& Point1 = Vertices[TriangleSet[CandiadateTriangle].VertexIndices[1]].Value;
725 const FVector2d& Point2 = Vertices[TriangleSet[CandiadateTriangle].VertexIndices[2]].Value;
726 double Slope0 = ComputePositiveSlope(Point0, Point1, NewVertex);
727 double Slope1 = ComputePositiveSlope(Point1, Point2, NewVertex);
728 double Slope2 = ComputePositiveSlope(Point2, Point0, NewVertex);
730 {
731 return true;
732 }
733 return false;
734 }
735
736 void AddTrianglesContainingNewVertexToSelectedTriangles(const FVector2d& NewVertex, TArray<int32>& CandiadateTriangles)
737 {
738 for (int32& TriangleIndex : CandiadateTriangles)
739 {
740 if(DoesTriangleContainingNewVertex(NewVertex, TriangleIndex))
741 {
742 SelectedTriangleIndices.Add(TriangleIndex);
743 TriangleIndex = -1;
744 }
745 }
746 }
747
748 void AddConnectedTrianglesToSelection(TArray<int32>& CandiadateTriangles)
749 {
750 EdgeVertexIndices.Reset((SelectedTriangleIndices.Num() + CandiadateTriangles.Num()) * 6);
751 FindBoundaryEdgesOfSelectedTriangles(EdgeVertexIndices);
752
753 bool bTriangleHasBeenAdded = true;
755 {
756 bTriangleHasBeenAdded = false;
757 for (int32& TriangleIndex : CandiadateTriangles)
758 {
759 if (TriangleIndex < 0)
760 {
761 continue;
762 }
763
764 int32 EndVertex = TriangleSet[TriangleIndex].VertexIndices[2];
765
766 bool bEdgeIsFound = false;
767 int32 Index = 0;
768 for (; Index < 3; Index++)
769 {
770 int32 StartVertex = TriangleSet[TriangleIndex].VertexIndices[Index];
771
772 for (int32 Endex = 0; Endex < EdgeVertexIndices.Num(); Endex += 2)
773 {
774 if (EdgeVertexIndices[Endex] == EndVertex && EdgeVertexIndices[Endex + 1] == StartVertex)
775 {
776 EdgeVertexIndices[Endex] = -1;
777 EdgeVertexIndices[Endex + 1] = -1;
778 bEdgeIsFound = true;
779 break;
780 }
781 }
782 if (bEdgeIsFound)
783 {
784 break;
785 }
786 EndVertex = StartVertex;
787 }
788
789 if (bEdgeIsFound)
790 {
791 SelectedTriangleIndices.Add(TriangleIndex);
792 EndVertex = TriangleSet[TriangleIndex].VertexIndices[2];
793 for (int32 Endex = 0; Endex < 3; Endex++)
794 {
795 int32 StartVertex = TriangleSet[TriangleIndex].VertexIndices[Endex];
796 if (Endex != Index)
797 {
798 EdgeVertexIndices.Add(StartVertex);
799 EdgeVertexIndices.Add(EndVertex);
800 }
801 EndVertex = StartVertex;
802 }
804 TriangleIndex = -1;
805 }
806 }
807 }
808 }
809
810#ifdef DEBUG_BOWYERWATSON
811 void DisplayEdges()
812 {
813 if (!bDisplay)
814 {
815 return;
816 }
817
818 F3DDebugSession _(TEXT("Edges"));
819 for (int32 Index = 0; Index < EdgeVertexIndices.Num(); Index += 2)
820 {
821 if (EdgeInstanceCount[Index / 2] < 2)
822 {
823 DisplaySegment(Vertices[EdgeVertexIndices[Index]].Value * DisplayScale, Vertices[EdgeVertexIndices[Index + 1]].Value * DisplayScale, 0, EVisuProperty::YellowCurve);
824 }
825 else
826 {
827 DisplaySegment(Vertices[EdgeVertexIndices[Index]].Value * DisplayScale, Vertices[EdgeVertexIndices[Index + 1]].Value * DisplayScale, 0, EVisuProperty::PurpleCurve);
828 }
829 }
830 };
831
832 void DisplayTriangles()
833 {
834 if (!bDisplay)
835 {
836 return;
837 }
838
839 F3DDebugSession _(TEXT("Triangles"));
840 for (int32 Index = 0; Index < TriangleSet.Num(); Index++)
841 {
842 DisplayTriangle(Index, EVisuProperty::BlueCurve);
843 }
844 //Wait();
845 };
846
848 {
849 if (!bDisplay)
850 {
851 return;
852 }
853
854 F3DDebugSession _(TEXT("Selected Triangles"));
855 for (int32 Index : SelectedTriangleIndices)
856 {
857 //F3DDebugSession _(TEXT("Triangle"));
858 DisplayTriangle(Index, EVisuProperty::BlueCurve);
859 }
860 //Wait();
861 };
862
864 {
865 if (!bDisplay)
866 {
867 return;
868 }
869
871
872 {
873 F3DDebugSession A(bDisplay, TEXT("Select Triangles Add"));
874 for (int32 TriangleIndex : AdditionalTriangleIndices)
875 {
876 if (TriangleIndex < 0)
877 {
878 continue;
879 }
880 DisplayTriangle(TriangleIndex, EVisuProperty::YellowCurve);
881 }
882 }
883 }
884
885
886 void DisplayTriangle(int32 Index, EVisuProperty Property)
887 {
888 if (!bDisplay)
889 {
890 return;
891 }
892
893 DisplaySegment(Vertices[TriangleSet[Index].VertexIndices[0]].Value * DisplayScale, Vertices[TriangleSet[Index].VertexIndices[1]].Value * DisplayScale, 0, Property);
894 DisplaySegment(Vertices[TriangleSet[Index].VertexIndices[1]].Value * DisplayScale, Vertices[TriangleSet[Index].VertexIndices[2]].Value * DisplayScale, 0, Property);
895 DisplaySegment(Vertices[TriangleSet[Index].VertexIndices[2]].Value * DisplayScale, Vertices[TriangleSet[Index].VertexIndices[0]].Value * DisplayScale, 0, Property);
896 //Wait();
897 };
898
900 {
901 F3DDebugSession A(TEXT("Selected Triangles Boundary"));
902
903 FVector2d Previous = Vertices[VertexToSlop[VertexToSlop.Num() - 1].Key].Value;
904 for (int Index = 0; Index < VertexToSlop.Num(); ++Index)
905 {
906 FVector2d VertexPoint = Vertices[VertexToSlop[Index].Key].Value;
910 }
911 }
912
913 void DisplayLocalVoronoiDiagram(const FVector2d& CandidateVertex, const FVector2d& NewVertex, const FVector2d& StartPoint, const FVector2d& EndPoint)
914 {
915 F3DDebugSession B(TEXT("Voronoi Diagram"));
916 {
917 F3DDebugSession A(TEXT("New Vertex"));
919 }
920 {
921 F3DDebugSession A(TEXT("Candidate"));
923 }
924 {
925 F3DDebugSession A(TEXT("Start"));
927
928 FVector2d Normal = NewVertex - StartPoint;
929 constexpr double HalfPi = -DOUBLE_PI / 2.;
931 FVector2d Tangent = Normal.Rotate(HalfPi) * 1000.;
932 FVector2d TangentPoint = StartPoint + Tangent;
933
936 }
937
938 {
939 F3DDebugSession A(TEXT("Start - Candidate"));
941 }
942
943 {
944 F3DDebugSession A(TEXT("End"));
946
947 FVector2d Normal = NewVertex - EndPoint;
948 constexpr double HalfPi = DOUBLE_PI / 2.;
950 FVector2d Tangent = Normal.Rotate(HalfPi) * 1000.;
951 FVector2d TangentPoint = EndPoint + Tangent;
952
955 }
956
957 {
958 F3DDebugSession A(TEXT("End - Candidate"));
960 }
961 }
962
963#endif
964
965};
966
967}
@ Normal
Definition AndroidInputInterface.h:116
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define FVector
Definition IOSSystemIncludes.h:8
@ Num
Definition MetalRHIPrivate.h:234
@ Vertex
Definition MetalRHIPrivate.h:223
#define DOUBLE_PI
Definition UnrealMathUtility.h:71
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void Reset(SizeType NewSize=0)
Definition Array.h:2246
UE_FORCEINLINE_HINT SizeType Emplace(ArgsType &&... Args)
Definition Array.h:2561
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
void Append(const TArray< OtherElementType, OtherAllocatorType > &Source)
Definition Array.h:2412
UE_FORCEINLINE_HINT void Reserve(SizeType Number)
Definition Array.h:3016
Definition Display.h:62
Definition Aabb.h:262
Definition BowyerWatsonTriangulator.h:16
int32 OuterEdgeCount() const
Definition BowyerWatsonTriangulator.h:507
TArray< int32 > GetOuterVertices() const
Definition BowyerWatsonTriangulator.h:559
void GetMesh(TArray< int32 > &Triangles)
Definition BowyerWatsonTriangulator.h:566
void GetOuterVertices(TSet< int32 > &OuterVertexIndices) const
Definition BowyerWatsonTriangulator.h:541
FBowyerWatsonTriangulator(TArray< TPair< int32, FVector2d > > &InVertices, TArray< int32 > &OutEdgeVertices)
Definition BowyerWatsonTriangulator.h:47
void GetOuterEdges(TArray< int32 > &OuterEdgeIndices) const
Definition BowyerWatsonTriangulator.h:523
void Triangulate()
Definition BowyerWatsonTriangulator.h:55
static const FTimePoint Now()
Definition Chrono.h:34
double DiagonalLength() const
Definition Aabb.h:108
const FName EdgeIndex("EdgeIndex")
Definition MeshAttributes.h:40
constexpr double PiSlope
Definition SlopeUtils.h:76
constexpr double RightSlope
Definition SlopeUtils.h:59
constexpr double ThreeRightSlope
Definition SlopeUtils.h:66
constexpr double TwoPiSlope
Definition SlopeUtils.h:81
Definition CADEntity.cpp:23
void DisplaySegment(const FVector &Point1, const FVector &Point2, FIdent Ident, EVisuProperty Property)
Definition Display.cpp:1268
void Wait(bool bMakeWait=true)
Definition Display.h:55
void DisplayPoint(const TPoint &Point, FIdent Ident)
Definition Display.h:145
double ComputeSlope(const FVector2d &StartPoint, const FVector2d &EndPoint)
Definition SlopeUtils.h:180
double ComputePositiveSlope(const FVector2d &StartPoint, const FVector2d &EndPoint, double ReferenceSlope)
Definition SlopeUtils.h:290
EVisuProperty
Definition Visu.h:15
@ YellowCurve
Definition Visu.h:29
@ PurpleCurve
Definition Visu.h:35
@ RedPoint
Definition Visu.h:32
@ BluePoint
Definition Visu.h:30
@ OrangeCurve
Definition Visu.h:41
@ GreenPoint
Definition Visu.h:36
@ OrangePoint
Definition Visu.h:40
@ YellowPoint
Definition Visu.h:28
@ BlueCurve
Definition Visu.h:31
@ GreenCurve
Definition Visu.h:37
uint64 FTimePoint
Definition Chrono.h:26
U16 Index
Definition radfft.cpp:71
Definition Tuple.h:652
Definition BowyerWatsonTriangulator.h:19
double SquareRadius
Definition BowyerWatsonTriangulator.h:21
FVector Center
Definition BowyerWatsonTriangulator.h:22
void Set(const int32 &Index0, const int32 &Index1, const int32 &Index2, const TArray< TPair< int32, FVector2d > > &InVertices)
Definition BowyerWatsonTriangulator.h:29
FTriangle(const int32 &Index0, const int32 &Index1, const int32 &Index2, const TArray< TPair< int32, FVector2d > > &InVertices)
Definition BowyerWatsonTriangulator.h:24
int32 VertexIndices[3]
Definition BowyerWatsonTriangulator.h:20
Definition Geometry.h:428
bool Normalize(T Tolerance=UE_SMALL_NUMBER)
Definition Vector2D.h:1154
static UE_FORCEINLINE_HINT double DistSquared(const TVector2< double > &V1, const TVector2< double > &V2)
Definition Vector2D.h:935