diff options
author | Howard Trickey <howard.trickey@gmail.com> | 2020-08-22 14:30:13 +0300 |
---|---|---|
committer | Howard Trickey <howard.trickey@gmail.com> | 2020-08-22 14:30:13 +0300 |
commit | 9810cfa1e83f173ccbdc1c3335183f93529838b5 (patch) | |
tree | 3f3d79feb348f1b41125c965ec2ce632a3a200f4 | |
parent | 0a6ef6950959ae0e86a5a7ff12262e78eb852a9f (diff) |
Addressed comments of reviewers on D8623.
Almost all changes asked for by Campbell and Jacques have been
addressed. The clang-tidy fixes will happen in the next commit.
-rw-r--r-- | build_files/build_environment/cmake/versions.cmake | 2 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_double2.hh | 7 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_double3.hh | 5 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_mesh_boolean.hh | 18 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_mesh_intersect.hh | 21 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_mpq2.hh | 5 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_mpq3.hh | 5 | ||||
-rw-r--r-- | source/blender/blenlib/intern/delaunay_2d.cc | 62 | ||||
-rw-r--r-- | source/blender/blenlib/intern/mesh_boolean.cc | 304 | ||||
-rw-r--r-- | source/blender/blenlib/intern/mesh_intersect.cc | 138 | ||||
-rw-r--r-- | source/blender/blenlib/tests/BLI_mesh_boolean_test.cc | 97 | ||||
-rw-r--r-- | source/blender/blenlib/tests/BLI_mesh_intersect_test.cc | 4 | ||||
-rw-r--r-- | source/blender/bmesh/tools/bmesh_boolean.cc | 21 |
13 files changed, 338 insertions, 351 deletions
diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake index e5a24e4fe13..37bfac8bfba 100644 --- a/build_files/build_environment/cmake/versions.cmake +++ b/build_files/build_environment/cmake/versions.cmake @@ -312,9 +312,11 @@ set(NASM_HASH f4fd1329b1713e1ccd34b2fc121c4bcd278c9f91cc4cb205ae8fcd2e4728dd14) set(XR_OPENXR_SDK_VERSION 1.0.8) set(XR_OPENXR_SDK_URI https://github.com/KhronosGroup/OpenXR-SDK/archive/release-${XR_OPENXR_SDK_VERSION}.tar.gz) set(XR_OPENXR_SDK_HASH c6de63d2e0f9029aa58dfa97cad8ce07) +set(ISPC_VERSION v1.13.0) set(ISPC_URI https://github.com/ispc/ispc/archive/${ISPC_VERSION}.tar.gz) set(ISPC_HASH 4bf5e8d0020c4b9980faa702c1a6f25f) set(GMP_VERSION 6.2.0) + set(GMP_URI https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.xz) set(GMP_HASH a325e3f09e6d91e62101e59f9bda3ec1) diff --git a/source/blender/blenlib/BLI_double2.hh b/source/blender/blenlib/BLI_double2.hh index a85f74ee442..654207d98f1 100644 --- a/source/blender/blenlib/BLI_double2.hh +++ b/source/blender/blenlib/BLI_double2.hh @@ -83,6 +83,11 @@ struct double2 { return a.x == b.x && a.y == b.y; } + friend bool operator!=(const double2 &a, const double2 &b) + { + return a.x != b.x || a.y != b.y; + } + friend std::ostream &operator<<(std::ostream &stream, const double2 &v) { stream << "(" << v.x << ", " << v.y << ")"; @@ -101,7 +106,7 @@ struct double2 { static double2 abs(const double2 &a) { - return double2(fabsf(a.x), fabsf(a.y)); + return double2(fabs(a.x), fabs(a.y)); } static double distance(const double2 &a, const double2 &b) diff --git a/source/blender/blenlib/BLI_double3.hh b/source/blender/blenlib/BLI_double3.hh index 11a88e121ca..fb9823c3ec0 100644 --- a/source/blender/blenlib/BLI_double3.hh +++ b/source/blender/blenlib/BLI_double3.hh @@ -176,6 +176,11 @@ struct double3 { return a.x == b.x && a.y == b.y && a.z == b.z; } + friend bool operator!=(const double3 &a, const double3 &b) + { + return a.x != b.x || a.y != b.y || a.z != b.z; + } + friend std::ostream &operator<<(std::ostream &stream, const double3 &v) { stream << "(" << v.x << ", " << v.y << ", " << v.z << ")"; diff --git a/source/blender/blenlib/BLI_mesh_boolean.hh b/source/blender/blenlib/BLI_mesh_boolean.hh index 324a5adecc7..2b5afb2bffc 100644 --- a/source/blender/blenlib/BLI_mesh_boolean.hh +++ b/source/blender/blenlib/BLI_mesh_boolean.hh @@ -30,12 +30,12 @@ namespace blender::meshintersect { /* Enum values after BOOLEAN_NONE need to match BMESH_ISECT_BOOLEAN_... values in * editmesh_intersect.c. */ -enum bool_optype { - BOOLEAN_NONE = -1, +enum class BoolOpType { + None = -1, /* Aligned with BooleanModifierOp. */ - BOOLEAN_ISECT = 0, - BOOLEAN_UNION = 1, - BOOLEAN_DIFFERENCE = 2, + Intersect = 0, + Union = 1, + Difference = 2, }; /* Do the boolean operation op on the mesh pm_in. @@ -52,8 +52,8 @@ enum bool_optype { * The output IMesh will have faces whose orig fields map back to faces and edges in * the input mesh. */ -IMesh boolean_mesh(IMesh &pm, - bool_optype op, +IMesh boolean_mesh(IMesh &imesh, + BoolOpType op, int nshapes, std::function<int(int)> shape_fn, bool use_self, @@ -64,8 +64,8 @@ IMesh boolean_mesh(IMesh &pm, * It is exposed mainly for unit testing, at the moment: boolean_mesh() uses * it to do most of its work. */ -IMesh boolean_trimesh(IMesh &tm, - bool_optype op, +IMesh boolean_trimesh(IMesh &trimesh, + BoolOpType op, int nshapes, std::function<int(int)> shape_fn, bool use_self, diff --git a/source/blender/blenlib/BLI_mesh_intersect.hh b/source/blender/blenlib/BLI_mesh_intersect.hh index 1c77a67877d..d7cf0b01823 100644 --- a/source/blender/blenlib/BLI_mesh_intersect.hh +++ b/source/blender/blenlib/BLI_mesh_intersect.hh @@ -34,6 +34,7 @@ # include "BLI_math_mpq.hh" # include "BLI_mpq3.hh" # include "BLI_span.hh" +# include "BLI_utility_mixins.hh" # include "BLI_vector.hh" namespace blender::meshintersect { @@ -62,14 +63,8 @@ struct Vert { Vert() = default; Vert(const mpq3 &mco, const double3 &dco, int id, int orig); - Vert(const Vert &other); - Vert(Vert &&other) noexcept; - ~Vert() = default; - Vert &operator=(const Vert &other); - Vert &operator=(Vert &&other) noexcept; - /* Test equality on the co_exact field. */ bool operator==(const Vert &other) const; @@ -127,14 +122,8 @@ struct Face { Face() = default; 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; - ~Face() = default; - Face &operator=(const Face &other); - Face &operator=(Face &&other) noexcept; - bool is_tri() const { return vert.size() == 3; @@ -190,20 +179,14 @@ std::ostream &operator<<(std::ostream &os, const Face *f); * ensure that only one instance of a Vert with a given co_exact will * exist. I.e., it dedups the vertices. */ -class IMeshArena { +class IMeshArena : NonCopyable, NonMovable { class IMeshArenaImpl; std::unique_ptr<IMeshArenaImpl> pimpl_; public: IMeshArena(); - IMeshArena(const IMeshArena &) = delete; - IMeshArena(IMeshArena &&) = delete; - ~IMeshArena(); - IMeshArena &operator=(const IMeshArena &) = delete; - IMeshArena &operator=(IMeshArena &&) = delete; - /* Provide hints to number of expected Verts and Faces expected * to be allocated. */ diff --git a/source/blender/blenlib/BLI_mpq2.hh b/source/blender/blenlib/BLI_mpq2.hh index a37140da5ec..86a7b0ac3a8 100644 --- a/source/blender/blenlib/BLI_mpq2.hh +++ b/source/blender/blenlib/BLI_mpq2.hh @@ -116,6 +116,11 @@ struct mpq2 { return a.x == b.x && a.y == b.y; } + friend bool operator!=(const mpq2 &a, const mpq2 &b) + { + return a.x != b.x || a.y != b.y; + } + friend std::ostream &operator<<(std::ostream &stream, const mpq2 &v) { stream << "(" << v.x << ", " << v.y << ")"; diff --git a/source/blender/blenlib/BLI_mpq3.hh b/source/blender/blenlib/BLI_mpq3.hh index fd47abe3dde..a0f1b342d06 100644 --- a/source/blender/blenlib/BLI_mpq3.hh +++ b/source/blender/blenlib/BLI_mpq3.hh @@ -198,6 +198,11 @@ struct mpq3 { return a.x == b.x && a.y == b.y && a.z == b.z; } + friend bool operator!=(const mpq3 &a, const mpq3 &b) + { + return a.x != b.x || a.y != b.y || a.z != b.z; + } + friend std::ostream &operator<<(std::ostream &stream, const mpq3 &v) { stream << "(" << v.x << ", " << v.y << ", " << v.z << ")"; diff --git a/source/blender/blenlib/intern/delaunay_2d.cc b/source/blender/blenlib/intern/delaunay_2d.cc index 0cb53a71432..18ce976da82 100644 --- a/source/blender/blenlib/intern/delaunay_2d.cc +++ b/source/blender/blenlib/intern/delaunay_2d.cc @@ -529,7 +529,7 @@ template<typename T> CDTVert<T>::CDTVert(const vec2<T> &pt) template<typename T> CDTVert<T> *CDTArrangement<T>::add_vert(const vec2<T> &pt) { CDTVert<T> *v = new CDTVert<T>(pt); - int index = static_cast<int>(this->verts.append_and_get_index(v)); + int index = this->verts.append_and_get_index(v); v->index = index; return v; } @@ -912,7 +912,7 @@ template<typename T> bool site_lexicographic_sort(const SiteInfo<T> &a, const Si */ template<typename T> void find_site_merges(Array<SiteInfo<T>> &sites) { - int n = static_cast<int>(sites.size()); + int n = sites.size(); for (int i = 0; i < n - 1; ++i) { int j = i + 1; while (j < n && sites[j].v->co == sites[i].v->co) { @@ -1154,7 +1154,7 @@ template<typename T> void dc_triangulate(CDTArrangement<T> *cdt, Array<SiteInfo< /* Compress sites in place to eliminted verts that merge to others. */ int i = 0; int j = 0; - int nsites = static_cast<int>(sites.size()); + int nsites = sites.size(); while (j < nsites) { /* Invariante: sites[0..i-1] have non-merged verts from 0..(j-1) in them. */ sites[i] = sites[j++]; @@ -1191,7 +1191,7 @@ template<typename T> void dc_triangulate(CDTArrangement<T> *cdt, Array<SiteInfo< */ template<typename T> void initial_triangulation(CDTArrangement<T> *cdt) { - int n = static_cast<int>(cdt->verts.size()); + int n = cdt->verts.size(); if (n <= 1) { return; } @@ -1433,7 +1433,8 @@ void fill_crossdata_for_intersect(const vec2<T> &curco, cd->out = se_vcva; } } - } break; + break; + } case vec2<T>::isect_result::LINE_LINE_EXACT: { if (lambda == 0) { fill_crossdata_for_through_vert(va, se_vcva, cd, cd_next); @@ -1447,7 +1448,8 @@ void fill_crossdata_for_intersect(const vec2<T> &curco, cd->out = se_vcva; } } - } break; + break; + } case vec2<T>::isect_result::LINE_LINE_NONE: { #ifdef WITH_GMP if (std::is_same<T, mpq_class>::value) { @@ -1462,7 +1464,8 @@ void fill_crossdata_for_intersect(const vec2<T> &curco, else { fill_crossdata_for_through_vert(vb, se_vcvb, cd, cd_next); } - } break; + break; + } case vec2<T>::isect_result::LINE_LINE_COLINEAR: { if (vec2<T>::distance_squared(va->co, v2->co) <= vec2<T>::distance_squared(vb->co, v2->co)) { fill_crossdata_for_through_vert(va, se_vcva, cd, cd_next); @@ -1470,7 +1473,8 @@ void fill_crossdata_for_intersect(const vec2<T> &curco, else { fill_crossdata_for_through_vert(vb, se_vcvb, cd, cd_next); } - } break; + break; + } } } // namespace blender::meshintersect @@ -1562,7 +1566,7 @@ template<typename T> void dump_crossings(const Vector<CrossData<T>, inline_crossings_size> &crossings) { std::cout << "CROSSINGS\n"; - for (int i = 0; i < static_cast<int>(crossings.size()); ++i) { + for (int i = 0; i < crossings.size(); ++i) { std::cout << i << ": "; const CrossData<T> &cd = crossings[i]; if (cd.lambda == 0) { @@ -1641,7 +1645,7 @@ void add_edge_constraint( Vector<CrossData<T>, inline_crossings_size> crossings; crossings.append(CrossData<T>(T(0), v1, nullptr, nullptr)); int n; - while (!((n = static_cast<int>(crossings.size())) > 0 && crossings[n - 1].vert == v2)) { + while (!((n = crossings.size()) > 0 && crossings[n - 1].vert == v2)) { crossings.append(CrossData<T>()); CrossData<T> *cd = &crossings[n - 1]; CrossData<T> *cd_next = &crossings[n]; @@ -1683,7 +1687,7 @@ void add_edge_constraint( * This loop marks certain crossings as "deleted", by setting * their lambdas to -1.0. */ - int ncrossings = static_cast<int>(crossings.size()); + int ncrossings = crossings.size(); for (int i = 2; i < ncrossings; ++i) { CrossData<T> *cd = &crossings[i]; if (cd->lambda == 0.0) { @@ -1816,8 +1820,8 @@ void add_edge_constraint( */ template<typename T> void add_edge_constraints(CDT_state<T> *cdt_state, const CDT_input<T> &input) { - int ne = static_cast<int>(input.edge.size()); - int nv = static_cast<int>(input.vert.size()); + int ne = input.edge.size(); + int nv = input.vert.size(); for (int i = 0; i < ne; i++) { int iv1 = input.edge[i].first; int iv2 = input.edge[i].second; @@ -1903,14 +1907,14 @@ static int power_of_10_greater_equal_to(int x) */ template<typename T> void add_face_constraints(CDT_state<T> *cdt_state, const CDT_input<T> &input) { - int nv = static_cast<int>(input.vert.size()); - int nf = static_cast<int>(input.face.size()); + int nv = input.vert.size(); + int nf = input.face.size(); int fstart = 0; SymEdge<T> *face_symedge0 = nullptr; CDTArrangement<T> *cdt = &cdt_state->cdt; int maxflen = 0; for (int f = 0; f < nf; f++) { - maxflen = max_ii(maxflen, static_cast<int>(input.face[f].size())); + maxflen = max_ii(maxflen, input.face[f].size()); } /* For convenience in debugging, make face_edge_offset be a power of 10. */ cdt_state->face_edge_offset = power_of_10_greater_equal_to( @@ -1921,7 +1925,7 @@ template<typename T> void add_face_constraints(CDT_state<T> *cdt_state, const CD */ BLI_assert(INT_MAX / cdt_state->face_edge_offset > nf); for (int f = 0; f < nf; f++) { - int flen = static_cast<int>(input.face[f].size()); + int flen = input.face[f].size(); if (flen <= 2) { /* Ignore faces with fewer than 3 vertices. */ fstart += flen; @@ -2199,7 +2203,7 @@ CDT_result<T> get_cdt_output(CDT_state<T> *cdt_state, * corresponding to the vert in position i in cdt->verts. * This first loop sets vert_to_output_map for unmerged verts. */ - int verts_size = static_cast<int>(cdt->verts.size()); + int verts_size = cdt->verts.size(); Array<int> vert_to_output_map(verts_size); int nv = 0; for (int i = 0; i < verts_size; ++i) { @@ -2300,9 +2304,9 @@ template<typename T> void add_input_verts(CDT_state<T> *cdt_state, const CDT_inp template<typename T> CDT_result<T> delaunay_calc(const CDT_input<T> &input, CDT_output_type output_type) { - int nv = static_cast<int>(input.vert.size()); - int ne = static_cast<int>(input.edge.size()); - int nf = static_cast<int>(input.face.size()); + int nv = input.vert.size(); + int ne = input.edge.size(); + int nf = input.face.size(); CDT_state<T> cdt_state(nv, ne, nf, input.epsilon); add_input_verts(&cdt_state, input); initial_triangulation(&cdt_state.cdt); @@ -2363,22 +2367,22 @@ extern "C" ::CDT_result *BLI_delaunay_2d_cdt_calc(const ::CDT_input *input, in, output_type); ::CDT_result *output = static_cast<::CDT_result *>(MEM_mallocN(sizeof(*output), __func__)); - int nv = output->verts_len = static_cast<int>(res.vert.size()); - int ne = output->edges_len = static_cast<int>(res.edge.size()); - int nf = output->faces_len = static_cast<int>(res.face.size()); + int nv = output->verts_len = res.vert.size(); + int ne = output->edges_len = res.edge.size(); + int nf = output->faces_len = res.face.size(); int tot_v_orig = 0; int tot_e_orig = 0; int tot_f_orig = 0; int tot_f_lens = 0; for (int v = 0; v < nv; ++v) { - tot_v_orig += static_cast<int>(res.vert_orig[v].size()); + tot_v_orig += res.vert_orig[v].size(); } for (int e = 0; e < ne; ++e) { - tot_e_orig += static_cast<int>(res.edge_orig[e].size()); + tot_e_orig += res.edge_orig[e].size(); } for (int f = 0; f < nf; ++f) { - tot_f_orig += static_cast<int>(res.face_orig[f].size()); - tot_f_lens += static_cast<int>(res.face[f].size()); + tot_f_orig += res.face_orig[f].size(); + tot_f_lens += res.face[f].size(); } output->vert_coords = static_cast<decltype(output->vert_coords)>( @@ -2427,7 +2431,7 @@ extern "C" ::CDT_result *BLI_delaunay_2d_cdt_calc(const ::CDT_input *input, int f_index = 0; for (int f = 0; f < nf; ++f) { output->faces_start_table[f] = f_index; - int flen = static_cast<int>(res.face[f].size()); + int flen = res.face[f].size(); output->faces_len_table[f] = flen; for (int j = 0; j < flen; ++j) { output->faces[f_index++] = res.face[f][j]; diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc index 0095ec95140..ff54ae128a9 100644 --- a/source/blender/blenlib/intern/mesh_boolean.cc +++ b/source/blender/blenlib/intern/mesh_boolean.cc @@ -235,11 +235,6 @@ class Patch { tri_.append(t); } - const Vector<int> &tri() const - { - return tri_; - } - int tot_tri() const { return tri_.size(); @@ -267,7 +262,7 @@ class Patch { static std::ostream &operator<<(std::ostream &os, const Patch &patch) { - os << "Patch " << patch.tri(); + os << "Patch " << patch.tris(); if (patch.cell_above != NO_INDEX) { os << " cell_above=" << patch.cell_above; } @@ -351,6 +346,16 @@ class PatchesInfo { return patch_.end(); } + Patch *begin() + { + return patch_.begin(); + } + + Patch *end() + { + return patch_.end(); + } + void add_new_patch_patch_edge(int p1, int p2, Edge e) { pp_edge_.add_new(std::pair<int, int>(p1, p2), e); @@ -363,7 +368,7 @@ class PatchesInfo { } }; -static bool apply_bool_op(int bool_optype, const Array<int> &winding); +static bool apply_bool_op(BoolOpType bool_optype, const Array<int> &winding); /* A Cell is a volume of 3-space, surrounded by patches. * We will partition all 3-space into Cells. @@ -374,8 +379,8 @@ class Cell { Array<int> winding_; int merged_to_{NO_INDEX}; bool winding_assigned_{false}; - /* flag_ will be true when this cell should be in the output volume. */ - bool flag_{false}; + /* in_output_volume_ will be true when this cell should be in the output volume. */ + bool in_output_volume_{false}; /* zero_volume_ will be true when this is a zero-volume cell (inside a stack of identical * triangles). */ bool zero_volume_{false}; @@ -393,14 +398,14 @@ class Cell { patches_.append_non_duplicates(p); } - const Vector<int> &patches() const + const Span<int> patches() const { - return patches_; + return Span<int>(patches_); } - const Array<int> &winding() const + const Span<int> winding() const { - return winding_; + return Span<int>(winding_); } void init_winding(int winding_len) @@ -414,17 +419,20 @@ class Cell { winding_assigned_ = true; } - void set_winding_and_flag(const Cell &from_cell, int shape, int delta, int bool_optype) + void set_winding_and_in_output_volume(const Cell &from_cell, + int shape, + int delta, + BoolOpType bool_optype) { std::copy(from_cell.winding().begin(), from_cell.winding().end(), winding_.begin()); winding_[shape] += delta; winding_assigned_ = true; - flag_ = apply_bool_op(bool_optype, winding_); + in_output_volume_ = apply_bool_op(bool_optype, winding_); } - bool flag() const + bool in_output_volume() const { - return flag_; + return in_output_volume_; } bool winding_assigned() const @@ -458,7 +466,7 @@ static std::ostream &operator<<(std::ostream &os, const Cell &cell) os << "Cell patches " << cell.patches(); if (cell.winding().size() > 0) { os << " winding=" << cell.winding(); - os << " flag=" << cell.flag(); + os << " in_output_volume=" << cell.in_output_volume(); } os << " zv=" << cell.zero_volume(); return os; @@ -511,7 +519,7 @@ class CellsInfo { int add_cell() { int index = cell_.append_and_get_index(Cell()); - return static_cast<int>(index); + return index; } Cell &cell(int c) @@ -544,6 +552,16 @@ class CellsInfo { return cell_.end(); } + Cell *begin() + { + return cell_.begin(); + } + + Cell *end() + { + return cell_.end(); + } + void init_windings(int winding_len) { for (Cell &cell : cell_) { @@ -628,8 +646,7 @@ static void merge_cells(int merge_to, int merge_from, CellsInfo &cinfo, PatchesI final_merge_to = merge_to_cell.merged_to(); merge_to_cell = cinfo.cell(final_merge_to); } - for (int p : pinfo.index_range()) { - Patch &patch = pinfo.patch(p); + for (Patch &patch : pinfo) { if (patch.cell_above == merge_from) { patch.cell_above = final_merge_to; } @@ -860,7 +877,6 @@ static void sort_by_signed_triangle_index(Vector<int> &g, { Array<int> signed_g(g.size()); for (int i : g.index_range()) { - const Face &tri = g[i] == EXTRA_TRI_INDEX ? *extra_tri : *tm.face(g[i]); bool rev; find_flap_vert(tri, e, &rev); @@ -890,7 +906,7 @@ static void sort_by_signed_triangle_index(Vector<int> &g, static Array<int> sort_tris_around_edge(const IMesh &tm, const TriMeshTopology &tmtopo, const Edge e, - const Span<int> &tris, + const Span<int> tris, const int t0, const Face *extra_tri) { @@ -921,7 +937,7 @@ static Array<int> sort_tris_around_edge(const IMesh &tm, Vector<int> g2; Vector<int> g3; Vector<int> g4; - Vector<int> *groups[] = {&g1, &g2, &g3, &g4}; + std::array<Vector<int> *, 4> groups = {&g1, &g2, &g3, &g4}; const Face &triref = *tm.face(tris[0]); for (int i : tris.index_range()) { if (i == 0) { @@ -1012,7 +1028,7 @@ static void find_cells_from_edge(const IMesh &tm, Array<int> sorted_tris = sort_tris_around_edge( tm, tmtopo, e, Span<int>(*edge_tris), (*edge_tris)[0], nullptr); - int n_edge_tris = static_cast<int>(edge_tris->size()); + int n_edge_tris = edge_tris->size(); Array<int> edge_patches(n_edge_tris); for (int i = 0; i < n_edge_tris; ++i) { edge_patches[i] = pinfo.tri_patch(sorted_tris[i]); @@ -1308,6 +1324,7 @@ static int find_cell_for_point_near_edge(mpq3 p, NO_INDEX, {NO_INDEX, NO_INDEX, NO_INDEX}, {false, false, false}); + BLI_assert(etris != nullptr); 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; @@ -1321,9 +1338,8 @@ static int find_cell_for_point_near_edge(mpq3 p, int dummy_index = p_sorted_dummy - sorted_tris.begin(); int prev_tri = (dummy_index == 0) ? sorted_tris[sorted_tris.size() - 1] : sorted_tris[dummy_index - 1]; - int next_tri = (dummy_index == static_cast<int>(sorted_tris.size() - 1)) ? - sorted_tris[0] : - sorted_tris[dummy_index + 1]; + int next_tri = (dummy_index == sorted_tris.size() - 1) ? sorted_tris[0] : + sorted_tris[dummy_index + 1]; if (dbg_level > 0) { std::cout << "prev tri to dummy = " << prev_tri << "; next tri to dummy = " << next_tri << "\n"; @@ -1414,7 +1430,7 @@ static int find_ambient_cell(const IMesh &tm, Edge ehull; mpq_class max_abs_slope = -1; for (Edge e : edges) { - const const Vert *v_other = (e.v0() == v_extreme) ? e.v1() : e.v0(); + 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) { @@ -1467,7 +1483,7 @@ static Edge find_good_sorting_edge(const Vert *testp, */ const mpq3 &co_closest = closestp->co_exact; const mpq3 &co_test = testp->co_exact; - BLI_assert(!(co_test == co_closest)); + BLI_assert(co_test != co_closest); mpq3 abscissa = co_test - co_closest; /* Find a non-zero-component axis of abscissa. */ int axis; @@ -1935,14 +1951,14 @@ static void finish_patch_cell_graph(const IMesh &tm, * triangle is part of. * Also, as soon as the winding numbers for a cell are set, use bool_optype * to decide whether that cell is included or excluded from the boolean output. - * If included, the cell's flag will be set to true. + * If included, the cell's in_output_volume will be set to true. */ -static void propagate_windings_and_flag(PatchesInfo &pinfo, - CellsInfo &cinfo, - int c_ambient, - bool_optype op, - int nshapes, - std::function<int(int)> shape_fn) +static void propagate_windings_and_in_output_volume(PatchesInfo &pinfo, + CellsInfo &cinfo, + int c_ambient, + BoolOpType op, + int nshapes, + std::function<int(int)> shape_fn) { int dbg_level = 0; if (dbg_level > 0) { @@ -1978,7 +1994,7 @@ static void propagate_windings_and_flag(PatchesInfo &pinfo, if (dbg_level > 1) { std::cout << " representative tri " << t << ": in shape " << shape << "\n"; } - cell_neighbor.set_winding_and_flag(cell, shape, winding_delta, op); + cell_neighbor.set_winding_and_in_output_volume(cell, shape, winding_delta, op); if (dbg_level > 1) { std::cout << " now cell_neighbor = " << cell_neighbor << "\n"; } @@ -2003,12 +2019,12 @@ static void propagate_windings_and_flag(PatchesInfo &pinfo, * Difference (first shape minus the rest): first winding number must be nonzero * and the rest must have at least one zero winding number. */ -static bool apply_bool_op(int bool_optype, const Array<int> &winding) +static bool apply_bool_op(BoolOpType bool_optype, const Array<int> &winding) { - int nw = static_cast<int>(winding.size()); + int nw = winding.size(); BLI_assert(nw > 0); switch (bool_optype) { - case BOOLEAN_ISECT: { + case BoolOpType::Intersect: { for (int i = 0; i < nw; ++i) { if (winding[i] == 0) { return false; @@ -2016,7 +2032,7 @@ static bool apply_bool_op(int bool_optype, const Array<int> &winding) } return true; } - case BOOLEAN_UNION: { + case BoolOpType::Union: { for (int i = 0; i < nw; ++i) { if (winding[i] != 0) { return true; @@ -2024,7 +2040,7 @@ static bool apply_bool_op(int bool_optype, const Array<int> &winding) } return false; } - case BOOLEAN_DIFFERENCE: { + case BoolOpType::Difference: { /* if nw > 2, make it shape 0 minus the union of the rest. */ if (winding[0] == 0) { return false; @@ -2044,11 +2060,11 @@ static bool apply_bool_op(int bool_optype, const Array<int> &winding) } } -/* Special processing for extract_from_flag_diffs to handle +/* Special processing for extract_from_in_output_volume_diffs to handle * triangles that are part of stacks of geometrically identical * triangles enclosing zero volume cells. */ -static void extract_zero_volume_cell_tris(Vector<const Face *> &out_tris, +static void extract_zero_volume_cell_tris(Vector<const Face *> &r_tris, const IMesh &tm_subdivided, const PatchesInfo &pinfo, const CellsInfo &cinfo, @@ -2131,8 +2147,8 @@ static void extract_zero_volume_cell_tris(Vector<const Face *> &out_tris, } std::cout << "\n"; } - if (above_stack_cell->flag() ^ below_stack_cell->flag()) { - bool need_flipped_tri = above_stack_cell->flag(); + if (above_stack_cell->in_output_volume() ^ below_stack_cell->in_output_volume()) { + bool need_flipped_tri = above_stack_cell->in_output_volume(); if (dbg_level > 0) { std::cout << "need tri " << (need_flipped_tri ? "flipped" : "") << "\n"; } @@ -2143,7 +2159,7 @@ static void extract_zero_volume_cell_tris(Vector<const Face *> &out_tris, if (dbg_level > 0) { std::cout << "using tri " << t_to_add << "\n"; } - out_tris.append(tm_subdivided.face(t_to_add)); + r_tris.append(tm_subdivided.face(t_to_add)); break; } } @@ -2157,25 +2173,26 @@ static void extract_zero_volume_cell_tris(Vector<const Face *> &out_tris, tri.is_intersect[2], tri.is_intersect[1], tri.is_intersect[0]}; const Face *flipped_f = arena->add_face( flipped_vs, f->orig, flipped_e_origs, flipped_is_intersect); - out_tris.append(flipped_f); + r_tris.append(flipped_f); } } } } /* Extract the output mesh from tm_subdivided and return it as a new mesh. - * The cells in cinfo must have cells-to-be-retained flagged. - * We keep only triangles between flagged and unflagged cells. - * We flip the normals of any triangle that has a flagged cell above - * and an unflagged cell below. + * The cells in cinfo must have cells-to-be-retained with in_output_volume set. + * We keep only triangles between those in the output volume and those not in. + * We flip the normals of any triangle that has an in_output_volume cell above + * and a not-in_output_volume cell below. * For all stacks of exact duplicate coplanar triangles, we want to * 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. + * whether the in_output_volume in_output_volumes on either side of the stack are + * different or the same. */ -static IMesh extract_from_flag_diffs(const IMesh &tm_subdivided, - const PatchesInfo &pinfo, - const CellsInfo &cinfo, - IMeshArena *arena) +static IMesh extract_from_in_output_volume_diffs(const IMesh &tm_subdivided, + const PatchesInfo &pinfo, + const CellsInfo &cinfo, + IMeshArena *arena) { constexpr int dbg_level = 0; if (dbg_level > 0) { @@ -2192,22 +2209,24 @@ static IMesh extract_from_flag_diffs(const IMesh &tm_subdivided, if (dbg_level > 0) { std::cout << "tri " << t << ": cell_above=" << patch.cell_above << " cell_below=" << patch.cell_below << "\n"; - std::cout << " flag_above=" << cell_above.flag() << " flag_below=" << cell_below.flag() - << "\n"; + std::cout << " in_output_volume_above=" << cell_above.in_output_volume() + << " in_output_volume_below=" << cell_below.in_output_volume() << "\n"; } bool adjacent_zero_volume_cell = cell_above.zero_volume() || cell_below.zero_volume(); any_zero_volume_cell |= adjacent_zero_volume_cell; - if (cell_above.flag() ^ cell_below.flag() && !adjacent_zero_volume_cell) { - bool flip = cell_above.flag(); + if (cell_above.in_output_volume() ^ cell_below.in_output_volume() && + !adjacent_zero_volume_cell) { + bool flip = cell_above.in_output_volume(); if (dbg_level > 0) { std::cout << "need tri " << t << " flip=" << flip << "\n"; } const Face *f = tm_subdivided.face(t); if (flip) { const Face &tri = *f; - 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 = { + std::array<const Vert *, 3> flipped_vs = {tri[0], tri[2], tri[1]}; + std::array<int, 3> flipped_e_origs = { + tri.edge_orig[2], tri.edge_orig[1], tri.edge_orig[0]}; + std::array<bool, 3> flipped_is_intersect = { tri.is_intersect[2], tri.is_intersect[1], tri.is_intersect[0]}; const Face *flipped_f = arena->add_face( flipped_vs, f->orig, flipped_e_origs, flipped_is_intersect); @@ -2224,16 +2243,16 @@ static IMesh extract_from_flag_diffs(const IMesh &tm_subdivided, return IMesh(out_tris); } -static const char *bool_optype_name(bool_optype op) +static const char *bool_optype_name(BoolOpType op) { switch (op) { - case BOOLEAN_NONE: + case BoolOpType::None: return "none"; - case BOOLEAN_ISECT: + case BoolOpType::Intersect: return "intersect"; - case BOOLEAN_UNION: + case BoolOpType::Union: return "union"; - case BOOLEAN_DIFFERENCE: + case BoolOpType::Difference: return "difference"; default: return "<unknown>"; @@ -2335,7 +2354,7 @@ static bool point_is_inside_shape(const IMesh &tm, * and return the mesh that is the boolean result. */ static IMesh gwn_boolean(const IMesh &tm, - bool_optype op, + BoolOpType op, int nshapes, std::function<int(int)> shape_fn, const PatchesInfo &pinfo, @@ -2379,15 +2398,15 @@ static IMesh gwn_boolean(const IMesh &tm, bool do_remove; bool do_flip; switch (op) { - case BOOLEAN_ISECT: + case BoolOpType::Intersect: do_remove = !inside; do_flip = false; break; - case BOOLEAN_UNION: + case BoolOpType::Union: do_remove = inside; do_flip = false; break; - case BOOLEAN_DIFFERENCE: + case BoolOpType::Difference: do_remove = (shape == 0) ? inside : !inside; do_flip = (shape == 1); break; @@ -2453,7 +2472,7 @@ static Array<const Face *> triangulate_poly(const Face *f, IMeshArena *arena) cdt_in.face = Array<Vector<int>>(1); cdt_in.face[0].reserve(flen); for (int i : f->index_range()) { - cdt_in.face[0].append(static_cast<int>(i)); + cdt_in.face[0].append(i); } /* Project poly along dominant axis of normal to get 2d coords. */ const mpq3 &poly_normal = f->plane.norm_exact; @@ -2463,12 +2482,11 @@ static Array<const Face *> triangulate_poly(const Face *f, IMeshArena *arena) * Yet another reversal happens if the poly normal in the dominant * direction is opposite that of the positive dominant axis. */ - int iflen = static_cast<int>(flen); bool rev1 = (axis == 1); bool rev2 = poly_normal[axis] < 0; bool rev = rev1 ^ rev2; - for (int i = 0; i < iflen; ++i) { - int ii = rev ? iflen - i - 1 : i; + for (int i = 0; i < flen; ++i) { + int ii = rev ? flen - i - 1 : i; mpq2 &p2d = cdt_in.vert[ii]; int k = 0; for (int j = 0; j < 3; ++j) { @@ -2512,16 +2530,16 @@ static Array<const Face *> triangulate_poly(const Face *f, IMeshArena *arena) } /* Return an IMesh that is a triangulation of a mesh with general - * polygonal faces, pm. + * polygonal faces, imesh. * Added diagonals will be distinguishable by having edge original * indices of NO_INDEX. */ -static IMesh triangulate_polymesh(IMesh &pm, IMeshArena *arena) +static IMesh triangulate_polymesh(IMesh &imesh, IMeshArena *arena) { Vector<const Face *> face_tris; constexpr int estimated_tris_per_face = 3; - face_tris.reserve(estimated_tris_per_face * pm.face_size()); - for (const Face *f : pm.faces()) { + face_tris.reserve(estimated_tris_per_face * imesh.face_size()); + for (const Face *f : imesh.faces()) { /* Tesselate face f, following plan similar to BM_face_calc_tesselation. */ int flen = f->size(); if (flen == 3) { @@ -2655,7 +2673,7 @@ static void init_face_merge_state(FaceMergeState *fms, constexpr int dbg_level = 0; /* Reserve enough faces and edges so that neither will have to resize. */ fms->face.reserve(tris.size() + 1); - fms->edge.reserve((3 * tris.size())); + fms->edge.reserve(3 * tris.size()); fms->edge_map.reserve(3 * tris.size()); if (dbg_level > 0) { std::cout << "\nINIT_FACE_MERGE_STATE\n"; @@ -2676,7 +2694,7 @@ static void init_face_merge_state(FaceMergeState *fms, mf.vert.append(tri[1]); mf.vert.append(tri[2]); mf.orig = tri.orig; - int f = static_cast<int>(fms->face.append_and_get_index(mf)); + int f = fms->face.append_and_get_index(mf); if (dbg_level > 1) { std::cout << "appended MergeFace for tri at f = " << f << "\n"; } @@ -2696,7 +2714,7 @@ static void init_face_merge_state(FaceMergeState *fms, new_me.is_intersect = tri.is_intersect[i]; new_me.dissolvable = (new_me.orig == NO_INDEX && !new_me.is_intersect); fms->edge.append(new_me); - me_index = static_cast<int>(fms->edge.size()) - 1; + me_index = fms->edge.size() - 1; fms->edge_map.add_new(canon_vs, me_index); if (dbg_level > 1) { std::cout << "added new me with me_index = " << me_index << "\n"; @@ -2764,8 +2782,8 @@ static bool dissolve_leaves_valid_bmesh(FaceMergeState *fms, { int a_edge_start = mf_left.edge.first_index_of_try(me_index); BLI_assert(a_edge_start != -1); - int alen = static_cast<int>(mf_left.vert.size()); - int blen = static_cast<int>(mf_right.vert.size()); + int alen = mf_left.vert.size(); + int blen = mf_right.vert.size(); int b_left_face = me.right_face; bool ok = true; /* Is there another edge, not me, in A's face, whose right face is B's left? */ @@ -2805,8 +2823,8 @@ static void splice_faces( int a_edge_start = mf_left.edge.first_index_of_try(me_index); int b_edge_start = mf_right.edge.first_index_of_try(me_index); 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()); + int alen = mf_left.vert.size(); + int blen = mf_right.vert.size(); Vector<const Vert *> splice_vert; Vector<int> splice_edge; splice_vert.reserve(alen + blen - 2); @@ -2898,7 +2916,7 @@ static void do_dissolve(FaceMergeState *fms) } } -/* Given that tris form a triangulation of a face or part of a face that was in pm_in, +/* Given that tris form a triangulation of a face or part of a face that was in imesh_in, * merge as many of the triangles together as possible, by dissolving the edges between them. * We can only dissolve triangulation edges that don't overlap real input edges, and we * can only dissolve them if doing so leaves the remaining faces able to create valid BMesh. @@ -2909,7 +2927,7 @@ static void do_dissolve(FaceMergeState *fms) */ static Vector<const Face *> merge_tris_for_face(Vector<int> tris, const IMesh &tm, - const IMesh &pm_in, + const IMesh &imesh_in, IMeshArena *arena) { constexpr int dbg_level = 0; @@ -2933,7 +2951,7 @@ static Vector<const Face *> merge_tris_for_face(Vector<int> tris, */ const Face &tri1 = *tm.face(tris[0]); const Face &tri2 = *tm.face(tris[1]); - const Face *in_face = pm_in.face(tri1.orig); + const Face *in_face = imesh_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) { @@ -2989,31 +3007,31 @@ static Vector<const Face *> merge_tris_for_face(Vector<int> tris, return ans; } -/* Return an array, paralleling pm_out.vert, saying which vertices can be dissolved. +/* Return an array, paralleling imesh_out.vert, saying which vertices can be dissolved. * A vertex v can be dissolved if (a) it is not an input vertex; (b) it has valence 2; * 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(IMesh &pm_out, int *r_count_dissolve) +static Array<bool> find_dissolve_verts(IMesh &imesh_out, int *r_count_dissolve) { - pm_out.populate_vert(); - /* dissolve[i] will say whether pm_out.vert(i) can be dissolved. */ - Array<bool> dissolve(pm_out.vert_size()); - for (int v_index : pm_out.vert_index_range()) { - const Vert &vert = *pm_out.vert(v_index); + imesh_out.populate_vert(); + /* dissolve[i] will say whether imesh_out.vert(i) can be dissolved. */ + Array<bool> dissolve(imesh_out.vert_size()); + for (int v_index : imesh_out.vert_index_range()) { + const Vert &vert = *imesh_out.vert(v_index); dissolve[v_index] = (vert.orig == NO_INDEX); } /* neighbors[i] will be a pair giving the up-to-two neighboring vertices - * of the vertex v in position i of pm_out.vert. + * of the vertex v in position i of imesh_out.vert. * If we encounter a third, then v will not be dissolvable. */ 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); + imesh_out.vert_size(), std::pair<const Vert *, const Vert *>(nullptr, nullptr)); + for (int f : imesh_out.face_index_range()) { + const Face &face = *imesh_out.face(f); for (int i : face.index_range()) { const Vert *v = face[i]; - int v_index = pm_out.lookup_vert(v); + int v_index = imesh_out.lookup_vert(v); BLI_assert(v_index != NO_INDEX); if (dissolve[v_index]) { const Vert *n1 = face[face.next_pos(i)]; @@ -3035,7 +3053,7 @@ static Array<bool> find_dissolve_verts(IMesh &pm_out, int *r_count_dissolve) } } int count = 0; - for (int v_out : pm_out.vert_index_range()) { + for (int v_out : imesh_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<const Vert *, const Vert *> &nbrs = neighbors[v_out]; @@ -3043,7 +3061,7 @@ static Array<bool> find_dissolve_verts(IMesh &pm_out, int *r_count_dissolve) BLI_assert(nbrs.second != nullptr); const mpq3 &co1 = nbrs.first->co_exact; const mpq3 &co2 = nbrs.second->co_exact; - const mpq3 &co = pm_out.vert(v_out)->co_exact; + const mpq3 &co = imesh_out.vert(v_out)->co_exact; mpq3 dir1 = co - co1; mpq3 dir2 = co2 - co; mpq3 cross = mpq3::cross(dir1, dir2); @@ -3060,20 +3078,20 @@ static Array<bool> find_dissolve_verts(IMesh &pm_out, int *r_count_dissolve) return dissolve; } -/* The dissolve array parallels the pm.vert array. Wherever it is true, +/* The dissolve array parallels the imesh.vert array. Wherever it is true, * 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. + * imesh.faces to account for the close-up of the gaps in imesh.vert. */ -static void dissolve_verts(IMesh *pm, const Array<bool> dissolve, IMeshArena *arena) +static void dissolve_verts(IMesh *imesh, const Array<bool> dissolve, IMeshArena *arena) { constexpr int inline_face_size = 100; Vector<bool, inline_face_size> face_pos_erase; - for (int f : pm->face_index_range()) { - const Face &face = *pm->face(f); + for (int f : imesh->face_index_range()) { + const Face &face = *imesh->face(f); face_pos_erase.clear(); int num_erase = 0; for (const Vert *v : face) { - int v_index = pm->lookup_vert(v); + int v_index = imesh->lookup_vert(v); BLI_assert(v_index != NO_INDEX); if (dissolve[v_index]) { face_pos_erase.append(true); @@ -3084,10 +3102,10 @@ static void dissolve_verts(IMesh *pm, const Array<bool> dissolve, IMeshArena *ar } } if (num_erase > 0) { - pm->erase_face_positions(f, face_pos_erase, arena); + imesh->erase_face_positions(f, face_pos_erase, arena); } } - pm->set_dirty_verts(); + imesh->set_dirty_verts(); } /* The main boolean function operates on a triangle IMesh and produces a @@ -3101,7 +3119,7 @@ static void dissolve_verts(IMesh *pm, const Array<bool> dissolve, IMeshArena *ar * or have several disconnected boundaries (e.g., faces with holes). */ static IMesh polymesh_from_trimesh_with_dissolve(const IMesh &tm_out, - const IMesh &pm_in, + const IMesh &imesh_in, IMeshArena *arena) { const int dbg_level = 0; @@ -3112,7 +3130,7 @@ static IMesh polymesh_from_trimesh_with_dissolve(const IMesh &tm_out, * face_output_tris[f] will be indices of triangles in tm_out * that have f as their original face. */ - int tot_in_face = pm_in.face_size(); + int tot_in_face = imesh_in.face_size(); Array<Vector<int>> face_output_tris(tot_in_face); for (int t : tm_out.face_index_range()) { const Face &tri = *tm_out.face(t); @@ -3132,7 +3150,7 @@ static IMesh polymesh_from_trimesh_with_dissolve(const IMesh &tm_out, */ Array<Vector<const Face *>> face_output_face(tot_in_face); int tot_out_face = 0; - for (int in_f : pm_in.face_index_range()) { + for (int in_f : imesh_in.face_index_range()) { if (dbg_level > 1) { std::cout << "merge tris for face " << in_f << "\n"; } @@ -3140,33 +3158,33 @@ static IMesh polymesh_from_trimesh_with_dissolve(const IMesh &tm_out, if (num_out_tris_for_face == 0) { continue; } - face_output_face[in_f] = merge_tris_for_face(face_output_tris[in_f], tm_out, pm_in, arena); + face_output_face[in_f] = merge_tris_for_face(face_output_tris[in_f], tm_out, imesh_in, arena); tot_out_face += face_output_face[in_f].size(); } Array<const Face *> face(tot_out_face); int out_f_index = 0; - for (int in_f : pm_in.face_index_range()) { + for (int in_f : imesh_in.face_index_range()) { 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(); } } - IMesh pm_out(face); + IMesh imesh_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. */ int count_dissolve; - Array<bool> v_dissolve = find_dissolve_verts(pm_out, &count_dissolve); + Array<bool> v_dissolve = find_dissolve_verts(imesh_out, &count_dissolve); if (count_dissolve > 0) { - dissolve_verts(&pm_out, v_dissolve, arena); + dissolve_verts(&imesh_out, v_dissolve, arena); } if (dbg_level > 1) { - write_obj_mesh(pm_out, "boolean_post_dissolve"); + write_obj_mesh(imesh_out, "boolean_post_dissolve"); } - return pm_out; + return imesh_out; } /* @@ -3176,7 +3194,7 @@ static IMesh polymesh_from_trimesh_with_dissolve(const IMesh &tm_out, * a number in the range 0 to nshapes-1, to say which shape that triangle is in. */ IMesh boolean_trimesh(IMesh &tm_in, - bool_optype op, + BoolOpType op, int nshapes, std::function<int(int)> shape_fn, bool use_self, @@ -3207,7 +3225,7 @@ IMesh boolean_trimesh(IMesh &tm_in, std::cout << "\nboolean_tm_input after intersection:\n" << tm_si; } /* It is possible for tm_si to be empty if all the input triangles are bogus/degenerate. */ - if (tm_si.face_size() == 0 || op == BOOLEAN_NONE) { + if (tm_si.face_size() == 0 || op == BoolOpType::None) { return tm_si; } auto si_shape_fn = [shape_fn, tm_si](int t) { return shape_fn(tm_si.face(t)->orig); }; @@ -3239,8 +3257,8 @@ IMesh boolean_trimesh(IMesh &tm_in, std::cout << "Could not find an ambient cell; input not valid?\n"; 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); + propagate_windings_and_in_output_volume(pinfo, cinfo, c_ambient, op, nshapes, si_shape_fn); + tm_out = extract_from_in_output_volume_diffs(tm_si, pinfo, cinfo, arena); if (dbg_level > 0) { /* Check if output is PWN. */ TriMeshTopology tm_out_topo(tm_out); @@ -3256,30 +3274,30 @@ IMesh boolean_trimesh(IMesh &tm_in, return tm_out; } -static void dump_test_spec(IMesh &pm) +static void dump_test_spec(IMesh &imesh) { - std::cout << "test spec = " << pm.vert_size() << " " << pm.face_size() << "\n"; - for (const Vert *v : pm.vertices()) { + std::cout << "test spec = " << imesh.vert_size() << " " << imesh.face_size() << "\n"; + for (const Vert *v : imesh.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 (const Face *f : pm.faces()) { + for (const Face *f : imesh.faces()) { for (const Vert *fv : *f) { - std::cout << pm.lookup_vert(fv) << " "; + std::cout << imesh.lookup_vert(fv) << " "; } std::cout << "\n"; } } -/* Do the boolean operation op on the polygon mesh pm_in. +/* Do the boolean operation op on the polygon mesh imesh_in. * See the header file for a complete description. */ -IMesh boolean_mesh(IMesh &pm, - bool_optype op, +IMesh boolean_mesh(IMesh &imesh, + BoolOpType op, int nshapes, std::function<int(int)> shape_fn, bool use_self, - IMesh *pm_triangulated, + IMesh *imesh_triangulated, IMeshArena *arena) { constexpr int dbg_level = 0; @@ -3288,17 +3306,17 @@ IMesh boolean_mesh(IMesh &pm, << nshapes << " operand" << (nshapes == 1 ? "" : "s") << " op=" << bool_optype_name(op) << "\n"; if (dbg_level > 1) { - write_obj_mesh(pm, "boolean_mesh_in"); - std::cout << pm; + write_obj_mesh(imesh, "boolean_mesh_in"); + std::cout << imesh; if (dbg_level > 2) { - dump_test_spec(pm); + dump_test_spec(imesh); } } } - IMesh *tm_in = pm_triangulated; + IMesh *tm_in = imesh_triangulated; IMesh our_triangulation; if (tm_in == nullptr) { - our_triangulation = triangulate_polymesh(pm, arena); + our_triangulation = triangulate_polymesh(imesh, arena); tm_in = &our_triangulation; } IMesh tm_out = boolean_trimesh(*tm_in, op, nshapes, shape_fn, use_self, arena); @@ -3306,7 +3324,7 @@ IMesh boolean_mesh(IMesh &pm, std::cout << "bool_trimesh_output:\n" << tm_out; write_obj_mesh(tm_out, "bool_trimesh_output"); } - IMesh ans = polymesh_from_trimesh_with_dissolve(tm_out, pm, arena); + IMesh ans = polymesh_from_trimesh_with_dissolve(tm_out, imesh, 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 38b17b7100e..32b423c9f2c 100644 --- a/source/blender/blenlib/intern/mesh_intersect.cc +++ b/source/blender/blenlib/intern/mesh_intersect.cc @@ -61,36 +61,6 @@ Vert::Vert(const mpq3 &mco, const double3 &dco, int id, int orig) { } -Vert::Vert(const Vert &other) - : co_exact(other.co_exact), co(other.co), id(other.id), orig(other.orig) -{ -} - -Vert::Vert(Vert &&other) noexcept - : co_exact(std::move(other.co_exact)), co(std::move(other.co)), id(other.id), orig(other.orig) -{ -} - -Vert &Vert::operator=(const Vert &other) -{ - if (this != &other) { - this->co_exact = other.co_exact; - this->co = other.co; - this->id = other.id; - this->orig = other.orig; - } - return *this; -} - -Vert &Vert::operator=(Vert &&other) noexcept -{ - this->co_exact = std::move(other.co_exact); - this->co = std::move(other.co); - this->id = other.id; - this->orig = other.orig; - return *this; -} - bool Vert::operator==(const Vert &other) const { return this->co_exact == other.co_exact; @@ -217,50 +187,6 @@ Face::Face(Span<const Vert *> verts, int id, int orig) : vert(verts), id(id), or plane = Plane(normal, d); } -Face::Face(const Face &other) - : vert(other.vert), - edge_orig(other.edge_orig), - is_intersect(other.is_intersect), - plane(other.plane), - id(other.id), - orig(other.orig) -{ -} - -Face::Face(Face &&other) noexcept - : vert(std::move(other.vert)), - edge_orig(std::move(other.edge_orig)), - is_intersect(std::move(other.is_intersect)), - plane(std::move(other.plane)), - id(other.id), - orig(other.orig) -{ -} - -Face &Face::operator=(const Face &other) -{ - if (this != &other) { - this->vert = other.vert; - this->edge_orig = other.edge_orig; - this->is_intersect = other.is_intersect; - this->plane = other.plane; - this->id = other.id; - this->orig = other.orig; - } - return *this; -} - -Face &Face::operator=(Face &&other) noexcept -{ - this->vert = std::move(other.vert); - this->edge_orig = std::move(other.edge_orig); - this->is_intersect = std::move(other.is_intersect); - this->plane = std::move(other.plane); - this->id = other.id; - this->orig = other.orig; - return *this; -} - bool Face::operator==(const Face &other) const { if (this->size() != other.size()) { @@ -338,7 +264,13 @@ std::ostream &operator<<(std::ostream &os, const Face *f) * exist. I.e., it dedups the vertices. */ +/* Uncomment the following to try using a spinlock instead of + * a mutex in the arena allocation routines. + * Initial tests showed that it doesn't seem to help very much, + * if at all, to use a spinlock. + */ // #define USE_SPINLOCK + class IMeshArena::IMeshArenaImpl { /* Don't use Vert itself as key since resizing may move @@ -696,7 +628,7 @@ void IMesh::populate_vert(int max_verts) void IMesh::erase_face_positions(int f_index, Span<bool> face_pos_erase, IMeshArena *arena) { const Face *cur_f = this->face(f_index); - int cur_len = static_cast<int>(cur_f->size()); + int cur_len = cur_f->size(); int num_to_erase = 0; for (int i : cur_f->index_range()) { if (face_pos_erase[i]) { @@ -2280,7 +2212,7 @@ static IMesh extract_subdivided_tri(const CDT_data &cd, { const CDT_result<mpq_class> &cdt_out = cd.cdt_out; int t_in_cdt = -1; - for (int i = 0; i < static_cast<int>(cd.input_face.size()); ++i) { + for (int i = 0; i < cd.input_face.size(); ++i) { if (cd.input_face[i] == t) { t_in_cdt = i; } @@ -2374,13 +2306,13 @@ class TriOverlaps { std::cout << "TriOverlaps construction\n"; } /* Tree type is 8 => octtree; axis = 6 => using XYZ axes only. */ - tree_ = BLI_bvhtree_new(static_cast<int>(tm.face_size()), FLT_EPSILON, 8, 6); + tree_ = BLI_bvhtree_new(tm.face_size(), FLT_EPSILON, 8, 6); /* In the common case of a binary boolean and no self intersection in * each shape, we will use two trees and simple bounding box overlap. */ bool two_trees_no_self = nshapes == 2 && !use_self; if (two_trees_no_self) { - tree_b_ = BLI_bvhtree_new(static_cast<int>(tm.face_size()), FLT_EPSILON, 8, 6); + tree_b_ = BLI_bvhtree_new(tm.face_size(), FLT_EPSILON, 8, 6); } float bbpts[6]; for (int t : tm.face_index_range()) { @@ -2390,15 +2322,15 @@ class TriOverlaps { int shape = shape_fn(tm.face(t)->orig); if (two_trees_no_self) { if (shape == 0) { - BLI_bvhtree_insert(tree_, static_cast<int>(t), bbpts, 2); + BLI_bvhtree_insert(tree_, t, bbpts, 2); } else if (shape == 1) { - BLI_bvhtree_insert(tree_b_, static_cast<int>(t), bbpts, 2); + BLI_bvhtree_insert(tree_b_, t, bbpts, 2); } } else { if (shape != -1) { - BLI_bvhtree_insert(tree_, static_cast<int>(t), bbpts, 2); + BLI_bvhtree_insert(tree_, t, bbpts, 2); } } } @@ -2494,6 +2426,17 @@ struct OverlapIttsData { } }; +/* Return a std::pair containing a and b in canonical order: + * With a <= b. + */ +static std::pair<int, int> canon_int_pair(int a, int b) +{ + if (a > b) { + std::swap(a, b); + } + return std::pair<int, int>(a, b); +} + static void calc_overlap_itts_range_func(void *__restrict userdata, const int iter, const TaskParallelTLS *__restrict UNUSED(tls)) @@ -2530,15 +2473,10 @@ static void calc_overlap_itts(Map<std::pair<int, int>, ITT_value> &itt_map, * This means we won't have to protect the itt_map.add_overwrite function with a lock. */ for (const BVHTreeOverlap &olap : ov.overlap()) { - int a = olap.indexA; - int b = olap.indexB; - if (a >= b) { - std::swap(a, b); - } - std::pair<int, int> key(a, b); + std::pair<int, int> key = canon_int_pair(olap.indexA, olap.indexB); if (!itt_map.contains(key)) { - int ca = clinfo.tri_cluster(a); - int cb = clinfo.tri_cluster(b); + int ca = clinfo.tri_cluster(key.first); + int cb = clinfo.tri_cluster(key.second); if (ca == NO_INDEX || ca != cb) { itt_map.add_new(key, ITT_value()); data.intersect_pairs.append(key); @@ -2606,12 +2544,7 @@ static void calc_subdivided_tri_range_func(void *__restrict userdata, Vector<ITT_value, inline_capacity> itts(otr.len); for (int j = otr.overlap_start; j < otr.overlap_start + otr.len; ++j) { int t_other = data->overlap[j].indexB; - int a = t; - int b = t_other; - if (a >= b) { - std::swap(a, b); - } - std::pair<int, int> key(a, b); + std::pair<int, int> key = canon_int_pair(t, t_other); ITT_value itt; if (data->itt_map.contains(key)) { itt = data->itt_map.lookup(key); @@ -2740,12 +2673,7 @@ static CDT_data calc_cluster_subdivided(const CoplanarClusterInfo &clinfo, if (dbg_level > 0) { std::cout << "use intersect(" << t << "," << t_other << "\n"; } - int a = t; - int b = t_other; - if (a >= b) { - std::swap(a, b); - } - std::pair<int, int> key(a, b); + std::pair<int, int> key = canon_int_pair(t, t_other); if (itt_map.contains(key)) { ITT_value itt = itt_map.lookup(key); if (itt.kind != INONE && itt.kind != ICOPLANAR) { @@ -2926,7 +2854,7 @@ static IMesh remove_degenerate_tris(const IMesh &tm_in) IMesh trimesh_self_intersect(const IMesh &tm_in, IMeshArena *arena) { return trimesh_nary_intersect( - tm_in, 1, [](int) { return 0; }, true, arena); + tm_in, 1, [](int UNUSED(t)) { return 0; }, true, arena); } IMesh trimesh_nary_intersect(const IMesh &tm_in, @@ -2973,9 +2901,9 @@ IMesh trimesh_nary_intersect(const IMesh &tm_in, } # ifdef PERFDEBUG perfdata_init(); - doperfmax(0, static_cast<int>(tm_in.face_size())); - doperfmax(1, static_cast<int>(clinfo.tot_cluster())); - doperfmax(2, static_cast<int>(tri_ov.overlap().size())); + doperfmax(0, tm_in.face_size()); + doperfmax(1, clinfo.tot_cluster()); + doperfmax(2, tri_ov.overlap().size()); # endif /* itt_map((a,b)) will hold the intersection value resulting from intersecting * triangles with indices a and b, where a < b. diff --git a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc index 397a86d98c3..79534c13124 100644 --- a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc +++ b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc @@ -15,7 +15,7 @@ #include "BLI_mpq3.hh" #include "BLI_vector.hh" -namespace blender::meshintersect { +namespace blender::meshintersect::tests { constexpr bool DO_OBJ = false; @@ -103,12 +103,16 @@ class IMeshBuilder { } }; +static int all_shape_zero(int UNUSED(t)) +{ + return 0; +} + TEST(boolean_trimesh, Empty) { IMeshArena arena; IMesh in; - IMesh out = boolean_trimesh( - in, BOOLEAN_NONE, 1, [](int) { return 0; }, true, &arena); + IMesh out = boolean_trimesh(in, BoolOpType::None, 1, all_shape_zero, true, &arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 0); EXPECT_EQ(out.face_size(), 0); @@ -136,8 +140,7 @@ TEST(boolean_trimesh, TetTetTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh( - mb.imesh, BOOLEAN_NONE, 1, [](int) { return 0; }, true, &mb.arena); + IMesh out = boolean_trimesh(mb.imesh, BoolOpType::None, 1, all_shape_zero, true, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 11); EXPECT_EQ(out.face_size(), 20); @@ -146,8 +149,7 @@ TEST(boolean_trimesh, TetTetTrimesh) } IMeshBuilder mb2(spec); - IMesh out2 = boolean_trimesh( - mb2.imesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb2.arena); + IMesh out2 = boolean_trimesh(mb2.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb2.arena); out2.populate_vert(); EXPECT_EQ(out2.vert_size(), 10); EXPECT_EQ(out2.face_size(), 16); @@ -157,7 +159,7 @@ TEST(boolean_trimesh, TetTetTrimesh) IMeshBuilder mb3(spec); IMesh out3 = boolean_trimesh( - mb3.imesh, BOOLEAN_UNION, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb3.arena); + mb3.imesh, BoolOpType::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); @@ -167,7 +169,7 @@ TEST(boolean_trimesh, TetTetTrimesh) IMeshBuilder mb4(spec); IMesh out4 = boolean_trimesh( - mb4.imesh, BOOLEAN_UNION, 2, [](int t) { return t < 4 ? 0 : 1; }, true, &mb4.arena); + mb4.imesh, BoolOpType::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); @@ -177,7 +179,7 @@ TEST(boolean_trimesh, TetTetTrimesh) IMeshBuilder mb5(spec); IMesh out5 = boolean_trimesh( - mb5.imesh, BOOLEAN_ISECT, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb5.arena); + mb5.imesh, BoolOpType::Intersect, 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); @@ -187,7 +189,12 @@ TEST(boolean_trimesh, TetTetTrimesh) IMeshBuilder mb6(spec); IMesh out6 = boolean_trimesh( - mb6.imesh, BOOLEAN_DIFFERENCE, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb6.arena); + mb6.imesh, + BoolOpType::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); @@ -197,7 +204,12 @@ TEST(boolean_trimesh, TetTetTrimesh) IMeshBuilder mb7(spec); IMesh out7 = boolean_trimesh( - mb7.imesh, BOOLEAN_DIFFERENCE, 2, [](int t) { return t < 4 ? 1 : 0; }, false, &mb7.arena); + mb7.imesh, + BoolOpType::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); @@ -228,8 +240,7 @@ TEST(boolean_trimesh, TetTet2Trimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh( - mb.imesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); + IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 10); EXPECT_EQ(out.face_size(), 16); @@ -272,8 +283,7 @@ TEST(boolean_trimesh, CubeTetTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh( - mb.imesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); + IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 14); EXPECT_EQ(out.face_size(), 24); @@ -305,7 +315,7 @@ TEST(boolean_trimesh, BinaryTetTetTrimesh) IMeshBuilder mb(spec); IMesh out = boolean_trimesh( - mb.imesh, BOOLEAN_ISECT, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb.arena); + mb.imesh, BoolOpType::Intersect, 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); @@ -336,8 +346,7 @@ TEST(boolean_trimesh, TetTetCoplanarTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh( - mb.imesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); + IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 5); EXPECT_EQ(out.face_size(), 6); @@ -368,8 +377,7 @@ TEST(boolean_trimesh, TetInsideTetTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh( - mb.imesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); + IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 4); EXPECT_EQ(out.face_size(), 4); @@ -400,8 +408,7 @@ TEST(boolean_trimesh, TetBesideTetTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh( - mb.imesh, BOOLEAN_UNION, 1, [](int) { return 0; }, true, &mb.arena); + IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 8); EXPECT_EQ(out.face_size(), 8); @@ -437,7 +444,7 @@ TEST(boolean_trimesh, DegenerateTris) IMeshBuilder mb(spec); IMesh out = boolean_trimesh( - mb.imesh, BOOLEAN_ISECT, 2, [](int t) { return t < 5 ? 0 : 1; }, false, &mb.arena); + mb.imesh, BoolOpType::Intersect, 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); @@ -469,7 +476,7 @@ TEST(boolean_polymesh, TetTet) IMeshBuilder mb(spec); IMesh out = boolean_mesh( - mb.imesh, BOOLEAN_NONE, 1, [](int) { return 0; }, true, nullptr, &mb.arena); + mb.imesh, BoolOpType::None, 1, all_shape_zero, true, nullptr, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 11); EXPECT_EQ(out.face_size(), 13); @@ -479,7 +486,13 @@ TEST(boolean_polymesh, TetTet) IMeshBuilder mb2(spec); IMesh out2 = boolean_mesh( - mb2.imesh, BOOLEAN_NONE, 2, [](int t) { return t < 4 ? 0 : 1; }, false, nullptr, &mb2.arena); + mb2.imesh, + BoolOpType::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); @@ -526,7 +539,7 @@ TEST(boolean_polymesh, CubeCube) write_obj_mesh(mb.imesh, "cube_cube_in"); } IMesh out = boolean_mesh( - mb.imesh, BOOLEAN_UNION, 1, [](int UNUSED(t)) { return 0; }, true, nullptr, &mb.arena); + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, nullptr, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 20); EXPECT_EQ(out.face_size(), 12); @@ -536,7 +549,13 @@ TEST(boolean_polymesh, CubeCube) IMeshBuilder mb2(spec); IMesh out2 = boolean_mesh( - mb2.imesh, BOOLEAN_NONE, 2, [](int t) { return t < 6 ? 0 : 1; }, false, nullptr, &mb2.arena); + mb2.imesh, + BoolOpType::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); @@ -577,7 +596,7 @@ TEST(boolean_polymesh, CubeCone) IMeshBuilder mb(spec); IMesh out = boolean_mesh( - mb.imesh, BOOLEAN_UNION, 1, [](int UNUSED(t)) { return 0; }, true, nullptr, &mb.arena); + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, nullptr, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 14); EXPECT_EQ(out.face_size(), 12); @@ -621,7 +640,13 @@ TEST(boolean_polymesh, CubeCubeCoplanar) IMeshBuilder mb(spec); IMesh out = boolean_mesh( - mb.imesh, BOOLEAN_UNION, 2, [](int t) { return t < 6 ? 0 : 1; }, false, nullptr, &mb.arena); + mb.imesh, + BoolOpType::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); @@ -654,7 +679,7 @@ TEST(boolean_polymesh, TetTeTCoplanarDiff) IMeshBuilder mb(spec); IMesh out = boolean_mesh( mb.imesh, - BOOLEAN_DIFFERENCE, + BoolOpType::Difference, 2, [](int t) { return t < 4 ? 0 : 1; }, false, @@ -704,7 +729,7 @@ TEST(boolean_polymesh, CubeCubeStep) IMeshBuilder mb(spec); IMesh out = boolean_mesh( mb.imesh, - BOOLEAN_DIFFERENCE, + BoolOpType::Difference, 2, [](int t) { return t < 6 ? 0 : 1; }, false, @@ -754,7 +779,7 @@ TEST(boolean_polymesh, CubeCyl4) IMeshBuilder mb(spec); IMesh out = boolean_mesh( mb.imesh, - BOOLEAN_DIFFERENCE, + BoolOpType::Difference, 2, [](int t) { return t < 6 ? 1 : 0; }, false, @@ -825,7 +850,7 @@ TEST(boolean_polymesh, CubeCubesubdivDiff) IMeshBuilder mb(spec); IMesh out = boolean_mesh( mb.imesh, - BOOLEAN_DIFFERENCE, + BoolOpType::Difference, 2, [](int t) { return t < 16 ? 1 : 0; }, false, @@ -866,7 +891,7 @@ TEST(boolean_polymesh, CubePlane) IMeshBuilder mb(spec); IMesh out = boolean_mesh( mb.imesh, - BOOLEAN_DIFFERENCE, + BoolOpType::Difference, 2, [](int t) { return t >= 1 ? 0 : 1; }, false, @@ -880,4 +905,4 @@ TEST(boolean_polymesh, CubePlane) } } -} // namespace blender::meshintersect +} // namespace blender::meshintersect::tests diff --git a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc index bb5e213364f..d4eebe84067 100644 --- a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc +++ b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc @@ -18,7 +18,7 @@ #define DO_REGULAR_TESTS 1 #define DO_PERF_TESTS 1 -namespace blender::meshintersect { +namespace blender::meshintersect::tests { constexpr bool DO_OBJ = false; @@ -1074,4 +1074,4 @@ TEST(mesh_intersect_perf, SphereGrid) #endif -} // namespace blender::meshintersect +} // namespace blender::meshintersect::tests diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc index b04b72dbe89..17ed581927a 100644 --- a/source/blender/bmesh/tools/bmesh_boolean.cc +++ b/source/blender/bmesh/tools/bmesh_boolean.cc @@ -218,13 +218,13 @@ static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out) */ int maxflen = 0; for (const Face *f : m_out.faces()) { - maxflen = max_ii(maxflen, static_cast<int>(f->size())); + maxflen = max_ii(maxflen, f->size()); } Array<BMVert *> face_bmverts(maxflen); Array<BMEdge *> face_bmedges(maxflen); for (const Face *f : m_out.faces()) { const Face &face = *f; - int flen = static_cast<int>(face.size()); + int flen = face.size(); for (int i = 0; i < flen; ++i) { const Vert *v = face[i]; int v_index = m_out.lookup_vert(v); @@ -337,7 +337,7 @@ static bool bmesh_boolean(BMesh *bm, void *user_data, const bool use_self, const bool use_separate_all, - const int boolean_mode) + const BoolOpType boolean_mode) { IMeshArena arena; IMesh m_triangulated; @@ -369,8 +369,8 @@ static bool bmesh_boolean(BMesh *bm, return -1; }; } - bool_optype op = static_cast<bool_optype>(boolean_mode); - IMesh m_out = boolean_mesh(m_in, op, nshapes, shape_fn, use_self, &m_triangulated, &arena); + IMesh m_out = boolean_mesh( + m_in, boolean_mode, nshapes, shape_fn, use_self, &m_triangulated, &arena); bool any_change = apply_mesh_output_to_bmesh(bm, m_out); if (use_separate_all) { /* We are supposed to separate all faces that are incident on intersection edges. */ @@ -411,7 +411,14 @@ bool BM_mesh_boolean(BMesh *bm, const int boolean_mode) { return blender::meshintersect::bmesh_boolean( - bm, looptris, looptris_tot, test_fn, user_data, use_self, false, boolean_mode); + bm, + looptris, + looptris_tot, + test_fn, + user_data, + use_self, + false, + static_cast<blender::meshintersect::BoolOpType>(boolean_mode)); } /* @@ -437,7 +444,7 @@ bool BM_mesh_boolean_knife(BMesh *bm, user_data, use_self, use_separate_all, - blender::meshintersect::BOOLEAN_NONE); + blender::meshintersect::BoolOpType::None); } #else bool BM_mesh_boolean(BMesh *UNUSED(bm), |