diff options
author | Howard Trickey <howard.trickey@gmail.com> | 2020-08-21 17:02:58 +0300 |
---|---|---|
committer | Howard Trickey <howard.trickey@gmail.com> | 2020-08-21 17:02:58 +0300 |
commit | 4b13eb278813ad14782bfa16881f27cdd59c2c6a (patch) | |
tree | 90d5d03675fc6294bb4d4ef966ac26f8835bc59c /source/blender/blenlib | |
parent | 481927d4d6e124af8f707cd9d8c97f9e8a127d0c (diff) |
Rename some classes at the suggestion of reviewers.
Mesh -> IMesh; MArena -> IMeshArena
Remove type abbreviations Vertp and Facep.
Diffstat (limited to 'source/blender/blenlib')
-rw-r--r-- | source/blender/blenlib/BLI_mesh_boolean.hh | 30 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_mesh_intersect.hh | 125 | ||||
-rw-r--r-- | source/blender/blenlib/intern/mesh_boolean.cc | 370 | ||||
-rw-r--r-- | source/blender/blenlib/intern/mesh_intersect.cc | 289 | ||||
-rw-r--r-- | source/blender/blenlib/tests/BLI_mesh_boolean_test.cc | 178 | ||||
-rw-r--r-- | source/blender/blenlib/tests/BLI_mesh_intersect_test.cc | 219 |
6 files changed, 614 insertions, 597 deletions
diff --git a/source/blender/blenlib/BLI_mesh_boolean.hh b/source/blender/blenlib/BLI_mesh_boolean.hh index b9b57216345..324a5adecc7 100644 --- a/source/blender/blenlib/BLI_mesh_boolean.hh +++ b/source/blender/blenlib/BLI_mesh_boolean.hh @@ -49,27 +49,27 @@ enum bool_optype { * of triangles, each of whose orig_field says which face in pm that triangle belongs to. * pm arg isn't const because we may populate its verts (for debugging). * Same goes for the pm_triangulated arg. - * The output Mesh will have faces whose orig fields map back to faces and edges in + * The output IMesh will have faces whose orig fields map back to faces and edges in * the input mesh. */ -Mesh boolean_mesh(Mesh &pm, - bool_optype op, - int nshapes, - std::function<int(int)> shape_fn, - bool use_self, - Mesh *pm_triangulated, - MArena *arena); +IMesh boolean_mesh(IMesh &pm, + bool_optype op, + int nshapes, + std::function<int(int)> shape_fn, + bool use_self, + IMesh *pm_triangulated, + IMeshArena *arena); -/* This is like boolean, but operates on Mesh's whose faces are all triangles. +/* This is like boolean, but operates on IMesh's whose faces are all triangles. * It is exposed mainly for unit testing, at the moment: boolean_mesh() uses * it to do most of its work. */ -Mesh boolean_trimesh(Mesh &tm, - bool_optype op, - int nshapes, - std::function<int(int)> shape_fn, - bool use_self, - MArena *arena); +IMesh boolean_trimesh(IMesh &tm, + bool_optype op, + int nshapes, + std::function<int(int)> shape_fn, + bool use_self, + IMeshArena *arena); } // namespace blender::meshintersect diff --git a/source/blender/blenlib/BLI_mesh_intersect.hh b/source/blender/blenlib/BLI_mesh_intersect.hh index 39738376b1a..1c77a67877d 100644 --- a/source/blender/blenlib/BLI_mesh_intersect.hh +++ b/source/blender/blenlib/BLI_mesh_intersect.hh @@ -77,13 +77,7 @@ struct Vert { uint64_t hash() const; }; -/* Use Vertp for Verts everywhere: can modify the pointer - * but not the underlying Vert, which should stay constant - * after creation. - */ -using Vertp = const Vert *; - -std::ostream &operator<<(std::ostream &os, Vertp v); +std::ostream &operator<<(std::ostream &os, const Vert *v); /* A Plane whose equation is dot(nprm, p) + d = 0. */ struct Plane { @@ -121,7 +115,7 @@ std::ostream &operator<<(std::ostream &os, const Plane &plane); * a Face also stores the Plane of the face. */ struct Face { - Array<Vertp> vert; + Array<const Vert *> vert; Array<int> edge_orig; Array<bool> is_intersect; Plane plane; @@ -131,8 +125,8 @@ struct Face { using FacePos = int; Face() = default; - Face(Span<Vertp> verts, int id, int orig, Span<int> edge_origs, Span<bool> is_intersect); - Face(Span<Vertp> verts, int id, int orig); + Face(Span<const Vert *> verts, int id, int orig, Span<int> edge_origs, Span<bool> is_intersect); + Face(Span<const Vert *> verts, int id, int orig); Face(const Face &other); Face(Face &&other) noexcept; @@ -162,7 +156,7 @@ struct Face { return (p + vert.size() - 1) % vert.size(); } - const Vertp &operator[](int index) const + const Vert *const &operator[](int index) const { return vert[index]; } @@ -172,12 +166,12 @@ struct Face { return vert.size(); } - const Vertp *begin() const + const Vert *const *begin() const { return vert.begin(); } - const Vertp *end() const + const Vert *const *end() const { return vert.end(); } @@ -188,29 +182,27 @@ struct Face { } }; -using Facep = const Face *; - -std::ostream &operator<<(std::ostream &os, Facep f); +std::ostream &operator<<(std::ostream &os, const Face *f); -/* MArena is the owner of the Vert and Face resources used +/* IMeshArena is the owner of the Vert and Face resources used * during a run of one of the meshintersect main functions. * It also keeps has a hash table of all Verts created so that it can * ensure that only one instance of a Vert with a given co_exact will * exist. I.e., it dedups the vertices. */ -class MArena { - class MArenaImpl; - std::unique_ptr<MArenaImpl> pimpl_; +class IMeshArena { + class IMeshArenaImpl; + std::unique_ptr<IMeshArenaImpl> pimpl_; public: - MArena(); - MArena(const MArena &) = delete; - MArena(MArena &&) = delete; + IMeshArena(); + IMeshArena(const IMeshArena &) = delete; + IMeshArena(IMeshArena &&) = delete; - ~MArena(); + ~IMeshArena(); - MArena &operator=(const MArena &) = delete; - MArena &operator=(MArena &&) = delete; + IMeshArena &operator=(const IMeshArena &) = delete; + IMeshArena &operator=(IMeshArena &&) = delete; /* Provide hints to number of expected Verts and Faces expected * to be allocated. @@ -225,42 +217,45 @@ class MArena { * or else allocates and returns a new one. The index field of a * newly allocated Vert will be the index in creation order. */ - Vertp add_or_find_vert(const mpq3 &co, int orig); - Vertp add_or_find_vert(const double3 &co, int orig); + const Vert *add_or_find_vert(const mpq3 &co, int orig); + const Vert *add_or_find_vert(const double3 &co, int orig); - Facep add_face(Span<Vertp> verts, int orig, Span<int> edge_origs, Span<bool> is_intersect); - Facep add_face(Span<Vertp> verts, int orig, Span<int> edge_origs); - Facep add_face(Span<Vertp> verts, int orig); + const Face *add_face(Span<const Vert *> verts, + int orig, + Span<int> edge_origs, + Span<bool> is_intersect); + const Face *add_face(Span<const Vert *> verts, int orig, Span<int> edge_origs); + const Face *add_face(Span<const Vert *> verts, int orig); /* The following return nullptr if not found. */ - Vertp find_vert(const mpq3 &co) const; - Facep find_face(Span<Vertp> verts) const; + const Vert *find_vert(const mpq3 &co) const; + const Face *find_face(Span<const Vert *> verts) const; }; -/* A blender::meshintersect::Mesh is a self-contained mesh structure +/* A blender::meshintersect::IMesh is a self-contained mesh structure * that can be used in Blenlib without depending on the rest of Blender. - * The Vert and Face resources used in the Mesh should be owned by - * some MArena. - * The Verts used by a Mesh can be recovered from the Faces, so - * are usually not stored, but on request, the Mesh can populate + * The Vert and Face resources used in the IMesh should be owned by + * some IMeshArena. + * The Verts used by a IMesh can be recovered from the Faces, so + * are usually not stored, but on request, the IMesh can populate * internal structures for indexing exactly the set of needed Verts, * and also going from a Vert pointer to the index in that system. */ -class Mesh { - Array<Facep> face_; - Array<Vertp> vert_; /* Only valid if vert_populated_. */ - Map<Vertp, int> vert_to_index_; /* Only valid if vert_populated_. */ +class IMesh { + Array<const Face *> face_; + Array<const Vert *> vert_; /* Only valid if vert_populated_. */ + Map<const Vert *, int> vert_to_index_; /* Only valid if vert_populated_. */ bool vert_populated_ = false; public: - Mesh() = default; - Mesh(Span<Facep> faces) : face_(faces) + IMesh() = default; + IMesh(Span<const Face *> faces) : face_(faces) { } - void set_faces(Span<Facep> faces); - Facep face(int index) const + void set_faces(Span<const Face *> faces); + const Face *face(int index) const { return face_[index]; } @@ -284,7 +279,7 @@ class Mesh { { vert_populated_ = false; vert_to_index_.clear(); - vert_ = Array<Vertp>(); + vert_ = Array<const Vert *>(); } /* Use the second of these if there is a good bound @@ -293,14 +288,14 @@ class Mesh { void populate_vert(); void populate_vert(int max_verts); - Vertp vert(int index) const + const Vert *vert(int index) const { BLI_assert(vert_populated_); return vert_[index]; } /* Returns index in vert_ where v is, or NO_INDEX. */ - int lookup_vert(Vertp v) const; + int lookup_vert(const Vert *v) const; IndexRange vert_index_range() const { @@ -313,45 +308,45 @@ class Mesh { return IndexRange(face_.size()); } - Span<Vertp> vertices() const + Span<const Vert *> vertices() const { BLI_assert(vert_populated_); - return Span<Vertp>(vert_); + return Span<const Vert *>(vert_); } - Span<Facep> faces() const + Span<const Face *> faces() const { - return Span<Facep>(face_); + return Span<const Face *>(face_); } /* Replace face at given index with one that elides the * vertices at the positions in face_pos_erase that are true. * Use arena to allocate the new face in. */ - void erase_face_positions(int f_index, Span<bool> face_pos_erase, MArena *arena); + void erase_face_positions(int f_index, Span<bool> face_pos_erase, IMeshArena *arena); }; -std::ostream &operator<<(std::ostream &os, const Mesh &mesh); +std::ostream &operator<<(std::ostream &os, const IMesh &mesh); /* The output will have dup vertices merged and degenerate triangles ignored. * If the input has overlapping coplanar triangles, then there will be * as many duplicates as there are overlaps in each overlapping triangular region. - * The orig field of each IndexedTriangle will give the orig index in the input TriMesh + * The orig field of each IndexedTriangle will give the orig index in the input IMesh * that the output triangle was a part of (input can have -1 for that field and then * the index in tri[] will be used as the original index). - * The orig structure of the output TriMesh gives the originals for vertices and edges. + * The orig structure of the output IMesh gives the originals for vertices and edges. * Note: if the input tm_in has a non-empty orig structure, then it is ignored. */ -Mesh trimesh_self_intersect(const Mesh &tm_in, MArena *arena); +IMesh trimesh_self_intersect(const IMesh &tm_in, IMeshArena *arena); -Mesh trimesh_nary_intersect(const Mesh &tm_in, - int nshapes, - std::function<int(int)> shape_fn, - bool use_self, - MArena *arena); +IMesh trimesh_nary_intersect(const IMesh &tm_in, + int nshapes, + std::function<int(int)> shape_fn, + bool use_self, + IMeshArena *arena); -/* This has the side effect of populating verts in the Mesh. */ -void write_obj_mesh(Mesh &m, const std::string &objname); +/* This has the side effect of populating verts in the IMesh. */ +void write_obj_mesh(IMesh &m, const std::string &objname); } /* namespace blender::meshintersect */ diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc index b76ff3c38a4..4a9bf28ac78 100644 --- a/source/blender/blenlib/intern/mesh_boolean.cc +++ b/source/blender/blenlib/intern/mesh_boolean.cc @@ -39,16 +39,16 @@ namespace blender::meshintersect { -/* Edge as two Vertp's, in a canonical order (lower vert id first). +/* Edge as two const Vert *'s, in a canonical order (lower vert id first). * We use the Vert id field for hashing to get algorithms * that yield predictable results from run-to-run and machine-to-machine. */ class Edge { - Vertp v_[2]{nullptr, nullptr}; + const Vert *v_[2]{nullptr, nullptr}; public: Edge() = default; - Edge(Vertp v0, Vertp v1) + Edge(const Vert *v0, const Vert *v1) { if (v0->id <= v1->id) { v_[0] = v0; @@ -60,17 +60,17 @@ class Edge { } } - Vertp v0() const + const Vert *v0() const { return v_[0]; } - Vertp v1() const + const Vert *v1() const { return v_[1]; } - Vertp operator[](int i) const + const Vert *operator[](int i) const { return v_[i]; } @@ -118,15 +118,15 @@ static std::ostream &operator<<(std::ostream &os, const Array<int> &iarr) return os; } -/* Holds information about topology of a Mesh that is all triangles. */ +/* Holds information about topology of an IMesh that is all triangles. */ class TriMeshTopology { /* Triangles that contain a given Edge (either order). */ Map<Edge, Vector<int> *> edge_tri_; /* Edges incident on each vertex. */ - Map<Vertp, Vector<Edge>> vert_edges_; + Map<const Vert *, Vector<Edge>> vert_edges_; public: - TriMeshTopology(const Mesh &tm); + TriMeshTopology(const IMesh &tm); TriMeshTopology(const TriMeshTopology &other) = delete; TriMeshTopology(const TriMeshTopology &&other) = delete; ~TriMeshTopology(); @@ -153,7 +153,7 @@ class TriMeshTopology { /* Which edges are incident on the given vertex? * We assume v has some incident edges. */ - const Vector<Edge> &vert_edges(Vertp v) const + const Vector<Edge> &vert_edges(const Vert *v) const { return vert_edges_.lookup(v); } @@ -164,7 +164,7 @@ class TriMeshTopology { } }; -TriMeshTopology::TriMeshTopology(const Mesh &tm) +TriMeshTopology::TriMeshTopology(const IMesh &tm) { const int dbg_level = 0; if (dbg_level > 0) { @@ -181,8 +181,8 @@ TriMeshTopology::TriMeshTopology(const Mesh &tm) const Face &tri = *tm.face(t); BLI_assert(tri.is_tri()); for (int i = 0; i < 3; ++i) { - Vertp v = tri[i]; - Vertp vnext = tri[(i + 1) % 3]; + const Vert *v = tri[i]; + const Vert *vnext = tri[(i + 1) % 3]; Edge e(v, vnext); Vector<Edge> *edges = vert_edges_.lookup_ptr(v); if (edges == nullptr) { @@ -284,7 +284,7 @@ static std::ostream &operator<<(std::ostream &os, const Patch &patch) } class PatchesInfo { - /* All of the Patches for a Mesh. */ + /* All of the Patches for a IMesh. */ Vector<Patch> patch_; /* Patch index for corresponding triangle. */ Array<int> tri_patch_; @@ -450,7 +450,7 @@ class Cell { /* Call this when it is possible that this Cell has zero volume, * and if it does, set zero_volume_ to true. */ - void check_for_zero_volume(const PatchesInfo &pinfo, const Mesh &mesh); + void check_for_zero_volume(const PatchesInfo &pinfo, const IMesh &mesh); }; static std::ostream &operator<<(std::ostream &os, const Cell &cell) @@ -464,7 +464,7 @@ static std::ostream &operator<<(std::ostream &os, const Cell &cell) return os; } -static bool tris_have_same_verts(const Mesh &mesh, int t1, int t2) +static bool tris_have_same_verts(const IMesh &mesh, int t1, int t2) { const Face &tri1 = *mesh.face(t1); const Face &tri2 = *mesh.face(t2); @@ -488,7 +488,7 @@ static bool tris_have_same_verts(const Mesh &mesh, int t1, int t2) * patches are geometrically identical triangles (perhaps flipped versions of each other). * If this Cell has zero volume, set its zero_volume_ member to true. */ -void Cell::check_for_zero_volume(const PatchesInfo &pinfo, const Mesh &mesh) +void Cell::check_for_zero_volume(const PatchesInfo &pinfo, const IMesh &mesh) { if (patches_.size() == 2) { const Patch &p1 = pinfo.patch(patches_[0]); @@ -553,7 +553,7 @@ class CellsInfo { }; /* For Debugging: write a .obj file showing the patch/cell structure or just the cells. */ -static void write_obj_cell_patch(const Mesh &m, +static void write_obj_cell_patch(const IMesh &m, const CellsInfo &cinfo, const PatchesInfo &pinfo, bool cells_only, @@ -576,11 +576,11 @@ static void write_obj_cell_patch(const Mesh &m, return; } - /* Copy Mesh so can populate verts. */ - Mesh mm = m; + /* Copy IMesh so can populate verts. */ + IMesh mm = m; mm.populate_vert(); f << "o cellpatch\n"; - for (Vertp v : mm.vertices()) { + for (const Vert *v : mm.vertices()) { const double3 dv = v->co; f << "v " << dv[0] << " " << dv[1] << " " << dv[2] << "\n"; } @@ -591,7 +591,7 @@ static void write_obj_cell_patch(const Mesh &m, for (int t : patch.tris()) { const Face &tri = *mm.face(t); f << "f "; - for (Vertp v : tri) { + for (const Vert *v : tri) { f << mm.lookup_vert(v) + 1 << " "; } f << "\n"; @@ -606,7 +606,7 @@ static void write_obj_cell_patch(const Mesh &m, for (int t : patch.tris()) { const Face &tri = *mm.face(t); f << "f "; - for (Vertp v : tri) { + for (const Vert *v : tri) { f << mm.lookup_vert(v) + 1 << " "; } f << "\n"; @@ -644,7 +644,7 @@ static void merge_cells(int merge_to, int merge_from, CellsInfo &cinfo, PatchesI } /* Partition the triangles of tm into Patches. */ -static PatchesInfo find_patches(const Mesh &tm, const TriMeshTopology &tmtopo) +static PatchesInfo find_patches(const IMesh &tm, const TriMeshTopology &tmtopo) { const int dbg_level = 0; if (dbg_level > 0) { @@ -744,10 +744,10 @@ static PatchesInfo find_patches(const Mesh &tm, const TriMeshTopology &tmtopo) * Also, e may be reversed in tri. * Set *r_rev to true if it is reversed, else false. */ -static Vertp find_flap_vert(const Face &tri, const Edge e, bool *r_rev) +static const Vert *find_flap_vert(const Face &tri, const Edge e, bool *r_rev) { *r_rev = false; - Vertp flapv; + const Vert *flapv; if (tri[0] == e.v0()) { if (tri[1] == e.v1()) { *r_rev = false; @@ -818,8 +818,8 @@ static int sort_tris_class(const Face &tri, const Face &tri0, const Edge e) mpq3 a2 = tri0[2]->co_exact; bool rev; bool rev0; - Vertp flapv0 = find_flap_vert(tri0, e, &rev0); - Vertp flapv = find_flap_vert(tri, e, &rev); + const Vert *flapv0 = find_flap_vert(tri0, e, &rev0); + const Vert *flapv = find_flap_vert(tri, e, &rev); if (dbg_level > 0) { std::cout << " t0 = " << tri0[0] << " " << tri0[1] << " " << tri0[2]; std::cout << " rev0 = " << rev0 << " flapv0 = " << flapv0 << "\n"; @@ -855,8 +855,8 @@ constexpr int EXTRA_TRI_INDEX = INT_MAX; */ static void sort_by_signed_triangle_index(Vector<int> &g, const Edge e, - const Mesh &tm, - Facep extra_tri) + const IMesh &tm, + const Face *extra_tri) { Array<int> signed_g(g.size()); for (int i : g.index_range()) { @@ -887,12 +887,12 @@ static void sort_by_signed_triangle_index(Vector<int> &g, * To accommodate this: * If extra_tri is non-null, then an index of EXTRA_TRI_INDEX should use it for the triangle. */ -static Array<int> sort_tris_around_edge(const Mesh &tm, +static Array<int> sort_tris_around_edge(const IMesh &tm, const TriMeshTopology &tmtopo, const Edge e, const Span<int> &tris, const int t0, - Facep extra_tri) + const Face *extra_tri) { /* Divide and conquer, quicksort-like sort. * Pick a triangle t0, then partition into groups: @@ -997,7 +997,7 @@ static Array<int> sort_tris_around_edge(const Mesh &tm, * bipartite graph edges between cells and patches. * Will modify pinfo and cinfo and the patches and cells they contain. */ -static void find_cells_from_edge(const Mesh &tm, +static void find_cells_from_edge(const IMesh &tm, const TriMeshTopology &tmtopo, PatchesInfo &pinfo, CellsInfo &cinfo, @@ -1094,7 +1094,7 @@ static void find_cells_from_edge(const Mesh &tm, /* Find the partition of 3-space into Cells. * This assigns the cell_above and cell_below for each Patch. */ -static CellsInfo find_cells(const Mesh &tm, const TriMeshTopology &tmtopo, PatchesInfo &pinfo) +static CellsInfo find_cells(const IMesh &tm, const TriMeshTopology &tmtopo, PatchesInfo &pinfo) { const int dbg_level = 0; if (dbg_level > 0) { @@ -1251,7 +1251,7 @@ static bool patch_cell_graph_ok(const CellsInfo &cinfo, const PatchesInfo &pinfo * this without being PWN. So this routine will be only * approximately right. */ -static bool is_pwn(const Mesh &tm, const TriMeshTopology &tmtopo) +static bool is_pwn(const IMesh &tm, const TriMeshTopology &tmtopo) { constexpr int dbg_level = 0; for (auto item : tmtopo.edge_tri_map_items()) { @@ -1293,21 +1293,21 @@ static bool is_pwn(const Mesh &tm, const TriMeshTopology &tmtopo) */ static int find_cell_for_point_near_edge(mpq3 p, const Edge &e, - const Mesh &tm, + const IMesh &tm, const TriMeshTopology &tmtopo, const PatchesInfo &pinfo, - MArena *arena) + IMeshArena *arena) { constexpr int dbg_level = 0; if (dbg_level > 0) { std::cout << "FIND_CELL_FOR_POINT_NEAR_EDGE, p=" << p << " e=" << e << "\n"; } const Vector<int> *etris = tmtopo.edge_tris(e); - Vertp dummy_vert = arena->add_or_find_vert(p, NO_INDEX); - Facep dummy_tri = arena->add_face({e.v0(), e.v1(), dummy_vert}, - NO_INDEX, - {NO_INDEX, NO_INDEX, NO_INDEX}, - {false, false, false}); + const Vert *dummy_vert = arena->add_or_find_vert(p, NO_INDEX); + const Face *dummy_tri = arena->add_face({e.v0(), e.v1(), dummy_vert}, + NO_INDEX, + {NO_INDEX, NO_INDEX, NO_INDEX}, + {false, false, false}); Array<int> edge_tris(etris->size() + 1); std::copy(etris->begin(), etris->end(), edge_tris.begin()); edge_tris[edge_tris.size() - 1] = EXTRA_TRI_INDEX; @@ -1355,25 +1355,25 @@ static int find_cell_for_point_near_edge(mpq3 p, * to the dummy triangle - thus revealing the cell that the point * known to be outside the whole mesh is in. */ -static int find_ambient_cell(const Mesh &tm, +static int find_ambient_cell(const IMesh &tm, const Vector<int> *component_patches, const TriMeshTopology &tmtopo, const PatchesInfo &pinfo, - MArena *arena) + IMeshArena *arena) { int dbg_level = 0; if (dbg_level > 0) { std::cout << "FIND_AMBIENT_CELL\n"; } /* First find a vertex with the maximum x value. */ - /* Prefer not to populate the verts in the Mesh just for this. */ - Vertp v_extreme; + /* Prefer not to populate the verts in the IMesh just for this. */ + const Vert *v_extreme; mpq_class extreme_x; if (component_patches == nullptr) { v_extreme = (*tm.face(0))[0]; extreme_x = v_extreme->co_exact.x; - for (Facep f : tm.faces()) { - for (Vertp v : *f) { + for (const Face *f : tm.faces()) { + for (const Vert *v : *f) { const mpq_class &x = v->co_exact.x; if (x > extreme_x) { v_extreme = v; @@ -1391,8 +1391,8 @@ static int find_ambient_cell(const Mesh &tm, extreme_x = v_extreme->co_exact.x; for (int p : *component_patches) { for (int t : pinfo.patch(p).tris()) { - Facep f = tm.face(t); - for (Vertp v : *f) { + const Face *f = tm.face(t); + for (const Vert *v : *f) { const mpq_class &x = v->co_exact.x; if (x > extreme_x) { v_extreme = v; @@ -1414,7 +1414,7 @@ static int find_ambient_cell(const Mesh &tm, Edge ehull; mpq_class max_abs_slope = -1; for (Edge e : edges) { - const Vertp v_other = (e.v0() == v_extreme) ? e.v1() : e.v0(); + const const Vert *v_other = (e.v0() == v_extreme) ? e.v1() : e.v0(); const mpq3 &co_other = v_other->co_exact; mpq_class delta_x = co_other.x - extreme_x; if (delta_x == 0) { @@ -1450,7 +1450,9 @@ static int find_ambient_cell(const Mesh &tm, * and then choose the edge that, when projected, has the maximum absolute * slope (regarding the line testp-closestp as the xaxis for slope computation). */ -static Edge find_good_sorting_edge(Vertp testp, Vertp closestp, const TriMeshTopology &tmtopo) +static Edge find_good_sorting_edge(const Vert *testp, + const Vert *closestp, + const TriMeshTopology &tmtopo) { constexpr int dbg_level = 0; if (dbg_level > 0) { @@ -1493,7 +1495,7 @@ static Edge find_good_sorting_edge(Vertp testp, Vertp closestp, const TriMeshTop Edge esort; const Vector<Edge> &edges = tmtopo.vert_edges(closestp); for (Edge e : edges) { - const Vertp v_other = (e.v0() == closestp) ? e.v1() : e.v0(); + const const Vert *v_other = (e.v0() == closestp) ? e.v1() : e.v0(); const mpq3 &co_other = v_other->co_exact; mpq3 evec = co_other - co_closest; /* Get projection of evec onto plane of abscissa and ordinate. */ @@ -1541,14 +1543,14 @@ static Edge find_good_sorting_edge(Vertp testp, Vertp closestp, const TriMeshTop * have a particular point (v) and we just want to determine the patches * that that point is between in sorting-around-an-edge order. */ -static int find_containing_cell(Vertp v, +static int find_containing_cell(const Vert *v, int t, int close_edge, int close_vert, const PatchesInfo &pinfo, - const Mesh &tm, + const IMesh &tm, const TriMeshTopology &tmtopo, - MArena *arena) + IMeshArena *arena) { constexpr int dbg_level = 0; if (dbg_level > 0) { @@ -1561,8 +1563,8 @@ static int find_containing_cell(Vertp v, close_edge = 0; } if (close_edge != -1) { - Vertp v0 = tri[close_edge]; - Vertp v1 = tri[(close_edge + 1) % 3]; + const Vert *v0 = tri[close_edge]; + const Vert *v1 = tri[(close_edge + 1) % 3]; const Vector<Edge> &edges = tmtopo.vert_edges(v0); if (dbg_level > 0) { std::cout << "look for edge containing " << v0 << " and " << v1 << "\n"; @@ -1581,7 +1583,7 @@ static int find_containing_cell(Vertp v, } else { int cv = close_vert; - Vertp vert_cv = tri[cv]; + const Vert *vert_cv = tri[cv]; if (vert_cv == v) { /* Need to use another one to find sorting edge. */ vert_cv = tri[(cv + 1) % 3]; @@ -1732,10 +1734,10 @@ struct ComponentContainer { static Vector<ComponentContainer> find_component_containers(int comp, const Vector<Vector<int>> &components, const Array<int> &ambient_cell, - const Mesh &tm, + const IMesh &tm, const PatchesInfo &pinfo, const TriMeshTopology &tmtopo, - MArena *arena) + IMeshArena *arena) { constexpr int dbg_level = 0; if (dbg_level > 0) { @@ -1744,7 +1746,7 @@ static Vector<ComponentContainer> find_component_containers(int comp, Vector<ComponentContainer> ans; int test_p = components[comp][0]; int test_t = pinfo.patch(test_p).tri(0); - Vertp test_v = tm.face(test_t)[0].vert[0]; + const Vert *test_v = tm.face(test_t)[0].vert[0]; if (dbg_level > 0) { std::cout << "test vertex in comp: " << test_v << "\n"; } @@ -1789,7 +1791,7 @@ static Vector<ComponentContainer> find_component_containers(int comp, if (dbg_level > 0) { std::cout << "closest tri to comp=" << comp << " in comp_other=" << comp_other << " is t" << nearest_tri << "\n"; - Facep tn = tm.face(nearest_tri); + const Face *tn = tm.face(nearest_tri); std::cout << "tri = " << tn << "\n"; std::cout << " (" << tn->vert[0]->co << "," << tn->vert[1]->co << "," << tn->vert[2]->co << ")\n"; @@ -1819,11 +1821,11 @@ static Vector<ComponentContainer> find_component_containers(int comp, * Connect the bipartite graph. This involves discovering the connected components * of the patches, then the nesting structure of those components. */ -static void finish_patch_cell_graph(const Mesh &tm, +static void finish_patch_cell_graph(const IMesh &tm, CellsInfo &cinfo, PatchesInfo &pinfo, const TriMeshTopology &tmtopo, - MArena *arena) + IMeshArena *arena) { constexpr int dbg_level = 0; if (dbg_level > 0) { @@ -2046,11 +2048,11 @@ static bool apply_bool_op(int bool_optype, const Array<int> &winding) * triangles that are part of stacks of geometrically identical * triangles enclosing zero volume cells. */ -static void extract_zero_volume_cell_tris(Vector<Facep> &out_tris, - const Mesh &tm_subdivided, +static void extract_zero_volume_cell_tris(Vector<const Face *> &out_tris, + const IMesh &tm_subdivided, const PatchesInfo &pinfo, const CellsInfo &cinfo, - MArena *arena) + IMeshArena *arena) { int dbg_level = 0; if (dbg_level > 0) { @@ -2146,14 +2148,14 @@ static void extract_zero_volume_cell_tris(Vector<Facep> &out_tris, } } if (t_to_add == NO_INDEX) { - Facep f = tm_subdivided.face(pinfo.patch(p).tri(0)); + const Face *f = tm_subdivided.face(pinfo.patch(p).tri(0)); const Face &tri = *f; /* We need flipped version or else we would have found it above. */ - Array<Vertp> flipped_vs = {tri[0], tri[2], tri[1]}; + Array<const Vert *> flipped_vs = {tri[0], tri[2], tri[1]}; Array<int> flipped_e_origs = {tri.edge_orig[2], tri.edge_orig[1], tri.edge_orig[0]}; Array<bool> flipped_is_intersect = { tri.is_intersect[2], tri.is_intersect[1], tri.is_intersect[0]}; - Facep flipped_f = arena->add_face( + const Face *flipped_f = arena->add_face( flipped_vs, f->orig, flipped_e_origs, flipped_is_intersect); out_tris.append(flipped_f); } @@ -2170,16 +2172,16 @@ static void extract_zero_volume_cell_tris(Vector<Facep> &out_tris, * include either one version of the triangle or none, depending on * whether the flags on either side of the stack are different or the same. */ -static Mesh extract_from_flag_diffs(const Mesh &tm_subdivided, - const PatchesInfo &pinfo, - const CellsInfo &cinfo, - MArena *arena) +static IMesh extract_from_flag_diffs(const IMesh &tm_subdivided, + const PatchesInfo &pinfo, + const CellsInfo &cinfo, + IMeshArena *arena) { constexpr int dbg_level = 0; if (dbg_level > 0) { std::cout << "\nEXTRACT_FROM_FLAG_DIFFS\n"; } - Vector<Facep> out_tris; + Vector<const Face *> out_tris; out_tris.reserve(tm_subdivided.face_size()); bool any_zero_volume_cell = false; for (int t : tm_subdivided.face_index_range()) { @@ -2200,14 +2202,14 @@ static Mesh extract_from_flag_diffs(const Mesh &tm_subdivided, if (dbg_level > 0) { std::cout << "need tri " << t << " flip=" << flip << "\n"; } - Facep f = tm_subdivided.face(t); + const Face *f = tm_subdivided.face(t); if (flip) { const Face &tri = *f; - Array<Vertp> flipped_vs = {tri[0], tri[2], tri[1]}; + Array<const Vert *> flipped_vs = {tri[0], tri[2], tri[1]}; Array<int> flipped_e_origs = {tri.edge_orig[2], tri.edge_orig[1], tri.edge_orig[0]}; Array<bool> flipped_is_intersect = { tri.is_intersect[2], tri.is_intersect[1], tri.is_intersect[0]}; - Facep flipped_f = arena->add_face( + const Face *flipped_f = arena->add_face( flipped_vs, f->orig, flipped_e_origs, flipped_is_intersect); out_tris.append(flipped_f); } @@ -2219,7 +2221,7 @@ static Mesh extract_from_flag_diffs(const Mesh &tm_subdivided, if (any_zero_volume_cell) { extract_zero_volume_cell_tris(out_tris, tm_subdivided, pinfo, cinfo, arena); } - return Mesh(out_tris); + return IMesh(out_tris); } static const char *bool_optype_name(bool_optype op) @@ -2243,9 +2245,9 @@ static const char *bool_optype_name(bool_optype op) static mpq3 calc_point_inside_tri(const Face &tri) { - Vertp v0 = tri.vert[0]; - Vertp v1 = tri.vert[1]; - Vertp v2 = tri.vert[2]; + const Vert *v0 = tri.vert[0]; + const Vert *v1 = tri.vert[1]; + const Vert *v2 = tri.vert[2]; mpq3 ans = v0->co_exact / 3 + v1->co_exact / 3 + v2->co_exact / 3; return ans; } @@ -2261,7 +2263,7 @@ static mpq3 calc_point_inside_tri(const Face &tri) * TOOD: speed up this calculation using the heirarchical algorithm in * that paper. */ -static double generalized_winding_number(const Mesh &tm, +static double generalized_winding_number(const IMesh &tm, std::function<int(int)> shape_fn, const double3 &testp, int shape) @@ -2272,15 +2274,15 @@ static double generalized_winding_number(const Mesh &tm, } double gwn = 0; for (int t : tm.face_index_range()) { - Facep f = tm.face(t); + const Face *f = tm.face(t); const Face &tri = *f; if (shape_fn(tri.orig) == shape) { if (dbg_level > 0) { std::cout << "accumulate for tri t = " << t << " = " << f << "\n"; } - Vertp v0 = tri.vert[0]; - Vertp v1 = tri.vert[1]; - Vertp v2 = tri.vert[2]; + const Vert *v0 = tri.vert[0]; + const Vert *v1 = tri.vert[1]; + const Vert *v2 = tri.vert[2]; double3 a = v0->co - testp; double3 b = v1->co - testp; double3 c = v2->co - testp; @@ -2319,7 +2321,7 @@ static double generalized_winding_number(const Mesh &tm, /* Return true if point testp is inside the volume implied by the * faces for which the shape_fn returns the value shape. */ -static bool point_is_inside_shape(const Mesh &tm, +static bool point_is_inside_shape(const IMesh &tm, std::function<int(int)> shape_fn, const double3 &testp, int shape) @@ -2335,19 +2337,19 @@ static bool point_is_inside_shape(const Mesh &tm, * mesh is supposed to be included or excluded in the boolean result, * and return the mesh that is the boolean result. */ -static Mesh gwn_boolean(const Mesh &tm, - bool_optype op, - int nshapes, - std::function<int(int)> shape_fn, - const PatchesInfo &pinfo, - MArena *arena) +static IMesh gwn_boolean(const IMesh &tm, + bool_optype op, + int nshapes, + std::function<int(int)> shape_fn, + const PatchesInfo &pinfo, + IMeshArena *arena) { constexpr int dbg_level = 0; if (dbg_level > 0) { std::cout << "GWN_BOOLEAN\n"; } - Mesh ans; - Vector<Facep> out_faces; + IMesh ans; + Vector<const Face *> out_faces; out_faces.reserve(tm.face_size()); BLI_assert(nshapes == 2); /* TODO: generalize. */ for (int p : pinfo.index_range()) { @@ -2401,18 +2403,18 @@ static Mesh gwn_boolean(const Mesh &tm, } if (!do_remove) { for (int t : patch.tris()) { - Facep f = tm.face(t); + const Face *f = tm.face(t); if (!do_flip) { out_faces.append(f); } else { const Face &tri = *f; /* We need flipped version of f. */ - Array<Vertp> flipped_vs = {tri[0], tri[2], tri[1]}; + Array<const Vert *> flipped_vs = {tri[0], tri[2], tri[1]}; Array<int> flipped_e_origs = {tri.edge_orig[2], tri.edge_orig[1], tri.edge_orig[0]}; Array<bool> flipped_is_intersect = { tri.is_intersect[2], tri.is_intersect[1], tri.is_intersect[0]}; - Facep flipped_f = arena->add_face( + const Face *flipped_f = arena->add_face( flipped_vs, f->orig, flipped_e_origs, flipped_is_intersect); out_faces.append(flipped_f); } @@ -2437,14 +2439,14 @@ static int find_cdt_edge(const CDT_result<mpq_class> &cdt_out, int v1, int v2) return -1; } -/* Tesselate face f into triangles and return an array of Facep +/* Tesselate face f into triangles and return an array of const Face * * giving that triangulation. * Care is taken so that the original edge index associated with * each edge in the output triangles either matches the original edge * for the (identical) edge of f, or else is -1. So diagonals added * for triangulation can later be indentified by having NO_INDEX for original. */ -static Array<Facep> triangulate_poly(Facep f, MArena *arena) +static Array<const Face *> triangulate_poly(const Face *f, IMeshArena *arena) { int flen = f->size(); CDT_input<mpq_class> cdt_in; @@ -2478,10 +2480,10 @@ static Array<Facep> triangulate_poly(Facep f, MArena *arena) } CDT_result<mpq_class> cdt_out = delaunay_2d_calc(cdt_in, CDT_INSIDE); int n_tris = cdt_out.face.size(); - Array<Facep> ans(n_tris); + Array<const Face *> ans(n_tris); for (int t = 0; t < n_tris; ++t) { int i_v_out[3]; - Vertp v[3]; + const Vert *v[3]; int eo[3]; for (int i = 0; i < 3; ++i) { i_v_out[i] = cdt_out.face[t][i]; @@ -2510,44 +2512,46 @@ static Array<Facep> triangulate_poly(Facep f, MArena *arena) return ans; } -/* Return a Mesh that is a triangulation of a mesh with general +/* Return an IMesh that is a triangulation of a mesh with general * polygonal faces, pm. * Added diagonals will be distinguishable by having edge original * indices of NO_INDEX. */ -static Mesh triangulate_polymesh(Mesh &pm, MArena *arena) +static IMesh triangulate_polymesh(IMesh &pm, IMeshArena *arena) { - Vector<Facep> face_tris; + Vector<const Face *> face_tris; constexpr int estimated_tris_per_face = 3; face_tris.reserve(estimated_tris_per_face * pm.face_size()); - for (Facep f : pm.faces()) { + for (const Face *f : pm.faces()) { /* Tesselate face f, following plan similar to BM_face_calc_tesselation. */ int flen = f->size(); if (flen == 3) { face_tris.append(f); } else if (flen == 4) { - Vertp v0 = (*f)[0]; - Vertp v1 = (*f)[1]; - Vertp v2 = (*f)[2]; - Vertp v3 = (*f)[3]; + const Vert *v0 = (*f)[0]; + const Vert *v1 = (*f)[1]; + const Vert *v2 = (*f)[2]; + const Vert *v3 = (*f)[3]; int eo_01 = f->edge_orig[0]; int eo_12 = f->edge_orig[1]; int eo_23 = f->edge_orig[2]; int eo_30 = f->edge_orig[3]; - Facep f0 = arena->add_face({v0, v1, v2}, f->orig, {eo_01, eo_12, -1}, {false, false, false}); - Facep f1 = arena->add_face({v0, v2, v3}, f->orig, {-1, eo_23, eo_30}, {false, false, false}); + const Face *f0 = arena->add_face( + {v0, v1, v2}, f->orig, {eo_01, eo_12, -1}, {false, false, false}); + const Face *f1 = arena->add_face( + {v0, v2, v3}, f->orig, {-1, eo_23, eo_30}, {false, false, false}); face_tris.append(f0); face_tris.append(f1); } else { - Array<Facep> tris = triangulate_poly(f, arena); - for (Facep tri : tris) { + Array<const Face *> tris = triangulate_poly(f, arena); + for (const Face *tri : tris) { face_tris.append(tri); } } } - return Mesh(face_tris); + return IMesh(face_tris); } /* If tri1 and tri2 have a common edge (in opposite orientation), return the indices into tri1 and @@ -2569,8 +2573,8 @@ struct MergeEdge { /* Length (squared) of the edge, used for sorting. */ double len_squared = 0.0; /* v1 and v2 are the ends of the edge, ordered so that v1->id < v2->id */ - Vertp v1 = nullptr; - Vertp v2 = nullptr; + const Vert *v1 = nullptr; + const Vert *v2 = nullptr; /* left_face and right_face are indices into FaceMergeState->face. */ int left_face = -1; int right_face = -1; @@ -2581,7 +2585,7 @@ struct MergeEdge { MergeEdge() = default; - MergeEdge(Vertp va, Vertp vb) + MergeEdge(const Vert *va, const Vert *vb) { if (va->id < vb->id) { this->v1 = va; @@ -2596,7 +2600,7 @@ struct MergeEdge { struct MergeFace { /* The current sequence of Verts forming this face. */ - Vector<Vertp> vert; + Vector<const Vert *> vert; /* For each position in face, what is index in FaceMergeState of edge for that position? */ Vector<int> edge; /* If not -1, merge_to gives a face index in FaceMergeState that this is merged to. */ @@ -2611,7 +2615,7 @@ struct FaceMergeState { * information (their left and right faces) and whether or not they are dissolvable. */ Vector<MergeEdge> edge; - /* edge_map maps a pair of Vertp ids (in canonical order: smaller id first) + /* edge_map maps a pair of const Vert * ids (in canonical order: smaller id first) * to the index in the above edge vector in which to find the corresonding MergeEdge. */ Map<std::pair<int, int>, int> edge_map; @@ -2623,7 +2627,7 @@ static std::ostream &operator<<(std::ostream &os, const FaceMergeState &fms) for (int f : fms.face.index_range()) { const MergeFace &mf = fms.face[f]; std::cout << f << ": orig=" << mf.orig << " verts "; - for (Vertp v : mf.vert) { + for (const Vert *v : mf.vert) { std::cout << v << " "; } std::cout << "\n"; @@ -2646,7 +2650,7 @@ static std::ostream &operator<<(std::ostream &os, const FaceMergeState &fms) */ static void init_face_merge_state(FaceMergeState *fms, const Vector<int> &tris, - const Mesh &tm, + const IMesh &tm, const double3 &norm) { constexpr int dbg_level = 0; @@ -2777,10 +2781,10 @@ static bool dissolve_leaves_valid_bmesh(FaceMergeState *fms, * One could avoid this O(n^2) algorithm if had a structure saying which faces a vertex touches. */ for (int a_v_index = 0; ok && a_v_index < alen; ++a_v_index) { - Vertp a_v = mf_left.vert[a_v_index]; + const Vert *a_v = mf_left.vert[a_v_index]; if (a_v != me.v1 && a_v != me.v2) { for (int b_v_index = 0; b_v_index < blen; ++b_v_index) { - Vertp b_v = mf_right.vert[b_v_index]; + const Vert *b_v = mf_right.vert[b_v_index]; if (a_v == b_v) { ok = false; } @@ -2804,7 +2808,7 @@ static void splice_faces( BLI_assert(a_edge_start != -1 && b_edge_start != -1); int alen = static_cast<int>(mf_left.vert.size()); int blen = static_cast<int>(mf_right.vert.size()); - Vector<Vertp> splice_vert; + Vector<const Vert *> splice_vert; Vector<int> splice_edge; splice_vert.reserve(alen + blen - 2); splice_edge.reserve(alen + blen - 2); @@ -2846,7 +2850,7 @@ static void splice_faces( } /* Given that fms has been properly initialized to contain a set of faces that - * together form a face or part of a face of the original Mesh, and that + * together form a face or part of a face of the original IMesh, and that * it has properly recorded with faces are dissolvable, dissolve as many edges as possible. * We try to dissolve in decreasing order of edge length, so that it is more likely * that the final output doesn't have awkward looking long edges with extreme angles. @@ -2904,17 +2908,17 @@ static void do_dissolve(FaceMergeState *fms) * Note: it is possible that some of the triangles in tris have reversed orientation * to the rest, so we have to handle the two cases separately. */ -static Vector<Facep> merge_tris_for_face(Vector<int> tris, - const Mesh &tm, - const Mesh &pm_in, - MArena *arena) +static Vector<const Face *> merge_tris_for_face(Vector<int> tris, + const IMesh &tm, + const IMesh &pm_in, + IMeshArena *arena) { constexpr int dbg_level = 0; if (dbg_level > 0) { std::cout << "merge_tris_for_face\n"; std::cout << "tris: " << tris << "\n"; } - Vector<Facep> ans; + Vector<const Face *> ans; if (tris.size() <= 1) { if (tris.size() == 1) { ans.append(tm.face(tris[0])); @@ -2930,7 +2934,7 @@ static Vector<Facep> merge_tris_for_face(Vector<int> tris, */ const Face &tri1 = *tm.face(tris[0]); const Face &tri2 = *tm.face(tris[1]); - Facep in_face = pm_in.face(tri1.orig); + const Face *in_face = pm_in.face(tri1.orig); if (in_face->size() == 4) { std::pair<int, int> estarts = find_tris_common_edge(tri1, tri2); if (estarts.first != -1 && tri1.edge_orig[estarts.first] == NO_INDEX) { @@ -2975,7 +2979,7 @@ static Vector<Facep> merge_tris_for_face(Vector<int> tris, e_orig[i] = fms.edge[mf.edge[i]].orig; is_intersect[i] = fms.edge[mf.edge[i]].is_intersect; } - Facep facep = arena->add_face(mf.vert, mf.orig, e_orig, is_intersect); + const Face *facep = arena->add_face(mf.vert, mf.orig, e_orig, is_intersect); ans.append(facep); if (dbg_level > 0) { std::cout << " " << facep << "\n"; @@ -2991,7 +2995,7 @@ static Vector<Facep> merge_tris_for_face(Vector<int> tris, * and (c) if v's two neighboring vertices are u and w, then (u,v,w) forms a straight line. * Return the number of dissolvable vertices in r_count_dissolve. */ -static Array<bool> find_dissolve_verts(Mesh &pm_out, int *r_count_dissolve) +static Array<bool> find_dissolve_verts(IMesh &pm_out, int *r_count_dissolve) { pm_out.populate_vert(); /* dissolve[i] will say whether pm_out.vert(i) can be dissolved. */ @@ -3004,19 +3008,19 @@ static Array<bool> find_dissolve_verts(Mesh &pm_out, int *r_count_dissolve) * of the vertex v in position i of pm_out.vert. * If we encounter a third, then v will not be dissolvable. */ - Array<std::pair<Vertp, Vertp>> neighbors(pm_out.vert_size(), - std::pair<Vertp, Vertp>(nullptr, nullptr)); + Array<std::pair<const Vert *, const Vert *>> neighbors( + pm_out.vert_size(), std::pair<const Vert *, const Vert *>(nullptr, nullptr)); for (int f : pm_out.face_index_range()) { const Face &face = *pm_out.face(f); for (int i : face.index_range()) { - Vertp v = face[i]; + const Vert *v = face[i]; int v_index = pm_out.lookup_vert(v); BLI_assert(v_index != NO_INDEX); if (dissolve[v_index]) { - Vertp n1 = face[face.next_pos(i)]; - Vertp n2 = face[face.prev_pos(i)]; - Vertp f_n1 = neighbors[v_index].first; - Vertp f_n2 = neighbors[v_index].second; + const Vert *n1 = face[face.next_pos(i)]; + const Vert *n2 = face[face.prev_pos(i)]; + const Vert *f_n1 = neighbors[v_index].first; + const Vert *f_n2 = neighbors[v_index].second; if (f_n1 != nullptr) { /* Already has a neighbor in another face; can't dissolve unless they are the same. */ if (!((n1 == f_n2 && n2 == f_n1) || (n1 == f_n1 && n2 == f_n2))) { @@ -3026,7 +3030,7 @@ static Array<bool> find_dissolve_verts(Mesh &pm_out, int *r_count_dissolve) } else { /* These are the first-seen neighbors. */ - neighbors[v_index] = std::pair<Vertp, Vertp>(n1, n2); + neighbors[v_index] = std::pair<const Vert *, const Vert *>(n1, n2); } } } @@ -3035,7 +3039,7 @@ static Array<bool> find_dissolve_verts(Mesh &pm_out, int *r_count_dissolve) for (int v_out : pm_out.vert_index_range()) { if (dissolve[v_out]) { dissolve[v_out] = false; /* Will set back to true if final condition is satisfied. */ - const std::pair<Vertp, Vertp> &nbrs = neighbors[v_out]; + const std::pair<const Vert *, const Vert *> &nbrs = neighbors[v_out]; if (nbrs.first != nullptr) { BLI_assert(nbrs.second != nullptr); const mpq3 &co1 = nbrs.first->co_exact; @@ -3061,7 +3065,7 @@ static Array<bool> find_dissolve_verts(Mesh &pm_out, int *r_count_dissolve) * remove the corresponding vertex from the vertices in the faces of * pm.faces to account for the close-up of the gaps in pm.vert. */ -static void dissolve_verts(Mesh *pm, const Array<bool> dissolve, MArena *arena) +static void dissolve_verts(IMesh *pm, const Array<bool> dissolve, IMeshArena *arena) { constexpr int inline_face_size = 100; Vector<bool, inline_face_size> face_pos_erase; @@ -3069,7 +3073,7 @@ static void dissolve_verts(Mesh *pm, const Array<bool> dissolve, MArena *arena) const Face &face = *pm->face(f); face_pos_erase.clear(); int num_erase = 0; - for (Vertp v : face) { + for (const Vert *v : face) { int v_index = pm->lookup_vert(v); BLI_assert(v_index != NO_INDEX); if (dissolve[v_index]) { @@ -3087,8 +3091,8 @@ static void dissolve_verts(Mesh *pm, const Array<bool> dissolve, MArena *arena) pm->set_dirty_verts(); } -/* The main boolean function operates on a triangle Mesh and produces a - * Triangle Mesh as output. +/* The main boolean function operates on a triangle IMesh and produces a + * Triangle IMesh as output. * This function converts back into a general polygonal mesh by removing * any possible triangulation edges (which can be identified because they * will have an original edge that is NO_INDEX. @@ -3097,9 +3101,9 @@ static void dissolve_verts(Mesh *pm, const Array<bool> dissolve, MArena *arena) * the "valid BMesh" property: we can't produce output faces that have repeated vertices in them, * or have several disconnected boundaries (e.g., faces with holes). */ -static Mesh polymesh_from_trimesh_with_dissolve(const Mesh &tm_out, - const Mesh &pm_in, - MArena *arena) +static IMesh polymesh_from_trimesh_with_dissolve(const IMesh &tm_out, + const IMesh &pm_in, + IMeshArena *arena) { const int dbg_level = 0; if (dbg_level > 1) { @@ -3124,10 +3128,10 @@ static Mesh polymesh_from_trimesh_with_dissolve(const Mesh &tm_out, } /* Merge triangles that we can from face_output_tri to make faces for output. - * face_output_face[f] will be new original Facep's that + * face_output_face[f] will be new original const Face *'s that * make up whatever part of the boolean output remains of input face f. */ - Array<Vector<Facep>> face_output_face(tot_in_face); + Array<Vector<const Face *>> face_output_face(tot_in_face); int tot_out_face = 0; for (int in_f : pm_in.face_index_range()) { if (dbg_level > 1) { @@ -3140,16 +3144,16 @@ static Mesh polymesh_from_trimesh_with_dissolve(const Mesh &tm_out, face_output_face[in_f] = merge_tris_for_face(face_output_tris[in_f], tm_out, pm_in, arena); tot_out_face += face_output_face[in_f].size(); } - Array<Facep> face(tot_out_face); + Array<const Face *> face(tot_out_face); int out_f_index = 0; for (int in_f : pm_in.face_index_range()) { - const Vector<Facep> &f_faces = face_output_face[in_f]; + const Vector<const Face *> &f_faces = face_output_face[in_f]; if (f_faces.size() > 0) { std::copy(f_faces.begin(), f_faces.end(), &face[out_f_index]); out_f_index += f_faces.size(); } } - Mesh pm_out(face); + IMesh pm_out(face); /* Dissolve vertices that were (a) not original; and (b) now have valence 2 and * are between two other vertices that are exactly in line with them. * These were created because of triangulation edges that have been dissolved. @@ -3172,12 +3176,12 @@ static Mesh polymesh_from_trimesh_with_dissolve(const Mesh &tm_out, * The shape_fn function should take a triangle index in tm_in and return * a number in the range 0 to nshapes-1, to say which shape that triangle is in. */ -Mesh boolean_trimesh(Mesh &tm_in, - bool_optype op, - int nshapes, - std::function<int(int)> shape_fn, - bool use_self, - MArena *arena) +IMesh boolean_trimesh(IMesh &tm_in, + bool_optype op, + int nshapes, + std::function<int(int)> shape_fn, + bool use_self, + IMeshArena *arena) { constexpr int dbg_level = 0; if (dbg_level > 0) { @@ -3190,9 +3194,9 @@ Mesh boolean_trimesh(Mesh &tm_in, } } if (tm_in.face_size() == 0) { - return Mesh(tm_in); + return IMesh(tm_in); } - Mesh tm_si; + IMesh tm_si; if (use_self) { tm_si = trimesh_self_intersect(tm_in, arena); } @@ -3210,7 +3214,7 @@ Mesh boolean_trimesh(Mesh &tm_in, auto si_shape_fn = [shape_fn, tm_si](int t) { return shape_fn(tm_si.face(t)->orig); }; TriMeshTopology tm_si_topo(tm_si); PatchesInfo pinfo = find_patches(tm_si, tm_si_topo); - Mesh tm_out; + IMesh tm_out; if (!is_pwn(tm_si, tm_si_topo)) { if (dbg_level > 0) { std::cout << "Input is not PWN, using gwn method\n"; @@ -3227,14 +3231,14 @@ Mesh boolean_trimesh(Mesh &tm_in, if (!pc_ok) { /* TODO: if bad input can lead to this, diagnose the problem. */ std::cout << "Something funny about input or a bug in boolean\n"; - return Mesh(tm_in); + return IMesh(tm_in); } cinfo.init_windings(nshapes); int c_ambient = find_ambient_cell(tm_si, nullptr, tm_si_topo, pinfo, arena); if (c_ambient == NO_INDEX) { /* TODO: find a way to propagate this error to user properly. */ std::cout << "Could not find an ambient cell; input not valid?\n"; - return Mesh(tm_si); + return IMesh(tm_si); } propagate_windings_and_flag(pinfo, cinfo, c_ambient, op, nshapes, si_shape_fn); tm_out = extract_from_flag_diffs(tm_si, pinfo, cinfo, arena); @@ -3253,15 +3257,15 @@ Mesh boolean_trimesh(Mesh &tm_in, return tm_out; } -static void dump_test_spec(Mesh &pm) +static void dump_test_spec(IMesh &pm) { std::cout << "test spec = " << pm.vert_size() << " " << pm.face_size() << "\n"; - for (Vertp v : pm.vertices()) { + for (const Vert *v : pm.vertices()) { std::cout << v->co_exact[0] << " " << v->co_exact[1] << " " << v->co_exact[2] << " # " << v->co[0] << " " << v->co[1] << " " << v->co[2] << "\n"; } - for (Facep f : pm.faces()) { - for (Vertp fv : *f) { + for (const Face *f : pm.faces()) { + for (const Vert *fv : *f) { std::cout << pm.lookup_vert(fv) << " "; } std::cout << "\n"; @@ -3271,13 +3275,13 @@ static void dump_test_spec(Mesh &pm) /* Do the boolean operation op on the polygon mesh pm_in. * See the header file for a complete description. */ -Mesh boolean_mesh(Mesh &pm, - bool_optype op, - int nshapes, - std::function<int(int)> shape_fn, - bool use_self, - Mesh *pm_triangulated, - MArena *arena) +IMesh boolean_mesh(IMesh &pm, + bool_optype op, + int nshapes, + std::function<int(int)> shape_fn, + bool use_self, + IMesh *pm_triangulated, + IMeshArena *arena) { constexpr int dbg_level = 0; if (dbg_level > 0) { @@ -3292,18 +3296,18 @@ Mesh boolean_mesh(Mesh &pm, } } } - Mesh *tm_in = pm_triangulated; - Mesh our_triangulation; + IMesh *tm_in = pm_triangulated; + IMesh our_triangulation; if (tm_in == nullptr) { our_triangulation = triangulate_polymesh(pm, arena); tm_in = &our_triangulation; } - Mesh tm_out = boolean_trimesh(*tm_in, op, nshapes, shape_fn, use_self, arena); + IMesh tm_out = boolean_trimesh(*tm_in, op, nshapes, shape_fn, use_self, arena); if (dbg_level > 1) { std::cout << "bool_trimesh_output:\n" << tm_out; write_obj_mesh(tm_out, "bool_trimesh_output"); } - Mesh ans = polymesh_from_trimesh_with_dissolve(tm_out, pm, arena); + IMesh ans = polymesh_from_trimesh_with_dissolve(tm_out, pm, arena); if (dbg_level > 0) { std::cout << "boolean_mesh output:\n" << ans; } diff --git a/source/blender/blenlib/intern/mesh_intersect.cc b/source/blender/blenlib/intern/mesh_intersect.cc index d0def5c06a2..50f7bb2a4ca 100644 --- a/source/blender/blenlib/intern/mesh_intersect.cc +++ b/source/blender/blenlib/intern/mesh_intersect.cc @@ -101,7 +101,7 @@ uint64_t Vert::hash() const return co_exact.hash(); } -std::ostream &operator<<(std::ostream &os, Vertp v) +std::ostream &operator<<(std::ostream &os, const Vert *v) { os << "v" << v->id; if (v->orig != NO_INDEX) { @@ -177,7 +177,8 @@ std::ostream &operator<<(std::ostream &os, const Plane &plane) return os; } -Face::Face(Span<Vertp> verts, int id, int orig, Span<int> edge_origs, Span<bool> is_intersect) +Face::Face( + Span<const Vert *> verts, int id, int orig, Span<int> edge_origs, Span<bool> is_intersect) : vert(verts), edge_orig(edge_origs), is_intersect(is_intersect), id(id), orig(orig) { mpq3 normal; @@ -197,7 +198,7 @@ Face::Face(Span<Vertp> verts, int id, int orig, Span<int> edge_origs, Span<bool> plane = Plane(normal, d); } -Face::Face(Span<Vertp> verts, int id, int orig) : vert(verts), id(id), orig(orig) +Face::Face(Span<const Vert *> verts, int id, int orig) : vert(verts), id(id), orig(orig) { mpq3 normal; if (vert.size() > 3) { @@ -300,10 +301,10 @@ bool Face::cyclic_equal(const Face &other) const return false; } -std::ostream &operator<<(std::ostream &os, Facep f) +std::ostream &operator<<(std::ostream &os, const Face *f) { os << "f" << f->id << "o" << f->orig << "["; - for (Vertp v : *f) { + for (const Vert *v : *f) { os << "v" << v->id; if (v->orig != NO_INDEX) { os << "o" << v->orig; @@ -330,7 +331,7 @@ std::ostream &operator<<(std::ostream &os, Facep f) return os; } -/* MArena is the owner of the Vert and Face resources used +/* IMeshArena is the owner of the Vert and Face resources used * during a run of one of the meshintersect main functions. * It also keeps has a hash table of all Verts created so that it can * ensure that only one instance of a Vert with a given co_exact will @@ -338,11 +339,11 @@ std::ostream &operator<<(std::ostream &os, Facep f) */ // #define USE_SPINLOCK -class MArena::MArenaImpl { +class IMeshArena::IMeshArenaImpl { /* Don't use Vert itself as key since resizing may move * pointers to the Vert around, and we need to have those pointers - * stay the same throughout the lifetime of the MArena. + * stay the same throughout the lifetime of the IMeshArena. */ struct VSetKey { Vert *vert; @@ -381,7 +382,7 @@ class MArena::MArenaImpl { # endif public: - MArenaImpl() + IMeshArenaImpl() { if (intersect_use_threading) { # ifdef USE_SPINLOCK @@ -391,9 +392,9 @@ class MArena::MArenaImpl { # endif } } - MArenaImpl(const MArenaImpl &) = delete; - MArenaImpl(MArenaImpl &&) = delete; - ~MArenaImpl() + IMeshArenaImpl(const IMeshArenaImpl &) = delete; + IMeshArenaImpl(IMeshArenaImpl &&) = delete; + ~IMeshArenaImpl() { if (intersect_use_threading) { # ifdef USE_SPINLOCK @@ -421,19 +422,22 @@ class MArena::MArenaImpl { return allocated_faces_.size(); } - Vertp add_or_find_vert(const mpq3 &co, int orig) + const Vert *add_or_find_vert(const mpq3 &co, int orig) { double3 dco(co[0].get_d(), co[1].get_d(), co[2].get_d()); return add_or_find_vert(co, dco, orig); } - Vertp add_or_find_vert(const double3 &co, int orig) + const Vert *add_or_find_vert(const double3 &co, int orig) { mpq3 mco(co[0], co[1], co[2]); return add_or_find_vert(mco, co, orig); } - Facep add_face(Span<Vertp> verts, int orig, Span<int> edge_origs, Span<bool> is_intersect) + const Face *add_face(Span<const Vert *> verts, + int orig, + Span<int> edge_origs, + Span<bool> is_intersect) { Face *f = new Face(verts, next_face_id_++, orig, edge_origs, is_intersect); if (intersect_use_threading) { @@ -454,22 +458,22 @@ class MArena::MArenaImpl { return f; } - Facep add_face(Span<Vertp> verts, int orig, Span<int> edge_origs) + const Face *add_face(Span<const Vert *> verts, int orig, Span<int> edge_origs) { Array<bool> is_intersect(verts.size(), false); return add_face(verts, orig, edge_origs, is_intersect); } - Facep add_face(Span<Vertp> verts, int orig) + const Face *add_face(Span<const Vert *> verts, int orig) { Array<int> edge_origs(verts.size(), NO_INDEX); Array<bool> is_intersect(verts.size(), false); return add_face(verts, orig, edge_origs, is_intersect); } - Vertp find_vert(const mpq3 &co) + const Vert *find_vert(const mpq3 &co) { - Vertp ans; + const Vert *ans; Vert vtry(co, double3(), NO_INDEX, NO_INDEX); VSetKey vskey(&vtry); if (intersect_use_threading) { @@ -500,7 +504,7 @@ class MArena::MArenaImpl { * Since it is only used for that purpose, access is not lock-protected. * The argument vs can be a cyclic shift of the actual stored Face. */ - Facep find_face(Span<Vertp> vs) + const Face *find_face(Span<const Vert *> vs) { Array<int> eorig(vs.size(), NO_INDEX); Array<bool> is_intersect(vs.size(), false); @@ -514,11 +518,11 @@ class MArena::MArenaImpl { } private: - Vertp add_or_find_vert(const mpq3 &mco, const double3 &dco, int orig) + const Vert *add_or_find_vert(const mpq3 &mco, const double3 &dco, int orig) { /* Don't allocate Vert yet, in case it is already there. */ Vert vtry(mco, dco, NO_INDEX, NO_INDEX); - Vertp ans; + const Vert *ans; VSetKey vskey(&vtry); if (intersect_use_threading) { # ifdef USE_SPINLOCK @@ -555,77 +559,80 @@ class MArena::MArenaImpl { }; }; -MArena::MArena() +IMeshArena::IMeshArena() { - pimpl_ = std::unique_ptr<MArenaImpl>(new MArenaImpl()); + pimpl_ = std::unique_ptr<IMeshArenaImpl>(new IMeshArenaImpl()); } -MArena::~MArena() +IMeshArena::~IMeshArena() { } -void MArena::reserve(int vert_num_hint, int face_num_hint) +void IMeshArena::reserve(int vert_num_hint, int face_num_hint) { pimpl_->reserve(vert_num_hint, face_num_hint); } -int MArena::tot_allocated_verts() const +int IMeshArena::tot_allocated_verts() const { return pimpl_->tot_allocated_verts(); } -int MArena::tot_allocated_faces() const +int IMeshArena::tot_allocated_faces() const { return pimpl_->tot_allocated_faces(); } -Vertp MArena::add_or_find_vert(const mpq3 &co, int orig) +const Vert *IMeshArena::add_or_find_vert(const mpq3 &co, int orig) { return pimpl_->add_or_find_vert(co, orig); } -Facep MArena::add_face(Span<Vertp> verts, int orig, Span<int> edge_origs, Span<bool> is_intersect) +const Face *IMeshArena::add_face(Span<const Vert *> verts, + int orig, + Span<int> edge_origs, + Span<bool> is_intersect) { return pimpl_->add_face(verts, orig, edge_origs, is_intersect); } -Facep MArena::add_face(Span<Vertp> verts, int orig, Span<int> edge_origs) +const Face *IMeshArena::add_face(Span<const Vert *> verts, int orig, Span<int> edge_origs) { return pimpl_->add_face(verts, orig, edge_origs); } -Facep MArena::add_face(Span<Vertp> verts, int orig) +const Face *IMeshArena::add_face(Span<const Vert *> verts, int orig) { return pimpl_->add_face(verts, orig); } -Vertp MArena::add_or_find_vert(const double3 &co, int orig) +const Vert *IMeshArena::add_or_find_vert(const double3 &co, int orig) { return pimpl_->add_or_find_vert(co, orig); } -Vertp MArena::find_vert(const mpq3 &co) const +const Vert *IMeshArena::find_vert(const mpq3 &co) const { return pimpl_->find_vert(co); } -Facep MArena::find_face(Span<Vertp> verts) const +const Face *IMeshArena::find_face(Span<const Vert *> verts) const { return pimpl_->find_face(verts); } -void Mesh::set_faces(Span<Facep> faces) +void IMesh::set_faces(Span<const Face *> faces) { face_ = faces; } -int Mesh::lookup_vert(Vertp v) const +int IMesh::lookup_vert(const Vert *v) const { BLI_assert(vert_populated_); return vert_to_index_.lookup_default(v, NO_INDEX); } -void Mesh::populate_vert() +void IMesh::populate_vert() { /* This is likely an overestimate, since verts are shared between * faces. It is ok if estimate is over or even under. @@ -635,15 +642,15 @@ void Mesh::populate_vert() populate_vert(estimate_num_verts); } -void Mesh::populate_vert(int max_verts) +void IMesh::populate_vert(int max_verts) { if (vert_populated_) { return; } vert_to_index_.reserve(max_verts); int next_allocate_index = 0; - for (Facep f : face_) { - for (Vertp v : *f) { + for (const Face *f : face_) { + for (const Vert *v : *f) { if (v->id == 1) { } int index = vert_to_index_.lookup_default(v, NO_INDEX); @@ -654,7 +661,7 @@ void Mesh::populate_vert(int max_verts) } } int tot_v = next_allocate_index; - vert_ = Array<Vertp>(tot_v); + vert_ = Array<const Vert *>(tot_v); for (auto item : vert_to_index_.items()) { int index = item.value; BLI_assert(index < tot_v); @@ -666,7 +673,7 @@ void Mesh::populate_vert(int max_verts) */ const bool fix_order = true; if (fix_order) { - std::sort(vert_.begin(), vert_.end(), [](Vertp a, Vertp b) { + std::sort(vert_.begin(), vert_.end(), [](const Vert *a, const Vert *b) { if (a->orig != NO_INDEX && b->orig != NO_INDEX) { return a->orig < b->orig; } @@ -679,16 +686,16 @@ void Mesh::populate_vert(int max_verts) return a->id < b->id; }); for (int i : vert_.index_range()) { - Vertp v = vert_[i]; + const Vert *v = vert_[i]; vert_to_index_.add_overwrite(v, i); } } vert_populated_ = true; } -void Mesh::erase_face_positions(int f_index, Span<bool> face_pos_erase, MArena *arena) +void IMesh::erase_face_positions(int f_index, Span<bool> face_pos_erase, IMeshArena *arena) { - Facep cur_f = this->face(f_index); + const Face *cur_f = this->face(f_index); int cur_len = static_cast<int>(cur_f->size()); int num_to_erase = 0; for (int i : cur_f->index_range()) { @@ -704,7 +711,7 @@ void Mesh::erase_face_positions(int f_index, Span<bool> face_pos_erase, MArena * /* Invalid erase. Don't do anything. */ return; } - Array<Vertp> new_vert(new_len); + Array<const Vert *> new_vert(new_len); Array<int> new_edge_orig(new_len); Array<bool> new_is_intersect(new_len); int new_index = 0; @@ -720,19 +727,19 @@ void Mesh::erase_face_positions(int f_index, Span<bool> face_pos_erase, MArena * this->face_[f_index] = arena->add_face(new_vert, cur_f->orig, new_edge_orig, new_is_intersect); } -std::ostream &operator<<(std::ostream &os, const Mesh &mesh) +std::ostream &operator<<(std::ostream &os, const IMesh &mesh) { if (mesh.has_verts()) { os << "Verts:\n"; int i = 0; - for (Vertp v : mesh.vertices()) { + for (const Vert *v : mesh.vertices()) { os << i << ": " << v << "\n"; ++i; } } os << "\nFaces:\n"; int i = 0; - for (Facep f : mesh.faces()) { + for (const Face *f : mesh.faces()) { os << i << ": " << f << "\n"; os << " plane=" << f->plane << " eorig=["; for (Face::FacePos p = 0; p < f->size(); ++p) { @@ -828,14 +835,14 @@ static bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b * the "less than" tests in isect_aabb_aabb_v3 are sufficient to detect * touching or overlap. */ -static Array<BoundingBox> calc_face_bounding_boxes(const Mesh &m) +static Array<BoundingBox> calc_face_bounding_boxes(const IMesh &m) { double max_abs_val = 0.0; Array<BoundingBox> ans(m.face_size()); for (int f : m.face_index_range()) { const Face &face = *m.face(f); BoundingBox &bb = ans[f]; - for (Vertp v : face) { + for (const Vert *v : face) { bb.combine(v->co); for (int i = 0; i < 3; ++i) { max_abs_val = max_dd(max_abs_val, fabs(v->co[i])); @@ -1210,7 +1217,7 @@ static bool non_trivially_2d_intersect(const mpq2 *a[3], const mpq2 *b[3]) * the triangles in cl, and that proj_axis is a good axis to project down * to solve this problem in 2d. */ -static bool non_trivially_coplanar_intersects(const Mesh &tm, +static bool non_trivially_coplanar_intersects(const IMesh &tm, int t, const CoplanarCluster &cl, int proj_axis) @@ -1251,16 +1258,16 @@ static bool non_trivially_coplanar_intersects(const Mesh &tm, * something other than a common vertex or a common edge? * The itt value is the result of calling intersect_tri_tri on tri1, tri2. */ -static bool non_trivial_intersect(const ITT_value &itt, Facep tri1, Facep tri2) +static bool non_trivial_intersect(const ITT_value &itt, const Face * tri1, const Face * tri2) { if (itt.kind == INONE) { return false; } - Facep tris[2] = {tri1, tri2}; + const Face * tris[2] = {tri1, tri2}; if (itt.kind == IPOINT) { bool has_p_as_vert[2] {false, false}; for (int i = 0; i < 2; ++i) { - for (Vertp v : *tris[i]) { + for (const Vert * v : *tris[i]) { if (itt.p1 == v->co_exact) { has_p_as_vert[i] = true; break; @@ -1433,7 +1440,7 @@ static int filter_orient3d(const double3 &a, const double3 &b, const double3 &c, * mpq3 test would also have returned that value. * When the return value is 0, we are not sure of the sign. */ -static int filter_tri_plane_vert_orient3d(const Face &tri, Vertp v) +static int filter_tri_plane_vert_orient3d(const Face &tri, const Vert *v) { return filter_orient3d(tri[0]->co, tri[1]->co, tri[2]->co, v->co); } @@ -1512,7 +1519,7 @@ static int filter_plane_side(const double3 &p, * where triangles share an edge or a vertex, but don't * otherwise intersect. */ -static bool may_non_trivially_intersect(Facep t1, Facep t2) +static bool may_non_trivially_intersect(const Face *t1, const Face *t2) { const Face &tri1 = *t1; const Face &tri2 = *t2; @@ -1520,9 +1527,9 @@ static bool may_non_trivially_intersect(Facep t1, Facep t2) Face::FacePos share2_pos[3]; int n_shared = 0; for (Face::FacePos p1 = 0; p1 < 3; ++p1) { - Vertp v1 = tri1[p1]; + const Vert *v1 = tri1[p1]; for (Face::FacePos p2 = 0; p2 < 3; ++p2) { - Vertp v2 = tri2[p2]; + const Vert *v2 = tri2[p2]; if (v1 == v2) { share1_pos[n_shared] = p1; share2_pos[n_shared] = p2; @@ -1555,16 +1562,16 @@ static bool may_non_trivially_intersect(Facep t1, Facep t2) * they are more expensive to check). */ Face::FacePos p = share2_pos[0]; - Vertp v2a = p == 0 ? tri2[1] : tri2[0]; - Vertp v2b = (p == 0 || p == 1) ? tri2[2] : tri2[1]; + const Vert *v2a = p == 0 ? tri2[1] : tri2[0]; + const Vert *v2b = (p == 0 || p == 1) ? tri2[2] : tri2[1]; int o1 = filter_tri_plane_vert_orient3d(tri1, v2a); int o2 = filter_tri_plane_vert_orient3d(tri1, v2b); if (o1 == o2 && o1 != 0) { return false; } p = share1_pos[0]; - Vertp v1a = p == 0 ? tri1[1] : tri1[0]; - Vertp v1b = (p == 0 || p == 1) ? tri1[2] : tri1[1]; + const Vert *v1a = p == 0 ? tri1[1] : tri1[0]; + const Vert *v1b = (p == 0 || p == 1) ? tri1[2] : tri1[1]; o1 = filter_tri_plane_vert_orient3d(tri2, v1a); o2 = filter_tri_plane_vert_orient3d(tri2, v1b); if (o1 == o2 && o1 != 0) { @@ -1599,7 +1606,7 @@ static inline mpq3 tti_interp(const mpq3 &a, const mpq3 &b, const mpq3 &c, const /* Return +1, 0, -1 as a + ad is above, on, or below the oriented plane containing a, b, c in CCW * order. This is the same as -oriented(a, b, c, a + ad), but uses fewer arithmetic operations. - * TODO: change arguments to Vertp and use floating filters. + * TODO: change arguments to const Vert * and use floating filters. */ static inline int tti_above(const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &ad) { @@ -1783,7 +1790,7 @@ static ITT_value itt_canon1(const mpq3 &p1, return ITT_value(ICOPLANAR); } -static ITT_value intersect_tri_tri(const Mesh &tm, int t1, int t2) +static ITT_value intersect_tri_tri(const IMesh &tm, int t1, int t2) { constexpr int dbg_level = 0; # ifdef PERFDEBUG @@ -1791,12 +1798,12 @@ static ITT_value intersect_tri_tri(const Mesh &tm, int t1, int t2) # endif const Face &tri1 = *tm.face(t1); const Face &tri2 = *tm.face(t2); - Vertp vp1 = tri1[0]; - Vertp vq1 = tri1[1]; - Vertp vr1 = tri1[2]; - Vertp vp2 = tri2[0]; - Vertp vq2 = tri2[1]; - Vertp vr2 = tri2[2]; + const Vert *vp1 = tri1[0]; + const Vert *vq1 = tri1[1]; + const Vert *vr1 = tri1[2]; + const Vert *vp2 = tri2[0]; + const Vert *vq2 = tri2[1]; + const Vert *vr2 = tri2[2]; if (dbg_level > 0) { std::cout << "\nINTERSECT_TRI_TRI t1=" << t1 << ", t2=" << t2 << "\n"; std::cout << " p1 = " << vp1 << "\n"; @@ -1992,7 +1999,7 @@ struct CDT_data { Vector<mpq2> vert; Vector<std::pair<int, int>> edge; Vector<Vector<int>> face; - Vector<int> input_face; /* Parallels face, gives id from input Mesh of input face. */ + Vector<int> input_face; /* Parallels face, gives id from input IMesh of input face. */ Vector<bool> is_reversed; /* Parallels face, says if input face orientation is opposite. */ CDT_result<mpq_class> cdt_out; /* Result of running CDT on input with (vert, edge, face). */ int proj_axis; @@ -2053,7 +2060,7 @@ static void prepare_need_edge(CDT_data &cd, const mpq3 &p1, const mpq3 &p2) cd.edge.append(std::pair<int, int>(v1, v2)); } -static void prepare_need_tri(CDT_data &cd, const Mesh &tm, int t) +static void prepare_need_tri(CDT_data &cd, const IMesh &tm, int t) { const Face &tri = *tm.face(t); int v0 = prepare_need_vert(cd, tri[0]->co_exact); @@ -2087,7 +2094,7 @@ static void prepare_need_tri(CDT_data &cd, const Mesh &tm, int t) cd.is_reversed.append(rev); } -static CDT_data prepare_cdt_input(const Mesh &tm, int t, const Vector<ITT_value> itts) +static CDT_data prepare_cdt_input(const IMesh &tm, int t, const Vector<ITT_value> itts) { CDT_data ans; ans.t_plane = tm.face(t)->plane; @@ -2112,7 +2119,7 @@ static CDT_data prepare_cdt_input(const Mesh &tm, int t, const Vector<ITT_value> return ans; } -static CDT_data prepare_cdt_input_for_cluster(const Mesh &tm, +static CDT_data prepare_cdt_input_for_cluster(const IMesh &tm, const CoplanarClusterInfo &clinfo, int c, const Vector<ITT_value> itts) @@ -2205,7 +2212,7 @@ static void do_cdt(CDT_data &cd) } static int get_cdt_edge_orig( - int i0, int i1, const CDT_data &cd, const Mesh &in_tm, bool *r_is_intersect) + int i0, int i1, const CDT_data &cd, const IMesh &in_tm, bool *r_is_intersect) { int foff = cd.cdt_out.face_edge_offset; *r_is_intersect = false; @@ -2226,7 +2233,7 @@ static int get_cdt_edge_orig( */ int in_tm_face_index = cd.input_face[in_face_index]; BLI_assert(in_tm_face_index < in_tm.face_size()); - Facep facep = in_tm.face(in_tm_face_index); + const Face *facep = in_tm.face(in_tm_face_index); BLI_assert(pos < facep->size()); bool is_rev = cd.is_reversed[in_face_index]; int eorig = is_rev ? facep->edge_orig[2 - pos] : facep->edge_orig[pos]; @@ -2252,10 +2259,13 @@ static int get_cdt_edge_orig( return NO_INDEX; } -/* Using the result of CDT in cd.cdt_out, extract a Mesh representing the subdivision +/* Using the result of CDT in cd.cdt_out, extract an IMesh representing the subdivision * of input triangle t, which should be an element of cd.input_face. */ -static Mesh extract_subdivided_tri(const CDT_data &cd, const Mesh &in_tm, int t, MArena *arena) +static IMesh extract_subdivided_tri(const CDT_data &cd, + const IMesh &in_tm, + int t, + IMeshArena *arena) { const CDT_result<mpq_class> &cdt_out = cd.cdt_out; int t_in_cdt = -1; @@ -2267,11 +2277,11 @@ static Mesh extract_subdivided_tri(const CDT_data &cd, const Mesh &in_tm, int t, if (t_in_cdt == -1) { std::cout << "Could not find " << t << " in cdt input tris\n"; BLI_assert(false); - return Mesh(); + return IMesh(); } int t_orig = in_tm.face(t)->orig; constexpr int inline_buf_size = 20; - Vector<Facep, inline_buf_size> faces; + Vector<const Face *, inline_buf_size> faces; for (int f : cdt_out.face.index_range()) { if (cdt_out.face_orig[f].contains(t_in_cdt)) { BLI_assert(cdt_out.face[f].size() == 3); @@ -2285,10 +2295,10 @@ static Mesh extract_subdivided_tri(const CDT_data &cd, const Mesh &in_tm, int t, * an original one, then it will already be in the arena * with the correct orig field. */ - Vertp v0 = arena->add_or_find_vert(v0co, NO_INDEX); - Vertp v1 = arena->add_or_find_vert(v1co, NO_INDEX); - Vertp v2 = arena->add_or_find_vert(v2co, NO_INDEX); - Facep facep; + const Vert *v0 = arena->add_or_find_vert(v0co, NO_INDEX); + const Vert *v1 = arena->add_or_find_vert(v1co, NO_INDEX); + const Vert *v2 = arena->add_or_find_vert(v2co, NO_INDEX); + const Face *facep; bool is_isect0; bool is_isect1; bool is_isect2; @@ -2309,13 +2319,13 @@ static Mesh extract_subdivided_tri(const CDT_data &cd, const Mesh &in_tm, int t, faces.append(facep); } } - return Mesh(faces); + return IMesh(faces); } -static Mesh extract_single_tri(const Mesh &tm, int t) +static IMesh extract_single_tri(const IMesh &tm, int t) { - Facep f = tm.face(t); - return Mesh({f}); + const Face *f = tm.face(t); + return IMesh({f}); } static bool bvhtreeverlap_cmp(const BVHTreeOverlap &a, const BVHTreeOverlap &b) @@ -2335,14 +2345,14 @@ class TriOverlaps { uint overlap_tot_{0}; struct CBData { - const Mesh &tm; + const IMesh &tm; std::function<int(int)> shape_fn; int nshapes; bool use_self; }; public: - TriOverlaps(const Mesh &tm, + TriOverlaps(const IMesh &tm, const Array<BoundingBox> &tri_bb, int nshapes, std::function<int(int)> shape_fn, @@ -2464,10 +2474,10 @@ class TriOverlaps { struct OverlapIttsData { Vector<std::pair<int, int>> intersect_pairs; Map<std::pair<int, int>, ITT_value> &itt_map; - const Mesh &tm; - MArena *arena; + const IMesh &tm; + IMeshArena *arena; - OverlapIttsData(Map<std::pair<int, int>, ITT_value> &itt_map, const Mesh &tm, MArena *arena) + OverlapIttsData(Map<std::pair<int, int>, ITT_value> &itt_map, const IMesh &tm, IMeshArena *arena) : itt_map(itt_map), tm(tm), arena(arena) { } @@ -2499,10 +2509,10 @@ static void calc_overlap_itts_range_func(void *__restrict userdata, * intersection for those will be handled by CDT, later. */ static void calc_overlap_itts(Map<std::pair<int, int>, ITT_value> &itt_map, - const Mesh &tm, + const IMesh &tm, const CoplanarClusterInfo &clinfo, const TriOverlaps &ov, - MArena *arena) + IMeshArena *arena) { OverlapIttsData data(itt_map, tm, arena); /* Put dummy values in itt_map intially, so map entries will exist when doing the range function. @@ -2541,11 +2551,11 @@ struct OverlapTriRange { int len; }; struct SubdivideTrisData { - Array<Mesh> &r_tri_subdivided; - const Mesh &tm; + Array<IMesh> &r_tri_subdivided; + const IMesh &tm; const Map<std::pair<int, int>, ITT_value> &itt_map; Span<BVHTreeOverlap> overlap; - MArena *arena; + IMeshArena *arena; /* This vector gives, for each tri in tm that has an intersection * we want to calculate: what the index of that tri in tm is, @@ -2554,11 +2564,11 @@ struct SubdivideTrisData { */ Vector<OverlapTriRange> overlap_tri_range; - SubdivideTrisData(Array<Mesh> &r_tri_subdivided, - const Mesh &tm, + SubdivideTrisData(Array<IMesh> &r_tri_subdivided, + const IMesh &tm, const Map<std::pair<int, int>, ITT_value> &itt_map, Span<BVHTreeOverlap> overlap, - MArena *arena) + IMeshArena *arena) : r_tri_subdivided(r_tri_subdivided), tm(tm), itt_map(itt_map), @@ -2618,12 +2628,12 @@ static void calc_subdivided_tri_range_func(void *__restrict userdata, * But don't do this for triangles that are part of a cluster. * Also, do nothing here if the answer is just the triangle itself. */ -static void calc_subdivided_tris(Array<Mesh> &r_tri_subdivided, - const Mesh &tm, +static void calc_subdivided_tris(Array<IMesh> &r_tri_subdivided, + const IMesh &tm, const Map<std::pair<int, int>, ITT_value> &itt_map, const CoplanarClusterInfo &clinfo, const TriOverlaps &ov, - MArena *arena) + IMeshArena *arena) { const int dbg_level = 0; if (dbg_level > 0) { @@ -2687,10 +2697,10 @@ static int find_first_overlap_index(const TriOverlaps &ov, int t) static CDT_data calc_cluster_subdivided(const CoplanarClusterInfo &clinfo, int c, - const Mesh &tm, + const IMesh &tm, const TriOverlaps &ov, const Map<std::pair<int, int>, ITT_value> &itt_map, - MArena *UNUSED(arena)) + IMeshArena *UNUSED(arena)) { constexpr int dbg_level = 0; BLI_assert(c < clinfo.tot_cluster()); @@ -2743,23 +2753,23 @@ static CDT_data calc_cluster_subdivided(const CoplanarClusterInfo &clinfo, return cd_data; } -static Mesh union_tri_subdivides(const blender::Array<Mesh> &tri_subdivided) +static IMesh union_tri_subdivides(const blender::Array<IMesh> &tri_subdivided) { int tot_tri = 0; - for (const Mesh &m : tri_subdivided) { + for (const IMesh &m : tri_subdivided) { tot_tri += m.face_size(); } - Array<Facep> faces(tot_tri); + Array<const Face *> faces(tot_tri); int face_index = 0; - for (const Mesh &m : tri_subdivided) { - for (Facep f : m.faces()) { + for (const IMesh &m : tri_subdivided) { + for (const Face *f : m.faces()) { faces[face_index++] = f; } } - return Mesh(faces); + return IMesh(faces); } -static CoplanarClusterInfo find_clusters(const Mesh &tm, const Array<BoundingBox> &tri_bb) +static CoplanarClusterInfo find_clusters(const IMesh &tm, const Array<BoundingBox> &tri_bb) { constexpr int dbg_level = 0; if (dbg_level > 0) { @@ -2849,12 +2859,12 @@ static CoplanarClusterInfo find_clusters(const Mesh &tm, const Array<BoundingBox return ans; } -static bool face_is_degenerate(Facep f) +static bool face_is_degenerate(const Face *f) { const Face &face = *f; - Vertp v0 = face[0]; - Vertp v1 = face[1]; - Vertp v2 = face[2]; + const Vert *v0 = face[0]; + const Vert *v1 = face[1]; + const Vert *v2 = face[2]; if (v0 == v1 || v0 == v2 || v1 == v2) { return true; } @@ -2876,10 +2886,10 @@ static bool face_is_degenerate(Facep f) return false; } -/* Does TriMesh tm have any triangles with zero area? */ -static bool has_degenerate_tris(const Mesh &tm) +/* Does triangle IMesh tm have any triangles with zero area? */ +static bool has_degenerate_tris(const IMesh &tm) { - for (Facep f : tm.faces()) { + for (const Face *f : tm.faces()) { if (face_is_degenerate(f)) { return true; } @@ -2887,12 +2897,12 @@ static bool has_degenerate_tris(const Mesh &tm) return false; } -static Mesh remove_degenerate_tris(const Mesh &tm_in) +static IMesh remove_degenerate_tris(const IMesh &tm_in) { - Mesh ans; - Vector<Facep> new_faces; + IMesh ans; + Vector<const Face *> new_faces; new_faces.reserve(tm_in.face_size()); - for (Facep f : tm_in.faces()) { + for (const Face *f : tm_in.faces()) { if (!face_is_degenerate(f)) { new_faces.append(f); } @@ -2902,20 +2912,23 @@ static Mesh remove_degenerate_tris(const Mesh &tm_in) } /* This is the main routine for calculating the self_intersection of a triangle mesh. */ -Mesh trimesh_self_intersect(const Mesh &tm_in, MArena *arena) +IMesh trimesh_self_intersect(const IMesh &tm_in, IMeshArena *arena) { return trimesh_nary_intersect( tm_in, 1, [](int) { return 0; }, true, arena); } -Mesh trimesh_nary_intersect( - const Mesh &tm_in, int nshapes, std::function<int(int)> shape_fn, bool use_self, MArena *arena) +IMesh trimesh_nary_intersect(const IMesh &tm_in, + int nshapes, + std::function<int(int)> shape_fn, + bool use_self, + IMeshArena *arena) { constexpr int dbg_level = 0; if (dbg_level > 0) { std::cout << "\nTRIMESH_NARY_INTERSECT nshapes=" << nshapes << " use_self=" << use_self << "\n"; - for (Facep f : tm_in.faces()) { + for (const Face *f : tm_in.faces()) { BLI_assert(f->is_tri()); UNUSED_VARS_NDEBUG(f); } @@ -2929,8 +2942,8 @@ Mesh trimesh_nary_intersect( /* Usually can use tm_in but if it has degenerate or illegal triangles, * then need to work on a copy of it without those triangles. */ - const Mesh *tm_clean = &tm_in; - Mesh tm_cleaned; + const IMesh *tm_clean = &tm_in; + IMesh tm_cleaned; if (has_degenerate_tris(tm_in)) { if (dbg_level > 0) { std::cout << "cleaning degenerate triangles\n"; @@ -2959,7 +2972,7 @@ Mesh trimesh_nary_intersect( Map<std::pair<int, int>, ITT_value> itt_map; itt_map.reserve(tri_ov.overlap().size()); calc_overlap_itts(itt_map, *tm_clean, clinfo, tri_ov, arena); - Array<Mesh> tri_subdivided(tm_clean->face_size()); + Array<IMesh> tri_subdivided(tm_clean->face_size()); calc_subdivided_tris(tri_subdivided, *tm_clean, itt_map, clinfo, tri_ov, arena); Array<CDT_data> cluster_subdivided(clinfo.tot_cluster()); for (int c : clinfo.index_range()) { @@ -2975,7 +2988,7 @@ Mesh trimesh_nary_intersect( tri_subdivided[t] = extract_single_tri(*tm_clean, t); } } - Mesh combined = union_tri_subdivides(tri_subdivided); + IMesh combined = union_tri_subdivides(tri_subdivided); if (dbg_level > 1) { std::cout << "TRIMESH_NARY_INTERSECT answer:\n"; std::cout << combined; @@ -3032,7 +3045,7 @@ static std::ostream &operator<<(std::ostream &os, const ITT_value &itt) } /* Writing the obj_mesh has the side effect of populating verts. */ -void write_obj_mesh(Mesh &m, const std::string &objname) +void write_obj_mesh(IMesh &m, const std::string &objname) { /* Would like to use BKE_tempdir_base() here, but that brings in dependence on kernel library. * This is just for developer debugging anyway, and should never be called in production Blender. @@ -3057,15 +3070,15 @@ void write_obj_mesh(Mesh &m, const std::string &objname) if (!m.has_verts()) { m.populate_vert(); } - for (Vertp v : m.vertices()) { + for (const Vert *v : m.vertices()) { const double3 dv = v->co; f << "v " << dv[0] << " " << dv[1] << " " << dv[2] << "\n"; } int i = 0; - for (Facep face : m.faces()) { + for (const Face *face : m.faces()) { /* OBJ files use 1-indexing for vertices. */ f << "f "; - for (Vertp v : *face) { + for (const Vert *v : *face) { int i = m.lookup_vert(v); BLI_assert(i != NO_INDEX); /* OBJ files use 1-indexing for vertices. */ diff --git a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc index 2cd6fdc6b4f..397a86d98c3 100644 --- a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc +++ b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc @@ -19,11 +19,11 @@ namespace blender::meshintersect { constexpr bool DO_OBJ = false; -/* Build and hold a Mesh from a string spec. Also hold and own resources used by Mesh. */ -class MeshBuilder { +/* Build and hold an IMesh from a string spec. Also hold and own resources used by IMesh. */ +class IMeshBuilder { public: - Mesh mesh; - MArena arena; + IMesh imesh; + IMeshArena arena; /* "Edge orig" indices are an encoding of <input face#, position in face of start of edge>. */ static constexpr int MAX_FACE_LEN = 1000; /* Used for forming "orig edge" indices only. */ @@ -44,7 +44,7 @@ class MeshBuilder { * mpq_class mpq_class mpq_clas [#verts lines] * int int int ... [#faces lines; indices into verts for given face] */ - MeshBuilder(const char *spec) + IMeshBuilder(const char *spec) { std::istringstream ss(spec); std::string line; @@ -56,8 +56,8 @@ class MeshBuilder { return; } arena.reserve(nv, nf); - Vector<Vertp> verts; - Vector<Facep> faces; + Vector<const Vert *> verts; + Vector<const Face *> faces; bool spec_ok = true; int v_index = 0; while (v_index < nv && spec_ok && getline(ss, line)) { @@ -76,7 +76,7 @@ class MeshBuilder { int f_index = 0; while (f_index < nf && spec_ok && getline(ss, line)) { std::istringstream fss(line); - Vector<Vertp> face_verts; + Vector<const Vert *> face_verts; Vector<int> edge_orig; int fpos = 0; while (spec_ok && fss >> v_index) { @@ -88,7 +88,7 @@ class MeshBuilder { edge_orig.append(edge_index(f_index, fpos)); ++fpos; } - Facep facep = arena.add_face(face_verts, f_index, edge_orig); + const Face *facep = arena.add_face(face_verts, f_index, edge_orig); faces.append(facep); ++f_index; } @@ -99,15 +99,15 @@ class MeshBuilder { std::cout << "Bad spec: " << spec; return; } - mesh = Mesh(faces); + imesh = IMesh(faces); } }; TEST(boolean_trimesh, Empty) { - MArena arena; - Mesh in; - Mesh out = boolean_trimesh( + IMeshArena arena; + IMesh in; + IMesh out = boolean_trimesh( in, BOOLEAN_NONE, 1, [](int) { return 0; }, true, &arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 0); @@ -135,9 +135,9 @@ TEST(boolean_trimesh, TetTetTrimesh) 6 4 7 )"; - MeshBuilder mb(spec); - Mesh out = boolean_trimesh( - mb.mesh, BOOLEAN_NONE, 1, [](int) { return 0; }, true, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = boolean_trimesh( + mb.imesh, BOOLEAN_NONE, 1, [](int) { return 0; }, true, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 11); EXPECT_EQ(out.face_size(), 20); @@ -145,9 +145,9 @@ TEST(boolean_trimesh, TetTetTrimesh) write_obj_mesh(out, "tettet_tm"); } - MeshBuilder mb2(spec); - Mesh out2 = boolean_trimesh( - mb2.mesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb2.arena); + IMeshBuilder mb2(spec); + IMesh out2 = boolean_trimesh( + mb2.imesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb2.arena); out2.populate_vert(); EXPECT_EQ(out2.vert_size(), 10); EXPECT_EQ(out2.face_size(), 16); @@ -155,9 +155,9 @@ TEST(boolean_trimesh, TetTetTrimesh) write_obj_mesh(out2, "tettet_union_tm"); } - MeshBuilder mb3(spec); - Mesh out3 = boolean_trimesh( - mb3.mesh, BOOLEAN_UNION, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb3.arena); + IMeshBuilder mb3(spec); + IMesh out3 = boolean_trimesh( + mb3.imesh, BOOLEAN_UNION, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb3.arena); out3.populate_vert(); EXPECT_EQ(out3.vert_size(), 10); EXPECT_EQ(out3.face_size(), 16); @@ -165,9 +165,9 @@ TEST(boolean_trimesh, TetTetTrimesh) write_obj_mesh(out3, "tettet_union_binary_tm"); } - MeshBuilder mb4(spec); - Mesh out4 = boolean_trimesh( - mb4.mesh, BOOLEAN_UNION, 2, [](int t) { return t < 4 ? 0 : 1; }, true, &mb4.arena); + IMeshBuilder mb4(spec); + IMesh out4 = boolean_trimesh( + mb4.imesh, BOOLEAN_UNION, 2, [](int t) { return t < 4 ? 0 : 1; }, true, &mb4.arena); out4.populate_vert(); EXPECT_EQ(out4.vert_size(), 10); EXPECT_EQ(out4.face_size(), 16); @@ -175,9 +175,9 @@ TEST(boolean_trimesh, TetTetTrimesh) write_obj_mesh(out4, "tettet_union_binary_self_tm"); } - MeshBuilder mb5(spec); - Mesh out5 = boolean_trimesh( - mb5.mesh, BOOLEAN_ISECT, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb5.arena); + IMeshBuilder mb5(spec); + IMesh out5 = boolean_trimesh( + mb5.imesh, BOOLEAN_ISECT, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb5.arena); out5.populate_vert(); EXPECT_EQ(out5.vert_size(), 4); EXPECT_EQ(out5.face_size(), 4); @@ -185,9 +185,9 @@ TEST(boolean_trimesh, TetTetTrimesh) write_obj_mesh(out5, "tettet_intersect_binary_tm"); } - MeshBuilder mb6(spec); - Mesh out6 = boolean_trimesh( - mb6.mesh, BOOLEAN_DIFFERENCE, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb6.arena); + IMeshBuilder mb6(spec); + IMesh out6 = boolean_trimesh( + mb6.imesh, BOOLEAN_DIFFERENCE, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb6.arena); out6.populate_vert(); EXPECT_EQ(out6.vert_size(), 6); EXPECT_EQ(out6.face_size(), 8); @@ -195,9 +195,9 @@ TEST(boolean_trimesh, TetTetTrimesh) write_obj_mesh(out6, "tettet_difference_binary_tm"); } - MeshBuilder mb7(spec); - Mesh out7 = boolean_trimesh( - mb7.mesh, BOOLEAN_DIFFERENCE, 2, [](int t) { return t < 4 ? 1 : 0; }, false, &mb7.arena); + IMeshBuilder mb7(spec); + IMesh out7 = boolean_trimesh( + mb7.imesh, BOOLEAN_DIFFERENCE, 2, [](int t) { return t < 4 ? 1 : 0; }, false, &mb7.arena); out7.populate_vert(); EXPECT_EQ(out7.vert_size(), 8); EXPECT_EQ(out7.face_size(), 12); @@ -227,9 +227,9 @@ TEST(boolean_trimesh, TetTet2Trimesh) 6 7 4 )"; - MeshBuilder mb(spec); - Mesh out = boolean_trimesh( - mb.mesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = boolean_trimesh( + mb.imesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 10); EXPECT_EQ(out.face_size(), 16); @@ -271,9 +271,9 @@ TEST(boolean_trimesh, CubeTetTrimesh) 10 11 8 )"; - MeshBuilder mb(spec); - Mesh out = boolean_trimesh( - mb.mesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = boolean_trimesh( + mb.imesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 14); EXPECT_EQ(out.face_size(), 24); @@ -303,9 +303,9 @@ TEST(boolean_trimesh, BinaryTetTetTrimesh) 6 4 7 )"; - MeshBuilder mb(spec); - Mesh out = boolean_trimesh( - mb.mesh, BOOLEAN_ISECT, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = boolean_trimesh( + mb.imesh, BOOLEAN_ISECT, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 4); EXPECT_EQ(out.face_size(), 4); @@ -335,9 +335,9 @@ TEST(boolean_trimesh, TetTetCoplanarTrimesh) 6 4 7 )"; - MeshBuilder mb(spec); - Mesh out = boolean_trimesh( - mb.mesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = boolean_trimesh( + mb.imesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 5); EXPECT_EQ(out.face_size(), 6); @@ -367,9 +367,9 @@ TEST(boolean_trimesh, TetInsideTetTrimesh) 6 4 7 )"; - MeshBuilder mb(spec); - Mesh out = boolean_trimesh( - mb.mesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = boolean_trimesh( + mb.imesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 4); EXPECT_EQ(out.face_size(), 4); @@ -399,9 +399,9 @@ TEST(boolean_trimesh, TetBesideTetTrimesh) 6 4 7 )"; - MeshBuilder mb(spec); - Mesh out = boolean_trimesh( - mb.mesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = boolean_trimesh( + mb.imesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 8); EXPECT_EQ(out.face_size(), 8); @@ -435,9 +435,9 @@ TEST(boolean_trimesh, DegenerateTris) 0 1 9 )"; - MeshBuilder mb(spec); - Mesh out = boolean_trimesh( - mb.mesh, BOOLEAN_ISECT, 2, [](int t) { return t < 5 ? 0 : 1; }, false, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = boolean_trimesh( + mb.imesh, BOOLEAN_ISECT, 2, [](int t) { return t < 5 ? 0 : 1; }, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 4); EXPECT_EQ(out.face_size(), 4); @@ -467,9 +467,9 @@ TEST(boolean_polymesh, TetTet) 6 4 7 )"; - MeshBuilder mb(spec); - Mesh out = boolean_mesh( - mb.mesh, BOOLEAN_NONE, 1, [](int) { return 0; }, true, nullptr, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = boolean_mesh( + mb.imesh, BOOLEAN_NONE, 1, [](int) { return 0; }, true, nullptr, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 11); EXPECT_EQ(out.face_size(), 13); @@ -477,9 +477,9 @@ TEST(boolean_polymesh, TetTet) write_obj_mesh(out, "tettet"); } - MeshBuilder mb2(spec); - Mesh out2 = boolean_mesh( - mb2.mesh, BOOLEAN_NONE, 2, [](int t) { return t < 4 ? 0 : 1; }, false, nullptr, &mb2.arena); + IMeshBuilder mb2(spec); + IMesh out2 = boolean_mesh( + mb2.imesh, BOOLEAN_NONE, 2, [](int t) { return t < 4 ? 0 : 1; }, false, nullptr, &mb2.arena); out2.populate_vert(); EXPECT_EQ(out2.vert_size(), 11); EXPECT_EQ(out2.face_size(), 13); @@ -521,12 +521,12 @@ TEST(boolean_polymesh, CubeCube) 11 9 13 15 )"; - MeshBuilder mb(spec); + IMeshBuilder mb(spec); if (DO_OBJ) { - write_obj_mesh(mb.mesh, "cube_cube_in"); + write_obj_mesh(mb.imesh, "cube_cube_in"); } - Mesh out = boolean_mesh( - mb.mesh, BOOLEAN_UNION, 1, [](int UNUSED(t)) { return 0; }, true, nullptr, &mb.arena); + IMesh out = boolean_mesh( + mb.imesh, BOOLEAN_UNION, 1, [](int UNUSED(t)) { return 0; }, true, nullptr, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 20); EXPECT_EQ(out.face_size(), 12); @@ -534,9 +534,9 @@ TEST(boolean_polymesh, CubeCube) write_obj_mesh(out, "cubecube_union"); } - MeshBuilder mb2(spec); - Mesh out2 = boolean_mesh( - mb2.mesh, BOOLEAN_NONE, 2, [](int t) { return t < 6 ? 0 : 1; }, false, nullptr, &mb2.arena); + IMeshBuilder mb2(spec); + IMesh out2 = boolean_mesh( + mb2.imesh, BOOLEAN_NONE, 2, [](int t) { return t < 6 ? 0 : 1; }, false, nullptr, &mb2.arena); out2.populate_vert(); EXPECT_EQ(out2.vert_size(), 22); EXPECT_EQ(out2.face_size(), 18); @@ -575,9 +575,9 @@ TEST(boolean_polymesh, CubeCone) 13 11 8 8 9 10 12 13)"; - MeshBuilder mb(spec); - Mesh out = boolean_mesh( - mb.mesh, BOOLEAN_UNION, 1, [](int UNUSED(t)) { return 0; }, true, nullptr, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = boolean_mesh( + mb.imesh, BOOLEAN_UNION, 1, [](int UNUSED(t)) { return 0; }, true, nullptr, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 14); EXPECT_EQ(out.face_size(), 12); @@ -619,9 +619,9 @@ TEST(boolean_polymesh, CubeCubeCoplanar) 15 11 9 13 )"; - MeshBuilder mb(spec); - Mesh out = boolean_mesh( - mb.mesh, BOOLEAN_UNION, 2, [](int t) { return t < 6 ? 0 : 1; }, false, nullptr, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = boolean_mesh( + mb.imesh, BOOLEAN_UNION, 2, [](int t) { return t < 6 ? 0 : 1; }, false, nullptr, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 16); EXPECT_EQ(out.face_size(), 12); @@ -651,9 +651,9 @@ TEST(boolean_polymesh, TetTeTCoplanarDiff) 6 4 7 )"; - MeshBuilder mb(spec); - Mesh out = boolean_mesh( - mb.mesh, + IMeshBuilder mb(spec); + IMesh out = boolean_mesh( + mb.imesh, BOOLEAN_DIFFERENCE, 2, [](int t) { return t < 4 ? 0 : 1; }, @@ -701,9 +701,9 @@ TEST(boolean_polymesh, CubeCubeStep) 15 11 9 13 )"; - MeshBuilder mb(spec); - Mesh out = boolean_mesh( - mb.mesh, + IMeshBuilder mb(spec); + IMesh out = boolean_mesh( + mb.imesh, BOOLEAN_DIFFERENCE, 2, [](int t) { return t < 6 ? 0 : 1; }, @@ -751,9 +751,9 @@ TEST(boolean_polymesh, CubeCyl4) 15 11 9 13 )"; - MeshBuilder mb(spec); - Mesh out = boolean_mesh( - mb.mesh, + IMeshBuilder mb(spec); + IMesh out = boolean_mesh( + mb.imesh, BOOLEAN_DIFFERENCE, 2, [](int t) { return t < 6 ? 1 : 0; }, @@ -822,9 +822,9 @@ TEST(boolean_polymesh, CubeCubesubdivDiff) 23 25 21 19 )"; - MeshBuilder mb(spec); - Mesh out = boolean_mesh( - mb.mesh, + IMeshBuilder mb(spec); + IMesh out = boolean_mesh( + mb.imesh, BOOLEAN_DIFFERENCE, 2, [](int t) { return t < 16 ? 1 : 0; }, @@ -863,9 +863,9 @@ TEST(boolean_polymesh, CubePlane) 11 7 5 9 )"; - MeshBuilder mb(spec); - Mesh out = boolean_mesh( - mb.mesh, + IMeshBuilder mb(spec); + IMesh out = boolean_mesh( + mb.imesh, BOOLEAN_DIFFERENCE, 2, [](int t) { return t >= 1 ? 0 : 1; }, diff --git a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc index 014e0e29ade..bb5e213364f 100644 --- a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc +++ b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc @@ -22,11 +22,11 @@ namespace blender::meshintersect { constexpr bool DO_OBJ = false; -/* Build and hold a Mesh from a string spec. Also hold and own resources used by Mesh. */ -class MeshBuilder { +/* Build and hold an IMesh from a string spec. Also hold and own resources used by IMesh. */ +class IMeshBuilder { public: - Mesh mesh; - MArena arena; + IMesh imesh; + IMeshArena arena; /* "Edge orig" indices are an encoding of <input face#, position in face of start of edge>. */ static constexpr int MAX_FACE_LEN = 1000; /* Used for forming "orig edge" indices only. */ @@ -47,7 +47,7 @@ class MeshBuilder { * mpq_class mpq_class mpq_clas [#verts lines] * int int int ... [#faces lines; indices into verts for given face] */ - MeshBuilder(const char *spec) + IMeshBuilder(const char *spec) { std::istringstream ss(spec); std::string line; @@ -59,8 +59,8 @@ class MeshBuilder { return; } arena.reserve(nv, nf); - Vector<Vertp> verts; - Vector<Facep> faces; + Vector<const Vert *> verts; + Vector<const Face *> faces; bool spec_ok = true; int v_index = 0; while (v_index < nv && spec_ok && getline(ss, line)) { @@ -81,7 +81,7 @@ class MeshBuilder { int f_index = 0; while (f_index < nf && spec_ok && getline(ss, line)) { std::istringstream fss(line); - Vector<Vertp> face_verts; + Vector<const Vert *> face_verts; Vector<int> edge_orig; int fpos = 0; while (spec_ok && fss >> v_index) { @@ -97,7 +97,7 @@ class MeshBuilder { spec_ok = false; } if (spec_ok) { - Facep facep = arena.add_face(face_verts, f_index, edge_orig); + const Face *facep = arena.add_face(face_verts, f_index, edge_orig); faces.append(facep); } ++f_index; @@ -109,17 +109,20 @@ class MeshBuilder { std::cout << "Bad spec: " << spec; return; } - mesh = Mesh(faces); + imesh = IMesh(faces); } }; -/* Return a Facep in mesh with verts equal to v0, v1, and v2, in +/* Return a const Face * in mesh with verts equal to v0, v1, and v2, in * some cyclic order; return nullptr if not found. */ -static Facep find_tri_with_verts(const Mesh &mesh, Vertp v0, Vertp v1, Vertp v2) +static const Face *find_tri_with_verts(const IMesh &mesh, + const Vert *v0, + const Vert *v1, + const Vert *v2) { Face f_arg({v0, v1, v2}, 0, NO_INDEX); - for (Facep f : mesh.faces()) { + for (const Face *f : mesh.faces()) { if (f->cyclic_equal(f_arg)) { return f; } @@ -128,11 +131,11 @@ static Facep find_tri_with_verts(const Mesh &mesh, Vertp v0, Vertp v1, Vertp v2) } /* How many instances of a triangle with v0, v1, v2 are in the mesh? */ -static int count_tris_with_verts(const Mesh &mesh, Vertp v0, Vertp v1, Vertp v2) +static int count_tris_with_verts(const IMesh &mesh, const Vert *v0, const Vert *v1, const Vert *v2) { Face f_arg({v0, v1, v2}, 0, NO_INDEX); int ans = 0; - for (Facep f : mesh.faces()) { + for (const Face *f : mesh.faces()) { if (f->cyclic_equal(f_arg)) { ++ans; } @@ -142,7 +145,7 @@ static int count_tris_with_verts(const Mesh &mesh, Vertp v0, Vertp v1, Vertp v2) /* What is the starting position, if any, of the edge (v0, v1), in either order, in f? -1 if none. */ -static int find_edge_pos_in_tri(Vertp v0, Vertp v1, Facep f) +static int find_edge_pos_in_tri(const Vert *v0, const Vert *v1, const Face *f) { for (int pos : f->index_range()) { int nextpos = f->next_pos(pos); @@ -156,17 +159,17 @@ static int find_edge_pos_in_tri(Vertp v0, Vertp v1, Facep f) #if DO_REGULAR_TESTS TEST(mesh_intersect, Mesh) { - Vector<Vertp> verts; - Vector<Facep> faces; - MArena arena; + Vector<const Vert *> verts; + Vector<const Face *> faces; + IMeshArena arena; verts.append(arena.add_or_find_vert(mpq3(0, 0, 1), 0)); verts.append(arena.add_or_find_vert(mpq3(1, 0, 1), 1)); verts.append(arena.add_or_find_vert(mpq3(0.5, 1, 1), 2)); faces.append(arena.add_face(verts, 0, {10, 11, 12})); - Mesh mesh(faces); - Facep f = mesh.face(0); + IMesh mesh(faces); + const Face *f = mesh.face(0); EXPECT_TRUE(f->is_tri()); EXPECT_EQ(f->plane.norm, double3(0.0, 0.0, 1.0)); EXPECT_EQ(f->plane.d, -1.0); @@ -181,12 +184,12 @@ TEST(mesh_intersect, OneTri) 0 1 2 )"; - MeshBuilder mb(spec); - Mesh imesh = trimesh_self_intersect(mb.mesh, &mb.arena); + IMeshBuilder mb(spec); + IMesh imesh = trimesh_self_intersect(mb.imesh, &mb.arena); imesh.populate_vert(); EXPECT_EQ(imesh.vert_size(), 3); EXPECT_EQ(imesh.face_size(), 1); - const Face f_in = *mb.mesh.face(0); + const Face f_in = *mb.imesh.face(0); const Face f_out = *imesh.face(0); EXPECT_EQ(f_in.orig, f_out.orig); for (int i = 0; i < 3; ++i) { @@ -209,29 +212,29 @@ TEST(mesh_intersect, TriTri) )"; /* Second triangle is smaller and congruent to first, resting on same base, partway along. */ - MeshBuilder mb(spec); - Mesh out = trimesh_self_intersect(mb.mesh, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 6); EXPECT_EQ(out.face_size(), 6); if (out.vert_size() == 6 && out.face_size() == 6) { - Vertp v0 = mb.arena.find_vert(mpq3(0, 0, 0)); - Vertp v1 = mb.arena.find_vert(mpq3(4, 0, 0)); - Vertp v2 = mb.arena.find_vert(mpq3(0, 4, 0)); - Vertp v3 = mb.arena.find_vert(mpq3(1, 0, 0)); - Vertp v4 = mb.arena.find_vert(mpq3(2, 0, 0)); - Vertp v5 = mb.arena.find_vert(mpq3(1, 1, 0)); + const Vert *v0 = mb.arena.find_vert(mpq3(0, 0, 0)); + const Vert *v1 = mb.arena.find_vert(mpq3(4, 0, 0)); + const Vert *v2 = mb.arena.find_vert(mpq3(0, 4, 0)); + const Vert *v3 = mb.arena.find_vert(mpq3(1, 0, 0)); + const Vert *v4 = mb.arena.find_vert(mpq3(2, 0, 0)); + const Vert *v5 = mb.arena.find_vert(mpq3(1, 1, 0)); EXPECT_TRUE(v0 != nullptr && v1 != nullptr && v2 != nullptr); EXPECT_TRUE(v3 != nullptr && v4 != nullptr && v5 != nullptr); if (v0 != nullptr && v1 != nullptr && v2 != nullptr && v3 != nullptr && v4 != nullptr && v5 != nullptr) { EXPECT_EQ(v0->orig, 0); EXPECT_EQ(v1->orig, 1); - Facep f0 = find_tri_with_verts(out, v4, v1, v5); - Facep f1 = find_tri_with_verts(out, v3, v4, v5); - Facep f2 = find_tri_with_verts(out, v0, v3, v5); - Facep f3 = find_tri_with_verts(out, v0, v5, v2); - Facep f4 = find_tri_with_verts(out, v5, v1, v2); + const Face *f0 = find_tri_with_verts(out, v4, v1, v5); + const Face *f1 = find_tri_with_verts(out, v3, v4, v5); + const Face *f2 = find_tri_with_verts(out, v0, v3, v5); + const Face *f3 = find_tri_with_verts(out, v0, v5, v2); + const Face *f4 = find_tri_with_verts(out, v5, v1, v2); EXPECT_TRUE(f0 != nullptr && f1 != nullptr && f2 != nullptr && f3 != nullptr && f4 != nullptr); /* For boolean to work right, there need to be two copies of the smaller triangle in the @@ -255,8 +258,8 @@ TEST(mesh_intersect, TriTri) if (e03 != -1 && e34 != -1 && e45 != -1 && e05 != -1 && e15 != -1) { EXPECT_EQ(f2->edge_orig[e03], 0); EXPECT_TRUE(f1->edge_orig[e34] == 0 || - f1->edge_orig[e34] == 1 * MeshBuilder::MAX_FACE_LEN); - EXPECT_EQ(f1->edge_orig[e45], 1 * MeshBuilder::MAX_FACE_LEN + 1); + f1->edge_orig[e34] == 1 * IMeshBuilder::MAX_FACE_LEN); + EXPECT_EQ(f1->edge_orig[e45], 1 * IMeshBuilder::MAX_FACE_LEN + 1); EXPECT_EQ(f3->edge_orig[e05], NO_INDEX); EXPECT_EQ(f0->edge_orig[e15], NO_INDEX); } @@ -283,29 +286,29 @@ TEST(mesh_intersect, TriTriReversed) 3 5 4 )"; - MeshBuilder mb(spec); - Mesh out = trimesh_self_intersect(mb.mesh, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 6); EXPECT_EQ(out.face_size(), 6); if (out.vert_size() == 6 && out.face_size() == 6) { - Vertp v0 = mb.arena.find_vert(mpq3(0, 0, 0)); - Vertp v1 = mb.arena.find_vert(mpq3(4, 0, 0)); - Vertp v2 = mb.arena.find_vert(mpq3(0, 4, 0)); - Vertp v3 = mb.arena.find_vert(mpq3(1, 0, 0)); - Vertp v4 = mb.arena.find_vert(mpq3(2, 0, 0)); - Vertp v5 = mb.arena.find_vert(mpq3(1, 1, 0)); + const Vert *v0 = mb.arena.find_vert(mpq3(0, 0, 0)); + const Vert *v1 = mb.arena.find_vert(mpq3(4, 0, 0)); + const Vert *v2 = mb.arena.find_vert(mpq3(0, 4, 0)); + const Vert *v3 = mb.arena.find_vert(mpq3(1, 0, 0)); + const Vert *v4 = mb.arena.find_vert(mpq3(2, 0, 0)); + const Vert *v5 = mb.arena.find_vert(mpq3(1, 1, 0)); EXPECT_TRUE(v0 != nullptr && v1 != nullptr && v2 != nullptr); EXPECT_TRUE(v3 != nullptr && v4 != nullptr && v5 != nullptr); if (v0 != nullptr && v1 != nullptr && v2 != nullptr && v3 != nullptr && v4 != nullptr && v5 != nullptr) { EXPECT_EQ(v0->orig, 0); EXPECT_EQ(v1->orig, 1); - Facep f0 = find_tri_with_verts(out, v4, v5, v1); - Facep f1 = find_tri_with_verts(out, v3, v5, v4); - Facep f2 = find_tri_with_verts(out, v0, v5, v3); - Facep f3 = find_tri_with_verts(out, v0, v2, v5); - Facep f4 = find_tri_with_verts(out, v5, v2, v1); + const Face *f0 = find_tri_with_verts(out, v4, v5, v1); + const Face *f1 = find_tri_with_verts(out, v3, v5, v4); + const Face *f2 = find_tri_with_verts(out, v0, v5, v3); + const Face *f3 = find_tri_with_verts(out, v0, v2, v5); + const Face *f4 = find_tri_with_verts(out, v5, v2, v1); EXPECT_TRUE(f0 != nullptr && f1 != nullptr && f2 != nullptr && f3 != nullptr && f4 != nullptr); /* For boolean to work right, there need to be two copies of the smaller triangle in the @@ -329,8 +332,8 @@ TEST(mesh_intersect, TriTriReversed) if (e03 != -1 && e34 != -1 && e45 != -1 && e05 != -1 && e15 != -1) { EXPECT_EQ(f2->edge_orig[e03], 2); EXPECT_TRUE(f1->edge_orig[e34] == 2 || - f1->edge_orig[e34] == 1 * MeshBuilder::MAX_FACE_LEN + 2); - EXPECT_EQ(f1->edge_orig[e45], 1 * MeshBuilder::MAX_FACE_LEN + 1); + f1->edge_orig[e34] == 1 * IMeshBuilder::MAX_FACE_LEN + 2); + EXPECT_EQ(f1->edge_orig[e45], 1 * IMeshBuilder::MAX_FACE_LEN + 1); EXPECT_EQ(f3->edge_orig[e05], NO_INDEX); EXPECT_EQ(f0->edge_orig[e15], NO_INDEX); } @@ -430,20 +433,20 @@ TEST(mesh_intersect, TwoTris) if (do_all_perms && verbose) { std::cout << "\nperms " << i << " " << j << "\n"; } - MArena arena; + IMeshArena arena; arena.reserve(2 * 3, 2); - Array<Vertp> f0_verts(3); - Array<Vertp> f1_verts(3); + Array<const Vert *> f0_verts(3); + Array<const Vert *> f1_verts(3); for (int k = 0; k < 3; ++k) { f0_verts[k] = arena.add_or_find_vert(verts[co1_i + perms[i][k]], k); } for (int k = 0; k < 3; ++k) { f1_verts[k] = arena.add_or_find_vert(verts[co2_i + perms[i][k]], k + 3); } - Facep f0 = arena.add_face(f0_verts, 0, {0, 1, 2}); - Facep f1 = arena.add_face(f1_verts, 1, {3, 4, 5}); - Mesh in_mesh({f0, f1}); - Mesh out_mesh = trimesh_self_intersect(in_mesh, &arena); + const Face *f0 = arena.add_face(f0_verts, 0, {0, 1, 2}); + const Face *f1 = arena.add_face(f1_verts, 1, {3, 4, 5}); + IMesh in_mesh({f0, f1}); + IMesh out_mesh = trimesh_self_intersect(in_mesh, &arena); out_mesh.populate_vert(); EXPECT_EQ(out_mesh.vert_size(), test_tris[test].nv_out); EXPECT_EQ(out_mesh.face_size(), test_tris[test].nf_out); @@ -490,8 +493,8 @@ TEST(mesh_intersect, OverlapCluster) 6 7 8 )"; - MeshBuilder mb(spec); - Mesh out = trimesh_self_intersect(mb.mesh, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 16); EXPECT_EQ(out.face_size(), 18); @@ -522,8 +525,8 @@ TEST(mesh_intersect, TriCornerCross1) 9 10 11 )"; - MeshBuilder mb(spec); - Mesh out = trimesh_self_intersect(mb.mesh, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 10); EXPECT_EQ(out.face_size(), 14); @@ -554,8 +557,8 @@ TEST(mesh_intersect, TriCornerCross2) 9 10 11 )"; - MeshBuilder mb(spec); - Mesh out = trimesh_self_intersect(mb.mesh, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 7); EXPECT_EQ(out.face_size(), 8); @@ -586,8 +589,8 @@ TEST(mesh_intersect, TriCornerCross3) 9 10 11 )"; - MeshBuilder mb(spec); - Mesh out = trimesh_self_intersect(mb.mesh, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 10); EXPECT_EQ(out.face_size(), 16); @@ -617,18 +620,18 @@ TEST(mesh_intersect, TetTet) 6 7 4 )"; - MeshBuilder mb(spec); - Mesh out = trimesh_self_intersect(mb.mesh, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 11); EXPECT_EQ(out.face_size(), 20); /* Expect there to be a triangle with these three verts, oriented this way, with original face 1. */ - Vertp v1 = mb.arena.find_vert(mpq3(2, 0, 0)); - Vertp v8 = mb.arena.find_vert(mpq3(0.5, 0.5, 1)); - Vertp v9 = mb.arena.find_vert(mpq3(1.5, 0.5, 1)); + const Vert *v1 = mb.arena.find_vert(mpq3(2, 0, 0)); + const Vert *v8 = mb.arena.find_vert(mpq3(0.5, 0.5, 1)); + const Vert *v9 = mb.arena.find_vert(mpq3(1.5, 0.5, 1)); EXPECT_TRUE(v1 != nullptr && v8 != nullptr && v9 != nullptr); - Facep f = mb.arena.find_face({v1, v8, v9}); + const Face *f = mb.arena.find_face({v1, v8, v9}); EXPECT_NE(f, nullptr); EXPECT_EQ(f->orig, 1); int v1pos = f->vert[0] == v1 ? 0 : (f->vert[1] == v1 ? 1 : 2); @@ -688,8 +691,8 @@ TEST(mesh_intersect, CubeCubeStep) 15 9 13 )"; - MeshBuilder mb(spec); - Mesh out = trimesh_self_intersect(mb.mesh, &mb.arena); + IMeshBuilder mb(spec); + IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 22); EXPECT_EQ(out.face_size(), 56); @@ -697,9 +700,9 @@ TEST(mesh_intersect, CubeCubeStep) write_obj_mesh(out, "test_cubecubestep"); } - MeshBuilder mb2(spec); - Mesh out2 = trimesh_nary_intersect( - mb2.mesh, 2, [](int t) { return t < 12 ? 0 : 1; }, false, &mb2.arena); + IMeshBuilder mb2(spec); + IMesh out2 = trimesh_nary_intersect( + mb2.imesh, 2, [](int t) { return t < 12 ? 0 : 1; }, false, &mb2.arena); out2.populate_vert(); EXPECT_EQ(out2.vert_size(), 22); EXPECT_EQ(out2.face_size(), 56); @@ -728,16 +731,16 @@ static void fill_sphere_data(int nrings, const double3 ¢er, double radius, bool triangulate, - MutableSpan<Facep> face, + MutableSpan<const Face *> face, int vid_start, int fid_start, - MArena *arena) + IMeshArena *arena) { int num_verts; int num_faces; get_sphere_params(nrings, nsegs, triangulate, &num_verts, &num_faces); BLI_assert(num_faces == face.size()); - Array<Vertp> vert(num_verts); + Array<const Vert *> vert(num_verts); const bool nrings_even = (nrings % 2 == 0); int half_nrings = nrings / 2; const bool nsegs_even = (nsegs % 2) == 0; @@ -820,12 +823,14 @@ static void fill_sphere_data(int nrings, double x = r_sin_theta * cos_phi + center[0]; double y = r_sin_theta * sin_phi + center[1]; double z = r_cos_theta + center[2]; - Vertp v = arena->add_or_find_vert(mpq3(x, y, z), vid++); + const Vert *v = arena->add_or_find_vert(mpq3(x, y, z), vid++); vert[vert_index_fn(s, r)] = v; } } - Vertp vtop = arena->add_or_find_vert(mpq3(center[0], center[1], center[2] + radius), vid++); - Vertp vbot = arena->add_or_find_vert(mpq3(center[0], center[1], center[2] - radius), vid++); + const Vert *vtop = arena->add_or_find_vert(mpq3(center[0], center[1], center[2] + radius), + vid++); + const Vert *vbot = arena->add_or_find_vert(mpq3(center[0], center[1], center[2] - radius), + vid++); vert[vert_index_fn(0, 0)] = vtop; vert[vert_index_fn(0, nrings)] = vbot; for (int s = 0; s < nsegs; ++s) { @@ -836,8 +841,8 @@ static void fill_sphere_data(int nrings, int i1 = vert_index_fn(s, rnext); int i2 = vert_index_fn(snext, rnext); int i3 = vert_index_fn(snext, r); - Facep f; - Facep f2 = nullptr; + const Face *f; + const Face *f2 = nullptr; if (r == 0) { f = arena->add_face({vert[i0], vert[i1], vert[i2]}, fid++, eid); } @@ -877,12 +882,12 @@ static void spheresphere_test(int nrings, double y_offset, bool use_self) } BLI_task_scheduler_init(); /* Without this, no parallelism. */ double time_start = PIL_check_seconds_timer(); - MArena arena; + IMeshArena arena; int nsegs = 2 * nrings; int num_sphere_verts; int num_sphere_tris; get_sphere_params(nrings, nsegs, true, &num_sphere_verts, &num_sphere_tris); - Array<Facep> tris(2 * num_sphere_tris); + Array<const Face *> tris(2 * num_sphere_tris); arena.reserve(2 * num_sphere_verts, 2 * num_sphere_tris); double3 center1(0.0, 0.0, 0.0); fill_sphere_data(nrings, @@ -890,7 +895,7 @@ static void spheresphere_test(int nrings, double y_offset, bool use_self) center1, 1.0, true, - MutableSpan<Facep>(tris.begin(), num_sphere_tris), + MutableSpan<const Face *>(tris.begin(), num_sphere_tris), 0, 0, &arena); @@ -900,14 +905,14 @@ static void spheresphere_test(int nrings, double y_offset, bool use_self) center2, 1.0, true, - MutableSpan<Facep>(tris.begin() + num_sphere_tris, num_sphere_tris), + MutableSpan<const Face *>(tris.begin() + num_sphere_tris, num_sphere_tris), num_sphere_verts, num_sphere_verts, &arena); - Mesh mesh(tris); + IMesh mesh(tris); double time_create = PIL_check_seconds_timer(); write_obj_mesh(mesh, "spheresphere_in"); - Mesh out; + IMesh out; if (use_self) { out = trimesh_self_intersect(mesh, &arena); } @@ -941,10 +946,10 @@ static void fill_grid_data(int x_subdiv, bool triangulate, double size, const double3 ¢er, - MutableSpan<Facep> face, + MutableSpan<const Face *> face, int vid_start, int fid_start, - MArena *arena) + IMeshArena *arena) { if (x_subdiv <= 1 || y_subdiv <= 1) { return; @@ -953,7 +958,7 @@ static void fill_grid_data(int x_subdiv, int num_faces; get_grid_params(x_subdiv, y_subdiv, triangulate, &num_verts, &num_faces); BLI_assert(face.size() == num_faces); - Array<Vertp> vert(num_verts); + Array<const Vert *> vert(num_verts); auto vert_index_fn = [x_subdiv](int ix, int iy) { return iy * x_subdiv + ix; }; auto face_index_fn = [x_subdiv](int ix, int iy) { return iy * (x_subdiv - 1) + ix; }; auto tri_index_fn = [x_subdiv](int ix, int iy, int tri) { @@ -969,7 +974,7 @@ static void fill_grid_data(int x_subdiv, double x = center[0] - r + ix * delta_x; double y = center[1] - r + iy * delta_y; double z = center[2]; - Vertp v = arena->add_or_find_vert(mpq3(x, y, z), vid++); + const Vert *v = arena->add_or_find_vert(mpq3(x, y, z), vid++); vert[vert_index_fn(ix, iy)] = v; } } @@ -981,13 +986,13 @@ static void fill_grid_data(int x_subdiv, int i2 = vert_index_fn(ix + 1, iy + 1); int i3 = vert_index_fn(ix + 1, iy); if (triangulate) { - Facep f = arena->add_face({vert[i0], vert[i1], vert[i2]}, fid++, eid); - Facep f2 = arena->add_face({vert[i2], vert[i3], vert[i0]}, fid++, eid); + const Face *f = arena->add_face({vert[i0], vert[i1], vert[i2]}, fid++, eid); + const Face *f2 = arena->add_face({vert[i2], vert[i3], vert[i0]}, fid++, eid); face[tri_index_fn(ix, iy, 0)] = f; face[tri_index_fn(ix, iy, 1)] = f2; } else { - Facep f = arena->add_face({vert[i0], vert[i1], vert[i2], vert[i3]}, fid++, eid); + const Face *f = arena->add_face({vert[i0], vert[i1], vert[i2], vert[i3]}, fid++, eid); face[face_index_fn(ix, iy)] = f; } } @@ -1007,7 +1012,7 @@ static void spheregrid_test(int nrings, int grid_level, double z_offset, bool us } BLI_task_scheduler_init(); /* Without this, no parallelism. */ double time_start = PIL_check_seconds_timer(); - MArena arena; + IMeshArena arena; int num_sphere_verts; int num_sphere_tris; int nsegs = 2 * nrings; @@ -1016,7 +1021,7 @@ static void spheregrid_test(int nrings, int grid_level, double z_offset, bool us int subdivs = 1 << grid_level; get_sphere_params(nrings, nsegs, true, &num_sphere_verts, &num_sphere_tris); get_grid_params(subdivs, subdivs, true, &num_grid_verts, &num_grid_tris); - Array<Facep> tris(num_sphere_tris + num_grid_tris); + Array<const Face *> tris(num_sphere_tris + num_grid_tris); arena.reserve(num_sphere_verts + num_grid_verts, num_sphere_tris + num_grid_tris); double3 center(0.0, 0.0, z_offset); fill_sphere_data(nrings, @@ -1024,7 +1029,7 @@ static void spheregrid_test(int nrings, int grid_level, double z_offset, bool us center, 1.0, true, - MutableSpan<Facep>(tris.begin(), num_sphere_tris), + MutableSpan<const Face *>(tris.begin(), num_sphere_tris), 0, 0, &arena); @@ -1033,14 +1038,14 @@ static void spheregrid_test(int nrings, int grid_level, double z_offset, bool us true, 4.0, double3(0, 0, 0), - MutableSpan<Facep>(tris.begin() + num_sphere_tris, num_grid_tris), + MutableSpan<const Face *>(tris.begin() + num_sphere_tris, num_grid_tris), num_sphere_verts, num_sphere_tris, &arena); - Mesh mesh(tris); + IMesh mesh(tris); double time_create = PIL_check_seconds_timer(); // write_obj_mesh(mesh, "spheregrid_in"); - Mesh out; + IMesh out; if (use_self) { out = trimesh_self_intersect(mesh, &arena); } |