UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
DynamicGraph.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
6
7#include "VectorTypes.h"
8#include "IndexTypes.h"
9#include "BoxTypes.h"
10#include "GeometryTypes.h"
11#include "Util/DynamicVector.h"
12#include "Util/IndexUtil.h"
13#include "Util/IteratorUtil.h"
14#include "Util/RefCountVector.h"
15#include "Util/SmallListSet.h"
16#include "VectorUtil.h"
17
18namespace UE
19{
20namespace Geometry
21{
22
23
25{
26public:
27 static constexpr int InvalidID = IndexConstants::InvalidID; // -1;
28 static constexpr int DuplicateEdgeID = -2;
29
30 struct FEdge
31 {
32 int A, B, Group;
33 };
34
36 {
38 }
40 {
42 }
43
44protected:
46
48
50 TDynamicVector<FEdge> edges; // each edge is a tuple (v0,v0,GroupID)
51
52 int timestamp = 0;
54
55 int max_group_id = 0;
56
57public:
59 : max_group_id(0)
60 {
61 }
62
64 {
65 }
66
67protected:
69 {
70 timestamp++;
71 if (bShapeChange)
72 {
74 }
75 }
76
77public:
78 int Timestamp() const
79 {
80 return timestamp;
81 }
82 int ShapeTimestamp() const
83 {
84 return shape_timestamp;
85 }
86
87 int VertexCount() const
88 {
90 }
91 int EdgeCount() const
92 {
93 return edges_refcount.GetCount();
94 }
95
96 // these values are (max_used+1), ie so an iteration should be < MaxVertexID, not <=
97 int MaxVertexID() const
98 {
100 }
101 int MaxEdgeID() const
102 {
104 }
105 int MaxGroupID() const
106 {
107 return max_group_id;
108 }
109
110 bool IsVertex(int VID) const
111 {
112 return vertices_refcount.IsValid(VID);
113 }
114 bool IsEdge(int EID) const
115 {
116 return edges_refcount.IsValid(EID);
117 }
118
123 {
125 return vertex_edges.MappedValues(VID, [VID, this](int EID) { return edge_other_v(EID, VID); });
126 }
127
132 {
134 return vertex_edges.Values(VID);
135 }
136
137 int GetVtxEdgeCount(int VID) const
138 {
139 return vertices_refcount.IsValid(VID) ? vertex_edges.GetCount(VID) : -1;
140 }
141
143 {
144 int max = 0;
145 for (int VID : vertices_refcount.Indices())
146 {
147 max = FMath::Max(max, vertex_edges.GetCount(VID));
148 }
149 return max;
150 }
151
153 {
155 }
156
157 int GetEdgeGroup(int EID) const
158 {
159 return edges_refcount.IsValid(EID) ? edges[EID].Group : -1;
160 }
161
162 void SetEdgeGroup(int EID, int GroupID)
163 {
166 {
167 edges[EID].Group = GroupID;
168 max_group_id = FMath::Max(max_group_id, GroupID + 1);
169 updateTimeStamp(false);
170 }
171 }
172
174 {
175 return max_group_id++;
176 }
177
178 FEdge GetEdge(int EID) const
179 {
181 }
182
183protected:
185 {
186 int VID = vertices_refcount.Allocate();
187 allocate_edges_list(VID);
188 updateTimeStamp(true);
189 return VID;
190 }
191
193 {
195 {
196 return false;
197 }
198 allocate_edges_list(Vid);
199 updateTimeStamp(true);
200 return true;
201 }
202
203private:
204 void allocate_edges_list(int VID)
205 {
206 if (VID < (int)vertex_edges.Size())
207 {
208 vertex_edges.Clear(VID);
209 }
211 }
212
213public:
214 int AppendEdge(const FEdge& E)
215 {
216 return AppendEdge(E.A, E.B, E.Group);
217 }
218 int AppendEdge(const FIndex2i& ev, int GID = -1)
219 {
220 return AppendEdge(ev[0], ev[1], GID);
221 }
222 int AppendEdge(int v0, int v1, int GID = -1)
223 {
224 if (IsVertex(v0) == false || IsVertex(v1) == false)
225 {
226 check(false);
227 return InvalidID;
228 }
229 if (v0 == v1)
230 {
231 check(false);
232 return InvalidID;
233 }
234 int e0 = FindEdge(v0, v1);
235 if (e0 != InvalidID)
236 return DuplicateEdgeID;
237
238 // Increment ref counts and update/create edges
241 max_group_id = FMath::Max(max_group_id, GID + 1);
242
243 // now safe to insert edge
244 int EID = add_edge(v0, v1, GID);
245
246 updateTimeStamp(true);
247 return EID;
248 }
249
250protected:
251 int add_edge(int A, int B, int GID)
252 {
253 if (B < A)
254 {
255 int t = B;
256 B = A;
257 A = t;
258 }
260 edges.InsertAt(FEdge{A, B, GID}, EID);
261
264 return EID;
265 }
266
267public:
268 //
269 // iterators
270 // The functions vertices() / triangles() / edges() are provided so you can do:
271 // for ( int EID : edges() ) { ... }
272 // and other related begin() / end() idioms
273 //
276 {
277 return vertices_refcount.Indices();
278 }
279
282 {
283 return edges_refcount.Indices();
284 }
285
286 template <typename T>
288
293 {
294 return edges_refcount.MappedIndices<FEdge>([this](int EID) {
295 return edges[EID];
296 });
297 }
298
299 int FindEdge(int VA, int VB) const
300 {
301 int vMax = FMath::Max(VA, VB);
302 for (int EID : vertex_edges.Values(FMath::Min(VA, VB)))
303 {
304 //if (edge_has_v(EID, vMax)) // (slower option; does not use the fact that edges always have larger vertex as B)
305 if (edges[EID].B == vMax)
306 {
307 return EID;
308 }
309 }
310 return InvalidID;
311 }
312
314 {
316 {
317 check(false);
319 }
320
324
326
327 // Decrement vertex refcounts. If any hit 1 and we got remove-isolated flag,
328 // we need to remove that vertex
329 for (int j = 0; j < 2; ++j)
330 {
331 int VID = ev[j];
334 {
336 check(vertices_refcount.IsValid(VID) == false);
337 vertex_edges.Clear(VID);
338 }
339 }
340
341 updateTimeStamp(true);
342 return EMeshResult::Ok;
343 }
344
346 {
347 for (int EID : VtxEdgesItr(VID))
348 {
350 if (result != EMeshResult::Ok)
351 return result;
352 }
353 return EMeshResult::Ok;
354 }
355
357 {
358 int VNew;
359 int ENewBN; // new edge [VNew,VB] (original was AB)
360 };
362 {
363 int EID = FindEdge(VA, VB);
364 if (EID == InvalidID)
365 {
367 }
368 return SplitEdge(EID, Split);
369 }
371 {
372 if (!IsEdge(EAB))
373 {
375 }
376
377 // look up primary edge
378 int eab_i = 3 * EAB;
379 int A = edges[EAB].A, B = edges[EAB].B;
380 int GID = edges[EAB].Group;
381 int f = append_new_split_vertex(A, B);
382
383 // rewrite edge bc, create edge af
384 int eaf = EAB;
388
389 // create new edge fb
390 int efb = add_edge(f, B, GID);
391
392 // update vertex refcounts
394
395 Split.VNew = f;
396 Split.ENewBN = efb;
397
398 updateTimeStamp(true);
399 return EMeshResult::Ok;
400 }
401
403 {
404 if (!IsEdge(EAB))
405 {
407 }
408
409 int f = ExistingMidVert;
410 if (!IsVertex(f))
411 {
413 }
414
415 // look up primary edge
416 int eab_i = 3 * EAB;
417 int A = edges[EAB].A, B = edges[EAB].B;
418 int GID = edges[EAB].Group;
419
420 int EAf = FindEdge(A, f);
421 int FIncr = 0; // track how much to increment the reference count of middle vertex, f
422 int BIncr = 0;
423 if (EAf != InvalidID)
424 {
425 RemoveEdge(EAB, false); // this will handle changes to refcounts, so no need to touch bIncr
426 edges[EAf].Group = GID;
427 }
428 else
429 {
430 // rewrite edge ab to create edge af
431 EAf = EAB;
435 FIncr++;
436 BIncr--;
437 }
438
439 int EfB = FindEdge(f, B);
440 if (EfB == InvalidID)
441 {
442 EfB = add_edge(f, B, GID);
443 FIncr++;
444 BIncr++;
445 }
446 else
447 {
448 edges[EfB].Group = GID;
449 }
450
451 // update middle vertex refcounts
452 vertices_refcount.Increment(f, (unsigned short) FIncr);
453 if (BIncr > 0)
454 {
455 vertices_refcount.Increment(B, (unsigned short) BIncr);
456 }
457 if (BIncr < 0)
458 {
459 unsigned short BDecr = (unsigned short) (-BIncr);
461 }
462
463 Split.VNew = f;
464 Split.ENewBN = EfB;
465
466 updateTimeStamp(true);
467 return EMeshResult::Ok;
468 }
469
470protected:
471 virtual int append_new_split_vertex(int A, int B)
472 {
473 // Not Implemented: DGraph2.append_new_split_vertex
475 return InvalidID;
476 }
477
478public:
480 {
481 int VKept;
483
484 int ECollapsed; // edge we collapsed
485 };
487 {
488 bool DiscardIsolatedVertices = true;
489
490 if (IsVertex(VKeep) == false || IsVertex(VRemove) == false)
491 {
493 }
494
495 int B = VKeep; // renaming for sanity. We remove A and keep B
496 int A = VRemove;
497
498 int EAB = FindEdge(A, B);
499 if (EAB == InvalidID)
500 {
502 }
503
504 // get rid of any edges that will be duplicates
505 bool done = false;
506 while (!done)
507 {
508 done = true;
509 for (int eax : vertex_edges.Values(A))
510 {
511 int o = edge_other_v(eax, A);
512 if (o != B && FindEdge(B, o) != InvalidID)
513 {
515 done = false;
516 break;
517 }
518 }
519 }
520
522 for (int eax : vertex_edges.Values(A))
523 {
524 int o = edge_other_v(eax, A);
525 if (o == B)
526 {
527 continue; // discard this edge
528 }
529 replace_edge_vertex(eax, A, B);
531 vertex_edges.Insert(B, eax);
533 }
534
539 {
540 vertices_refcount.Decrement(A); // second Decrement discards isolated vtx
541 check(!IsVertex(A));
542 }
543
545
546 Collapse.VKept = VKeep;
547 Collapse.VRemoved = VRemove;
548 Collapse.ECollapsed = EAB;
549
550 updateTimeStamp(true);
551 return EMeshResult::Ok;
552 }
553
554protected:
555 bool edge_has_v(int EID, int VID) const
556 {
557 return (edges[EID].A == VID) || (edges[EID].B == VID);
558 }
559 int edge_other_v(int EID, int VID) const
560 {
561 int ev0 = edges[EID].A, ev1 = edges[EID].B;
562 return (ev0 == VID) ? ev1 : ((ev1 == VID) ? ev0 : InvalidID);
563 }
564 int replace_edge_vertex(int EID, int VOld, int VNew)
565 {
566 int A = edges[EID].A, B = edges[EID].B;
567 if (A == VOld)
568 {
569 edges[EID].A = FMath::Min(B, VNew);
570 edges[EID].B = FMath::Max(B, VNew);
571 return 0;
572 }
573 else if (B == VOld)
574 {
575 edges[EID].A = FMath::Min(A, VNew);
576 edges[EID].B = FMath::Max(A, VNew);
577 return 1;
578 }
579 else
580 return -1;
581 }
582
583public:
584 bool IsCompact() const
585 {
587 }
588 bool IsCompactV() const
589 {
590 return vertices_refcount.IsDense();
591 }
592
593 bool IsBoundaryVertex(int VID) const
594 {
595 return vertices_refcount.IsValid(VID) && vertex_edges.GetCount(VID) == 1;
596 }
597
598 bool IsJunctionVertex(int VID) const
599 {
600 return vertices_refcount.IsValid(VID) && vertex_edges.GetCount(VID) > 2;
601 }
602
603 bool IsRegularVertex(int VID) const
604 {
605 return vertices_refcount.IsValid(VID) && vertex_edges.GetCount(VID) == 2;
606 }
607
608
614 {
615 bool is_ok = true;
616 TFunction<void(bool)> CheckOrFailF = [&](bool b)
617 {
618 is_ok = is_ok && b;
619 };
621 {
622 CheckOrFailF = [&](bool b)
623 {
624 checkf(b, TEXT("FEdgeLoop::CheckValidity failed!"));
625 is_ok = is_ok && b;
626 };
627 }
629 {
630 CheckOrFailF = [&](bool b)
631 {
632 ensureMsgf(b, TEXT("FEdgeLoop::CheckValidity failed!"));
633 is_ok = is_ok && b;
634 };
635 }
636
637 // edge verts/tris must exist
638 for (int EID : EdgeIndices())
639 {
645 CheckOrFailF(ev[0] < ev[1]);
646 }
647
648 // verify compact check
650 if (is_compact)
651 {
652 for (int VID = 0; VID < VertexCount(); ++VID)
653 {
655 }
656 }
657
658 // vertex edges must exist and reference this vert
659 for (int VID : VertexIndices())
660 {
662
663 //FVector3d V = GetVertex(VID);
664 //CheckOrFailF(double.IsNaN(V.SquaredLength()) == false);
665 //CheckOrFailF(double.IsInfinity(V.SquaredLength()) == false);
666
667 for (int edgeid : vertex_edges.Values(VID))
668 {
671
672 int otherV = edge_other_v(edgeid, VID);
673 int e2 = FindEdge(VID, otherV);
676 e2 = FindEdge(otherV, VID);
679 }
680
682 }
683
685
686 return is_ok;
687 }
688
689protected:
690 virtual void subclass_validity_checks(TFunction<void(bool)> CheckOrFailF) const
691 {
692 }
693
694 inline void debug_check_is_vertex(int V) const
695 {
696 check(IsVertex(V));
697 }
698
699 inline void debug_check_is_edge(int E) const
700 {
701 check(IsEdge(E));
702 }
703};
704
710{
711public:
713 {
714 return append_vertex_internal();
715 }
716
717protected:
718 // internal used in SplitEdge
719 virtual int append_new_split_vertex(int A, int B) override
720 {
721 return AppendVertex();
722 }
723};
724
725
726} // end namespace UE::Geometry
727} // end namespace UE
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
EGLSurface EGLint timestamp
Definition AndroidOpenGLFunctions.h:13
#define check(expr)
Definition AssertionMacros.h:314
#define ensureMsgf( InExpression, InFormat,...)
Definition AssertionMacros.h:465
#define unimplemented()
Definition AssertionMacros.h:321
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
#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 Split(a, ahi, alo)
Definition Predicates.inl:204
Definition AndroidPlatformMisc.h:14
Definition DynamicGraph.h:710
int AppendVertex()
Definition DynamicGraph.h:712
virtual int append_new_split_vertex(int A, int B) override
Definition DynamicGraph.h:719
Definition DynamicGraph.h:25
int EdgeCount() const
Definition DynamicGraph.h:91
bool insert_vertex_internal(int32 Vid)
Definition DynamicGraph.h:192
bool IsCompact() const
Definition DynamicGraph.h:584
void updateTimeStamp(bool bShapeChange)
Definition DynamicGraph.h:68
int AllocateEdgeGroup()
Definition DynamicGraph.h:173
static FEdge InvalidEdge3()
Definition DynamicGraph.h:39
bool IsBoundaryVertex(int VID) const
Definition DynamicGraph.h:593
EMeshResult SplitEdge(int VA, int VB, FEdgeSplitInfo &Split)
Definition DynamicGraph.h:361
int replace_edge_vertex(int EID, int VOld, int VNew)
Definition DynamicGraph.h:564
void SetEdgeGroup(int EID, int GroupID)
Definition DynamicGraph.h:162
value_iteration< FEdge > Edges() const
Definition DynamicGraph.h:292
static constexpr int DuplicateEdgeID
Definition DynamicGraph.h:28
bool IsVertex(int VID) const
Definition DynamicGraph.h:110
int edge_other_v(int EID, int VID) const
Definition DynamicGraph.h:559
virtual void subclass_validity_checks(TFunction< void(bool)> CheckOrFailF) const
Definition DynamicGraph.h:690
FRefCountVector edges_refcount
Definition DynamicGraph.h:49
int GetMaxVtxEdgeCount() const
Definition DynamicGraph.h:142
int shape_timestamp
Definition DynamicGraph.h:53
int AppendEdge(int v0, int v1, int GID=-1)
Definition DynamicGraph.h:222
EMeshResult SplitEdgeWithExistingVertex(int EAB, int ExistingMidVert, FEdgeSplitInfo &Split)
Definition DynamicGraph.h:402
FSmallListSet::ValueEnumerable VtxEdgesItr(int VID) const
Definition DynamicGraph.h:131
int GetEdgeGroup(int EID) const
Definition DynamicGraph.h:157
virtual bool CheckValidity(EValidityCheckFailMode FailMode=EValidityCheckFailMode::Check) const
Definition DynamicGraph.h:613
bool IsRegularVertex(int VID) const
Definition DynamicGraph.h:603
EMeshResult RemoveVertex(int VID, bool bRemoveIsolatedVertices)
Definition DynamicGraph.h:345
static FIndex2i InvalidEdgeV()
Definition DynamicGraph.h:35
FIndex2i GetEdgeV(int EID) const
Definition DynamicGraph.h:152
void debug_check_is_edge(int E) const
Definition DynamicGraph.h:699
int append_vertex_internal()
Definition DynamicGraph.h:184
EMeshResult SplitEdge(int EAB, FEdgeSplitInfo &Split)
Definition DynamicGraph.h:370
int max_group_id
Definition DynamicGraph.h:55
TDynamicVector< FEdge > edges
Definition DynamicGraph.h:50
int FindEdge(int VA, int VB) const
Definition DynamicGraph.h:299
int Timestamp() const
Definition DynamicGraph.h:78
FDynamicGraph()
Definition DynamicGraph.h:58
void debug_check_is_vertex(int V) const
Definition DynamicGraph.h:694
bool IsEdge(int EID) const
Definition DynamicGraph.h:114
int add_edge(int A, int B, int GID)
Definition DynamicGraph.h:251
int MaxEdgeID() const
Definition DynamicGraph.h:101
int ShapeTimestamp() const
Definition DynamicGraph.h:82
vertex_iterator VertexIndices() const
Definition DynamicGraph.h:275
int VertexCount() const
Definition DynamicGraph.h:87
int AppendEdge(const FIndex2i &ev, int GID=-1)
Definition DynamicGraph.h:218
FRefCountVector::IndexEnumerable vertex_iterator
Definition DynamicGraph.h:274
bool edge_has_v(int EID, int VID) const
Definition DynamicGraph.h:555
FEdge GetEdge(int EID) const
Definition DynamicGraph.h:178
int AppendEdge(const FEdge &E)
Definition DynamicGraph.h:214
edge_iterator EdgeIndices() const
Definition DynamicGraph.h:281
static constexpr int InvalidID
Definition DynamicGraph.h:27
virtual int append_new_split_vertex(int A, int B)
Definition DynamicGraph.h:471
int MaxGroupID() const
Definition DynamicGraph.h:105
int timestamp
Definition DynamicGraph.h:52
EMeshResult CollapseEdge(int VKeep, int VRemove, FEdgeCollapseInfo &Collapse)
Definition DynamicGraph.h:486
FRefCountVector::IndexEnumerable edge_iterator
Definition DynamicGraph.h:280
bool IsJunctionVertex(int VID) const
Definition DynamicGraph.h:598
FSmallListSet vertex_edges
Definition DynamicGraph.h:47
FRefCountVector vertices_refcount
Definition DynamicGraph.h:45
EMeshResult RemoveEdge(int EID, bool bRemoveIsolatedVertices)
Definition DynamicGraph.h:313
virtual ~FDynamicGraph()
Definition DynamicGraph.h:63
int MaxVertexID() const
Definition DynamicGraph.h:97
int GetVtxEdgeCount(int VID) const
Definition DynamicGraph.h:137
bool IsCompactV() const
Definition DynamicGraph.h:588
FSmallListSet::MappedValueEnumerable VtxVerticesItr(int VID) const
Definition DynamicGraph.h:122
Definition RefCountVector.h:445
Definition RefCountVector.h:25
MappedEnumerable< ToType > MappedIndices(TFunction< ToType(int)> MapFunc) const
Definition RefCountVector.h:497
bool AllocateAt(int Index)
Definition RefCountVector.h:158
size_t GetMaxIndex() const
Definition RefCountVector.h:56
size_t GetCount() const
Definition RefCountVector.h:51
bool IsDense() const
Definition RefCountVector.h:61
void Decrement(int Index, unsigned short DecrementCount=1)
Definition RefCountVector.h:139
int GetRefCount(int Index) const
Definition RefCountVector.h:76
int Increment(int Index, unsigned short IncrementCount=1)
Definition RefCountVector.h:132
bool IsValid(int Index) const
Definition RefCountVector.h:66
int Allocate()
Definition RefCountVector.h:102
IndexEnumerable Indices() const
Definition RefCountVector.h:458
Definition SmallListSet.h:36
GEOMETRYCORE_API void AllocateAt(int32 ListIndex)
Definition SmallListSet.cpp:44
GEOMETRYCORE_API void Insert(int32 ListIndex, int32 Value)
Definition SmallListSet.cpp:195
size_t Size() const
Definition SmallListSet.h:75
ValueEnumerable Values(int32 ListIndex) const
Definition SmallListSet.h:571
GEOMETRYCORE_API bool Remove(int32 ListIndex, int32 Value)
Definition SmallListSet.cpp:242
MappedValueEnumerable MappedValues(int32 ListIndex, TFunction< int32(int32)> MapFunc) const
Definition SmallListSet.h:660
int32 GetCount(int32 ListIndex) const
Definition SmallListSet.h:155
GEOMETRYCORE_API void Clear(int32 ListIndex)
Definition SmallListSet.cpp:305
Definition DynamicVector.h:27
constexpr int InvalidID
Definition IndexTypes.h:13
EMeshResult
Definition GeometryTypes.h:18
EValidityCheckFailMode
Definition GeometryTypes.h:72
Definition AdvancedWidgetsModule.cpp:13
int ECollapsed
Definition DynamicGraph.h:484
int VRemoved
Definition DynamicGraph.h:482
int VKept
Definition DynamicGraph.h:481
Definition DynamicGraph.h:357
int VNew
Definition DynamicGraph.h:358
int ENewBN
Definition DynamicGraph.h:359
Definition DynamicGraph.h:31
int A
Definition DynamicGraph.h:32
int B
Definition DynamicGraph.h:32
int Group
Definition DynamicGraph.h:32
Definition IndexTypes.h:27