UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
SamplerAbstract.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 "Geo/GeoEnum.h"
7#include "Geo/Curves/Curve.h"
8#include "Math/Boundary.h"
9#include "Math/Geometry.h"
10#include "Math/Point.h"
11
12//#define DEBUG_CURVE_SAMPLING
13//#define CHECK_RESULT_MAKE_ISO_POLYLINE
14
15namespace UE::CADKernel
16{
17
18template<typename PolylineType, typename PointType>
20{
21public:
22
24 {
28
33
35 {
37 Index = InIndex;
38 }
39
40 constexpr bool IsCandidatePoint()
41 {
42 return Sampling != Polyline;
43 }
44
45 constexpr bool IsSamplingPoint()
46 {
47 return Sampling == Polyline;
48 }
49 };
50
60
61 virtual ~TCurveSamplerAbstract() = default;
62
66 virtual void Sample()
67 {
70 }
71
72protected:
73
75 virtual void EvaluatesNewCandidatePoints() = 0;
76
81 virtual int32 CheckSamplingError(int32 FirstIndex, int32 EndIndex) = 0;
82
89
93 virtual void SamplingInitalizing()
94 {
96 Sampling.Empty(100);
97
98 CandidatePoints.Empty(100);
99
100 // Initialization of the algorithm with the not derivable coordinates of the curve and at least 5 temporary points
102 {
103 TArray<double> NotDerivableCoordinates;
104 GetNotDerivableCoordinates(NotDerivableCoordinates);
105
106 NotDerivableCoordinates.Insert(Boundary.Min, 0);
107 NotDerivableCoordinates.Add(Boundary.Max);
108
109 ComplementaryPointOffset = NotDerivableCoordinates.Num() < 10 ? 10 : 1;
110
111 NextCoordinates.Empty(NotDerivableCoordinates.Num() * (ComplementaryPointOffset + 1));
113
114 for (int32 Index = 0; Index < NotDerivableCoordinates.Num() - 1; ++Index)
115 {
116 if (AddIntermediateCoordinates(NotDerivableCoordinates[Index], NotDerivableCoordinates[Index + 1], ComplementaryPointOffset))
117 {
118 NextCoordinates.Add(NotDerivableCoordinates[Index + 1]);
119 }
120 }
121 }
122
123 // #cadkernel_check: Could we do a MoveTem?
124 CandidatePoints.SwapCoordinates(NextCoordinates);
126
127 // Not Derivable points and boundaries initialize the sampling
130 {
132 IsOptimalSegments.Add(false);
133 }
134 // Remove last entered entry to IsOptimalSegments as this is to track segments
136
137 CandidatePoints.RemoveComplementaryPoints(ComplementaryPointOffset);
138 }
139
144 {
145 if (IsOptimalSegments.Num() == 0)
146 {
147 // #cadkernel_check: What does this mean that IsOptimalSegments is empty.
148 // Why only one CandidatePoints?
149 return;
150 }
151
152 // < 100000 : check to avoid that the process loops endlessly
154 while (CandidatePointsCount && Sampling.Coordinates.Num() < 100000)
155 {
157
160
161 // indices of TmpPoints and TmpCoordinates
164
165 int32 SegmentIndex = 0;
166
167 do
168 {
170 {
172 continue;
173 }
174
176
177 do
178 {
180 {
182 }
183 else
184 {
186 }
187
188 // if the next candidate point is biggest than the next sampling point, no chord check can be done.
189 // an intermediate point is added.
190 // the next segment is processed
192 {
195 break;
196 }
197
200 {
202 {
204 }
205 else
206 {
208 continue;
209 }
210 }
211 else
212 {
214 }
215
216 // An existing point is reached
218 {
222 }
223 else
224 {
228 }
229
231
232 } while (StartSamplingSegmentIndex < IsOptimalSegments.Num() && EndStudySegment.Index < Sampling.Coordinates.Num() - 1);
233
234 CandidatePoints.SwapCoordinates(NextCoordinates);
236
238
239#ifdef DEBUG_CURVE_SAMPLING
240 DisplaySampling(CurveIndex == CurveToDisplay, 0);
241#endif
242 }
243
244#ifdef CHECK_RESULT_MAKE_ISO_POLYLINE
245 CheckResult();
246#endif
247
248 }
249
252 {
254 {
255 return false;
256 }
257 double DeltaCoord = (UMax - UMin) / (PointNum + 1);
258 double UCoord = UMin;
259 for (int32 Index = 0; Index < PointNum; Index++)
260 {
263 }
264
265 return true;
266 };
267
314
315 int32 GetFirstNeighbor(int32 NeighborIndex, const double StartCoordinate, const PolylineType& Points, const int32 Increment, double& NeighborCoordinate)
316 {
317 NeighborCoordinate = Points.Coordinates[NeighborIndex];
318 if (FMath::IsNearlyEqual(NeighborCoordinate, StartCoordinate) && Points.Coordinates.IsValidIndex(NeighborIndex + Increment))
319 {
320 NeighborIndex += Increment;
321 NeighborCoordinate = Points.Coordinates[NeighborIndex];;
322 }
323 return NeighborIndex;
324 };
325
326 int32 CountOfNeededPointsToRespectChordError(const PointType& PointA, const PointType& PointB, double ChordError)
327 {
328 double ABLength = PointType::Distance(PointA, PointB) / 2;
329 // Max segment length to respect the chord error
331 return (int32)(2 + (ABLength / LengthToHave + 0.5));
332 };
333
334 int32 CheckTangentError(const PointType& APoint, double ACoordinate, const PointType& BPoint, double BCoordinate, int32 FirstIndex, int32 EndIndex, int32 InStartSamplingSegmentIndex)
335 {
336 PointType Middle = CandidatePoints.GetPoints()[FirstIndex];
337
339
340 if (FirstIndex > 0 && InStartSamplingSegmentIndex > 0)
341 {
342 // get the first previous point in Sampling or CandidatePoints
345
348
350
352 if (ChordA > 4 * DesiredChordError)
353 {
355 }
356 }
357
358 Middle = CandidatePoints.GetPoints()[EndIndex - 1];
359 if (EndIndex + 1 < CandidatePoints.Coordinates.Num())
360 {
363
366
368
370 if (ChordB > 4 * DesiredChordError)
371 {
373 }
374 }
375
376 return CountOfNeededPoints;
377 };
378
379protected:
380
382
383 // Final sampling of the curve. This polyline will be completed at each iteration
385
387
390
393
398
403
410
413
415
416#ifdef DEBUG_CURVE_SAMPLING
417public:
418 int32 CurveIndex = 0;
420
421 void DisplaySampling(bool bDisplay, int32 Step)
422 {
423 if (bDisplay)
424 {
425 {
426 int32 Index = 0;
427 F3DDebugSession G(FString::Printf(TEXT("Curve %d"), Step));
428 for (const FVector& Point : Sampling.GetPoints())
429 {
431 }
432
433 for (int32 Index = 0; Index < Sampling.GetPoints().Num() - 1; ++Index)
434 {
436 {
437 DisplaySegment(Sampling.GetPoints()[Index], Sampling.GetPoints()[Index + 1], Index, EVisuProperty::BlueCurve);
438 }
439 else
440 {
442 }
443 }
444 }
445 {
446 int32 Index = 0;
447 F3DDebugSession G(FString::Printf(TEXT("Next Point Tmp %d"), Step));
448 for (const FVector& Point : CandidatePoints.GetPoints())
449 {
451 }
452 }
453 Wait();
454 }
455 }
456#endif
457
458#ifdef CHECK_RESULT_MAKE_ISO_POLYLINE
459 void CheckResult()
460 {
461 // Check the result
462 NextCoordinates.Empty(Sampling.Coordinates.Num());
463
464 for (int32 Index = 0; Index < Sampling.Coordinates.Num() - 1; ++Index)
465 {
466 AddIntermediateCoordinates(Sampling.Coordinates[Index], Sampling.Coordinates[Index + 1], 1);
467 }
468 CandidatePoints.SwapCoordinates(NextCoordinates);
470
471 double MinError[2] = { HUGE_VALUE, HUGE_VALUE };
472 double MaxError[2] = { 0., 0. };
473 double ErrorSum[2] = { 0., 0. };
474 double SquareErrorSum[2] = { 0., 0. };
475
476 int32 EvaluationCount = CandidatePoints.Coordinates.Num();
477
478 for (int32 Index = 0; Index < EvaluationCount; ++Index)
479 {
480 double CurvilinearAbscise;
482 double ChordError = ProjectedPoint.Distance(CandidatePoints.GetPoints()[Index]);
483
484 MinError[0] = FMath::Min(MinError[0], ChordError);
485 MaxError[0] = FMath::Max(MaxError[0], ChordError);
486 ErrorSum[0] += ChordError;
488
489 double ABCoordinate = Sampling.Coordinates[Index + 1] - Sampling.Coordinates[Index];
490 double AMCoordinate = CandidatePoints.Coordinates[Index] - Sampling.Coordinates[Index];
491 PointType MApproximate = Sampling.GetPoints()[Index] + (AMCoordinate / ABCoordinate) * (Sampling.GetPoints()[Index + 1] - Sampling.GetPoints()[Index]);
493
494 MinError[1] = FMath::Min(MinError[1], ParametrizationError);
495 MaxError[1] = FMath::Max(MaxError[1], ParametrizationError);
498 }
499 double ChordMed = ErrorSum[0] / EvaluationCount;
501
502 double ParamMed = ErrorSum[1] / EvaluationCount;
504
505 FMessage::Printf(EVerboseLevel::Log, TEXT("Chord Desired Med Sd Min Max %f %f %f %f %f"), MaxError, ChordMed, ChordStandartDeviation, MinError[0], MaxError[0]);
506 FMessage::Printf(EVerboseLevel::Log, TEXT("Param Desired Med Sd Min Max %f %f %f %f %f"), MaxError, ParamMed, ParamStandartDeviation, MinError[1], MaxError[1]);
507 }
508#endif
509};
510
511} // ns UE::CADKernel
#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 HUGE_VALUE
Definition Types.h:16
@ Num
Definition MetalRHIPrivate.h:234
#define UE_DOUBLE_SMALL_NUMBER
Definition UnrealMathUtility.h:139
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
ElementType Pop(EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:1196
UE_FORCEINLINE_HINT void EmplaceAt(SizeType Index, ArgsType &&... Args)
Definition Array.h:2665
SizeType Insert(std::initializer_list< ElementType > InitList, const SizeType InIndex)
Definition Array.h:1875
void Empty(SizeType Slack=0)
Definition Array.h:2273
Definition Display.h:62
static void Printf(EVerboseLevel Level, const FmtType &Text, Types... Args)
Definition Message.h:29
Definition SamplerAbstract.h:20
void CompletesPolyline(int32 NeededPointNumber, int32 IntermediateIndex)
Definition SamplerAbstract.h:276
const TArray< double > & TmpPolylineCoordinates
Definition SamplerAbstract.h:388
TSamplingPoint EndStudySegment
Definition SamplerAbstract.h:409
virtual void EvaluatesNewCandidatePoints()=0
virtual ~TCurveSamplerAbstract()=default
void RunSampling()
Definition SamplerAbstract.h:143
virtual void GetNotDerivableCoordinates(TArray< double > &OutNotDerivableCoordinates)
Definition SamplerAbstract.h:86
double DesiredChordError
Definition SamplerAbstract.h:414
virtual void Sample()
Definition SamplerAbstract.h:66
virtual int32 CheckSamplingError(int32 FirstIndex, int32 EndIndex)=0
int32 GetFirstNeighbor(int32 NeighborIndex, const double StartCoordinate, const PolylineType &Points, const int32 Increment, double &NeighborCoordinate)
Definition SamplerAbstract.h:315
PolylineType & Sampling
Definition SamplerAbstract.h:384
TArray< char > IsOptimalSegments
Definition SamplerAbstract.h:392
virtual void SamplingInitalizing()
Definition SamplerAbstract.h:93
TArray< double > NextCoordinates
Definition SamplerAbstract.h:412
FLinearBoundary Boundary
Definition SamplerAbstract.h:381
int32 EndSamplingSegmentIndex
Definition SamplerAbstract.h:402
bool AddIntermediateCoordinates(double UMin, double UMax, int32 PointNum)
Definition SamplerAbstract.h:251
const TArray< double > & SamplingCoordinates
Definition SamplerAbstract.h:389
int32 CheckTangentError(const PointType &APoint, double ACoordinate, const PointType &BPoint, double BCoordinate, int32 FirstIndex, int32 EndIndex, int32 InStartSamplingSegmentIndex)
Definition SamplerAbstract.h:334
int32 CountOfNeededPointsToRespectChordError(const PointType &PointA, const PointType &PointB, double ChordError)
Definition SamplerAbstract.h:326
PolylineType CandidatePoints
Definition SamplerAbstract.h:386
TCurveSamplerAbstract(const FLinearBoundary &InBoundary, PolylineType &OutPolyline, double InDesiredChordError)
Definition SamplerAbstract.h:51
int32 StartSamplingSegmentIndex
Definition SamplerAbstract.h:397
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
@ YellowCurve
Definition Visu.h:29
@ BluePoint
Definition Visu.h:30
@ YellowPoint
Definition Visu.h:28
@ BlueCurve
Definition Visu.h:31
@ Point
Definition Visu.h:17
@ Log
Definition Types.h:107
U16 Index
Definition radfft.cpp:71
static UE_FORCEINLINE_HINT bool IsNearlyEqual(float A, float B, float ErrorTolerance=UE_SMALL_NUMBER)
Definition UnrealMathUtility.h:388
static constexpr UE_FORCEINLINE_HINT T Square(const T A)
Definition UnrealMathUtility.h:578
Definition Boundary.h:18
double Max
Definition Boundary.h:24
double Min
Definition Boundary.h:23
constexpr bool IsSamplingPoint()
Definition SamplerAbstract.h:45
constexpr bool IsCandidatePoint()
Definition SamplerAbstract.h:40
TSamplingPoint(const PolylineType &InSampling)
Definition SamplerAbstract.h:29
int32 Index
Definition SamplerAbstract.h:27
const PolylineType * Polyline
Definition SamplerAbstract.h:26
void Set(const PolylineType &InPolyline, int32 InIndex)
Definition SamplerAbstract.h:34
const PolylineType * Sampling
Definition SamplerAbstract.h:25