Enzo
Loading...
Searching...
No Matches
Mesh.h
1#pragma once
2#include "Engine/Primitives/Primitive.h"
3#include <CGAL/Simple_cartesian.h>
4#include <CGAL/Surface_mesh/Surface_mesh.h>
5#include <span>
6#include <tbb/spin_mutex.h>
7#include <unordered_set>
8
9namespace enzo::geo {
10using Kernel = CGAL::Simple_cartesian<double>;
11using Point = Kernel::Point_3;
12using Vector = Kernel::Vector_3;
13using HeMesh = CGAL::Surface_mesh<Point>;
14using vertexDescriptor = HeMesh::Vertex_index;
15using faceDescriptor = HeMesh::Face_index;
16using V_index = HeMesh::Vertex_index;
17using F_index = HeMesh::Face_index;
18
19class Mesh;
20class FaceNormalHandle;
21class VertexNormalHandle;
22
31class Mesh : public Primitive
32{
33 public:
34 Mesh(std::string_view path = "/mesh");
35 Mesh(const Mesh& other);
36 Mesh& operator=(const Mesh& rhs);
37 ~Mesh() override = default;
38
39 PrimType getType() const override { return PrimType::MESH; }
40 std::shared_ptr<Primitive> clone() const override { return std::make_shared<Mesh>(*this); }
41 TransformClass transformType() const override
42 {
43 return TransformClass::POINT | TransformClass::PRIMITIVE;
44 }
45 void applyTransform(
46 const Matrix4& mat,
47 TransformClass transformClass = TransformClass::POINT
48 ) override;
49 void applyTransform(
50 const Transform& transform,
51 TransformClass transformClass = TransformClass::POINT
52 )
53 {
54 applyTransform(transform.getMatrix(), transformClass);
55 }
56 bool canMerge() const override { return true; }
57 void merge(std::shared_ptr<Primitive> other) override;
58 bool hasPoints() const override { return true; }
59
65 // TODO: benchmark addFace vs addFaces to quantify the speedup
66 Offset addFace(const std::vector<Offset>& pointOffsets, bool closed = true);
75 std::vector<Offset> addFaces(
76 std::span<const Offset> pointOffsetsFlat,
77 std::span<const Offset> vertexCounts,
78 bool closed = true
79 );
80 Offset addPoint(const Vector3& pos);
87 std::vector<Offset> addPoints(std::span<const Vector3> positions);
96 std::vector<Offset>
97 duplicatePoints(std::span<const Offset> srcPointOffsets, bool copyAttributes = true);
98
99 void deleteFaces(const std::vector<Offset>& faceOffsets, bool andPoints = true);
101 void deleteAllFaces(bool andPoints = true);
102 void deletePoints(const std::vector<Offset>& pointOffsets) override
103 {
104 deletePoints(pointOffsets, false);
105 }
106 void deletePoints(const std::vector<Offset>& pointOffsets, bool andFaces);
107 void deleteVertices(const std::vector<Offset>& vertOffsets);
108 bool isValidFace(Offset offset) const;
109 bool isValidVertex(Offset offset) const;
110 bool isValidPoint(Offset offset) const override;
111
112 void defragment() override;
113
114 void merge(Mesh& other);
115
116 HeMesh computeHalfEdgeMesh();
117
118 std::unordered_set<Offset>::const_iterator soloPointsBegin() const;
119 std::unordered_set<Offset>::const_iterator soloPointsEnd() const;
120
121 void setPointPos(const Offset offset, const Vector3& pos);
126 std::span<const Offset> getFaceStartVertices() const;
127 Vector3 getPosFromVert(Offset vertexOffset) const;
128 Vector3 getPointPos(Offset pointOffset) const;
129 unsigned int getFaceVertCount(Offset faceOffset) const
130 {
131 return vertexCountFaceHandle_[faceOffset];
132 }
133 unsigned int getFacePointCount(Offset faceOffset) const;
134 Offset getVertexFace(Offset vertexOffset) const;
135
136 Offset getPointVertex(Offset vertexOffset) const
137 {
138 return pointOffsetVertexHandle_.getValue(vertexOffset);
139 }
140
141 std::span<const intT> getFacePoints(Offset faceOffset) const
142 {
143 const Offset start = getFaceStartVertices()[faceOffset];
144 const unsigned int count = getFaceVertCount(faceOffset);
145 return pointOffsetVertexHandle_.getSpan().subspan(start, count);
146 }
147
152 std::span<const intT> vertexPointSpan() const { return pointOffsetVertexHandle_.getSpan(); }
153
158 std::span<const Vector3> pointPosSpan() const { return posPointHandle_.getSpan(); }
159
160 Offset getNumFaces() const { return getElementCount(attr::AttributeOwner::FACE); }
161 Offset getNumVerts() const { return getElementCount(attr::AttributeOwner::VERTEX); }
162 Offset getNumSoloPoints() const;
163
164 // Face Iterator
166 {
167 FaceOffsets(const Mesh& mesh) : mesh_(mesh) {}
168 struct Iterator
169 {
170 using iterator_category = std::forward_iterator_tag;
171 using difference_type = std::ptrdiff_t;
172 using value_type = Offset;
173
174 explicit Iterator(Offset current) : curOffset_(current) {}
175 value_type operator*() const { return curOffset_; }
176 Iterator& operator++()
177 {
178 ++curOffset_;
179 return *this;
180 }
181 Iterator operator++(int)
182 {
183 Iterator tmp = *this;
184 ++(*this);
185 return tmp;
186 }
187 friend bool operator==(const Iterator& a, const Iterator& b)
188 {
189 return a.curOffset_ == b.curOffset_;
190 }
191 friend bool operator!=(const Iterator& a, const Iterator& b)
192 {
193 return a.curOffset_ != b.curOffset_;
194 }
195
196 private:
197 Offset curOffset_ = 0;
198 };
199 Iterator begin() const { return Iterator(0); }
200 Iterator end() const { return Iterator(mesh_.getNumFaces()); }
201
203 std::vector<Offset> toVector() const
204 {
205 std::vector<Offset> offsets;
206 offsets.reserve(mesh_.getNumFaces());
207 for (const Offset faceOffset : *this)
208 offsets.push_back(faceOffset);
209 return offsets;
210 }
211
212 private:
213 const Mesh& mesh_;
214 };
215 // TODO walk only valid faces like Primitive::PointOffsets once deletion settles. For now it is
216 // dense.
217 FaceOffsets getFaces() const { return FaceOffsets(*this); }
218
222 {
223 return createGroup(attr::AttributeOwner::VERTEX, std::move(name));
224 }
228 {
229 return createGroup(attr::AttributeOwner::FACE, std::move(name));
230 }
232 void addToVertexGroup(const std::string& name, const std::vector<Offset>& offsets)
233 {
234 addToGroup(attr::AttributeOwner::VERTEX, name, offsets);
235 }
237 void addToFaceGroup(const std::string& name, const std::vector<Offset>& offsets)
238 {
239 addToGroup(attr::AttributeOwner::FACE, name, offsets);
240 }
241
242 boolT isClosed(Offset faceOffset) const;
243
244 void computeFaceStartVertices() const;
245
259 FaceNormalHandle getFaceNormal(bool precompute = false) const;
260
272 VertexNormalHandle getVertexNormal(bool precompute = false) const;
273
274 friend class FaceNormalHandle;
275 friend class VertexNormalHandle;
276
277 protected:
278 attr::attribVector& getAttributeStore(const attr::AttributeOwner& owner) override;
279 const attr::attribVector& getAttributeStore(const attr::AttributeOwner& owner) const override;
280 attr::attribVector& getGroupStore(const attr::AttributeOwner& owner) override;
281 const attr::attribVector& getGroupStore(const attr::AttributeOwner& owner) const override;
282
283 private:
284 void mergeAppend(std::shared_ptr<attr::Attribute> dst, std::shared_ptr<attr::Attribute> src);
285 template <typename T>
286 void mergeAppendImpl(std::shared_ptr<attr::Attribute> dst, std::shared_ptr<attr::Attribute> src)
287 {
288 auto dstHandle = attr::AttributeHandle<T>(dst);
289 auto srcHandle = attr::AttributeHandle<T>(src);
290
291 const Offset srcCount = srcHandle.getSize();
292 const Offset dstCount = dstHandle.getSize();
293
294 dstHandle.resize(dstCount + srcCount);
295
296 for (Offset i = 0; i < srcCount; ++i)
297 {
298 const T value = srcHandle.getValue(i);
299 const Offset dstOffset = dstCount + i;
300 dstHandle.setValue(dstOffset, value);
301 }
302 };
303
304 attr::attribVector vertexAttributes_;
305 attr::attribVector faceAttributes_;
306 attr::attribVector vertexGroups_;
307 attr::attribVector faceGroups_;
308
309 mutable std::unordered_set<Offset> soloPoints_;
310 mutable bool soloPointsDirty_ = true;
311 void rebuildSoloPoints() const;
312 bool needsDefrag_ = false;
313
314 mutable std::vector<Offset> faceStarts_;
315 mutable std::vector<Offset> vertexFaces_;
316
317 mutable std::atomic<bool> faceStartsDirty_{true};
318 mutable tbb::spin_mutex faceStartsMutex_;
319
320 // intrinsic handles
321 enzo::attr::AttributeHandleInt vertexCountFaceHandle_;
322 enzo::attr::AttributeHandleBool closedFaceHandle_;
323 enzo::attr::AttributeHandleInt pointOffsetVertexHandle_;
325 enzo::attr::AttributeHandleBool validFaceHandle_;
326 enzo::attr::AttributeHandleBool validVertexHandle_;
327 enzo::attr::AttributeHandleBool validPointHandle_;
328};
329
340class FaceNormalHandle
341{
342 public:
343 Vector3 operator[](Offset faceOffset) const
344 {
345 if (cached_) return (*cached_)[faceOffset];
346 if (!precomputed_.empty()) return precomputed_[faceOffset];
347 return computeNormal(faceOffset);
348 }
349
350 private:
351 friend class Mesh;
352 FaceNormalHandle(const Mesh& mesh, bool precompute);
353 Vector3 computeNormal(Offset faceOffset) const;
354 const Mesh& mesh_;
355 std::optional<attr::AttributeHandleRO<Vector3>> cached_;
356 std::vector<Vector3> precomputed_;
357};
358
367class VertexNormalHandle
368{
369 public:
370 Vector3 operator[](Offset vertexOffset) const;
371
372 private:
373 friend class Mesh;
374 VertexNormalHandle(const Mesh& mesh, bool precompute);
375 const Mesh& mesh_;
376 std::optional<attr::AttributeHandleRO<Vector3>> cached_;
377 FaceNormalHandle faceNormals_;
378};
379} // namespace enzo::geo
size_t Offset
enzo::Offset is the internal discontinuous index of an element in a given AttributeOwner.
Definition Types.h:100
AttributeOwner
The segment of geometry that owns a particular attribute.
Definition Types.h:22
Read write accessor for enzo::attr::Attribute.
std::span< const T > getSpan() const
Contiguous read only view over all stored values.
Definition AttributeHandle.h:153
T getValue(size_t offset) const
Gets the value at a given offset.
Definition AttributeHandle.h:134
Read accessor for per-face normals.
Polygonal mesh primitive with point, vertex, and face attributes.
std::span< const Offset > getFaceStartVertices() const
Contiguous view of each face's starting vertex offset.
Definition Mesh.cpp:749
FaceNormalHandle getFaceNormal(bool precompute=false) const
Returns a handle for reading per-face normals.
Definition Mesh.cpp:876
void deleteAllFaces(bool andPoints=true)
Removes every face from the mesh.
Definition Mesh.cpp:387
std::vector< Offset > duplicatePoints(std::span< const Offset > srcPointOffsets, bool copyAttributes=true)
Duplicates existing points into new points carrying the same positions.
Definition Mesh.cpp:586
Offset addFace(const std::vector< Offset > &pointOffsets, bool closed=true)
Adds a single face. Avoid for multiple faces in a loop as a single call to addFaces is much more perf...
Definition Mesh.cpp:245
void addToVertexGroup(const std::string &name, const std::vector< Offset > &offsets)
Marks the given offsets as members of the vertex group.
Definition Mesh.h:232
VertexNormalHandle getVertexNormal(bool precompute=false) const
Returns a handle for reading per-vertex normals.
Definition Mesh.cpp:881
std::span< const intT > vertexPointSpan() const
Contiguous view mapping each vertex offset to its point offset.
Definition Mesh.h:152
std::vector< Offset > addFaces(std::span< const Offset > pointOffsetsFlat, std::span< const Offset > vertexCounts, bool closed=true)
Adds many faces in a single call.
Definition Mesh.cpp:285
attr::AttributeHandleBool createVertexGroup(std::string name)
Creates a vertex group.
Definition Mesh.h:221
attr::AttributeHandleBool createFaceGroup(std::string name)
Creates a face group.
Definition Mesh.h:227
std::vector< Offset > addPoints(std::span< const Vector3 > positions)
Adds many points in a single call.
Definition Mesh.cpp:554
void addToFaceGroup(const std::string &name, const std::vector< Offset > &offsets)
Marks the given offsets as members of the face group.
Definition Mesh.h:237
void defragment() override
Compacts storage, removing entries marked invalid so offsets are contiguous again.
Definition Mesh.cpp:468
std::span< const Vector3 > pointPosSpan() const
Contiguous view of every point position.
Definition Mesh.h:158
size_t getElementCount(const attr::AttributeOwner &owner) const
Returns the number of elements in the given owner's store.
Definition Primitive.cpp:154
attr::AttributeHandleBool createGroup(attr::AttributeOwner owner, std::string name)
Creates a group on the given owner.
Definition Primitive.cpp:166
void addToGroup(attr::AttributeOwner owner, const std::string &name, const std::vector< Offset > &offsets)
Marks the given offsets as members of the group.
Definition Primitive.cpp:175
Read accessor for per-vertex normals.
Definition Mesh.h:166
std::vector< Offset > toVector() const
Collects the face offsets into a vector for callers that need one.
Definition Mesh.h:203