From f2b0492a03b3fee488a8b4821db2301b9a466650 Mon Sep 17 00:00:00 2001 From: Taylor Holliday Date: Thu, 26 Sep 2024 09:33:38 -0700 Subject: [PATCH 01/11] add index type-safety to VecView --- src/utilities/include/manifold/vec_view.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/utilities/include/manifold/vec_view.h b/src/utilities/include/manifold/vec_view.h index f0a310ab9..0411365c5 100644 --- a/src/utilities/include/manifold/vec_view.h +++ b/src/utilities/include/manifold/vec_view.h @@ -18,12 +18,17 @@ namespace manifold { +/** + * Override this for a custom index type. e.g. HalfedgeIndex + */ +inline size_t GetIndex(size_t x) { return x; } + /** * View for Vec, can perform offset operation. * This will be invalidated when the original vector is dropped or changes * length. Roughly equivalent to std::span from c++20 */ -template +template class VecView { public: using Iter = T *; @@ -45,14 +50,14 @@ class VecView { // allows conversion to a const VecView operator VecView() const { return {ptr_, size_}; } - inline const T &operator[](size_t i) const { + inline const T &operator[](Ix i) const { ASSERT(i < size_, std::out_of_range("Vec out of range")); - return ptr_[i]; + return ptr_[GetIndex(i)]; } - inline T &operator[](size_t i) { + inline T &operator[](Ix i) { ASSERT(i < size_, std::out_of_range("Vec out of range")); - return ptr_[i]; + return ptr_[GetIndex(i)]; } IterC cbegin() const { return ptr_; } From 973bda26236a6e2454a453fe93511a415a85a6c2 Mon Sep 17 00:00:00 2001 From: Taylor Holliday Date: Thu, 26 Sep 2024 09:34:06 -0700 Subject: [PATCH 02/11] add HalfedgeIndex --- src/manifold/src/shared.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/manifold/src/shared.h b/src/manifold/src/shared.h index a40bc04b8..2a7fdb3fd 100644 --- a/src/manifold/src/shared.h +++ b/src/manifold/src/shared.h @@ -116,6 +116,16 @@ inline vec3 GetBarycentric(const vec3& v, const mat3& triPos, } } +/** + * @brief Type-safety for half-edge indices. + * + */ +struct HalfedgeIndex { + int ix; +}; + +inline size_t GetIndex(HalfedgeIndex ix) { return ix.ix; } + /** * The fundamental component of the halfedge data structure used for storing and * operating on the Manifold. From 67ebc5e37cb4e8f9df1f3baaeac549059f4d9bf5 Mon Sep 17 00:00:00 2001 From: Taylor Holliday Date: Thu, 26 Sep 2024 11:23:59 -0700 Subject: [PATCH 03/11] add index type-safety to Vec --- src/utilities/include/manifold/vec.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utilities/include/manifold/vec.h b/src/utilities/include/manifold/vec.h index db85d8ed3..36d16d627 100644 --- a/src/utilities/include/manifold/vec.h +++ b/src/utilities/include/manifold/vec.h @@ -28,7 +28,7 @@ namespace manifold { /** @addtogroup Private * @{ */ -template +template class Vec; /* @@ -39,8 +39,8 @@ class Vec; * implementation that did not consider things like non-trivial * constructor/destructor, please keep T trivial. */ -template -class Vec : public VecView { +template +class Vec : public VecView { public: Vec() {} From 84672b4917910574514186f00ed105fd6ff25857 Mon Sep 17 00:00:00 2001 From: Taylor Holliday Date: Thu, 26 Sep 2024 14:56:53 -0700 Subject: [PATCH 04/11] fix index checking --- src/utilities/include/manifold/vec_view.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utilities/include/manifold/vec_view.h b/src/utilities/include/manifold/vec_view.h index 0411365c5..21666b976 100644 --- a/src/utilities/include/manifold/vec_view.h +++ b/src/utilities/include/manifold/vec_view.h @@ -51,12 +51,12 @@ class VecView { operator VecView() const { return {ptr_, size_}; } inline const T &operator[](Ix i) const { - ASSERT(i < size_, std::out_of_range("Vec out of range")); + ASSERT(GetIndex(i) < size_, std::out_of_range("Vec out of range")); return ptr_[GetIndex(i)]; } inline T &operator[](Ix i) { - ASSERT(i < size_, std::out_of_range("Vec out of range")); + ASSERT(GetIndex(i) < size_, std::out_of_range("Vec out of range")); return ptr_[GetIndex(i)]; } From 171ca20bb16826a81530413a917253a12c316b05 Mon Sep 17 00:00:00 2001 From: Taylor Holliday Date: Thu, 26 Sep 2024 14:57:45 -0700 Subject: [PATCH 05/11] move HalfedgeIndex, add overload of NextHalfedge --- src/manifold/src/shared.h | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/manifold/src/shared.h b/src/manifold/src/shared.h index 2a7fdb3fd..b6bff0019 100644 --- a/src/manifold/src/shared.h +++ b/src/manifold/src/shared.h @@ -40,6 +40,27 @@ inline int NextHalfedge(int current) { return current; } +/** + * @brief Type-safety for half-edge indices. + * + */ +struct HalfedgeIndex { + int ix; + + bool operator==(const HalfedgeIndex& rhs) const { return ix == rhs.ix; } + bool operator!=(const HalfedgeIndex& rhs) const { return ix != rhs.ix; } + HalfedgeIndex operator+(int rhs) const { return {ix + rhs}; } +}; + +inline size_t GetIndex(HalfedgeIndex ix) { return ix.ix; } + +// XXX: should be a member function on HalfedgeIndex +inline HalfedgeIndex NextHalfedge(HalfedgeIndex current) { + ++current.ix; + if (current.ix % 3 == 0) current.ix -= 3; + return current; +} + inline mat3 NormalTransform(const mat4x3& transform) { return glm::inverse(glm::transpose(mat3(transform))); } @@ -116,16 +137,6 @@ inline vec3 GetBarycentric(const vec3& v, const mat3& triPos, } } -/** - * @brief Type-safety for half-edge indices. - * - */ -struct HalfedgeIndex { - int ix; -}; - -inline size_t GetIndex(HalfedgeIndex ix) { return ix.ix; } - /** * The fundamental component of the halfedge data structure used for storing and * operating on the Manifold. From e00949e10bbee39f42c089bc146f2802555b5cf8 Mon Sep 17 00:00:00 2001 From: Taylor Holliday Date: Thu, 26 Sep 2024 15:01:19 -0700 Subject: [PATCH 06/11] add ctor --- src/manifold/src/shared.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/manifold/src/shared.h b/src/manifold/src/shared.h index b6bff0019..edfc05bf3 100644 --- a/src/manifold/src/shared.h +++ b/src/manifold/src/shared.h @@ -47,6 +47,9 @@ inline int NextHalfedge(int current) { struct HalfedgeIndex { int ix; + // For now, implicit conversion from int + HalfedgeIndex(int ix) : ix(ix) {} + bool operator==(const HalfedgeIndex& rhs) const { return ix == rhs.ix; } bool operator!=(const HalfedgeIndex& rhs) const { return ix != rhs.ix; } HalfedgeIndex operator+(int rhs) const { return {ix + rhs}; } From 0424ade7b5dbd14b888d5d85d5e3c0b0e812441a Mon Sep 17 00:00:00 2001 From: Taylor Holliday Date: Thu, 26 Sep 2024 15:01:31 -0700 Subject: [PATCH 07/11] add HalfedgeIndex::Next --- src/manifold/src/shared.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/manifold/src/shared.h b/src/manifold/src/shared.h index edfc05bf3..dd31863f1 100644 --- a/src/manifold/src/shared.h +++ b/src/manifold/src/shared.h @@ -53,6 +53,14 @@ struct HalfedgeIndex { bool operator==(const HalfedgeIndex& rhs) const { return ix == rhs.ix; } bool operator!=(const HalfedgeIndex& rhs) const { return ix != rhs.ix; } HalfedgeIndex operator+(int rhs) const { return {ix + rhs}; } + + // Index of next halfedge about the triangle. + HalfedgeIndex Next() const { + HalfedgeIndex current = *this; + ++current.ix; + if (current.ix % 3 == 0) current.ix -= 3; + return current; + } }; inline size_t GetIndex(HalfedgeIndex ix) { return ix.ix; } From cdc968ee647b236b26af8df5b13518706b559a82 Mon Sep 17 00:00:00 2001 From: Taylor Holliday Date: Thu, 26 Sep 2024 15:12:28 -0700 Subject: [PATCH 08/11] add member functions to HalfedgeIndex --- src/manifold/src/shared.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/manifold/src/shared.h b/src/manifold/src/shared.h index dd31863f1..2bf114ea8 100644 --- a/src/manifold/src/shared.h +++ b/src/manifold/src/shared.h @@ -49,10 +49,24 @@ struct HalfedgeIndex { // For now, implicit conversion from int HalfedgeIndex(int ix) : ix(ix) {} + HalfedgeIndex(const HalfedgeIndex& other) : ix(other.ix) {} + HalfedgeIndex() : ix(-1) {} bool operator==(const HalfedgeIndex& rhs) const { return ix == rhs.ix; } + bool operator==(int rhs) const { return ix == rhs; } bool operator!=(const HalfedgeIndex& rhs) const { return ix != rhs.ix; } + bool operator!=(int rhs) const { return ix != rhs; } HalfedgeIndex operator+(int rhs) const { return {ix + rhs}; } + HalfedgeIndex operator+=(int rhs) { + ix += rhs; + return *this; + } + HalfedgeIndex operator/(int rhs) const { + DEBUG_ASSERT(rhs == 3, logicErr, "Not dividing face index by 3"); + return {ix / rhs}; + } + + operator int() const { return ix; } // Index of next halfedge about the triangle. HalfedgeIndex Next() const { @@ -61,6 +75,9 @@ struct HalfedgeIndex { if (current.ix % 3 == 0) current.ix -= 3; return current; } + + bool IsNull() const { return ix == -1; } + bool IsNotNull() const { return ix != -1; } }; inline size_t GetIndex(HalfedgeIndex ix) { return ix.ix; } From a0a10fef804d3b349a57ac6a321b0b7b07e83093 Mon Sep 17 00:00:00 2001 From: Taylor Holliday Date: Thu, 26 Sep 2024 15:13:40 -0700 Subject: [PATCH 09/11] gradually introduce HalfedgeIndex --- src/manifold/src/boolean3.cpp | 6 +++--- src/manifold/src/mesh_fixes.h | 2 +- src/manifold/src/quickhull.cpp | 2 +- src/manifold/src/shared.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/manifold/src/boolean3.cpp b/src/manifold/src/boolean3.cpp index 3f6b88650..3ea2a5574 100644 --- a/src/manifold/src/boolean3.cpp +++ b/src/manifold/src/boolean3.cpp @@ -81,7 +81,7 @@ struct CopyFaceEdges { const int q1 = 3 * q2 + j; const Halfedge edge = halfedgesQ[q1]; int a = pX; - int b = edge.IsForward() ? q1 : edge.pairedHalfedge; + int b = edge.IsForward() ? q1 : edge.pairedHalfedge.ix; if (inverted) std::swap(a, b); pXq1.Set(idx + static_cast(j), a, b); } @@ -302,7 +302,7 @@ struct Kernel02 { for (const int i : {0, 1, 2}) { const int q1 = 3 * q2 + i; const Halfedge edge = halfedgeQ[q1]; - const int q1F = edge.IsForward() ? q1 : edge.pairedHalfedge; + const int q1F = edge.IsForward() ? q1 : edge.pairedHalfedge.ix; if (!forward) { const int qVert = halfedgeQ[q1F].startVert; @@ -416,7 +416,7 @@ struct Kernel12 { for (const int i : {0, 1, 2}) { const int q1 = 3 * q2 + i; const Halfedge edge = halfedgesQ[q1]; - const int q1F = edge.IsForward() ? q1 : edge.pairedHalfedge; + const int q1F = edge.IsForward() ? q1 : edge.pairedHalfedge.ix; const int64_t key = forward ? SparseIndices::EncodePQ(p1, q1F) : SparseIndices::EncodePQ(q1F, p1); const size_t idx = monobound_quaternary_search(p1q1, key); diff --git a/src/manifold/src/mesh_fixes.h b/src/manifold/src/mesh_fixes.h index cc2a103e6..60ae2780a 100644 --- a/src/manifold/src/mesh_fixes.h +++ b/src/manifold/src/mesh_fixes.h @@ -29,7 +29,7 @@ struct TransformTangents { void operator()(const int edgeOut) { const int edgeIn = - invert ? halfedge[FlipHalfedge(edgeOut)].pairedHalfedge : edgeOut; + invert ? halfedge[FlipHalfedge(edgeOut)].pairedHalfedge.ix : edgeOut; tangent[edgeOut + edgeOffset] = vec4(transform * vec3(oldTangents[edgeIn]), oldTangents[edgeIn].w); } diff --git a/src/manifold/src/quickhull.cpp b/src/manifold/src/quickhull.cpp index 2cec252dd..9429a76a6 100644 --- a/src/manifold/src/quickhull.cpp +++ b/src/manifold/src/quickhull.cpp @@ -193,7 +193,7 @@ HalfEdgeMesh::HalfEdgeMesh(const MeshBuilder& builderObject, i = 0; for (const auto& halfEdge : builderObject.halfedges) { - if (halfEdge.pairedHalfedge != -1) { + if (halfEdge.pairedHalfedge.IsNotNull()) { halfedges.push_back({halfEdge.endVert, halfEdge.pairedHalfedge, builderObject.halfedgeToFace[i]}); halfedgeToFace.push_back(builderObject.halfedgeToFace[i]); diff --git a/src/manifold/src/shared.h b/src/manifold/src/shared.h index 2bf114ea8..b22f3b3d3 100644 --- a/src/manifold/src/shared.h +++ b/src/manifold/src/shared.h @@ -171,7 +171,7 @@ inline vec3 GetBarycentric(const vec3& v, const mat3& triPos, */ struct Halfedge { int startVert, endVert; - int pairedHalfedge; + HalfedgeIndex pairedHalfedge; bool IsForward() const { return startVert < endVert; } bool operator<(const Halfedge& other) const { return startVert == other.startVert ? endVert < other.endVert From 4b8f823d0329a6afb5a22732feea155205b779d6 Mon Sep 17 00:00:00 2001 From: Taylor Holliday Date: Thu, 26 Sep 2024 15:59:58 -0700 Subject: [PATCH 10/11] use auto --- src/manifold/src/boolean_result.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/manifold/src/boolean_result.cpp b/src/manifold/src/boolean_result.cpp index c92288fec..0db442f10 100644 --- a/src/manifold/src/boolean_result.cpp +++ b/src/manifold/src/boolean_result.cpp @@ -302,9 +302,9 @@ void AppendPartialEdges(Manifold::Impl &outR, Vec &wholeHalfedgeP, // while remapping them to the output using vP2R. Use the verts position // projected along the edge vector to pair them up, then distribute these // edges to their faces. - Vec &halfedgeR = outR.halfedge_; + auto &halfedgeR = outR.halfedge_; const Vec &vertPosP = inP.vertPos_; - const Vec &halfedgeP = inP.halfedge_; + const auto &halfedgeP = inP.halfedge_; for (auto &value : edgesP) { const int edgeP = value.first; From a3563fc2f9decc10877c827511deb429aab197ea Mon Sep 17 00:00:00 2001 From: Taylor Holliday Date: Thu, 26 Sep 2024 16:02:19 -0700 Subject: [PATCH 11/11] use auto --- src/manifold/src/boolean_result.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/manifold/src/boolean_result.cpp b/src/manifold/src/boolean_result.cpp index 0db442f10..36adbad61 100644 --- a/src/manifold/src/boolean_result.cpp +++ b/src/manifold/src/boolean_result.cpp @@ -376,7 +376,7 @@ void AppendNewEdges( Vec &halfedgeRef, const Vec &facePQ2R, const int numFaceP) { ZoneScoped; // Pair up each edge's verts and distribute to faces based on indices in key. - Vec &halfedgeR = outR.halfedge_; + auto &halfedgeR = outR.halfedge_; Vec &vertPosR = outR.vertPos_; for (auto &value : edgesNew) {