UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
TriangleTypes.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 "VectorUtil.h"
7#include "IndexTypes.h"
8#include "BoxTypes.h"
9#include "SegmentTypes.h"
10
11namespace UE
12{
13namespace Geometry
14{
15
16using namespace UE::Math;
17
21namespace TriangleUtil
22{
26 template<typename RealType>
28 {
30 }
31
32};
33
34
35
36
37template<typename RealType>
39{
41
43
45 {
46 V[0] = V0;
47 V[1] = V1;
48 V[2] = V2;
49 }
50
52 {
53 V[0] = VIn[0];
54 V[1] = VIn[1];
55 V[2] = VIn[2];
56 }
57
58 TVector2<RealType> BarycentricPoint(RealType Bary0, RealType Bary1, RealType Bary2) const
59 {
60 return Bary0 * V[0] + Bary1 * V[1] + Bary2 * V[2];
61 }
62
64 {
65 return BaryCoords[0] * V[0] + BaryCoords[1] * V[1] + BaryCoords[2] * V[2];
66 }
67
72
79 static RealType SignedArea(const TVector2<RealType>& A, const TVector2<RealType>& B, const TVector2<RealType>& C)
80 {
81 return ((RealType)0.5) * ((A.X*B.Y - A.Y*B.X) + (B.X*C.Y - B.Y*C.X) + (C.X*A.Y - C.Y*A.X));
82 }
83
85 RealType SignedArea() const
86 {
87 return SignedArea(V[0], V[1], V[2]);
88 }
89
91 RealType Area() const
92 {
94 }
95
96
105 {
106 RealType Sign1 = Orient(A, B, QueryPoint);
107 RealType Sign2 = Orient(B, C, QueryPoint);
108 RealType Sign3 = Orient(C, A, QueryPoint);
109 return (Sign1*Sign2 > 0) && (Sign2*Sign3 > 0) && (Sign3*Sign1 > 0);
110 }
111
114 {
115 return IsInside(V[0], V[1], V[2], QueryPoint);
116 }
117
118
124 const TVector2<RealType>& C, const TVector2<RealType>& QueryPoint, RealType Tolerance = (RealType)0)
125 {
126 RealType Sign1 = TSegment2<RealType>::GetSide(A, B, QueryPoint, Tolerance);
127 RealType Sign2 = TSegment2<RealType>::GetSide(B, C, QueryPoint, Tolerance);
128 RealType Sign3 = TSegment2<RealType>::GetSide(C, A, QueryPoint, Tolerance);
129
130 // If any of the signs are opposite, then definitely outside
131 if (Sign1 * Sign2 < 0 || Sign2 * Sign3 < 0 || Sign3 * Sign1 < 0)
132 {
133 return false;
134 }
135
136 // If some signs were zero, then things are more complicated because we are either colinear
137 // with that edge, or the edge is degenerate enough to get a 0 value on the DotPerp.
138 int NumZero = static_cast<int>(Sign1 == 0) + static_cast<int>(Sign2 == 0) + static_cast<int>(Sign3 == 0);
139 switch (NumZero)
140 {
141 case 0:
142 // All were nonzero and none disagreed, so inside.
143 return true;
144 case 1:
145 // If only one sign was zero, seems more than likely that we're on that edge.
146 // Hard to imagine some underflow case where that isn't actually the case, but we'll
147 // do the segment check just in case.
148 return Sign1 == 0 ? TSegment2<RealType>::IsOnSegment(A, B, QueryPoint, Tolerance)
151 case 2:
152 // Two signs were zero, so we expect to be on the vertex between those edges
153 return Sign1 != 0 ? TVector2<RealType>::DistSquared(QueryPoint, C) <= Tolerance * Tolerance
154 : Sign2 != 0 ? TVector2<RealType>::DistSquared(QueryPoint, A) <= Tolerance * Tolerance
155 : TVector2<RealType>::DistSquared(QueryPoint, B) <= Tolerance * Tolerance;
156 case 3:
157 // All three signs were zero. We're dealing with a denerate triangle of some
158 // sort. It should be sufficient to check any two segments
161 default:
162 return ensure(false);
163 }
164 }
165
170 bool IsInsideOrOn(const TVector2<RealType>& QueryPoint, RealType Tolerance = 0) const
171 {
172 return IsInsideOrOn(V[0], V[1], V[2], QueryPoint, Tolerance);
173 }
174
175
181 int IsInsideOrOn_Oriented(const TVector2<RealType>& QueryPoint, RealType Tolerance = (RealType)0) const
182 {
183 return IsInsideOrOn_Oriented(V[0], V[1], V[2], QueryPoint, Tolerance);
184 }
185
192 const TVector2<RealType>& QueryPoint, RealType Tolerance = (RealType)0)
193 {
194 checkSlow(Orient(A, B, C) <= 0); // TODO: remove this checkSlow; it's just to make sure the orientation is as expected
195
196 RealType Sign1 = TSegment2<RealType>::GetSide(A, B, QueryPoint, Tolerance);
197 if (Sign1 > 0)
198 {
199 return 1;
200 }
201
202 RealType Sign2 = TSegment2<RealType>::GetSide(B, C, QueryPoint, Tolerance);
203 if (Sign2 > 0)
204 {
205 return 1;
206 }
207
208 RealType Sign3 = TSegment2<RealType>::GetSide(A, C, QueryPoint, Tolerance);
209 if (Sign3 < 0) // note this edge is queried backwards so the sign test is also backwards
210 {
211 return 1;
212 }
213
214 // If some signs were zero, then things are more complicated because we are either colinear
215 // with that edge, or the edge is degenerate enough to get a 0 value on the DotPerp.
216 int NumZero = static_cast<int>(Sign1 == 0) + static_cast<int>(Sign2 == 0) + static_cast<int>(Sign3 == 0);
217 bool bIsOnEdge = false;
218
219 switch (NumZero)
220 {
221 case 0:
222 // All signs were nonzero and in the correct direction, so must be inside triangle.
223 return -1;
224 case 1:
225 // If only one sign was zero, seems more than likely that we're on the opposite edge.
226 // Hard to imagine some underflow case where that isn't actually the case, but we'll
227 // do the segment check just in case.
231 break;
232 case 2:
233 // Two signs were zero, so it better be on the vertex between those edges
234 bIsOnEdge = Sign1 != 0 ? TVector2<RealType>::DistSquared(QueryPoint, C) <= Tolerance * Tolerance
235 : Sign2 != 0 ? TVector2<RealType>::DistSquared(QueryPoint, A) <= Tolerance * Tolerance
236 : TVector2<RealType>::DistSquared(QueryPoint, B) <= Tolerance * Tolerance;
237 break;
238 case 3:
239 // All three signs were zero. We're dealing with a degenerate triangle of some
240 // sort. It should be sufficient to check any two segments.
243 break;
244 default:
245 ensure(false);
246 }
247 return bIsOnEdge ? 0 : 1;
248 }
249
250
251};
252
255
256
257
258
259
260
261template<typename RealType>
263{
265
267
269 {
270 V[0] = V0;
271 V[1] = V1;
272 V[2] = V2;
273 }
274
276 {
277 V[0] = VIn[0];
278 V[1] = VIn[1];
279 V[2] = VIn[2];
280 }
281
282 TVector<RealType> BarycentricPoint(RealType Bary0, RealType Bary1, RealType Bary2) const
283 {
284 return Bary0*V[0] + Bary1*V[1] + Bary2*V[2];
285 }
286
288 {
289 return BaryCoords[0]*V[0] + BaryCoords[1]*V[1] + BaryCoords[2]*V[2];
290 }
291
296
299 {
300 return VectorUtil::Normal(V[0], V[1], V[2]);
301 }
302
305 {
306 constexpr RealType f = 1.0 / 3.0;
307 return TVector<RealType>(
308 (V[0].X + V[1].X + V[2].X) * f,
309 (V[0].Y + V[1].Y + V[2].Y) * f,
310 (V[0].Z + V[1].Z + V[2].Z) * f
311 );
312 }
313
315 void Expand(RealType Delta)
316 {
318 V[0] += Delta * ((V[0] - Centroid).Normalized());
319 V[1] += Delta * ((V[1] - Centroid).Normalized());
320 V[2] += Delta * ((V[2] - Centroid).Normalized());
321 }
322};
323
327
328
329// Note: More TetUtil functions are in TetUtil.h; this subset is here for use by the TTetrahedron3 struct below
330namespace TetUtil
331{
332 // @return a C array of vertex orderings for each of the 4 triangle faces of a tetrahedron
333 template<bool bReverseOrientation = false>
335 {
336 const static FIndex3i FaceMap[4]{ FIndex3i(0,1,2), FIndex3i(0,3,1), FIndex3i(0,2,3), FIndex3i(1,3,2) };
337 const static FIndex3i FaceMapRev[4]{ FIndex3i(1,0,2), FIndex3i(3,0,1), FIndex3i(2,0,3), FIndex3i(3,1,2) };
338 if constexpr (bReverseOrientation)
339 {
340 return FaceMapRev;
341 }
342 else
343 {
344 return FaceMap;
345 }
346 }
347}
348
349template<typename RealType>
351{
353
355
357 {
358 V[0] = V0;
359 V[1] = V1;
360 V[2] = V2;
361 V[3] = V3;
362 }
363
365 {
366 V[0] = VIn[0];
367 V[1] = VIn[1];
368 V[2] = VIn[2];
369 V[3] = VIn[3];
370 }
371
372 TVector<RealType> BarycentricPoint(RealType Bary0, RealType Bary1, RealType Bary2, RealType Bary3) const
373 {
374 return Bary0 * V[0] + Bary1 * V[1] + Bary2 * V[2] + Bary3 * V[3];
375 }
376
378 {
379 return BaryCoords[0] * V[0] + BaryCoords[1] * V[1] + BaryCoords[2] * V[2] + BaryCoords[3] * V[3];
380 }
381
383 {
385 RetBounds.Contain(V[0]);
386 RetBounds.Contain(V[1]);
387 RetBounds.Contain(V[2]);
388 RetBounds.Contain(V[3]);
389 return RetBounds;
390 }
391
392 // Get the ith triangular face of the tetrahedron, as indices into the four tetrahedron vertices
393 template<bool bReverseOrientation = false>
395 {
396 return TetUtil::GetTetFaceOrdering<bReverseOrientation>()[Idx];
397 }
398
399 template<bool bReverseOrientation = false>
405
408 {
409 constexpr RealType f = 1.0 / 4.0;
410 return TVector<RealType>(
411 (V[0].X + V[1].X + V[2].X + V[3].X) * f,
412 (V[0].Y + V[1].Y + V[2].Y + V[3].Y) * f,
413 (V[0].Z + V[1].Z + V[2].Z + V[3].Z) * f
414 );
415 }
416};
417
420
421
422} // end namespace UE::Geometry
423} // end namespace UE
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define ensure( InExpression)
Definition AssertionMacros.h:464
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 X(Name, Desc)
Definition FormatStringSan.h:47
Definition MathUtil.h:150
static RealType Sqrt(const RealType Value)
Definition MathUtil.h:342
static RealType Abs(const RealType Value)
Definition MathUtil.h:215
const FIndex3i * GetTetFaceOrdering()
Definition TriangleTypes.h:334
RealType EquilateralEdgeLengthForArea(RealType TriArea)
Definition TriangleTypes.h:27
TVector< RealType > BarycentricCoords(const TVector< RealType > &Point, const TVector< RealType > &V0, const TVector< RealType > &V1, const TVector< RealType > &V2)
Definition VectorUtil.h:371
TVector< RealType > Normal(const TVector< RealType > &V0, const TVector< RealType > &V1, const TVector< RealType > &V2)
Definition VectorUtil.h:70
TTetrahedron3< float > FTetrahedron3f
Definition TriangleTypes.h:418
TTriangle2< double > FTriangle2d
Definition TriangleTypes.h:254
TTetrahedron3< double > FTetrahedron3d
Definition TriangleTypes.h:419
T Orient(const UE::Math::TVector2< T > &A, const UE::Math::TVector2< T > &B, const UE::Math::TVector2< T > &C)
Definition VectorTypes.h:33
TTriangle3< int > FTriangle3i
Definition TriangleTypes.h:326
TTriangle2< float > FTriangle2f
Definition TriangleTypes.h:253
TTriangle3< double > FTriangle3d
Definition TriangleTypes.h:325
TTriangle3< float > FTriangle3f
Definition TriangleTypes.h:324
Definition Sphere.cpp:10
Definition AdvancedWidgetsModule.cpp:13
Definition IndexTypes.h:158
Definition BoxTypes.h:247
void Contain(const TVector< RealType > &V)
Definition BoxTypes.h:438
static bool IsOnSegment(const TVector2< T > &A, const TVector2< T > &B, const TVector2< T > &QueryPt, T Tolerance=(T) 0)
Definition SegmentTypes.h:394
int GetSide(const TVector2< T > &QueryPoint, T Tolerance=0)
Definition SegmentTypes.h:206
Definition TriangleTypes.h:351
static FIndex3i GetFaceIndices(int32 Idx)
Definition TriangleTypes.h:394
TTriangle3< RealType > GetFace(int32 Idx) const
Definition TriangleTypes.h:400
TAxisAlignedBox3< RealType > Bounds() const
Definition TriangleTypes.h:382
TVector< RealType > V[4]
Definition TriangleTypes.h:352
TTetrahedron3(const TVector< RealType > VIn[4])
Definition TriangleTypes.h:364
TTetrahedron3()
Definition TriangleTypes.h:354
TVector< RealType > BarycentricPoint(RealType Bary0, RealType Bary1, RealType Bary2, RealType Bary3) const
Definition TriangleTypes.h:372
TTetrahedron3(const TVector< RealType > &V0, const TVector< RealType > &V1, const TVector< RealType > &V2, const TVector< RealType > &V3)
Definition TriangleTypes.h:356
TVector< RealType > Centroid() const
Definition TriangleTypes.h:407
TVector< RealType > BarycentricPoint(const TVector4< RealType > &BaryCoords) const
Definition TriangleTypes.h:377
Definition TriangleTypes.h:39
TVector2< RealType > V[3]
Definition TriangleTypes.h:40
static bool IsInside(const TVector2< RealType > &A, const TVector2< RealType > &B, const TVector2< RealType > &C, const TVector2< RealType > &QueryPoint)
Definition TriangleTypes.h:104
TVector< RealType > GetBarycentricCoords(const TVector2< RealType > &Point) const
Definition TriangleTypes.h:68
static bool IsInsideOrOn(const TVector2< RealType > &A, const TVector2< RealType > &B, const TVector2< RealType > &C, const TVector2< RealType > &QueryPoint, RealType Tolerance=(RealType) 0)
Definition TriangleTypes.h:123
RealType Area() const
Definition TriangleTypes.h:91
TVector2< RealType > BarycentricPoint(RealType Bary0, RealType Bary1, RealType Bary2) const
Definition TriangleTypes.h:58
TTriangle2()
Definition TriangleTypes.h:42
TTriangle2(const TVector2< RealType > VIn[3])
Definition TriangleTypes.h:51
RealType SignedArea() const
Definition TriangleTypes.h:85
static int IsInsideOrOn_Oriented(const TVector2< RealType > &A, const TVector2< RealType > &B, const TVector2< RealType > &C, const TVector2< RealType > &QueryPoint, RealType Tolerance=(RealType) 0)
Definition TriangleTypes.h:191
int IsInsideOrOn_Oriented(const TVector2< RealType > &QueryPoint, RealType Tolerance=(RealType) 0) const
Definition TriangleTypes.h:181
static RealType SignedArea(const TVector2< RealType > &A, const TVector2< RealType > &B, const TVector2< RealType > &C)
Definition TriangleTypes.h:79
bool IsInsideOrOn(const TVector2< RealType > &QueryPoint, RealType Tolerance=0) const
Definition TriangleTypes.h:170
TVector2< RealType > BarycentricPoint(const TVector< RealType > &BaryCoords) const
Definition TriangleTypes.h:63
TTriangle2(const TVector2< RealType > &V0, const TVector2< RealType > &V1, const TVector2< RealType > &V2)
Definition TriangleTypes.h:44
bool IsInside(const TVector2< RealType > &QueryPoint) const
Definition TriangleTypes.h:113
Definition TriangleTypes.h:263
TVector< RealType > GetBarycentricCoords(const TVector< RealType > &Point) const
Definition TriangleTypes.h:292
TVector< RealType > BarycentricPoint(RealType Bary0, RealType Bary1, RealType Bary2) const
Definition TriangleTypes.h:282
void Expand(RealType Delta)
Definition TriangleTypes.h:315
TTriangle3(const TVector< RealType > &V0, const TVector< RealType > &V1, const TVector< RealType > &V2)
Definition TriangleTypes.h:268
TVector< RealType > BarycentricPoint(const TVector< RealType > &BaryCoords) const
Definition TriangleTypes.h:287
TVector< RealType > Normal() const
Definition TriangleTypes.h:298
TTriangle3(const TVector< RealType > VIn[3])
Definition TriangleTypes.h:275
TVector< RealType > V[3]
Definition TriangleTypes.h:264
TTriangle3()
Definition TriangleTypes.h:266
TVector< RealType > Centroid() const
Definition TriangleTypes.h:304
Definition Vector2D.h:38
static UE_FORCEINLINE_HINT T DistSquared(const TVector2< T > &V1, const TVector2< T > &V2)
Definition Vector2D.h:935
Definition Vector4.h:30
Definition Vector.h:51