UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
Polyline.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "VectorTypes.h"
6#include "SegmentTypes.h"
7#include "LineTypes.h"
8#include "BoxTypes.h"
9
10namespace UE
11{
12namespace Geometry
13{
14
15using namespace UE::Math;
16
17
18/*
19 * TPolylinePolicy represents a collection of needed support classes for TPolyline depending on the required dimension
20 */
21
22template<typename T, int DIM>
24{};
25
26template<typename T>
27class TPolylinePolicy<T, 3>
28{
29public:
33};
34
35template<typename T>
36class TPolylinePolicy<T, 2>
37{
38public:
42};
43
47template<typename T, int D>
49{
50protected:
54
57
58public:
59
60
62 {
63 }
64
71
75 TPolyline(const VectorType& Point0, const VectorType& Point1)
76 {
77 Vertices.Add(Point0);
78 Vertices.Add(Point1);
79 }
80
84 const VectorType& operator[](int Index) const
85 {
86 return Vertices[Index];
87 }
88
93 {
94 return Vertices[Index];
95 }
96
97
101 const VectorType& Start() const
102 {
103 return Vertices[0];
104 }
105
109 const VectorType& End() const
110 {
111 return Vertices[Vertices.Num()-1];
112 }
113
114
119 {
120 return Vertices;
121 }
122
126 int VertexCount() const
127 {
128 return Vertices.Num();
129 }
130
134 int SegmentCount() const
135 {
136 return Vertices.Num()-1;
137 }
138
139
141 void Clear()
142 {
143 Vertices.Reset();
144 }
145
150 {
152 }
153
157 void AppendVertices(const TArray<VectorType>& NewVertices)
158 {
159 Vertices.Append(NewVertices);
160 }
161
165 template<typename OtherVectorType>
167 {
168 int32 NumV = NewVertices.Num();
170 for (int32 k = 0; k < NumV; ++k)
171 {
172 Vertices.Append( (VectorType)NewVertices[k] );
173 }
174 }
175
179 void Set(int VertexIndex, const VectorType& Position)
180 {
181 Vertices[VertexIndex] = Position;
182 }
183
187 void RemoveVertex(int VertexIndex)
188 {
189 Vertices.RemoveAt(VertexIndex);
190 }
191
195 void SetVertices(const TArray<VectorType>& NewVertices)
196 {
197 int NumVerts = NewVertices.Num();
199 for (int k = 0; k < NumVerts; ++k)
200 {
201 Vertices[k] = NewVertices[k];
202 }
203 }
204
205
209 void Reverse()
210 {
211 int32 j = Vertices.Num() - 1;
212 for (int32 VertexIndex = 0; VertexIndex < j; VertexIndex++, j--)
213 {
214 Swap(Vertices[VertexIndex], Vertices[j]);
215 }
216 }
217
218
223 VectorType GetTangent(int VertexIndex) const
224 {
225 if (VertexIndex == 0)
226 {
227 return (Vertices[1] - Vertices[0]).Normalized();
228 }
229 int NumVerts = Vertices.Num();
230 if (VertexIndex == NumVerts - 1)
231 {
232 return (Vertices[NumVerts-1] - Vertices[NumVerts-2]).Normalized();
233 }
234 return (Vertices[VertexIndex+1] - Vertices[VertexIndex-1]).Normalized();
235 }
236
237
238
242 SegmentType GetSegment(int SegmentIndex) const
243 {
244 return SegmentType(Vertices[SegmentIndex], Vertices[SegmentIndex+1]);
245 }
246
247
253 VectorType GetSegmentPoint(int SegmentIndex, T SegmentParam) const
254 {
255 SegmentType seg(Vertices[SegmentIndex], Vertices[SegmentIndex + 1]);
256 return seg.PointAt(SegmentParam);
257 }
258
259
265 VectorType GetSegmentPointUnitParam(int SegmentIndex, T SegmentParam) const
266 {
267 SegmentType seg(Vertices[SegmentIndex], Vertices[SegmentIndex + 1]);
268 return seg.PointBetween(SegmentParam);
269 }
270
271
272
277 {
278 BoxType box = BoxType::Empty();
279 int NumVertices = Vertices.Num();
280 for (int k = 0; k < NumVertices; ++k)
281 {
282 box.Contain(Vertices[k]);
283 }
284 return box;
285 }
286
287
288
292 T Length() const
293 {
294 T length = 0;
295 int N = SegmentCount();
296 for (int i = 0; i < N; ++i)
297 {
298 length += Distance(Vertices[i], Vertices[i+1]);
299 }
300 return length;
301 }
302
303
304
309 {
310 public:
311 inline bool operator!()
312 {
313 return i < Polyline->SegmentCount();
314 }
315 inline SegmentType operator*() const
316 {
318 return SegmentType(Polyline->Vertices[i], Polyline->Vertices[i+1]);
319 }
320 inline SegmentIterator & operator++() // prefix
321 {
322 i++;
323 return *this;
324 }
325 inline SegmentIterator operator++(int) // postfix
326 {
327 SegmentIterator copy(*this);
328 i++;
329 return copy;
330 }
331 inline bool operator==(const SegmentIterator & i3) { return i3.Polyline == Polyline && i3.i == i; }
332 inline bool operator!=(const SegmentIterator & i3) { return i3.Polyline != Polyline || i3.i != i; }
333 protected:
335 int i;
336 inline SegmentIterator(const TPolyline<T, D>* p, int iCur) : Polyline(p), i(iCur) {}
337 friend class TPolyline;
338 };
339 friend class SegmentIterator;
340
342 {
343 return SegmentIterator(this, 0);
344 }
345
350 {
351 public:
355 SegmentIterator begin() { return Polyline->SegmentItr(); }
356 SegmentIterator end() { return SegmentIterator(Polyline, Polyline->SegmentCount()); }
357 };
358
363 {
364 return SegmentEnumerable(this);
365 }
366
367
368
369
370
371
380 {
383 T dist = TNumericLimits<T>::Max();
384 int N = SegmentCount();
385 for (int vi = 0; vi < N; ++vi)
386 {
387 // @todo can't we just use segment function here now?
389 T t = (QueryPoint - seg.Center).Dot(seg.Direction);
391 if (t >= seg.Extent)
392 {
393 d = UE::Geometry::DistanceSquared(seg.EndPoint(), QueryPoint);
394 }
395 else if (t <= -seg.Extent)
396 {
397 d = UE::Geometry::DistanceSquared(seg.StartPoint(), QueryPoint);
398 }
399 else
400 {
401 d = UE::Geometry::DistanceSquared(seg.PointAt(t), QueryPoint);
402 }
403 if (d < dist)
404 {
405 dist = d;
407 NearestSegParamOut = TMathUtil<T>::Clamp(t, -seg.Extent, seg.Extent);
408 }
409 }
410 return dist;
411 }
412
413
414
421 {
422 int seg; T segt;
423 return DistanceSquared(QueryPoint, seg, segt);
424 }
425
426
427
428
433 {
434 T avg = 0; int N = Vertices.Num();
435 for (int i = 1; i < N; ++i) {
436 avg += Distance(Vertices[i], Vertices[i - 1]);
437 }
438 return avg / (T)(N-1);
439 }
440
445 {
446 if (InDistance <= 0)
447 {
448 return Vertices[0];
449 }
450
452 const int N = Vertices.Num();
453 for (int i = 1; i < N; ++i)
454 {
455 const T SegmentLength = Distance(Vertices[i], Vertices[i - 1]);
456 if (SegmentLength > 0 && SegmentLength > RemainingDistance)
457 {
458 return Lerp(Vertices[i - 1], Vertices[i], RemainingDistance / SegmentLength);
459 }
460 RemainingDistance -= SegmentLength;
461 }
462
463 return Vertices.Last();
464 }
465
470 {
471 if (InDistance <= 0)
472 {
473 return Vertices.Last();
474 }
475
477 const int N = Vertices.Num();
478 for (int i = N-1; i > 0; --i)
479 {
480 const T SegmentLength = Distance(Vertices[i], Vertices[i - 1]);
481 if (SegmentLength > 0 && SegmentLength > RemainingDistance)
482 {
483 return Lerp(Vertices[i], Vertices[i-1], RemainingDistance / SegmentLength);
484 }
485 RemainingDistance -= SegmentLength;
486 }
487
488 return Vertices[0];
489 }
490
495 {
496 const T Alpha = (T)1 / (T)3;
497 const T OneMinusAlpha = (T)2 / (T)3;
498
499 int N = Vertices.Num() - 1;
500 NewPolyline.Vertices.SetNum(2*N);
501 NewPolyline.Vertices[0] = Vertices[0];
502 int k = 1;
503 for (int i = 1; i < N; ++i)
504 {
505 const VectorType& Prev = Vertices[i-1];
506 const VectorType& Cur = Vertices[i];
507 const VectorType& Next = Vertices[i+1];
508 NewPolyline.Vertices[k++] = Alpha * Prev + OneMinusAlpha * Cur;
509 NewPolyline.Vertices[k++] = OneMinusAlpha * Cur + Alpha * Next;
510 }
511 NewPolyline.Vertices[k] = Vertices[N];
512 }
513
520 {
521 const int32 VertexCount = Vertices.Num();
522 if (VertexCount < 3)
523 {
524 // we need at least 3 vertices to be able to simplify a line
525 return;
526 }
527
528 TArray<VectorType> NewVertices;
529 NewVertices.Reserve(VertexCount);
530
531 // STAGE 1. Vertex Reduction within tolerance of prior vertex cluster
532 if (ClusterTolerance > 0)
533 {
535 NewVertices.Add(Vertices[0]); // keep the first vertex
536 for (int32 Index = 1; Index < VertexCount-1; Index++)
537 {
539 {
540 continue;
541 }
542 NewVertices.Add(Vertices[Index]);
543 }
544 NewVertices.Add(Vertices.Last()); // keep the last vertex
545 }
546 else
547 {
548 NewVertices = Vertices;
549 }
550
551 // STAGE 2. Douglas-Peucker polyline simplification
552 TArray<bool> Marked;
553 if (LineDeviationTolerance > 0 && NewVertices.Num() >= 3)
554 {
555 Marked.SetNumZeroed(NewVertices.Num());
556
557 // mark the first and last vertices to make sure we keep them
558 Marked[0] = true;
559 Marked.Last() = true;
560 SimplifyDouglasPeucker(LineDeviationTolerance, NewVertices, 0, NewVertices.Num()-1, Marked);
561 }
562
563 // STAGE 3. Copy back values in Vertices
564 if (Marked.IsEmpty())
565 {
566 // we have not run Douglas-Pecker so we can just copy the list
567 Vertices = MoveTemp(NewVertices);
568 }
569 else
570 {
571 // only keep the marked ones
572 Vertices.Reset();
573 const int32 MarkedCount = Marked.Num();
574 for (int32 Index=0; Index<MarkedCount; ++Index)
575 {
576 if (Marked[Index])
577 {
578 Vertices.Add(NewVertices[Index]);
579 }
580 }
581 }
582 }
583
584private:
585 // Polygon simplification
586 // code adapted from: http://softsurfer.com/Archive/algorithm_0205/algorithm_0205.htm
587 // simplifyDP():
588 // This is the Douglas-Peucker recursive simplification routine
589 // It just marks Vertices that are part of the simplified polyline
590 // for approximating the polyline subchain v[j] to v[k].
591 // Input: tol = approximation tolerance
592 // v[] = polyline array of vertex points
593 // j,k = indices for the subchain v[j] to v[k]
594 // Output: mk[] = array of markers matching vertex array v[]
595 static void SimplifyDouglasPeucker(T Tolerance, const TArray<VectorType>& Vertices, int32 j, int32 k, TArray<bool>& Marked)
596 {
597 Marked.SetNum(Vertices.Num());
598 if (k <= j + 1) // there is nothing to simplify
599 return;
600
601 // check for adequate approximation by segment S from v[j] to v[k]
602 int maxi = j; // index of vertex farthest from S
603 T maxd2 = 0; // distance squared of farthest vertex
604 T tol2 = Tolerance * Tolerance; // tolerance squared
605 SegmentType S = SegmentType(Vertices[j], Vertices[k]); // segment from v[j] to v[k]
606
607 // test each vertex v[i] for max distance from S
608 // Note: this works in any dimension (2D, 3D, ...)
609 for (int i = j + 1; i < k; i++)
610 {
611 T dv2 = S.DistanceSquared(Vertices[i]);
612 if (dv2 <= maxd2)
613 continue;
614 // v[i] is a max vertex
615 maxi = i;
616 maxd2 = dv2;
617 }
618 if (maxd2 > tol2) // error is worse than the tolerance
619 {
620 // split the polyline at the farthest vertex from S
621 Marked[maxi] = true; // mark v[maxi] for the simplified polyline
622 // recursively simplify the two subpolylines at v[maxi]
623 SimplifyDouglasPeucker(Tolerance, Vertices, j, maxi, Marked); // polyline v[j] to v[maxi]
624 SimplifyDouglasPeucker(Tolerance, Vertices, maxi, k, Marked); // polyline v[maxi] to v[k]
625 }
626 // else the approximation is OK, so ignore intermediate Vertices
627 return;
628 }
629};
630
631} // end namespace UE::Geometry
632} // end namespace UE
#define check(expr)
Definition AssertionMacros.h:314
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
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
UE_NODEBUG UE_FORCEINLINE_HINT ElementType & Last(SizeType IndexFromTheEnd=0) UE_LIFETIMEBOUND
Definition Array.h:1263
void RemoveAt(SizeType Index, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2083
void Reset(SizeType NewSize=0)
Definition Array.h:2246
void SetNum(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2308
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
static RealType Clamp(const RealType Value, const RealType ClampMin, const RealType ClampMax)
Definition MathUtil.h:222
TSegment2< T > SegmentType
Definition Polyline.h:40
TAxisAlignedBox2< T > BoxType
Definition Polyline.h:41
TVector2< T > VectorType
Definition Polyline.h:39
TSegment3< T > SegmentType
Definition Polyline.h:31
TAxisAlignedBox3< T > BoxType
Definition Polyline.h:32
TVector< T > VectorType
Definition Polyline.h:30
Definition Polyline.h:24
SegmentEnumerable()
Definition Polyline.h:353
SegmentEnumerable(const TPolyline< T, D > *p)
Definition Polyline.h:354
const TPolyline< T, D > * Polyline
Definition Polyline.h:352
SegmentIterator end()
Definition Polyline.h:356
SegmentIterator begin()
Definition Polyline.h:355
bool operator!()
Definition Polyline.h:311
int i
Definition Polyline.h:335
SegmentIterator operator++(int)
Definition Polyline.h:325
bool operator==(const SegmentIterator &i3)
Definition Polyline.h:331
bool operator!=(const SegmentIterator &i3)
Definition Polyline.h:332
SegmentType operator*() const
Definition Polyline.h:315
SegmentIterator(const TPolyline< T, D > *p, int iCur)
Definition Polyline.h:336
SegmentIterator & operator++()
Definition Polyline.h:320
const TPolyline< T, D > * Polyline
Definition Polyline.h:334
Definition Polyline.h:49
const VectorType & operator[](int Index) const
Definition Polyline.h:84
BoxType GetBounds() const
Definition Polyline.h:276
int SegmentCount() const
Definition Polyline.h:134
TPolyline(const TArray< VectorType > &VertexList)
Definition Polyline.h:68
VectorType GetPointFromLastVertex(const T InDistance) const
Definition Polyline.h:469
T DistanceSquared(const VectorType &QueryPoint, int &NearestSegIndexOut, T &NearestSegParamOut) const
Definition Polyline.h:379
TPolyline()
Definition Polyline.h:61
T Length() const
Definition Polyline.h:292
void Clear()
Definition Polyline.h:141
VectorType GetTangent(int VertexIndex) const
Definition Polyline.h:223
const TArray< VectorType > & GetVertices() const
Definition Polyline.h:118
SegmentType GetSegment(int SegmentIndex) const
Definition Polyline.h:242
const VectorType & End() const
Definition Polyline.h:109
void Simplify(T ClusterTolerance, T LineDeviationTolerance)
Definition Polyline.h:519
VectorType GetPointFromFirstVertex(const T InDistance) const
Definition Polyline.h:444
SegmentEnumerable Segments() const
Definition Polyline.h:362
TArray< VectorType > Vertices
Definition Polyline.h:56
void SetVertices(const TArray< VectorType > &NewVertices)
Definition Polyline.h:195
void RemoveVertex(int VertexIndex)
Definition Polyline.h:187
VectorType & operator[](int Index)
Definition Polyline.h:92
void SmoothSubdivide(TPolyline< T, D > &NewPolyline) const
Definition Polyline.h:494
TPolylinePolicy< T, D >::BoxType BoxType
Definition Polyline.h:53
void AppendVertices(const TArray< VectorType > &NewVertices)
Definition Polyline.h:157
SegmentIterator SegmentItr() const
Definition Polyline.h:341
T AverageEdgeLength() const
Definition Polyline.h:432
VectorType GetSegmentPointUnitParam(int SegmentIndex, T SegmentParam) const
Definition Polyline.h:265
int VertexCount() const
Definition Polyline.h:126
VectorType GetSegmentPoint(int SegmentIndex, T SegmentParam) const
Definition Polyline.h:253
void AppendVertices(const TArray< OtherVectorType > &NewVertices)
Definition Polyline.h:166
void Set(int VertexIndex, const VectorType &Position)
Definition Polyline.h:179
void AppendVertex(const VectorType &Position)
Definition Polyline.h:149
TPolylinePolicy< T, D >::SegmentType SegmentType
Definition Polyline.h:52
TPolylinePolicy< T, D >::VectorType VectorType
Definition Polyline.h:51
void Reverse()
Definition Polyline.h:209
T DistanceSquared(const VectorType &QueryPoint) const
Definition Polyline.h:420
const VectorType & Start() const
Definition Polyline.h:101
TPolyline(const VectorType &Point0, const VectorType &Point1)
Definition Polyline.h:75
T DistanceSquared(const UE::Math::TVector2< T > &V1, const UE::Math::TVector2< T > &V2)
Definition VectorTypes.h:82
Definition Sphere.cpp:10
Definition AdvancedWidgetsModule.cpp:13
U16 Index
Definition radfft.cpp:71
Definition NumericLimits.h:41
Definition BoxTypes.h:637
Definition BoxTypes.h:247
Definition SegmentTypes.h:23
Definition SegmentTypes.h:447
Definition Vector2D.h:38
Definition Vector.h:51