diff --git a/src/polymesh/EdgeHandle.hh b/src/polymesh/EdgeHandle.hh deleted file mode 100644 index b398187f8764b27e1176a040ebe5bf9be03761d8..0000000000000000000000000000000000000000 --- a/src/polymesh/EdgeHandle.hh +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "EdgeIndex.hh" - -namespace polymesh -{ -struct Mesh; - -struct EdgeHandle -{ - Mesh const* mesh; - EdgeIndex idx; - - EdgeHandle(Mesh const* mesh, EdgeIndex idx) : mesh(mesh), idx(idx) {} -}; -} diff --git a/src/polymesh/EdgeIndex.hh b/src/polymesh/EdgeIndex.hh deleted file mode 100644 index d44ff035e4e2aa44ba39bea2ec6e01fc674ad7bd..0000000000000000000000000000000000000000 --- a/src/polymesh/EdgeIndex.hh +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -namespace polymesh -{ -struct EdgeIndex -{ - int value = -1; - - EdgeIndex() = default; - explicit EdgeIndex(int idx) : value(idx) {} - - bool is_valid() const { return value >= 0; } - static EdgeIndex invalid() { return {}; } - - bool operator==(EdgeIndex const& rhs) const { return value == rhs.value; } - bool operator!=(EdgeIndex const& rhs) const { return value != rhs.value; } -}; -} diff --git a/src/polymesh/FaceHandle.hh b/src/polymesh/FaceHandle.hh deleted file mode 100644 index 5c7eb487e8cf11e933d070d938668c546cb33549..0000000000000000000000000000000000000000 --- a/src/polymesh/FaceHandle.hh +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "FaceIndex.hh" - -namespace polymesh -{ -struct Mesh; - -struct FaceHandle -{ - Mesh const* mesh; - FaceIndex idx; - - FaceHandle(Mesh const* mesh, FaceIndex idx) : mesh(mesh), idx(idx) {} -}; -} diff --git a/src/polymesh/FaceIndex.hh b/src/polymesh/FaceIndex.hh deleted file mode 100644 index 46b561ad12dcff7a0247a2f11ab0fd78d8abe573..0000000000000000000000000000000000000000 --- a/src/polymesh/FaceIndex.hh +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -namespace polymesh -{ -struct FaceIndex -{ - int value = -1; - - FaceIndex() = default; - explicit FaceIndex(int idx) : value(idx) {} - - bool is_valid() const { return value >= 0; } - static FaceIndex invalid() { return {}; } - - bool operator==(FaceIndex const& rhs) const { return value == rhs.value; } - bool operator!=(FaceIndex const& rhs) const { return value != rhs.value; } -}; - -} diff --git a/src/polymesh/HalfedgeHandle.hh b/src/polymesh/HalfedgeHandle.hh deleted file mode 100644 index 718b48b1263f0e0223b868f2cae1b6ece9779fbc..0000000000000000000000000000000000000000 --- a/src/polymesh/HalfedgeHandle.hh +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "HalfedgeIndex.hh" - -namespace polymesh -{ -struct Mesh; - -struct HalfedgeHandle -{ - Mesh const* mesh; - HalfedgeIndex idx; - - HalfedgeHandle(Mesh const* mesh, HalfedgeIndex idx) : mesh(mesh), idx(idx) {} -}; -} diff --git a/src/polymesh/HalfedgeIndex.hh b/src/polymesh/HalfedgeIndex.hh deleted file mode 100644 index a6a412484ae8f436a58cfafd332a4062d9673071..0000000000000000000000000000000000000000 --- a/src/polymesh/HalfedgeIndex.hh +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -namespace polymesh -{ -struct HalfedgeIndex -{ - int value = -1; - - HalfedgeIndex() = default; - explicit HalfedgeIndex(int idx) : value(idx) {} - - bool is_valid() const { return value >= 0; } - static HalfedgeIndex invalid() { return {}; } - - bool operator==(HalfedgeIndex const& rhs) const { return value == rhs.value; } - bool operator!=(HalfedgeIndex const& rhs) const { return value != rhs.value; } -}; - -} diff --git a/src/polymesh/Iterators.hh b/src/polymesh/Iterators.hh deleted file mode 100644 index 853c2ba179f8b0496023b4134f9eff88f690b315..0000000000000000000000000000000000000000 --- a/src/polymesh/Iterators.hh +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include <cassert> - -#include "EdgeHandle.hh" -#include "FaceHandle.hh" -#include "HalfedgeHandle.hh" -#include "VertexHandle.hh" - -// For iterator interfaces, see http://anderberg.me/2016/07/04/c-custom-iterators/ -// Note: some iterator methods are implemented at the end of Mesh.hh to ensure inlining - -namespace polymesh -{ -struct skipping_vertex_iterator -{ - skipping_vertex_iterator() = default; - skipping_vertex_iterator(VertexHandle handle) : handle(handle) {} - - VertexHandle operator*() const { return handle; } - skipping_vertex_iterator& operator++(); - skipping_vertex_iterator operator++(int) - { - auto i = *this; - return ++i; - } - bool operator==(skipping_vertex_iterator const& rhs) const - { - assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); - return handle.idx == rhs.handle.idx; - } - bool operator!=(skipping_vertex_iterator const& rhs) const - { - assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); - return handle.idx != rhs.handle.idx; - } - -private: - VertexHandle handle; -}; - -struct vertex_iterator -{ - vertex_iterator() = default; - vertex_iterator(VertexHandle handle) : handle(handle) {} - - VertexHandle operator*() const { return handle; } - vertex_iterator& operator++(); - vertex_iterator operator++(int) - { - auto i = *this; - return ++i; - } - bool operator==(vertex_iterator const& rhs) const - { - assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); - return handle.idx == rhs.handle.idx; - } - bool operator!=(vertex_iterator const& rhs) const - { - assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); - return handle.idx != rhs.handle.idx; - } - -private: - VertexHandle handle; -}; -} diff --git a/src/polymesh/Mesh.hh b/src/polymesh/Mesh.hh index 0e5ba04442b807e409473f89458067cf3a58b092..9db31abad4fc24e4c3f7caae79c57d76d30eaa15 100644 --- a/src/polymesh/Mesh.hh +++ b/src/polymesh/Mesh.hh @@ -1,20 +1,30 @@ #pragma once #include <cstddef> +#include <memory> #include <vector> -#include "EdgeHandle.hh" -#include "FaceHandle.hh" -#include "HalfedgeHandle.hh" -#include "VertexHandle.hh" - -#include "Ranges.hh" +#include "cursors.hh" +#include "ranges.hh" namespace polymesh { +using SharedMesh = std::shared_ptr<Mesh>; + /** - * @brief Half-Edge Mesh Datastructure + * @brief Half-edge Mesh Datastructure + * + * * Primitives are accessed via the smart collections mesh.<primitive>() + * (where <primitive> can be vertices, edges, faces, or halfedges) + * + * * Primitives can be added via <primitive>().add() + * (added primitives are at the end of the collection) * + * * Primitives can be deleted via <primitive>().delete(...) + * (deleted primitives are invalidated (flagged for removal). call compactify() to remove them) + * + * * `for (auto h : <primitive>())` iterates over _all_ primitives, including invalid ones + * (`for (auto h : valid_<primitive>())` skips over invalid ones) */ struct Mesh { @@ -24,51 +34,35 @@ public: /// vertices(), faces(), ... /// get handle from index - FaceHandle handle_of(FaceIndex idx) const { return {this, idx}; } - EdgeHandle handle_of(EdgeIndex idx) const { return {this, idx}; } - VertexHandle handle_of(VertexIndex idx) const { return {this, idx}; } - HalfedgeHandle handle_of(HalfedgeIndex idx) const { return {this, idx}; } + face_handle handle_of(face_index idx) const { return {this, idx}; } + edge_handle handle_of(edge_index idx) const { return {this, idx}; } + vertex_handle handle_of(vertex_index idx) const { return {this, idx}; } + halfedge_handle handle_of(halfedge_index idx) const { return {this, idx}; } - /// number of primitives - /// CAUTION: includes deleted ones! - int size_faces() const { return mFaces.size(); } - int size_vertices() const { return mVertices.size(); } - int size_halfedges() const { return mHalfedges.size(); } - int size_edges() const { return mHalfedges.size() >> 1; } - - /// iterator ranges for primitives + /// smart collections for primitives INCLUDING deleted ones + /// Also primary interfaces for querying size and adding primitives /// /// CAUTION: includes deleted ones! /// use compactify() to ensure that no deleted ones exist - /// use valid_xyz() to skip deleted ones during iteration (slower) + /// use valid_<primitive>() to skip deleted ones during iteration (slower) /// - /// NOTE: adding primitives does NOT invalidate ranges. (newly added ones are processed at the end) + /// NOTE: adding primitives does NOT invalidate ranges. (newly added ones are NOT processed though) /// deleting primitives does NOT invalidate ranges. - vertex_range vertices() const { return {vertices_begin(), vertices_end()}; } - skipping_vertex_range valid_vertices() const { return {valid_vertices_begin(), valid_vertices_end()}; } - - /// begin/end for ranges - vertex_iterator vertices_begin() const { return {{this, VertexIndex(0)}}; } - vertex_iterator vertices_end() const { return {{this, VertexIndex::invalid()}}; } - skipping_vertex_iterator valid_vertices_begin() const { return {{this, VertexIndex(0)}}; } - skipping_vertex_iterator valid_vertices_end() const { return {{this, VertexIndex::invalid()}}; } + vertex_collection vertices() { return {this}; } + face_collection faces() { return {this}; } + edge_collection edges() { return {this}; } + halfedge_collection halfedges() { return {this}; } - // modifiers -public: - /// TODO: - /// add_vertex/he/h/... - - /// Adds a single non-connected vertex - /// Does NOT invalidate iterators! - VertexHandle add_vertex(); - - /// Adds a face consisting of N vertices - template <size_t N> - FaceHandle add_face(const VertexHandle (&vhandles)[N]); - FaceHandle add_face(VertexHandle v0, VertexHandle v1, VertexHandle v2); - FaceHandle add_face(VertexHandle v0, VertexHandle v1, VertexHandle v2, VertexHandle v3); - FaceHandle add_face(std::vector<VertexHandle> vhandles); - FaceHandle add_face(VertexHandle const *vhandles, size_t vcnt); + /// smart collections for VALID primitives (EXCLUDING deleted ones) + /// + /// NOTE: if mesh.is_compact() is guaranteed, <primitive>() is faster than valid_<primitive>() + /// + /// NOTE: adding primitives does NOT invalidate ranges. (newly added ones are NOT processed though) + /// deleting primitives does NOT invalidate ranges. (they will be skipped) + valid_vertex_collection valid_vertices() const { return {this}; } + valid_face_collection valid_faces() const { return {this}; } + valid_edge_collection valid_edges() const { return {this}; } + valid_halfedge_collection valid_halfedges() const { return {this}; } // helper public: @@ -81,184 +75,466 @@ public: /// Asserts that mesh invariants hold, e.g. that the half-edge stored in a face actually bounds that face void assert_consistency() const; + // ctor +public: + Mesh() = default; + + /// Meshes can be neither moved nor copied because properties depend on the Mesh address + Mesh(Mesh const &) = delete; + Mesh(Mesh &&) = delete; + Mesh &operator=(Mesh const &) = delete; + Mesh &operator=(Mesh &&) = delete; + + /// Creates a new mesh and returns a shared_ptr to it + static SharedMesh create() { return std::make_shared<Mesh>(); } + + // internal helper +private: // reserves a certain number of primitives void reserve_faces(size_t capacity) { mFaces.reserve(capacity); } void reserve_vertices(size_t capacity) { mVertices.reserve(capacity); } + void reserve_edges(size_t capacity) { mHalfedges.reserve(capacity * 2); } void reserve_halfedges(size_t capacity) { mHalfedges.reserve(capacity); } - // returns the next valid idx starting AFTER the given one - // NOTE: the result can be invalid if the input was the last valid one - VertexIndex next_valid_idx_after(VertexIndex idx) const; - EdgeIndex next_valid_idx_after(EdgeIndex idx) const; - FaceIndex next_valid_idx_after(FaceIndex idx) const; - HalfedgeIndex next_valid_idx_after(HalfedgeIndex idx) const; - // returns the next valid idx starting BEFORE the given one counting downwards - VertexIndex prev_valid_idx_before(VertexIndex idx) const; - EdgeIndex prev_valid_idx_before(EdgeIndex idx) const; - FaceIndex prev_valid_idx_before(FaceIndex idx) const; - HalfedgeIndex prev_valid_idx_before(HalfedgeIndex idx) const; + int size_faces() const { return mFaces.size(); } + int size_vertices() const { return mVertices.size(); } + int size_edges() const { return mHalfedges.size() >> 1; } + int size_halfedges() const { return mHalfedges.size(); } + + int size_valid_faces() const { return mFaces.size() - mDeletedFaces; } + int size_valid_vertices() const { return mVertices.size() - mDeletedVertices; } + int size_valid_edges() const { return (mHalfedges.size() - mDeletedHalfedges) >> 1; } + int size_valid_halfedges() const { return mHalfedges.size() - mDeletedHalfedges; } + + // returns the next valid idx (returns the given one if valid) + // NOTE: the result can be invalid if no valid one was found + vertex_index next_valid_idx_from(vertex_index idx) const; + edge_index next_valid_idx_from(edge_index idx) const; + face_index next_valid_idx_from(face_index idx) const; + halfedge_index next_valid_idx_from(halfedge_index idx) const; + // returns the next valid idx (returns the given one if valid) counting DOWNWARDS + vertex_index prev_valid_idx_from(vertex_index idx) const; + edge_index prev_valid_idx_from(edge_index idx) const; + face_index prev_valid_idx_from(face_index idx) const; + halfedge_index prev_valid_idx_from(halfedge_index idx) const; + + /// Adds a single non-connected vertex + /// Does NOT invalidate iterators! + vertex_handle add_vertex(); + + /// Adds a face consisting of N vertices + /// The vertices must already be sorted in CCW order + /// (note: trying to add already existing halfedges triggers assertions) + face_handle add_face(vertex_handle const *vhandles, size_t vcnt); + + // Iterators + vertex_iterator vertices_begin() const { return {{this, vertex_index(0)}}; } + vertex_iterator vertices_end() const { return {{this, vertex_index(mVertices.size())}}; } + valid_vertex_iterator valid_vertices_begin() const { return {{this, vertex_index(0)}}; } + valid_vertex_iterator valid_vertices_end() const { return {{this, vertex_index(mVertices.size())}}; } + + face_iterator faces_begin() const { return {{this, face_index(0)}}; } + face_iterator faces_end() const { return {{this, face_index(mFaces.size())}}; } + valid_face_iterator valid_faces_begin() const { return {{this, face_index(0)}}; } + valid_face_iterator valid_faces_end() const { return {{this, face_index(mFaces.size())}}; } + + edge_iterator edges_begin() const { return {{this, edge_index(0)}}; } + edge_iterator edges_end() const { return {{this, edge_index(mHalfedges.size() >> 1)}}; } + valid_edge_iterator valid_edges_begin() const { return {{this, edge_index(0)}}; } + valid_edge_iterator valid_edges_end() const { return {{this, edge_index(mHalfedges.size() >> 1)}}; } + + halfedge_iterator halfedges_begin() const { return {{this, halfedge_index(0)}}; } + halfedge_iterator halfedges_end() const { return {{this, halfedge_index(mHalfedges.size())}}; } + valid_halfedge_iterator valid_halfedges_begin() const { return {{this, halfedge_index(0)}}; } + valid_halfedge_iterator valid_halfedges_end() const { return {{this, halfedge_index(mHalfedges.size())}}; } // internal datastructures private: - struct Face + struct face { - HalfedgeIndex halfedge; ///< one half-edge bounding this face + halfedge_index halfedge; ///< one half-edge bounding this face bool is_valid() const { return halfedge.is_valid(); } - void set_deleted() { halfedge = HalfedgeIndex::invalid(); } + void set_deleted() { halfedge = halfedge_index::invalid(); } }; - struct Vertex + struct vertex { - HalfedgeIndex outgoing_halfedge; + halfedge_index outgoing_halfedge; /// a vertex can be valid even without outgoing halfedge bool is_valid() const { return outgoing_halfedge.value >= -1; } - void set_deleted() { outgoing_halfedge = HalfedgeIndex(-2); } + void set_deleted() { outgoing_halfedge = halfedge_index(-2); } }; - struct Halfedge + struct halfedge { - VertexIndex vertex; - FaceIndex face; ///< might be invalid if boundary - HalfedgeIndex next_halfedge; ///< CCW - HalfedgeIndex prev_halfedge; ///< CW + vertex_index vertex; + face_index face; ///< might be invalid if boundary + halfedge_index next_halfedge; ///< CCW + halfedge_index prev_halfedge; ///< CW // opposite half-edge idx is "idx ^ 1" // edge idx is "idx >> 1" bool is_valid() const { return vertex.is_valid(); } bool is_boundary() const { return !face.is_valid(); } - void set_deleted() { vertex = VertexIndex::invalid(); } + void set_deleted() { vertex = vertex_index::invalid(); } }; // internal primitives private: - std::vector<Face> mFaces; - std::vector<Vertex> mVertices; - std::vector<Halfedge> mHalfedges; + std::vector<face> mFaces; + std::vector<vertex> mVertices; + std::vector<halfedge> mHalfedges; // internal state private: bool mCompact = true; + int mDeletedFaces = 0; + int mDeletedVertices = 0; + int mDeletedHalfedges = 0; + + // friends +private: + friend struct vertex_handle; + friend struct vertex_collection; + friend struct vertex_iterator; + friend struct valid_vertex_iterator; + friend struct valid_vertex_collection; + + friend struct face_handle; + friend struct face_collection; + friend struct face_iterator; + friend struct valid_face_iterator; + friend struct valid_face_collection; + + friend struct edge_handle; + friend struct edge_collection; + friend struct edge_iterator; + friend struct valid_edge_iterator; + friend struct valid_edge_collection; + + friend struct halfedge_handle; + friend struct halfedge_collection; + friend struct halfedge_iterator; + friend struct valid_halfedge_iterator; + friend struct valid_halfedge_collection; }; /// ======== IMPLEMENTATION ======== -VertexHandle Mesh::add_vertex() +vertex_handle Mesh::add_vertex() { auto idx = (int)mVertices.size(); - mVertices.push_back(Vertex()); - return handle_of(VertexIndex(idx)); + mVertices.push_back(vertex()); + /// TODO: properties + return handle_of(vertex_index(idx)); } -FaceHandle Mesh::add_face(const VertexHandle *vhandles, size_t vcnt) +face_handle Mesh::add_face(const vertex_handle *vhandles, size_t vcnt) { auto fidx = (int)mFaces.size(); - Face f; + face f; + /// TODO: properties assert(0 && "implement me"); /// TODO mFaces.push_back(f); - return handle_of(FaceIndex(fidx)); -} - -FaceHandle Mesh::add_face(VertexHandle v0, VertexHandle v1, VertexHandle v2) -{ - VertexHandle vs[3] = {v0, v1, v2}; - return add_face(vs); -} - -FaceHandle Mesh::add_face(VertexHandle v0, VertexHandle v1, VertexHandle v2, VertexHandle v3) -{ - VertexHandle vs[4] = {v0, v1, v2, v3}; - return add_face(vs); -} - -FaceHandle Mesh::add_face(std::vector<VertexHandle> vhandles) -{ - return add_face(vhandles.data(), vhandles.size()); + return handle_of(face_index(fidx)); } -template <size_t N> -FaceHandle Mesh::add_face(const VertexHandle (&vhandles)[N]) +vertex_index Mesh::next_valid_idx_from(vertex_index idx) const { - return add_face(vhandles, N); -} - -VertexIndex Mesh::next_valid_idx_after(VertexIndex idx) const -{ - for (auto i = idx.value + 1; i < (int)mVertices.size(); ++i) + for (auto i = idx.value; i < (int)mVertices.size(); ++i) if (mVertices[i].is_valid()) - return VertexIndex(i); - return {}; // invalid + return vertex_index(i); + return vertex_index(mVertices.size()); // end index } -VertexIndex Mesh::prev_valid_idx_before(VertexIndex idx) const +vertex_index Mesh::prev_valid_idx_from(vertex_index idx) const { - for (auto i = idx.value - 1; i >= 0; --i) + for (auto i = idx.value; i >= 0; --i) if (mVertices[i].is_valid()) - return VertexIndex(i); + return vertex_index(i); return {}; // invalid } -EdgeIndex Mesh::next_valid_idx_after(EdgeIndex idx) const +edge_index Mesh::next_valid_idx_from(edge_index idx) const { - for (auto i = (idx.value + 1) << 1; i < (int)mHalfedges.size(); i += 2) + for (auto i = idx.value << 1; i < (int)mHalfedges.size(); i += 2) if (mHalfedges[i].is_valid()) - return EdgeIndex(i >> 1); - return {}; // invalid + return edge_index(i >> 1); + return edge_index(mHalfedges.size() >> 1); // end index } -EdgeIndex Mesh::prev_valid_idx_before(EdgeIndex idx) const +edge_index Mesh::prev_valid_idx_from(edge_index idx) const { - for (auto i = (idx.value - 1) << 1; i >= 0; i -= 2) + for (auto i = idx.value << 1; i >= 0; i -= 2) if (mHalfedges[i].is_valid()) - return EdgeIndex(i >> 1); + return edge_index(i >> 1); return {}; // invalid } -FaceIndex Mesh::next_valid_idx_after(FaceIndex idx) const +face_index Mesh::next_valid_idx_from(face_index idx) const { - for (auto i = idx.value + 1; i < (int)mFaces.size(); ++i) + for (auto i = idx.value; i < (int)mFaces.size(); ++i) if (mFaces[i].is_valid()) - return FaceIndex(i); - return {}; // invalid + return face_index(i); + return face_index(mFaces.size()); // end index } -FaceIndex Mesh::prev_valid_idx_before(FaceIndex idx) const +face_index Mesh::prev_valid_idx_from(face_index idx) const { - for (auto i = idx.value - 1; i >= 0; --i) + for (auto i = idx.value; i >= 0; --i) if (mFaces[i].is_valid()) - return FaceIndex(i); + return face_index(i); return {}; // invalid } -HalfedgeIndex Mesh::next_valid_idx_after(HalfedgeIndex idx) const +halfedge_index Mesh::next_valid_idx_from(halfedge_index idx) const { - for (auto i = idx.value + 1; i < (int)mHalfedges.size(); ++i) + for (auto i = idx.value; i < (int)mHalfedges.size(); ++i) if (mHalfedges[i].is_valid()) - return HalfedgeIndex(i); - return {}; // invalid + return halfedge_index(i); + return halfedge_index(mHalfedges.size()); // end index } -HalfedgeIndex Mesh::prev_valid_idx_before(HalfedgeIndex idx) const +halfedge_index Mesh::prev_valid_idx_from(halfedge_index idx) const { - for (auto i = idx.value - 1; i >= 0; --i) + for (auto i = idx.value; i >= 0; --i) if (mHalfedges[i].is_valid()) - return HalfedgeIndex(i); + return halfedge_index(i); return {}; // invalid } /// ======== ITERATOR IMPLEMENTATION ======== -skipping_vertex_iterator &skipping_vertex_iterator::operator++() +valid_vertex_iterator &valid_vertex_iterator::operator++() { - handle.idx = handle.mesh->next_valid_idx_after(handle.idx); + handle.idx.value++; + handle.idx = handle.mesh->next_valid_idx_from(handle.idx); return *this; } vertex_iterator &vertex_iterator::operator++() { handle.idx.value++; - if (handle.idx.value >= handle.mesh->size_vertices()) - handle.idx.value = -1; return *this; } + +valid_face_iterator &valid_face_iterator::operator++() +{ + handle.idx.value++; + handle.idx = handle.mesh->next_valid_idx_from(handle.idx); + return *this; +} +face_iterator &face_iterator::operator++() +{ + handle.idx.value++; + return *this; +} + +valid_edge_iterator &valid_edge_iterator::operator++() +{ + handle.idx.value++; + handle.idx = handle.mesh->next_valid_idx_from(handle.idx); + return *this; +} +edge_iterator &edge_iterator::operator++() +{ + handle.idx.value++; + return *this; +} + +valid_halfedge_iterator &valid_halfedge_iterator::operator++() +{ + handle.idx.value++; + handle.idx = handle.mesh->next_valid_idx_from(handle.idx); + return *this; +} +halfedge_iterator &halfedge_iterator::operator++() +{ + handle.idx.value++; + return *this; +} + +/// ======== RANGES IMPLEMENTATION ======== + +// - Vertices - + +int vertex_collection::size() const +{ + return mesh->size_vertices(); +} + +void vertex_collection::reserve(int capacity) const +{ + mesh->reserve_vertices(capacity); +} + +vertex_handle vertex_collection::add() const +{ + return mesh->add_vertex(); +} + +vertex_iterator vertex_collection::begin() const +{ + return mesh->vertices_begin(); +} + +vertex_iterator vertex_collection::end() const +{ + return mesh->vertices_end(); +} + +int valid_vertex_collection::size() const +{ + return mesh->size_valid_vertices(); +} + +valid_vertex_iterator valid_vertex_collection::begin() const +{ + return mesh->valid_vertices_begin(); +} + +valid_vertex_iterator valid_vertex_collection::end() const +{ + return mesh->valid_vertices_end(); +} + +// - Faces - + +int face_collection::size() const +{ + return mesh->size_faces(); +} + +void face_collection::reserve(int capacity) const +{ + mesh->reserve_faces(capacity); +} + +face_handle face_collection::add_face(const vertex_handle *vhandles, size_t vcnt) const +{ + return mesh->add_face(vhandles, vcnt); +} + +face_handle face_collection::add_face(vertex_handle v0, vertex_handle v1, vertex_handle v2) const +{ + vertex_handle vs[3] = {v0, v1, v2}; + return add_face(vs); +} + +face_handle face_collection::add_face(vertex_handle v0, vertex_handle v1, vertex_handle v2, vertex_handle v3) const +{ + vertex_handle vs[4] = {v0, v1, v2, v3}; + return add_face(vs); +} + +face_handle face_collection::add_face(std::vector<vertex_handle> const &vhandles) const +{ + return add_face(vhandles.data(), vhandles.size()); +} + +template <size_t N> +face_handle face_collection::add_face(const vertex_handle (&vhandles)[N]) const +{ + return add_face(vhandles, N); +} + +face_iterator face_collection::begin() const +{ + return mesh->faces_begin(); +} + +face_iterator face_collection::end() const +{ + return mesh->faces_end(); +} + +int valid_face_collection::size() const +{ + return mesh->size_valid_faces(); +} + +valid_face_iterator valid_face_collection::begin() const +{ + return mesh->valid_faces_begin(); +} + +valid_face_iterator valid_face_collection::end() const +{ + return mesh->valid_faces_end(); +} + +// - Edges - + +int edge_collection::size() const +{ + return mesh->size_edges(); +} + +void edge_collection::reserve(int capacity) const +{ + mesh->reserve_edges(capacity); +} + +edge_iterator edge_collection::begin() const +{ + return mesh->edges_begin(); +} + +edge_iterator edge_collection::end() const +{ + return mesh->edges_end(); +} + +int valid_edge_collection::size() const +{ + return mesh->size_valid_edges(); +} + +valid_edge_iterator valid_edge_collection::begin() const +{ + return mesh->valid_edges_begin(); +} + +valid_edge_iterator valid_edge_collection::end() const +{ + return mesh->valid_edges_end(); +} + +// - Halfedges - + +int halfedge_collection::size() const +{ + return mesh->size_halfedges(); +} + +void halfedge_collection::reserve(int capacity) const +{ + mesh->reserve_halfedges(capacity); +} + +halfedge_iterator halfedge_collection::begin() const +{ + return mesh->halfedges_begin(); +} + +halfedge_iterator halfedge_collection::end() const +{ + return mesh->halfedges_end(); +} + +int valid_halfedge_collection::size() const +{ + return mesh->size_valid_halfedges(); +} + +valid_halfedge_iterator valid_halfedge_collection::begin() const +{ + return mesh->valid_halfedges_begin(); +} + +valid_halfedge_iterator valid_halfedge_collection::end() const +{ + return mesh->valid_halfedges_end(); +} } diff --git a/src/polymesh/Ranges.hh b/src/polymesh/Ranges.hh deleted file mode 100644 index cf754cbc8b827609012b61712d0afbd1b71b314e..0000000000000000000000000000000000000000 --- a/src/polymesh/Ranges.hh +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "Iterators.hh" - -namespace polymesh -{ -template<typename IteratorT> -struct iterator_range -{ - IteratorT _begin; - IteratorT _end; - - IteratorT begin() const { return _begin; } - IteratorT end() const { return _end; } -}; - -using vertex_range = iterator_range<vertex_iterator>; -using skipping_vertex_range = iterator_range<skipping_vertex_iterator>; -} diff --git a/src/polymesh/VertexHandle.hh b/src/polymesh/VertexHandle.hh deleted file mode 100644 index 4e859aef5efd29ed1f054fae9741b161ee59feed..0000000000000000000000000000000000000000 --- a/src/polymesh/VertexHandle.hh +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "VertexIndex.hh" - -namespace polymesh -{ -struct Mesh; - -struct VertexHandle -{ - Mesh const* mesh; - VertexIndex idx; - - VertexHandle(Mesh const* mesh, VertexIndex idx) : mesh(mesh), idx(idx) {} -}; -} diff --git a/src/polymesh/VertexIndex.hh b/src/polymesh/VertexIndex.hh deleted file mode 100644 index ab55c5747356bec975aa7c3875eb4a76b4dc00af..0000000000000000000000000000000000000000 --- a/src/polymesh/VertexIndex.hh +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -namespace polymesh -{ -struct VertexIndex -{ - int value = -1; - - VertexIndex() = default; - explicit VertexIndex(int idx) : value(idx) {} - - bool is_valid() const { return value >= 0; } - static VertexIndex invalid() { return {}; } - - bool operator==(VertexIndex const& rhs) const { return value == rhs.value; } - bool operator!=(VertexIndex const& rhs) const { return value != rhs.value; } -}; -} diff --git a/src/polymesh/cursors.hh b/src/polymesh/cursors.hh new file mode 100644 index 0000000000000000000000000000000000000000..15de6afa3fe110eb5b483a6e0e822bced0c56dee --- /dev/null +++ b/src/polymesh/cursors.hh @@ -0,0 +1,118 @@ +#pragma once + +namespace polymesh +{ +struct Mesh; + +// ======================== INDICES ======================== + +struct face_index +{ + int value = -1; + + face_index() = default; + explicit face_index(int idx) : value(idx) {} + + bool is_valid() const { return value >= 0; } + static face_index invalid() { return {}; } + + bool operator==(face_index const& rhs) const { return value == rhs.value; } + bool operator!=(face_index const& rhs) const { return value != rhs.value; } +}; + +struct vertex_index +{ + int value = -1; + + vertex_index() = default; + explicit vertex_index(int idx) : value(idx) {} + + bool is_valid() const { return value >= 0; } + static vertex_index invalid() { return {}; } + + bool operator==(vertex_index const& rhs) const { return value == rhs.value; } + bool operator!=(vertex_index const& rhs) const { return value != rhs.value; } +}; + +struct edge_index +{ + int value = -1; + + edge_index() = default; + explicit edge_index(int idx) : value(idx) {} + + bool is_valid() const { return value >= 0; } + static edge_index invalid() { return {}; } + + bool operator==(edge_index const& rhs) const { return value == rhs.value; } + bool operator!=(edge_index const& rhs) const { return value != rhs.value; } +}; + +struct halfedge_index +{ + int value = -1; + + halfedge_index() = default; + explicit halfedge_index(int idx) : value(idx) {} + + bool is_valid() const { return value >= 0; } + static halfedge_index invalid() { return {}; } + + bool operator==(halfedge_index const& rhs) const { return value == rhs.value; } + bool operator!=(halfedge_index const& rhs) const { return value != rhs.value; } +}; + +// ======================== HANDLES ======================== + +struct face_handle +{ + Mesh const* mesh; + face_index idx; + + face_handle(Mesh const* mesh, face_index idx) : mesh(mesh), idx(idx) {} + + bool operator==(face_index const& rhs) const { return idx == rhs; } + bool operator!=(face_index const& rhs) const { return idx != rhs; } + bool operator==(face_handle const& rhs) const { return mesh == rhs.mesh && idx == rhs.idx; } + bool operator!=(face_handle const& rhs) const { return mesh != rhs.mesh || idx != rhs.idx; } +}; + +struct vertex_handle +{ + Mesh const* mesh; + vertex_index idx; + + vertex_handle(Mesh const* mesh, vertex_index idx) : mesh(mesh), idx(idx) {} + + bool operator==(vertex_index const& rhs) const { return idx == rhs; } + bool operator!=(vertex_index const& rhs) const { return idx != rhs; } + bool operator==(vertex_handle const& rhs) const { return mesh == rhs.mesh && idx == rhs.idx; } + bool operator!=(vertex_handle const& rhs) const { return mesh != rhs.mesh || idx != rhs.idx; } +}; + +struct edge_handle +{ + Mesh const* mesh; + edge_index idx; + + edge_handle(Mesh const* mesh, edge_index idx) : mesh(mesh), idx(idx) {} + + bool operator==(edge_index const& rhs) const { return idx == rhs; } + bool operator!=(edge_index const& rhs) const { return idx != rhs; } + bool operator==(edge_handle const& rhs) const { return mesh == rhs.mesh && idx == rhs.idx; } + bool operator!=(edge_handle const& rhs) const { return mesh != rhs.mesh || idx != rhs.idx; } +}; + +struct halfedge_handle +{ + Mesh const* mesh; + halfedge_index idx; + + halfedge_handle(Mesh const* mesh, halfedge_index idx) : mesh(mesh), idx(idx) {} + + bool operator==(halfedge_index const& rhs) const { return idx == rhs; } + bool operator!=(halfedge_index const& rhs) const { return idx != rhs; } + bool operator==(halfedge_handle const& rhs) const { return mesh == rhs.mesh && idx == rhs.idx; } + bool operator!=(halfedge_handle const& rhs) const { return mesh != rhs.mesh || idx != rhs.idx; } +}; +} diff --git a/src/polymesh/iterators.hh b/src/polymesh/iterators.hh new file mode 100644 index 0000000000000000000000000000000000000000..96ed27cab8222e02d44c5c93ee76690aa8de3981 --- /dev/null +++ b/src/polymesh/iterators.hh @@ -0,0 +1,227 @@ +#pragma once + +#include <cassert> + +#include "cursors.hh" + +// For iterator interfaces, see http://anderberg.me/2016/07/04/c-custom-iterators/ +// Note: some iterator methods are implemented at the end of Mesh.hh to ensure inlining + +namespace polymesh +{ +struct valid_vertex_iterator +{ + valid_vertex_iterator() = default; + valid_vertex_iterator(vertex_handle handle) : handle(handle) {} + + vertex_handle operator*() const { return handle; } + valid_vertex_iterator& operator++(); + valid_vertex_iterator operator++(int) + { + auto i = *this; + return ++i; + } + bool operator==(valid_vertex_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx == rhs.handle.idx; + } + bool operator!=(valid_vertex_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx != rhs.handle.idx; + } + +private: + vertex_handle handle; +}; + +struct vertex_iterator +{ + vertex_iterator() = default; + vertex_iterator(vertex_handle handle) : handle(handle) {} + + vertex_handle operator*() const { return handle; } + vertex_iterator& operator++(); + vertex_iterator operator++(int) + { + auto i = *this; + return ++i; + } + bool operator==(vertex_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx == rhs.handle.idx; + } + bool operator!=(vertex_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx != rhs.handle.idx; + } + +private: + vertex_handle handle; +}; + +struct valid_face_iterator +{ + valid_face_iterator() = default; + valid_face_iterator(face_handle handle) : handle(handle) {} + + face_handle operator*() const { return handle; } + valid_face_iterator& operator++(); + valid_face_iterator operator++(int) + { + auto i = *this; + return ++i; + } + bool operator==(valid_face_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx == rhs.handle.idx; + } + bool operator!=(valid_face_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx != rhs.handle.idx; + } + +private: + face_handle handle; +}; + +struct face_iterator +{ + face_iterator() = default; + face_iterator(face_handle handle) : handle(handle) {} + + face_handle operator*() const { return handle; } + face_iterator& operator++(); + face_iterator operator++(int) + { + auto i = *this; + return ++i; + } + bool operator==(face_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx == rhs.handle.idx; + } + bool operator!=(face_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx != rhs.handle.idx; + } + +private: + face_handle handle; +}; + +struct valid_edge_iterator +{ + valid_edge_iterator() = default; + valid_edge_iterator(edge_handle handle) : handle(handle) {} + + edge_handle operator*() const { return handle; } + valid_edge_iterator& operator++(); + valid_edge_iterator operator++(int) + { + auto i = *this; + return ++i; + } + bool operator==(valid_edge_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx == rhs.handle.idx; + } + bool operator!=(valid_edge_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx != rhs.handle.idx; + } + +private: + edge_handle handle; +}; + +struct edge_iterator +{ + edge_iterator() = default; + edge_iterator(edge_handle handle) : handle(handle) {} + + edge_handle operator*() const { return handle; } + edge_iterator& operator++(); + edge_iterator operator++(int) + { + auto i = *this; + return ++i; + } + bool operator==(edge_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx == rhs.handle.idx; + } + bool operator!=(edge_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx != rhs.handle.idx; + } + +private: + edge_handle handle; +}; + +struct valid_halfedge_iterator +{ + valid_halfedge_iterator() = default; + valid_halfedge_iterator(halfedge_handle handle) : handle(handle) {} + + halfedge_handle operator*() const { return handle; } + valid_halfedge_iterator& operator++(); + valid_halfedge_iterator operator++(int) + { + auto i = *this; + return ++i; + } + bool operator==(valid_halfedge_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx == rhs.handle.idx; + } + bool operator!=(valid_halfedge_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx != rhs.handle.idx; + } + +private: + halfedge_handle handle; +}; + +struct halfedge_iterator +{ + halfedge_iterator() = default; + halfedge_iterator(halfedge_handle handle) : handle(handle) {} + + halfedge_handle operator*() const { return handle; } + halfedge_iterator& operator++(); + halfedge_iterator operator++(int) + { + auto i = *this; + return ++i; + } + bool operator==(halfedge_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx == rhs.handle.idx; + } + bool operator!=(halfedge_iterator const& rhs) const + { + assert(handle.mesh == rhs.handle.mesh && "comparing iterators from different meshes"); + return handle.idx != rhs.handle.idx; + } + +private: + halfedge_handle handle; +}; +} diff --git a/src/polymesh/ranges.hh b/src/polymesh/ranges.hh new file mode 100644 index 0000000000000000000000000000000000000000..74ee945b47f786027609aca7e56156648d7e0007 --- /dev/null +++ b/src/polymesh/ranges.hh @@ -0,0 +1,160 @@ +#pragma once + +#include <cstddef> +#include <vector> + +#include "iterators.hh" + +namespace polymesh +{ +/// Collection of all vertices of a mesh, including deleted ones +/// Basically a smart std::vector +struct vertex_collection +{ + Mesh* mesh; + + /// Number of vertices, INCLUDING deleted/invalid ones + /// O(1) computation + int size() const; + /// Ensures that a given number of vertices can be stored without reallocation + void reserve(int capacity) const; + + /// Adds a new vertex and returns its handle + /// Does NOT invalidate any iterator! + vertex_handle add() const; + + // TODO: delete + + // Iteration: + vertex_iterator begin() const; + vertex_iterator end() const; +}; + +/// Same as vertex_collection but only including valid, non-deleted vertices +/// (a bit slower than the normal collection) +/// (if mesh->is_compact(), identical to vertex_collection) +struct valid_vertex_collection +{ + Mesh const* mesh; + + /// Number of vertices, EXCLUDING deleted/invalid ones + /// O(1) computation + int size() const; + + // Iteration: + valid_vertex_iterator begin() const; + valid_vertex_iterator end() const; +}; + +/// Collection of all faces of a mesh, including deleted ones +/// Basically a smart std::vector +struct face_collection +{ + Mesh* mesh; + + /// Number of vertices, INCLUDING deleted/invalid ones + /// O(1) computation + int size() const; + /// Ensures that a given number of faces can be stored without reallocation + void reserve(int capacity) const; + + /// Adds a face consisting of N vertices + /// The vertices must already be sorted in CCW order + /// (note: trying to add already existing halfedges triggers assertions) + template <size_t N> + face_handle add_face(const vertex_handle (&vhandles)[N]) const; + face_handle add_face(vertex_handle v0, vertex_handle v1, vertex_handle v2) const; + face_handle add_face(vertex_handle v0, vertex_handle v1, vertex_handle v2, vertex_handle v3) const; + face_handle add_face(std::vector<vertex_handle> const &vhandles) const; + face_handle add_face(vertex_handle const *vhandles, size_t vcnt) const; + + // TODO: delete + + // Iteration: + face_iterator begin() const; + face_iterator end() const; +}; + +/// Same as face_collection but only including valid, non-deleted faces +/// (a bit slower than the normal collection) +/// (if mesh->is_compact(), identical to face_collection) +struct valid_face_collection +{ + Mesh const* mesh; + + /// Number of faces, EXCLUDING deleted/invalid ones + /// O(1) computation + int size() const; + + // Iteration: + valid_face_iterator begin() const; + valid_face_iterator end() const; +}; + +/// Collection of all edges of a mesh, including deleted ones +/// Basically a smart std::vector +struct edge_collection +{ + Mesh* mesh; + + /// Number of vertices, INCLUDING deleted/invalid ones + /// O(1) computation + int size() const; + /// Ensures that a given number of edges can be stored without reallocation + void reserve(int capacity) const; + + // Iteration: + edge_iterator begin() const; + edge_iterator end() const; +}; + +/// Same as edge_collection but only including valid, non-deleted edges +/// (a bit slower than the normal collection) +/// (if mesh->is_compact(), identical to edge_collection) +struct valid_edge_collection +{ + Mesh const* mesh; + + /// Number of edges, EXCLUDING deleted/invalid ones + /// O(1) computation + int size() const; + + // Iteration: + valid_edge_iterator begin() const; + valid_edge_iterator end() const; +}; + +/// Collection of all half-edges of a mesh, including deleted ones +/// Basically a smart std::vector +struct halfedge_collection +{ + Mesh* mesh; + + /// Number of vertices, INCLUDING deleted/invalid ones + /// O(1) computation + int size() const; + /// Ensures that a given number of half-edges can be stored without reallocation + void reserve(int capacity) const; + + // Iteration: + halfedge_iterator begin() const; + halfedge_iterator end() const; +}; + +/// Same as halfedge_collection but only including valid, non-deleted halfedges +/// (a bit slower than the normal collection) +/// (if mesh->is_compact(), identical to halfedge_collection) +struct valid_halfedge_collection +{ + Mesh const* mesh; + + /// Number of halfedges, EXCLUDING deleted/invalid ones + /// O(1) computation + int size() const; + + // Iteration: + valid_halfedge_iterator begin() const; + valid_halfedge_iterator end() const; +}; + +}