UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
LoopCleaner.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 "Core/Factory.h"
6#include "Math/SlopeUtils.h"
11
12
13
14namespace UE::CADKernel
15{
16class FGrid;
17class FIsoSegment;
18class FIsoTriangulator;
19class FLoopNode;
20class FMeshingTolerances;
21
22namespace LoopCleanerImpl
23{
24typedef TFunction<double(const FVector2d&, const FVector2d&, double)> GetSlopeMethod;
29
41
43{
44 return &Node->GetNextNode();
45}
46
48{
49 return &Node->GetPreviousNode();
50}
51
52inline const FLoopNode* GetNextConstNodeImpl(const FLoopNode* Node)
53{
54 return &Node->GetNextNode();
55}
56
58{
59 return &Node->GetPreviousNode();
60}
61
63{
64 return (const FLoopNode*)&Segment->GetFirstNode();
65};
66
68{
69 return (const FLoopNode*)&Segment->GetSecondNode();
70};
71
72inline void RemoveDeletedNodes(TArray<FLoopNode*>& NodesOfLoop)
73{
74 int32 Index = NodesOfLoop.IndexOfByPredicate([](FLoopNode* Node) { return Node->IsDelete(); });
75 if (Index == INDEX_NONE)
76 {
77 return;
78 }
79 int32 NewIndex = Index;
80 for (; Index < NodesOfLoop.Num(); ++Index)
81 {
82 if (!NodesOfLoop[Index]->IsDelete())
83 {
84 NodesOfLoop[NewIndex++] = NodesOfLoop[Index];
85 }
86 }
87 NodesOfLoop.SetNum(NewIndex);
88}
89
90}
91
92
94{
95private:
96 FGrid& Grid;
97 const FMeshingTolerances& Tolerances;
98
99 TArray<FLoopNode>& LoopNodes;
100 TArray<FIsoSegment*>& LoopSegments;
101 TFactory<FIsoSegment>& IsoSegmentFactory;
102
103 bool bDisplay;
104
105 TArray<FLoopNode*> BestStartNodeOfLoops;
106
107 // Fields for the processing loop
109 int32 LoopIndex;
110
115 TArray<FLoopNode*> NodesOfLoop;
116
121 int32 NodesOfLoopCount;
122
124 int32 StartSegmentIndex;
125 int32 SegmentCount;
126
133 int32 NextLoopFirstSegmentIndex;
134
135 bool bLoopOrientation;
136 TArray<TPair<double, double>> Intersections;
137 FIntersectionSegmentTool LoopSegmentsIntersectionTool;
138
143
144public:
145
146 FLoopCleaner(FIsoTriangulator& Triangulator);
147
148 bool Run();
149
150private:
151
152 bool CleanLoops();
153 bool UncrossLoops(bool bAddProcessedLoop);
154
159 void FindBestLoopExtremity();
160
161 //
162 // ========= CleanLoops methods ==========
163 //
164
168 bool RemoveLoopPicks();
169 bool RemoveLoopPicks(TArray<FIsoSegment*>& Loop);
170
171 bool RemovePickRecursively(FLoopNode* Node0, FLoopNode* Node1);
172 bool FindAndRemoveCoincidence(FLoopNode*& StartNode);
173
177 bool CheckAndRemovePick(const FVector2d& PreviousPoint, const FVector2d& NodeToRemovePoint, const FVector2d& NextPoint, FLoopNode& NodeToRemove)
178 {
180 bool bRemoveNode = false;
181 if (Slope < 0.1)
182 {
187 {
188 bRemoveNode = true;
189 }
190 }
191
192 if (bRemoveNode)
193 {
194 return RemoveNodeOfLoop(NodeToRemove);
195 }
196 return false;
197 };
198
202 bool CheckAndRemoveCoincidence(const FVector2d& Point0, const FVector2d& Point1, FLoopNode& NodeToRemove)
203 {
204 double SquareDistance = FVector2d::DistSquared(Point0, Point1);
205 if (SquareDistance < Tolerances.SquareGeometricTolerance2)
206 {
207 return RemoveNodeOfLoop(NodeToRemove);
208 }
209 return false;
210 };
211
215 bool RemoveNodeOfLoop(FLoopNode& NodeToRemove);
216
217 void FindLoopIntersections();
218
222 bool RemoveSelfIntersectionsOfLoop();
223
224 bool RemoveIntersection(TPair<double, double>& Intersection);
225 bool RemoveOutgoingLoop(const TPair<double, double>& Intersection, const TPair<double, double>& NextIntersection);
226 bool RemoveIntersectionsOfSubLoop(int32 IntersectionIndex, int32 IntersectionCount);
227 bool RemoveOuterNode(const TPair<double, double>& Intersection);
228 bool SwapNodes(const TPair<double, double>& Intersection);
229
233 bool RemovePickOrCoincidenceBetween(FLoopNode* StartNode, FLoopNode* StopNode);
234
246 bool TryToSwapSegmentsOrRemoveLoop(const TPair<double, double>& Intersection);
247 void SwapSubLoopOrientation(int32 FirstSegmentIndex, int32 LastSegmentIndex);
248 bool RemoveSubLoop(FLoopNode* StartNode, FLoopNode* EndNode);
249
251 void MoveNodeBehindSegment(const FIsoSegment& IntersectingSegment, FLoopNode& NodeToMove);
252 void MoveNode(FLoopNode& NodeToMove, FVector2d& NewPosition);
253
254 void FixLoopOrientation();
255 EOrientation GetLoopOrientation(const FLoopNode* StartNode);
256
257 //
258 // ========= UncrossLoops methods ==========
259 //
260
265 bool TryToRemoveIntersectionOfTwoConsecutiveIntersectingSegments(const FIsoSegment& IntersectingSegment, FIsoSegment& Segment);
266 void RemoveIntersectionByMovingOutsideSegmentNodeInside(const FIsoSegment& IntersectingSegment, const FIsoSegment& Segment, bool bIsSameInnerLoop);
267
268 //bool TryToRemoveSelfIntersectionByMovingTheClosedOusidePoint(const FIsoSegment& Segment0, const FIsoSegment& Segment1);
269 //bool TryToRemoveIntersectionByMovingTheClosedOusidePoint(const FIsoSegment& Segment0, const FIsoSegment& Segment1);
270
271 void OffsetSegment(FIsoSegment& Segment, FSegment2D& Segment2D, FSegment2D& IntersectingSegment2D);
272 void OffsetNode(FLoopNode& Node, FSegment2D& IntersectingSegment2D);
273
274
275 //
276 // ========= Commun methods ==========
277 //
278
279 void SwapSegments(FIsoSegment& Segment0, FIsoSegment& Segment1);
280
281 bool IsAPinch(const LoopCleanerImpl::FPinchIntersectionContext& Contex) const;
282
292 bool DisconnectCoincidentNodes(const LoopCleanerImpl::FPinchIntersectionContext& Contex);
293
304 bool DisconnectCrossingSegments(LoopCleanerImpl::FPinchIntersectionContext& Context);
305
312 bool MovePickBehind(const TPair<double, double>& Intersection, bool bKeyIsExtremity);
313
314
315 //
316 // ========= Other ==========
317 //
318
319 bool CheckMainLoopConsistency();
320
321 FLoopNode* GetNodeAt(int32 Index)
322 {
323 while (Index >= NodesOfLoopCount)
324 {
325 Index -= NodesOfLoopCount;
326 }
327
328 FLoopNode* Node = NodesOfLoop[Index];
329 if (Node->IsDelete())
330 {
331#ifdef GET_NODE_AT
332 Wait();
333#endif
334 return nullptr;
335 }
336
337 return Node;
338 };
339
340 int32 NextSegmentIndex(int32 StartIndex)
341 {
342 ++StartIndex;
343 return FitSegmentIndex(StartIndex);
344 };
345
346 int32 NextIndex(int32 StartIndex)
347 {
348 ++StartIndex;
349 return FitNodeIndex(StartIndex);
350 };
351
352 int32 FitNodeIndex(int32 Index)
353 {
354 while (Index >= NodesOfLoopCount)
355 {
356 Index -= NodesOfLoopCount;
357 }
358 return Index;
359 };
360
361 int32 FitSegmentIndex(int32 Index)
362 {
363 while (Index >= NextLoopFirstSegmentIndex)
364 {
365 Index -= SegmentCount;
366 }
367 return Index;
368 };
369
371
372 void GetLoopNodeStartingFrom(FLoopNode* StartNode, TArray<FLoopNode*>& Loop)
373 {
374 FLoopNode* Node = StartNode;
375 Loop.Empty(LoopNodes.Num());
376 Loop.Add(StartNode);
377 for (Node = GetNext(Node); Node != StartNode; Node = GetNext(Node))
378 {
379 Loop.Add(Node);
380 }
381 }
382
383 bool UpdateNodesOfLoop()
384 {
386 NodesOfLoopCount = NodesOfLoop.Num();
387 if (NodesOfLoopCount < 3)
388 {
389 return false;
390 }
391 return true;
392 }
393
394 /*
395 * Update NextLoopFirstSegmentIndex i.e. the Index of the first segment of the next loop (for iteration purpose)
396 */
397 void UpdateNextLoopFirstSegmentIndex(int32 NewLoopIndex)
398 {
399 NextLoopFirstSegmentIndex = LoopSegments.IndexOfByPredicate([&](FIsoSegment* Segment) {
400 return ((FLoopNode&)Segment->GetFirstNode()).GetLoopIndex() > NewLoopIndex;
401 });
402 if (NextLoopFirstSegmentIndex == INDEX_NONE)
403 {
404 NextLoopFirstSegmentIndex = LoopSegments.Num();
405 }
406 SegmentCount = NextLoopFirstSegmentIndex - StartSegmentIndex;
407 }
408
409 void RemoveSegmentOfLoops(FIsoSegment* Segment)
410 {
411 LoopSegments.RemoveSingle(Segment);
412 NextLoopFirstSegmentIndex--;
413 SegmentCount--;
414 }
415
416#ifdef CADKERNEL_DEBUG
417 void DisplayIntersection(const TPair<double, double>& Intersection)
418 {
419 if (bDisplay)
420 {
421 F3DDebugSession _(FString::Printf(TEXT("Intersection %f %f"), Intersection.Key, Intersection.Value));
422
423 FLoopNode* Segment0End = GetNodeAt(NextIndex((int32)Intersection.Key));
424 FLoopNode* Segment1Start = GetNodeAt((int32)Intersection.Value);
425
426 if (Segment0End == nullptr || Segment1Start == nullptr)
427 {
428 return;
429 }
430
431 Grid.DisplayIsoSegment(EGridSpace::UniformScaled, *Segment0End, *GetPrevious(Segment0End), 0, EVisuProperty::RedCurve);
432 Grid.DisplayIsoSegment(EGridSpace::UniformScaled, *Segment1Start, *GetNext(Segment1Start), 0, EVisuProperty::RedCurve);
433 Grid.DisplayIsoNode(EGridSpace::UniformScaled, *GetPrevious(Segment0End), 0, EVisuProperty::RedPoint);
435 }
436 };
437#endif
438
439};
440
441}
@ 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
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void SetNum(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2308
SizeType RemoveSingle(const ElementType &Item)
Definition Array.h:3060
SizeType IndexOfByPredicate(Predicate Pred) const
Definition Array.h:1423
Definition AndroidPlatformMisc.h:14
Definition Display.h:62
Definition Grid.h:46
Definition IntersectionSegmentTool.h:395
bool IsDelete() const
Definition IsoNode.h:92
Definition IsoSegment.h:52
Definition IsoTriangulator.h:79
Definition LoopCleaner.h:94
bool Run()
Definition LoopCleaner.cpp:33
Definition IsoNode.h:285
FLoopNode & GetPreviousNode() const
Definition IsoNode.h:341
FLoopNode & GetNextNode() const
Definition IsoNode.h:346
Definition ParametricMesherConstantes.h:17
const double SquareGeometricTolerance2
Definition ParametricMesherConstantes.h:22
Definition Factory.h:18
const FLoopNode * GetSecondNode(const FIsoSegment *Segment)
Definition LoopCleaner.h:67
const FLoopNode * GetFirstNode(const FIsoSegment *Segment)
Definition LoopCleaner.h:62
const FLoopNode * GetPreviousConstNodeImpl(const FLoopNode *Node)
Definition LoopCleaner.h:57
FLoopNode * GetPreviousNodeImpl(FLoopNode *Node)
Definition LoopCleaner.h:47
TFunction< double(const FVector2d &, const FVector2d &, double)> GetSlopeMethod
Definition LoopCleaner.h:24
FLoopNode * GetNextNodeImpl(FLoopNode *Node)
Definition LoopCleaner.h:42
void RemoveDeletedNodes(TArray< FLoopNode * > &NodesOfLoop)
Definition LoopCleaner.h:72
TPair< FLoopNode *, FLoopNode * > FLoopSection
Definition LoopCleaner.h:28
const FLoopNode * GetNextConstNodeImpl(const FLoopNode *Node)
Definition LoopCleaner.h:52
Definition CADEntity.cpp:23
EOrientation
Definition GeoEnum.h:82
void Wait(bool bMakeWait=true)
Definition Display.h:55
@ UniformScaled
Definition MeshEnum.h:20
double ComputeUnorientedSlope(const FVector2d &StartPoint, const FVector2d &EndPoint, double ReferenceSlope)
Definition SlopeUtils.h:337
@ RedPoint
Definition Visu.h:32
@ RedCurve
Definition Visu.h:33
U16 Index
Definition radfft.cpp:71
Definition Tuple.h:652
FLoopNode * Nodes[2][3]
Definition LoopCleaner.h:33
FPinchIntersectionContext(const TPair< double, double > &InIntersection)
Definition LoopCleaner.h:36
TArray< const FVector2d * > Points[2]
Definition LoopCleaner.h:34
const TPair< double, double > & Intersection
Definition LoopCleaner.h:32
Definition Geometry.h:250
static UE_FORCEINLINE_HINT double DistSquared(const TVector2< double > &V1, const TVector2< double > &V2)
Definition Vector2D.h:935