UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
MeshFaceSelection.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3// Port of geometry3cpp MeshFaceSelection
4
5#pragma once
6
9#include "EdgeLoop.h"
10
11namespace UE
12{
13namespace Geometry
14{
15
16class FMeshVertexSelection;
17class FMeshEdgeSelection;
18
19
21{
22private:
23 const FDynamicMesh3* Mesh;
24
25 TSet<int> Selected;
26
27public:
28
30 {
31 Mesh = mesh;
32 }
33
34 // convert vertex selection to face selection. Require at least minCount verts of
35 // tri to be selected (valid values are 1,2,3)
37
38 // select a group
43
48 TSet<int>::TRangedForIterator begin() { return Selected.begin(); }
49 TSet<int>::TRangedForConstIterator begin() const { return Selected.begin(); }
50 TSet<int>::TRangedForIterator end() { return Selected.end(); }
51 TSet<int>::TRangedForConstIterator end() const { return Selected.end(); }
52
53
54private:
55
56 void add(int tid)
57 {
58 Selected.Add(tid);
59 }
60 void remove(int tid)
61 {
62 Selected.Remove(tid);
63 }
64
65public:
66
67
68 int Num() const
69 {
70 return Selected.Num();
71 }
72
73
74
75 bool IsSelected(int tid) const
76 {
77 return Selected.Contains(tid);
78 }
79
80 bool Contains(int tid) const
81 {
82 return Selected.Contains(tid);
83 }
84
85 void Select(int tid)
86 {
87 ensure(Mesh->IsTriangle(tid));
88 if (Mesh->IsTriangle(tid))
89 {
90 add(tid);
91 }
92 }
93
96 {
97 for (int32 tid : Enumerable)
98 {
99 if (Mesh->IsTriangle(tid))
100 {
101 add(tid);
102 }
103 }
104 }
105
106 void Select(TFunctionRef<bool(int)> SelectF)
107 {
108 int NT = Mesh->MaxTriangleID();
109 for (int tID = 0; tID < NT; ++tID)
110 {
111 if (Mesh->IsTriangle(tID) && SelectF(tID))
112 {
113 add(tID);
114 }
115 }
116 }
117
118
119 void SelectVertexOneRing(int vid)
120 {
121 Mesh->EnumerateVertexTriangles(vid, [&](int tid)
122 {
123 add(tid);
124 });
125 }
127 {
128 for (int vid : Vertices)
129 {
131 }
132 }
133
135 {
136 FIndex2i et = Mesh->GetEdgeT(eid);
137 add(et.A);
139 {
140 add(et.B);
141 }
142 }
143
144
145 void Deselect(int tid)
146 {
147 remove(tid);
148 }
150 {
151 for (int TID : Triangles)
152 {
153 remove(TID);
154 }
155 }
156
157 template<typename EnumerableType>
159 {
160 for (int32 tid : Enumerable)
161 {
162 remove(tid);
163 }
164 }
165
167 {
168 Selected.Empty();
169 }
170
171
172 void SelectGroup(int gid)
173 {
174 int NT = Mesh->MaxTriangleID();
175 for (int tid = 0; tid < NT; ++tid)
176 {
177 if (Mesh->IsTriangle(tid) && Mesh->GetTriangleGroup(tid) == gid)
178 {
179 add(tid);
180 }
181 }
182 }
184 {
185 int NT = Mesh->MaxTriangleID();
186 for (int tid = 0; tid < NT; ++tid)
187 {
188 if (Mesh->IsTriangle(tid) && Mesh->GetTriangleGroup(tid) != gid)
189 {
190 add(tid);
191 }
192 }
193 }
195 {
196 // cannot just iterate over selected tris because remove() will change them...
197 int NT = Mesh->MaxTriangleID();
198 for (int tid = 0; tid < NT; ++tid)
199 {
200 if (Mesh->IsTriangle(tid) && Mesh->GetTriangleGroup(tid) == gid)
201 {
202 remove(tid);
203 }
204 }
205 }
206
210 template<typename EnumerableType, typename StorageType>
212 {
213 for ( int32 tid : Selected )
214 {
215 if (SubtractSet.Contains(tid) == false)
216 {
218 }
219 }
220 }
221
225 template<typename EnumerableType, typename StorageType>
227 {
228 for (int32 tid : Selected)
229 {
230 if (IntersectSet.Contains(tid))
231 {
233 }
234 }
235 }
236
237 const TSet<int>& AsSet() const
238 {
239 return Selected;
240 }
242 {
243 return Selected.Array();
244 }
246 {
247 TBitArray<FDefaultBitArrayAllocator> Bitmap(false, Mesh->MaxTriangleID());
248 for (int tid : Selected)
249 {
250 Bitmap[tid] = true;
251 }
252 return Bitmap;
253 }
254
259 {
260 if (Mesh->IsEdge(eid))
261 {
262 FIndex2i EdgeT = Mesh->GetEdgeT(eid);
263 bool bA = Selected.Contains(EdgeT.A);
265 {
266 return TPair<bool, bool>(true, true);
267 }
268 else if (Selected.Contains(EdgeT.B) != bA)
269 {
270 return TPair<bool, bool>(true, false);
271 }
272 }
273 return TPair<bool, bool>(false, false);
274 }
275
276
281 {
282 TArray<int> result;
283 for (int tid : Selected)
284 {
285 FIndex3i nbr_tris = Mesh->GetTriNeighbourTris(tid);
286 for (int j = 0; j < 3; ++j)
287 {
288 if (nbr_tris[j] != FDynamicMesh3::InvalidID && IsSelected(nbr_tris[j]) == false)
289 {
290 result.Add(nbr_tris[j]);
291 }
292 }
293 }
294 return result;
295 }
296
297
302 {
303 TArray<int> result;
304 for (int tid : Selected)
305 {
306 FIndex3i nbr_tris = Mesh->GetTriNeighbourTris(tid);
307 if (IsSelected(nbr_tris.A) == false || IsSelected(nbr_tris.B) == false || IsSelected(nbr_tris.C) == false)
308 {
309 result.Add(tid);
310 }
311 }
312 return result;
313 }
314
315
316 void ExpandToFaceNeighbours(const TUniqueFunction<bool(int)>& FilterF = nullptr)
317 {
319
320 for (int tid : Selected) {
321 FIndex3i nbr_tris = Mesh->GetTriNeighbourTris(tid);
322 for (int j = 0; j < 3; ++j)
323 {
324 if (FilterF && FilterF(nbr_tris[j]) == false)
325 {
326 continue;
327 }
329 {
330 ToAdd.Add(nbr_tris[j]);
331 }
332 }
333 }
334
335 for (int ID : ToAdd)
336 {
337 add(ID);
338 }
339 }
340 void ExpandToFaceNeighbours(int rounds, const TUniqueFunction<bool(int)>& FilterF = nullptr)
341 {
342 for (int k = 0; k < rounds; ++k)
343 {
345 }
346 }
347
348
356 GEOMETRYCORE_API void ExpandToOneRingNeighbours(const TUniqueFunction<bool(int)>& FilterF = nullptr);
357
365 GEOMETRYCORE_API void ExpandToOneRingNeighbours(int nRings, const TUniqueFunction<bool(int)>& FilterF = nullptr);
366
375
380 void FloodFill(int tSeed, const TUniqueFunction<bool(int)>& TriFilterF = nullptr, const TUniqueFunction<bool(int)>& EdgeFilterF = nullptr)
381 {
382 TArray<int> Seeds = { tSeed };
384 }
389 void FloodFill(const TArray<int>& Seeds, const TUniqueFunction<bool(int)>& TriFilterF = nullptr, const TUniqueFunction<bool(int)>& EdgeFilterF = nullptr)
390 {
392 for (int Seed : Seeds)
393 {
394 add(Seed);
395 }
396 while (stack.Num() > 0)
397 {
398 int TID = stack.Back();
399 stack.PopBack();
400
401 FIndex3i nbrs = Mesh->GetTriNeighbourTris(TID);
402 for (int j = 0; j < 3; ++j)
403 {
404 int nbr_tid = nbrs[j];
406 {
407 continue;
408 }
409 if (TriFilterF && TriFilterF(nbr_tid) == false)
410 {
411 continue;
412 }
413 int EID = Mesh->GetTriEdge(TID, j);
414 if (EdgeFilterF && EdgeFilterF(EID) == false)
415 {
416 continue;
417 }
418 add(nbr_tid);
419
420 stack.Add(nbr_tid);
421 }
422 }
423 }
424
425
426
427 // return true if we clipped something
429 {
430 TArray<int> ToRemove; // temp array so we don't remove as we iterate the set
431 for (int tid : Selected)
432 {
433 if (is_fin(tid, bClipLoners))
434 {
436 }
437 }
438 for (int tid : ToRemove)
439 {
440 remove(tid);
441 }
442 return ToRemove.Num() > 0;
443 }
444
445
446 // return true if we filled any ears.
448 {
449 // [TODO] not efficient! checks each nbr 3 times !! ugh!!
451 for (int tid : Selected)
452 {
453 FIndex3i nbr_tris = Mesh->GetTriNeighbourTris(tid);
454 for (int j = 0; j < 3; ++j)
455 {
456 int nbr_t = nbr_tris[j];
457 if (IsSelected(nbr_t))
458 {
459 continue;
460 }
461 if (is_ear(nbr_t, bFillTinyHoles))
462 {
463 temp.Add(nbr_t);
464 }
465 }
466 }
467 for (int tid : temp)
468 {
469 add(tid);
470 }
471 return temp.Num() > 0;
472 }
473
474 // returns true if selection was modified
475 bool LocalOptimize(bool bClipFins, bool bFillEars, bool bFillTinyHoles = true, bool bClipLoners = true, bool bRemoveBowties = false)
476 {
477 bool bModified = false;
478 bool done = false;
479 int count = 0;
480 do
481 {
485 done = !(bDidClip || bDidEars || bDidBows); // only done if did nothing this pass
486 bModified = bModified || !done;
487 } while (!done && count++ < 25);
488 if (bRemoveBowties)
489 {
490 remove_bowties(); // do a final pass of this because it is usually the most problematic...
491 }
492 return bModified;
493 }
494
496 {
497 return LocalOptimize(true, true, true, true, bRemoveBowties);
498 }
499
500
501
502
509 return remove_bowties();
510 }
512 {
514 bool bModified = false;
515 bool done = false;
516 TSet<int> vertices;
517 while (!done)
518 {
519 done = true;
520 vertices.Empty();
521 for (int tid : Selected)
522 {
523 FIndex3i tv = Mesh->GetTriangle(tid);
524 vertices.Add(tv.A); vertices.Add(tv.B); vertices.Add(tv.C);
525 }
526
527 for (int vid : vertices)
528 {
529 if (is_bowtie_vtx(vid))
530 {
531 Mesh->EnumerateVertexTriangles(vid, [&](int TID)
532 {
533 Deselect(TID);
534 });
535 done = false;
536 }
537 }
538 if (done == false)
539 {
540 bModified = true;
541 }
542 }
543 return bModified;
544 }
545
546private:
547 bool is_bowtie_vtx(int vid) const
548 {
549 int border_edges = 0;
550 for (int eid : Mesh->VtxEdgesItr(vid))
551 {
552 FIndex2i et = Mesh->GetEdgeT(eid);
554 {
555 bool in_a = IsSelected(et.A);
556 bool in_b = IsSelected(et.B);
557 if (in_a != in_b)
558 {
559 border_edges++;
560 }
561 }
562 else
563 {
564 if (IsSelected(et.A))
565 {
566 border_edges++;
567 }
568 }
569 }
570 return border_edges > 2;
571 }
572
573 void count_nbrs(int tid, int& nbr_in, int& nbr_out, int& bdry_e) const
574 {
575 FIndex3i nbr_tris = Mesh->GetTriNeighbourTris(tid);
576 nbr_in = 0; nbr_out = 0; bdry_e = 0;
577 for ( int j = 0; j < 3; ++j )
578 {
579 int nbr_t = nbr_tris[j];
581 {
582 bdry_e++;
583 }
584 else if (IsSelected(nbr_t) == true)
585 {
586 nbr_in++;
587 }
588 else
589 {
590 nbr_out++;
591 }
592 }
593 }
594 bool is_ear(int tid, bool include_tiny_holes) const
595 {
596 if (IsSelected(tid) == true)
597 {
598 return false;
599 }
600 int nbr_in, nbr_out, bdry_e;
601 count_nbrs(tid, nbr_in, nbr_out, bdry_e);
602 if (bdry_e == 2 && nbr_in == 1)
603 {
604 return true; // unselected w/ 2 boundary edges, nbr is in
605 }
606 else if (nbr_in == 2)
607 {
608 if (bdry_e == 1 || nbr_out == 1)
609 {
610 return true; // unselected w/ 2 selected nbrs
611 }
612 }
613 else if (include_tiny_holes && nbr_in == 3)
614 {
615 return true;
616 }
617 return false;
618 }
619 bool is_fin(int tid, bool include_loners) const
620 {
621 if (IsSelected(tid) == false)
622 {
623 return false;
624 }
625 int nbr_in, nbr_out, bdry_e;
626 count_nbrs(tid, nbr_in, nbr_out, bdry_e);
627 return (nbr_in == 1 && nbr_out == 2) ||
628 (include_loners == true && nbr_in == 0 && nbr_out == 3);
629 }
630
631
632};
633
634
635} // end namespace UE::Geometry
636} // end namespace UE
#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
Definition ArrayView.h:139
Definition Array.h:670
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
Definition BitArray.h:350
Definition AssetRegistryState.h:50
Definition FunctionFwd.h:19
Definition DynamicMesh3.h:108
static constexpr int InvalidID
Definition DynamicMesh3.h:158
Definition MeshFaceSelection.h:21
GEOMETRYCORE_API void ContractBorderByOneRingNeighbours(int NumRings=1, bool bContractFromMeshBoundary=false, const TUniqueFunction< bool(int)> &FilterF=nullptr)
Definition MeshFaceSelection.cpp:149
int Num() const
Definition MeshFaceSelection.h:68
TSet< int >::TRangedForConstIterator end() const
Definition MeshFaceSelection.h:51
bool LocalOptimize(bool bClipFins, bool bFillEars, bool bFillTinyHoles=true, bool bClipLoners=true, bool bRemoveBowties=false)
Definition MeshFaceSelection.h:475
bool Contains(int tid) const
Definition MeshFaceSelection.h:80
void SelectVertexOneRing(int vid)
Definition MeshFaceSelection.h:119
TSet< int >::TRangedForIterator begin()
Definition MeshFaceSelection.h:48
void Select(int tid)
Definition MeshFaceSelection.h:85
TSet< int >::TRangedForIterator end()
Definition MeshFaceSelection.h:50
bool RemoveBowties()
Definition MeshFaceSelection.h:508
void SetDifference(const EnumerableType &SubtractSet, StorageType &DifferenceStorage) const
Definition MeshFaceSelection.h:211
bool LocalOptimize(bool bRemoveBowties=true)
Definition MeshFaceSelection.h:495
void SelectEdgeTris(int eid)
Definition MeshFaceSelection.h:134
const TSet< int > & AsSet() const
Definition MeshFaceSelection.h:237
bool ClipFins(bool bClipLoners)
Definition MeshFaceSelection.h:428
void FloodFill(int tSeed, const TUniqueFunction< bool(int)> &TriFilterF=nullptr, const TUniqueFunction< bool(int)> &EdgeFilterF=nullptr)
Definition MeshFaceSelection.h:380
bool remove_bowties()
Definition MeshFaceSelection.h:511
TSet< int >::TRangedForConstIterator begin() const
Definition MeshFaceSelection.h:49
bool IsSelected(int tid) const
Definition MeshFaceSelection.h:75
void SetIntersection(const EnumerableType &IntersectSet, StorageType &IntersectionStorage) const
Definition MeshFaceSelection.h:226
void Deselect(TArrayView< const int > Triangles)
Definition MeshFaceSelection.h:149
void SelectGroupInverse(int gid)
Definition MeshFaceSelection.h:183
void DeselectAll()
Definition MeshFaceSelection.h:166
TArray< int > FindBorderTris() const
Definition MeshFaceSelection.h:301
GEOMETRYCORE_API void ExpandToOneRingNeighbours(const TUniqueFunction< bool(int)> &FilterF=nullptr)
Definition MeshFaceSelection.cpp:53
bool FillEars(bool bFillTinyHoles)
Definition MeshFaceSelection.h:447
FMeshFaceSelection(const FDynamicMesh3 *mesh)
Definition MeshFaceSelection.h:29
TArray< int > AsArray() const
Definition MeshFaceSelection.h:241
TBitArray< FDefaultBitArrayAllocator > AsBitArray() const
Definition MeshFaceSelection.h:245
void ExpandToFaceNeighbours(const TUniqueFunction< bool(int)> &FilterF=nullptr)
Definition MeshFaceSelection.h:316
FMeshFaceSelection(const FDynamicMesh3 *mesh, int group_id)
Definition MeshFaceSelection.h:39
void ExpandToFaceNeighbours(int rounds, const TUniqueFunction< bool(int)> &FilterF=nullptr)
Definition MeshFaceSelection.h:340
void Deselect(const EnumerableType &Enumerable)
Definition MeshFaceSelection.h:158
void FloodFill(const TArray< int > &Seeds, const TUniqueFunction< bool(int)> &TriFilterF=nullptr, const TUniqueFunction< bool(int)> &EdgeFilterF=nullptr)
Definition MeshFaceSelection.h:389
TPair< bool, bool > IsSelectionBoundaryEdge(int32 eid) const
Definition MeshFaceSelection.h:258
void Deselect(int tid)
Definition MeshFaceSelection.h:145
TArray< int > FindNeighbourTris() const
Definition MeshFaceSelection.h:280
void SelectVertexOneRings(TArrayView< const int > Vertices)
Definition MeshFaceSelection.h:126
void Select(TFunctionRef< bool(int)> SelectF)
Definition MeshFaceSelection.h:106
void Select(const EnumerableType &Enumerable)
Definition MeshFaceSelection.h:95
void DeselectGroup(int gid)
Definition MeshFaceSelection.h:194
void SelectGroup(int gid)
Definition MeshFaceSelection.h:172
Definition MeshVertexSelection.h:19
Definition DynamicVector.h:27
void Add(const Type &Data)
Definition DynamicVector.h:662
const Type & Back() const
Definition DynamicVector.h:167
void PopBack()
Definition DynamicVector.h:717
size_t Num() const
Definition DynamicVector.h:147
constexpr int InvalidID
Definition IndexTypes.h:13
@ Mesh
Definition VulkanCommon.h:39
Definition AdvancedWidgetsModule.cpp:13
Definition Tuple.h:652
Definition IndexTypes.h:27
Definition IndexTypes.h:158