RavEngine
Loading...
Searching...
No Matches
ExtDelaunayTetrahedralizer.h
1// Redistribution and use in source and binary forms, with or without
2// modification, are permitted provided that the following conditions
3// are met:
4// * Redistributions of source code must retain the above copyright
5// notice, this list of conditions and the following disclaimer.
6// * Redistributions in binary form must reproduce the above copyright
7// notice, this list of conditions and the following disclaimer in the
8// documentation and/or other materials provided with the distribution.
9// * Neither the name of NVIDIA CORPORATION nor the names of its
10// contributors may be used to endorse or promote products derived
11// from this software without specific prior written permission.
12//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24//
25// Copyright (c) 2008-2022 NVIDIA Corporation. All rights reserved.
26
27#ifndef EXT_DELAUNAY_TETRAHEDRALIZER_H
28#define EXT_DELAUNAY_TETRAHEDRALIZER_H
29
30#include "foundation/PxArray.h"
31#include "foundation/PxVec3.h"
32#include "foundation/PxHashSet.h"
33#include "GuTetrahedron.h"
34#include "ExtVec3.h"
35
36namespace physx
37{
38
39namespace Ext
40{
41 using Edge = PxPair<PxI32, PxI32>;
42 using Tetrahedron = Gu::TetrahedronT<PxI32>;
43 using Tetrahedron16 = Gu::TetrahedronT<PxI16>;
44
45 void buildNeighborhood(const PxArray<Tetrahedron>& tets, PxArray<PxI32>& result);
46 void buildNeighborhood(const PxI32* tets, PxU32 numTets, PxArray<PxI32>& result);
47
48 PX_FORCE_INLINE PxF64 tetVolume(const Vec3& a, const Vec3& b, const Vec3& c, const Vec3& d)
49 {
50 return (-1.0 / 6.0) * (a - d).dot((b - d).cross(c - d));
51 }
52
53 PX_FORCE_INLINE PxF64 tetVolume(const Tetrahedron& tet, const PxArray<Vec3>& points)
54 {
55 return tetVolume(points[tet[0]], points[tet[1]], points[tet[2]], points[tet[3]]);
56 }
57
58 //Returns the intersection (set operation) of two sorted lists
59 PX_FORCE_INLINE void intersectionOfSortedLists(const PxArray<PxI32>& sorted1, const PxArray<PxI32>& sorted2, PxArray<PxI32>& result)
60 {
61 PxU32 a = 0;
62 PxU32 b = 0;
63 result.clear();
64 while (a < sorted1.size() && b < sorted2.size())
65 {
66 if (sorted1[a] == sorted2[b])
67 {
68 result.pushBack(sorted1[a]);
69 ++a;
70 ++b;
71 }
72 else if (sorted1[a] > sorted2[b])
73 ++b;
74 else
75 ++a;
76 }
77 }
78
79 PX_FORCE_INLINE bool intersectionOfSortedListsContainsElements(const PxArray<PxI32>& sorted1, const PxArray<PxI32>& sorted2)
80 {
81 PxU32 a = 0;
82 PxU32 b = 0;
83 while (a < sorted1.size() && b < sorted2.size())
84 {
85 if (sorted1[a] == sorted2[b])
86 return true;
87 else if (sorted1[a] > sorted2[b])
88 ++b;
89 else
90 ++a;
91 }
92 return false;
93 }
94
95
97 {
98 public:
99 virtual PxF64 quality(const PxArray<PxI32> tetIndices) const = 0;
100
101 virtual PxF64 quality(const PxArray<Tetrahedron> tetrahedraToCheck) const = 0;
102
103 virtual bool improved(PxF64 previousQuality, PxF64 newQuality) const = 0;
104
105 virtual ~BaseTetAnalyzer() {}
106 };
107
109 {
110 const PxArray<Vec3>& points;
111 const PxArray<Tetrahedron>& tetrahedra;
112
113 public:
114 MinimizeMaxAmipsEnergy(const PxArray<Vec3>& points_, const PxArray<Tetrahedron>& tetrahedra_) : points(points_), tetrahedra(tetrahedra_)
115 {}
116
117 PxF64 quality(const PxArray<PxI32> tetIndices) const;
118
119 PxF64 quality(const PxArray<Tetrahedron> tetrahedraToCheck) const;
120
121 bool improved(PxF64 previousQuality, PxF64 newQuality) const;
122
123 virtual ~MinimizeMaxAmipsEnergy() {}
124
125 private:
126 PX_NOCOPY(MinimizeMaxAmipsEnergy)
127 };
128
130 {
131 const PxArray<Vec3>& points;
132 const PxArray<Tetrahedron>& tetrahedra;
133
134 public:
135 MaximizeMinTetVolume(const PxArray<Vec3>& points_, const PxArray<Tetrahedron>& tetrahedra_) : points(points_), tetrahedra(tetrahedra_)
136 {}
137
138 PxF64 quality(const PxArray<PxI32> tetIndices) const;
139
140 PxF64 quality(const PxArray<Tetrahedron> tetrahedraToCheck) const;
141
142 bool improved(PxF64 previousQuality, PxF64 newQuality) const;
143
144 virtual ~MaximizeMinTetVolume() {}
145
146 private:
147 PX_NOCOPY(MaximizeMinTetVolume)
148 };
149
150
151
152 //Helper class to extract surface triangles from a tetmesh
154 {
155 public:
156 PxI32 A;
157 PxI32 B;
158 PxI32 C;
159 bool Flipped;
160
161 PX_FORCE_INLINE SortedTriangle(PxI32 a, PxI32 b, PxI32 c)
162 {
163 A = a; B = b; C = c; Flipped = false;
164 if (A > B) { PxSwap(A, B); Flipped = !Flipped; }
165 if (B > C) { PxSwap(B, C); Flipped = !Flipped; }
166 if (A > B) { PxSwap(A, B); Flipped = !Flipped; }
167 }
168 };
169
171 {
172 PX_FORCE_INLINE std::size_t operator()(const SortedTriangle& k) const
173 {
174 return k.A ^ k.B ^ k.C;
175 }
176
177 PX_FORCE_INLINE bool equal(const SortedTriangle& first, const SortedTriangle& second) const
178 {
179 return first.A == second.A && first.B == second.B && first.C == second.C;
180 }
181 };
182
183
185 {
186 PxArray<PxI32> facesStart;
187 PxHashSet<PxI32> tetsDoneStart;
188 PxArray<PxI32> resultStart;
189 PxArray<PxI32> facesEnd;
190 PxHashSet<PxI32> tetsDoneEnd;
191 PxArray<PxI32> resultEnd;
192 };
193
195 {
196 public:
197
198 void clear()
199 {
200 faces.forceSize_Unsafe(0);
201 hashSet.clear();
202 }
203
204 PxArray<PxI32> faces;
205 PxHashSet<PxI32> hashSet;
206
207 };
208
209 //Incremental delaunay tetrahedralizer
211 {
212 public:
213 //The bounds specified must contain all points that will get inserted by calling insertPoints.
214 DelaunayTetrahedralizer(const Vec3& min, const Vec3& max);
215
217
218 void initialize(PxArray<Vec3>& points, PxArray<Tetrahedron>& tets);
219
220 //Inserts a bunch of new points into the tetrahedralization and keeps the delaunay condition satisfied. The new result will
221 //get stored in the tetrahedra array. Points to insert must already be present in inPoints, the indices of the points to insert
222 //can be controlled with start and end index (end index is exclusive, start index is inclusive)
223 void insertPoints(const PxArray<Vec3>& inPoints, PxI32 start, PxI32 end, PxArray<Tetrahedron>& tetrahedra);
224
225 bool insertPoints(const PxArray<Vec3>& inPoints, PxI32 start, PxI32 end);
226
227 void exportTetrahedra(PxArray<Tetrahedron>& tetrahedra);
228
229 bool canCollapseEdge(PxI32 edgeVertexToKeep, PxI32 edgeVertexToRemove, PxF64 volumeChangeThreshold = 0.1, BaseTetAnalyzer* tetAnalyzer = NULL);
230 bool canCollapseEdge(PxI32 edgeVertexToKeep, PxI32 edgeVertexToRemove, const PxArray<PxI32>& tetsConnectedToA, const PxArray<PxI32>& tetsConnectedToB,
231 PxF64& qualityAfterCollapse, PxF64 volumeChangeThreshold = 0.1, BaseTetAnalyzer* tetAnalyzer = NULL);
232
233 void collapseEdge(PxI32 edgeVertexToKeep, PxI32 edgeVertexToRemove);
234
235 void collapseEdge(PxI32 edgeVertexAToKeep, PxI32 edgeVertexBToRemove, const PxArray<PxI32>& tetsConnectedToA, const PxArray<PxI32>& tetsConnectedToB);
236
237 void collectTetsConnectedToVertex(PxI32 vertexIndex, PxArray<PxI32>& tetIds);
238
239 void collectTetsConnectedToVertex(PxArray<PxI32>& faces, PxHashSet<PxI32>& tetsDone, PxI32 vertexIndex, PxArray<PxI32>& tetIds);
240
241 void collectTetsConnectedToEdge(PxI32 edgeStart, PxI32 edgeEnd, PxArray<PxI32>& tetIds);
242
243 PX_FORCE_INLINE const Vec3& point(PxI32 index) const { return centeredNormalizedPoints[index]; }
244
245 PX_FORCE_INLINE PxU32 numPoints() const { return centeredNormalizedPoints.size(); }
246
247 PX_FORCE_INLINE PxArray<Vec3>& points() { return centeredNormalizedPoints; }
248 PX_FORCE_INLINE const PxArray<Vec3>& points() const { return centeredNormalizedPoints; }
249
250 PxU32 addPoint(const Vec3& p)
251 {
252 centeredNormalizedPoints.pushBack(p);
253 vertexToTet.pushBack(-1);
254 return centeredNormalizedPoints.size() - 1;
255 }
256
257 PX_FORCE_INLINE const Tetrahedron& tetrahedron(PxI32 index) const { return result[index]; }
258
259 PX_FORCE_INLINE PxU32 numTetrahedra() const { return result.size(); }
260
261 PX_FORCE_INLINE PxArray<Tetrahedron>& tetrahedra() { return result; }
262 PX_FORCE_INLINE const PxArray<Tetrahedron>& tetrahedra() const { return result; }
263
264 void copyInternalPointsTo(PxArray<Vec3>& points) { points = centeredNormalizedPoints; }
265
266 bool optimizeByFlipping(PxArray<PxI32>& affectedFaces, const BaseTetAnalyzer& qualityAnalyzer);
267
268 void insertPointIntoEdge(PxI32 newPointIndex, PxI32 edgeA, PxI32 edgeB, PxArray<PxI32>& affectedTets, BaseTetAnalyzer* qualityAnalyzer = NULL);
269
270 bool removeEdgeByFlip(PxI32 edgeA, PxI32 edgeB, PxArray<PxI32>& tetIndices, BaseTetAnalyzer* qualityAnalyzer = NULL);
271
272 void addLockedEdges(const PxArray<Gu::IndexedTriangleT<PxI32>>& triangles);
273
274 void addLockedTriangles(const PxArray<Gu::IndexedTriangleT<PxI32>>& triangles);
275
276 void clearLockedEdges() { lockedEdges.clear(); }
277
278 void clearLockedTriangles() { lockedTriangles.clear(); }
279
280 bool recoverEdgeByFlip(PxI32 eStart, PxI32 eEnd, RecoverEdgeMemoryCache& cache);
281
282 void generateTetmeshEnforcingEdges(const PxArray<Vec3>& trianglePoints, const PxArray<Gu::IndexedTriangleT<PxI32>>& triangles, PxArray<PxArray<PxI32>>& allEdges,
283 PxArray<PxArray<PxI32>>& pointToOriginalTriangle,
284 PxArray<Vec3>& points, PxArray<Tetrahedron>& finalTets);
285
286 private:
287 PxArray<Vec3> centeredNormalizedPoints;
288 PxArray<PxI32> neighbors;
289 PxArray<PxI32> unusedTets;
290 PxArray<PxI32> vertexToTet;
292 PxI32 numAdditionalPointsAtBeginning = 4;
293
295 PxHashSet<PxU64> lockedEdges;
296
297 StackMemory stackMemory;
298 PX_NOCOPY(DelaunayTetrahedralizer)
299 };
300
302 {
303 PxI32 A;
304 PxI32 B;
305 PxF64 Length;
306
307 EdgeWithLength(PxI32 a_, PxI32 b_, PxF64 length_)
308 {
309 A = a_;
310 B = b_;
311 Length = length_;
312 }
313 };
314
315 PX_FORCE_INLINE bool operator <(const EdgeWithLength& lhs, const EdgeWithLength& rhs)
316 {
317 return lhs.Length < rhs.Length;
318 }
319
321 {
322 PxI32 A;
323 PxI32 B;
324 PxF64 Q;
325 PxF64 L;
326 bool InteriorEdge;
327
328 SplitEdge(PxI32 a, PxI32 b, PxF64 q, PxF64 l, bool interiorEdge)
329 {
330 A = a;
331 B = b;
332 Q = q;
333 L = l;
334 InteriorEdge = interiorEdge;
335 }
336 };
337
338 PX_FORCE_INLINE bool operator >(const SplitEdge& lhs, const SplitEdge& rhs)
339 {
340 if (lhs.Q == rhs.Q)
341 return lhs.L > rhs.L;
342 return lhs.Q > rhs.Q;
343 }
344
345
346 bool optimizeByCollapsing(DelaunayTetrahedralizer& del, const PxArray<EdgeWithLength>& edges,
347 PxArray<PxArray<PxI32>>& pointToOriginalTriangle, PxI32 numFixPoints, BaseTetAnalyzer* qualityAnalyzer = NULL);
348
349 bool optimizeBySwapping(DelaunayTetrahedralizer& del, const PxArray<EdgeWithLength>& edges,
350 const PxArray<PxArray<PxI32>>& pointToOriginalTriangle, BaseTetAnalyzer* qualityAnalyzer);
351
352 bool optimizeBySplitting(DelaunayTetrahedralizer& del, const PxArray<EdgeWithLength>& edges, const PxArray<PxArray<PxI32>>& pointToOriginalTriangle,
353 PxI32 maxPointsToInsert = -1, bool sortByQuality = false, BaseTetAnalyzer* qualityAnalyzer = NULL, PxF64 qualityThreshold = 10);
354
355 //Modified tetmesh quality improvement implementation of the method described in https://cs.nyu.edu/~yixinhu/tetwild.pdf Section 3.2 Mesh Improvement
356 void optimize(DelaunayTetrahedralizer& del, PxArray<PxArray<PxI32>>& pointToOriginalTriangle, PxI32 numFixPoints,
357 PxArray<Vec3>& optimizedPoints, PxArray<Tetrahedron>& optimizedTets, PxI32 numPasses = 10);
358}
359}
360
361#endif
362
Definition ExtDelaunayTetrahedralizer.h:97
Definition ExtDelaunayTetrahedralizer.h:211
Definition ExtDelaunayTetrahedralizer.h:130
Definition ExtDelaunayTetrahedralizer.h:109
Definition ExtDelaunayTetrahedralizer.h:195
Definition ExtVec3.h:39
Definition PxArray.h:53
PX_FORCE_INLINE void forceSize_Unsafe(uint32_t size)
Definition PxArray.h:507
PX_FORCE_INLINE T & pushBack(const T &a)
Definition PxArray.h:296
Definition PxHashSet.h:77
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39
Definition ExtDelaunayTetrahedralizer.h:302
Definition ExtDelaunayTetrahedralizer.h:185
Definition ExtDelaunayTetrahedralizer.h:321
Definition ExtDelaunayTetrahedralizer.h:171
Definition GuTriangle.h:48
Definition GuPCMContactConvexCommon.h:340