UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
MeshAdapter.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "TriangleTypes.h"
6#include "VectorTypes.h"
7
8#include "Math/IntVector.h"
9#include "Math/Vector.h"
10#include "IndexTypes.h"
11
12namespace UE
13{
14namespace Geometry
15{
16
17using namespace UE::Math;
18
22template <typename RealType>
43
46
53{
54public:
55
57
58 template<typename TriangleMeshAdapterType>
60 {
61 EIDtoVIDs.Reset();
62 EIDtoTIDs.Reset();
63 EIDtoTIDSpillID.Reset();
64 SpillIDtoTIDs.Reset();
65
66 TArray<FLocalIntArray> VIDtoNbrVIDs; // temp arrays, 1:1 with VIDtoEIDs
67 VIDtoEIDs.SetNum(InMesh.MaxVertexID());
68 VIDtoNbrVIDs.SetNum(VIDtoEIDs.Num());
69 TIDtoEIDs.SetNum(InMesh.MaxTriangleID());
70
71 auto AddEdge = [&VIDtoNbrVIDs, this](int32 A, int32 B, int32 TID) -> int32
72 {
74
77 if (Nbrs.Find(B, BSubIdx)) // edge already exists
78 {
79 FoundEID = VIDtoEIDs[A][BSubIdx];
80 // if it was only on one triangle, add this as the second triangle
81 if (EIDtoTIDs[FoundEID].B == INDEX_NONE)
82 {
83 EIDtoTIDs[FoundEID].B = TID;
84 }
85 else // non-manifold case; build the spill mapping to hold the (hopefully few) non-manifold edges' neighbors
86 {
87 if (EIDtoTIDSpillID.IsEmpty())
88 {
89 EIDtoTIDSpillID.Init(INDEX_NONE, EIDtoVIDs.Num());
90 }
91 int32& SpillID = EIDtoTIDSpillID[FoundEID];
92 if (SpillID == INDEX_NONE)
93 {
94 SpillID = SpillIDtoTIDs.Emplace();
95 }
96 SpillIDtoTIDs[SpillID].Add(TID);
97 }
98 }
99 // edge didn't exist yet; create it
100 else
101 {
102 FIndex2i SortedAB{ A,B }; // to match FDynamicMesh3 convention, store the vertices on the edge in index-sorted order
103 SortedAB.Sort();
104 FoundEID = EIDtoVIDs.Add({ SortedAB.A,SortedAB.B });
105 EIDtoTIDs.Add({ TID,INDEX_NONE });
106 checkSlow(EIDtoTIDs.Num() == EIDtoVIDs.Num());
107
108 BSubIdx = Nbrs.Add(B);
109 VIDtoEIDs[A].Add(FoundEID);
110 VIDtoNbrVIDs[B].Add(A);
111 VIDtoEIDs[B].Add(FoundEID);
112 if (!EIDtoTIDSpillID.IsEmpty())
113 {
114 EIDtoTIDSpillID.Add(INDEX_NONE);
115 }
116 }
117 return FoundEID;
118 };
119
120 for (int32 TID = 0; TID < InMesh.MaxTriangleID(); ++TID)
121 {
122 if (!InMesh.IsTriangle(TID))
123 {
124 continue;
125 }
126 const FIndex3i Tri = InMesh.GetTriangle(TID);
127 FIndex3i& TriEdges = TIDtoEIDs[TID];
128 for (int32 SubIdx = 0, PrevIdx = 2; SubIdx < 3; PrevIdx = SubIdx++)
129 {
130 int32 EID = AddEdge(Tri[SubIdx], Tri[PrevIdx], TID);
132 }
133 }
134 }
135
137 {
138 return EIDtoVIDs.Num();
139 }
140
141 bool IsEdge(int32 EID) const
142 {
143 return EIDtoVIDs.IsValidIndex(EID);
144 }
145
147 {
148 return GetEdgeT(EID).B == INDEX_NONE;
149 }
150
152 {
153 return FIndex2i(EIDtoVIDs[EID].A, EIDtoVIDs[EID].B);
154 }
155
156 // Return up to two of the triangles on edge EID; to access all triangles of a non-manifold edge, use EnumerateEdgeTriangles
158 {
159 return FIndex2i(EIDtoTIDs[EID].A, EIDtoTIDs[EID].B);
160 }
161
163 {
164 return TIDtoEIDs[TID];
165 }
166
167 // @return a single triangle connected to the given vertex, or INDEX_NONE if the vertex has no triangles
169 {
170 if (VIDtoEIDs[VID].IsEmpty())
171 {
172 return INDEX_NONE;
173 }
174 return EIDtoTIDs[VIDtoEIDs[VID][0]].A;
175 }
176
179 {
180 for (int32 EID : VIDtoEIDs[VertexID])
181 {
182 const FIndex2i& VIDs = EIDtoVIDs[EID];
183 if (VIDs.A == VertexID)
184 {
185 VertexFunc(VIDs.B);
186 }
187 else
188 {
189 VertexFunc(VIDs.A);
190 }
191 }
192 }
193
196 {
197 for (int32 EID : VIDtoEIDs[VertexID])
198 {
199 EdgeFunc(EID);
200 }
201 }
202
203 // Note: Use templated TTriangleMeshAdapterEdgeConnectivity for a version of this method matching the FDynamicMesh3 interface
205 template<typename TriangleMeshAdapterType>
207 {
208 for (int32 EID : VIDtoEIDs[VertexID])
209 {
210 const int32 OtherVID = EIDtoVIDs[EID].OtherElement(VertexID);
213 {
214 FIndex3i Tri = InMesh.GetTriangle(TID);
215 // Each triangle is associate with two edges on the vertex; we report the triangle only for the 'outgoing' edge
216 bool bIsTriangleOutgoingEdge = false;
217 for (int32 SubIdx = 0, PrevIdx = 2; SubIdx < 3; PrevIdx = SubIdx++)
218 {
219 if (Tri[PrevIdx] == VertexID && Tri[SubIdx] == OtherVID)
220 {
222 }
223 }
225 {
227 }
228 }
229 );
230 }
231 }
232
235 {
236 const FIndex2i& EdgeT = EIDtoTIDs[EdgeID];
238 if (EdgeT.B != INDEX_NONE)
239 {
241
242 // enumerate non-manifold triangles if present
243 if (!EIDtoTIDSpillID.IsEmpty())
244 {
245 int32 SpillID = EIDtoTIDSpillID[EdgeID];
246 if (SpillID != INDEX_NONE)
247 {
248 for (int32 TID : SpillIDtoTIDs[SpillID])
249 {
251 }
252 }
253 }
254 }
255 }
256
257private:
258 TArray<FLocalIntArray> VIDtoEIDs; // Map VID -> one-ring neighborhood of EIDs
259 TArray<FIndex2i> EIDtoVIDs; // Map EID -> pair of vertex IDs on the edge (lower index first)
260 TArray<FIndex2i> EIDtoTIDs; // Map EID -> up to two triangle IDs on the edge. If a boundary edge, second index is INDEX_NONE
261 TArray<FIndex3i> TIDtoEIDs; // Map TID -> the three edges on the triangle
262
263 // These arrays will only be populated if the input mesh was 'edge-non-manifold' -- i.e., had more than two triangle on some edges
264 // Each non-manifold edge has a 'Spill ID' corresponding to an array of all additional neighboring triangle IDs
265 TArray<int32> EIDtoTIDSpillID; // Map EID -> index in SpillID array
266 TArray<TArray<int32, TInlineAllocator<2>>> SpillIDtoTIDs; // Map SpillID -> additional neighboring triangles of edge
267};
268
269// Templated version of FTriangleMeshAdapterEdgeConnectivity, to provide an FDynamicMesh3-compatible interface for methods that require additional mesh data
270template<typename TriangleMeshType>
272{
273public:
275 {
276 check(SourceMesh);
277 BuildEdgeConnectivity(*SourceMesh);
278 }
279
284private:
285 const TriangleMeshType* SourceMesh = nullptr;
286};
287
294{
295 return {
296 [&](int) { return true; },
297 [&](int) { return true; },
298 [&]() { return Triangles.Num(); },
299 [&]() { return Vertices.Num(); },
300 [&]() { return Triangles.Num(); },
301 [&]() { return Vertices.Num(); },
302 [&]() { return 0; },
303 [&](int Idx) { return FIndex3i(Triangles[Idx]); },
304 [&](int Idx) { return FVector3d(Vertices[Idx]); }};
305}
306
307
311template<typename IndexType, typename OutRealType, typename InVectorType=FVector>
313{
316
322
324 {
325 }
326
330
331 inline bool IsTriangle(int32 Index) const
332 {
334 }
335
336 inline bool IsVertex(int32 Index) const
337 {
338 return SourceVertices->IsValidIndex(Index);
339 }
340
341 inline int32 MaxTriangleID() const
342 {
343 return SourceTriangles->Num() / 3;
344 }
345
346 inline int32 MaxVertexID() const
347 {
348 return SourceVertices->Num();
349 }
350
351 // Counts are same as MaxIDs, because these are compact meshes
352 inline int32 TriangleCount() const
353 {
354 return SourceTriangles->Num() / 3;
355 }
356
357 inline int32 VertexCount() const
358 {
359 return SourceVertices->Num();
360 }
361
362 inline uint64 GetChangeStamp() const
363 {
364 return 1; // source data doesn't have a timestamp concept
365 }
366
368 {
369 int32 Start = Index * 3;
370 return FIndex3i((int)(*SourceTriangles)[Start], (int)(*SourceTriangles)[Start+1], (int)(*SourceTriangles)[Start+2]);
371 }
372
377
385
386};
387
388
393template<typename IndexVectorType, typename OutRealType, typename InVectorType = FVector>
395{
398
404
408
412
413 inline bool IsTriangle(int32 Index) const
414 {
416 }
417
418 inline bool IsVertex(int32 Index) const
419 {
420 return SourceVertices->IsValidIndex(Index);
421 }
422
423 inline int32 MaxTriangleID() const
424 {
425 return SourceTriangles->Num();
426 }
427
428 inline int32 MaxVertexID() const
429 {
430 return SourceVertices->Num();
431 }
432
433 // Counts are same as MaxIDs, because these are compact meshes
434 inline int32 TriangleCount() const
435 {
436 return SourceTriangles->Num();
437 }
438
439 inline int32 VertexCount() const
440 {
441 return SourceVertices->Num();
442 }
443
444 inline uint64 GetChangeStamp() const
445 {
446 return 1; // source data doesn't have a timestamp concept
447 }
448
450 {
451 const IndexVectorType& Tri = (*SourceTriangles)[Index];
452 return FIndex3i((int)Tri[0], (int)Tri[1], (int)Tri[2]);
453 }
454
459
461 {
462 const IndexVectorType& Tri = (*SourceTriangles)[TriIndex];
463 V0 = TVector<OutRealType>((*SourceVertices)[Tri[0]]);
464 V1 = TVector<OutRealType>((*SourceVertices)[Tri[1]]);
465 V2 = TVector<OutRealType>((*SourceVertices)[Tri[2]]);
466 }
467
468};
469
471
472
479template <class WrappedMeshType>
481{
483
485 {
486 IsTriangle = [this](int index) { return WrappedAdapter->IsTriangle(index); };
487 IsVertex = [this](int index) { return WrappedAdapter->IsVertex(index); };
488 MaxTriangleID = [this]() { return WrappedAdapter->MaxTriangleID(); };
489 MaxVertexID = [this]() { return WrappedAdapter->MaxVertexID(); };
490 TriangleCount = [this]() { return WrappedAdapter->TriangleCount(); };
491 VertexCount = [this]() { return WrappedAdapter->VertexCount(); };
492 GetChangeStamp = [this]() { return WrappedAdapter->GetChangeStamp(); };
493 GetTriangle = [this](int32 TriangleID) { return WrappedAdapter->GetTriangle(TriangleID); };
494 GetVertex = [this](int32 VertexID) { return WrappedAdapter->GetVertex(VertexID); };
495 }
496};
497
498
499
500} // end namespace UE::Geometry
501} // end namespace UE
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
@ INDEX_NONE
Definition CoreMiscDefines.h:150
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FPlatformTypes::uint64 uint64
A 64-bit unsigned integer.
Definition Platform.h:1117
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE::Math::TVector< double > FVector3d
Definition MathFwd.h:60
const bool
Definition NetworkReplayStreaming.h:178
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void Reset(SizeType NewSize=0)
Definition Array.h:2246
UE_REWRITE bool IsEmpty() const
Definition Array.h:1133
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
UE_NODEBUG UE_FORCEINLINE_HINT bool IsValidIndex(SizeType Index) const
Definition Array.h:1122
void Init(const ElementType &Element, SizeType Number)
Definition Array.h:3043
Definition AssetRegistryState.h:50
Definition AndroidPlatformMisc.h:14
int32 GetSingleVertexTriangle(int32 VID) const
Definition MeshAdapter.h:168
void EnumerateVertexVertices(int32 VertexID, TFunctionRef< void(int32)> VertexFunc) const
Definition MeshAdapter.h:178
void EnumerateEdgeTriangles(int32 EdgeID, TFunctionRef< void(int32)> TriangleFunc) const
Definition MeshAdapter.h:234
void BuildEdgeConnectivity(const TriangleMeshAdapterType &InMesh)
Definition MeshAdapter.h:59
void EnumerateVertexTriangles(int32 VertexID, TFunctionRef< void(int32)> TriangleFunc, const TriangleMeshAdapterType &InMesh) const
Definition MeshAdapter.h:206
int32 MaxEdgeID() const
Definition MeshAdapter.h:136
void EnumerateVertexEdges(int32 VertexID, TFunctionRef< void(int32)> EdgeFunc) const
Definition MeshAdapter.h:195
bool IsBoundaryEdge(int32 EID) const
Definition MeshAdapter.h:146
FIndex3i GetTriEdges(int32 TID) const
Definition MeshAdapter.h:162
FIndex2i GetEdgeT(int32 EID) const
Definition MeshAdapter.h:157
FIndex2i GetEdgeV(int32 EID) const
Definition MeshAdapter.h:151
bool IsEdge(int32 EID) const
Definition MeshAdapter.h:141
TTriangleMeshAdapterEdgeConnectivity(const TriangleMeshType *InMesh)
Definition MeshAdapter.h:274
void EnumerateVertexTriangles(int32 VertexID, TFunctionRef< void(int32)> TriangleFunc) const
Definition MeshAdapter.h:280
FTriangleMeshAdapterd GetArrayMesh(TArray< FVector > &Vertices, TArray< FIntVector > &Triangles)
Definition MeshAdapter.h:293
TTriangleMeshAdapter< double > FTriangleMeshAdapterd
Definition MeshAdapter.h:44
TIndexMeshArrayAdapter< uint32, double > FIndexMeshArrayAdapterd
Definition MeshAdapter.h:470
TTriangleMeshAdapter< float > FTriangleMeshAdapterf
Definition MeshAdapter.h:45
Definition Sphere.cpp:10
Definition AdvancedWidgetsModule.cpp:13
U16 Index
Definition radfft.cpp:71
Definition IndexTypes.h:27
int B
Definition IndexTypes.h:32
void Sort()
Definition IndexTypes.h:112
Definition IndexTypes.h:158
int B
Definition IndexTypes.h:164
int A
Definition IndexTypes.h:163
int C
Definition IndexTypes.h:165
Definition MeshAdapter.h:313
TIndexMeshArrayAdapter(const TArray< InVectorType > *SourceVerticesIn, const TArray< IndexType > *SourceTrianglesIn)
Definition MeshAdapter.h:327
bool IsTriangle(int32 Index) const
Definition MeshAdapter.h:331
void GetTriVertices(int32 TriIndex, UE::Math::TVector< OutRealType > &V0, UE::Math::TVector< OutRealType > &V1, UE::Math::TVector< OutRealType > &V2) const
Definition MeshAdapter.h:378
void SetSources(const TArray< InVectorType > *SourceVerticesIn, const TArray< IndexType > *SourceTrianglesIn)
Definition MeshAdapter.h:317
int32 TriangleCount() const
Definition MeshAdapter.h:352
int32 MaxTriangleID() const
Definition MeshAdapter.h:341
uint64 GetChangeStamp() const
Definition MeshAdapter.h:362
int32 MaxVertexID() const
Definition MeshAdapter.h:346
TIndexMeshArrayAdapter()
Definition MeshAdapter.h:323
const TArray< InVectorType > * SourceVertices
Definition MeshAdapter.h:314
const TArray< IndexType > * SourceTriangles
Definition MeshAdapter.h:315
TVector< OutRealType > GetVertex(int32 Index) const
Definition MeshAdapter.h:373
int32 VertexCount() const
Definition MeshAdapter.h:357
FIndex3i GetTriangle(int32 Index) const
Definition MeshAdapter.h:367
bool IsVertex(int32 Index) const
Definition MeshAdapter.h:336
Definition MeshAdapter.h:395
int32 VertexCount() const
Definition MeshAdapter.h:439
const TArray< InVectorType > * SourceVertices
Definition MeshAdapter.h:396
bool IsVertex(int32 Index) const
Definition MeshAdapter.h:418
TIndexVectorMeshArrayAdapter()
Definition MeshAdapter.h:405
void SetSources(const TArray< InVectorType > *SourceVerticesIn, const TArray< IndexVectorType > *SourceTrianglesIn)
Definition MeshAdapter.h:399
int32 MaxVertexID() const
Definition MeshAdapter.h:428
int32 TriangleCount() const
Definition MeshAdapter.h:434
TIndexVectorMeshArrayAdapter(const TArray< InVectorType > *SourceVerticesIn, const TArray< IndexVectorType > *SourceTrianglesIn)
Definition MeshAdapter.h:409
TVector< OutRealType > GetVertex(int32 Index) const
Definition MeshAdapter.h:455
bool IsTriangle(int32 Index) const
Definition MeshAdapter.h:413
int32 MaxTriangleID() const
Definition MeshAdapter.h:423
const TArray< IndexVectorType > * SourceTriangles
Definition MeshAdapter.h:397
FIndex3i GetTriangle(int32 Index) const
Definition MeshAdapter.h:449
void GetTriVertices(int32 TriIndex, UE::Math::TVector< OutRealType > &V0, UE::Math::TVector< OutRealType > &V1, UE::Math::TVector< OutRealType > &V2) const
Definition MeshAdapter.h:460
uint64 GetChangeStamp() const
Definition MeshAdapter.h:444
Definition MeshAdapter.h:481
WrappedMeshType * WrappedAdapter
Definition MeshAdapter.h:482
TMeshWrapperAdapterd(WrappedMeshType *WrappedAdapterIn)
Definition MeshAdapter.h:484
Definition MeshAdapter.h:24
TFunction< FIndex3i(int32)> GetTriangle
Definition MeshAdapter.h:32
TFunction< bool(int32 index)> IsVertex
Definition MeshAdapter.h:26
TFunction< int32()> MaxVertexID
Definition MeshAdapter.h:28
TFunction< int32()> MaxTriangleID
Definition MeshAdapter.h:27
TFunction< bool(int32 index)> IsTriangle
Definition MeshAdapter.h:25
TFunction< uint64()> GetChangeStamp
Definition MeshAdapter.h:31
void GetTriVertices(int TID, UE::Math::TVector< RealType > &V0, UE::Math::TVector< RealType > &V1, UE::Math::TVector< RealType > &V2) const
Definition MeshAdapter.h:35
TFunction< int32()> VertexCount
Definition MeshAdapter.h:30
TFunction< TVector< RealType >(int32)> GetVertex
Definition MeshAdapter.h:33
TFunction< int32()> TriangleCount
Definition MeshAdapter.h:29
Definition Vector.h:51