diff options
author | Howard Trickey <howard.trickey@gmail.com> | 2021-06-05 21:31:08 +0300 |
---|---|---|
committer | Howard Trickey <howard.trickey@gmail.com> | 2021-06-05 21:31:08 +0300 |
commit | 8e43ef5f318690d4924bd0861f5fd37a85999083 (patch) | |
tree | ef951ca5b1bb1014e8144616aeab0b0f74e5859a /source/blender/blenlib/intern/mesh_boolean.cc | |
parent | edaaa2afddb2132e56f39791e559b084b6df8773 (diff) |
Exact Boolean: speed up when there are many separate components.
Use bounding box tests quickly tell that two components cannot
have a containment relation between each other. This change
cut about 0.6s off a test with 25 big icospheres.
Diffstat (limited to 'source/blender/blenlib/intern/mesh_boolean.cc')
-rw-r--r-- | source/blender/blenlib/intern/mesh_boolean.cc | 80 |
1 files changed, 68 insertions, 12 deletions
diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc index 00d53a010b0..2b286de5120 100644 --- a/source/blender/blenlib/intern/mesh_boolean.cc +++ b/source/blender/blenlib/intern/mesh_boolean.cc @@ -1863,6 +1863,7 @@ static Vector<ComponentContainer> find_component_containers(int comp, const IMesh &tm, const PatchesInfo &pinfo, const TriMeshTopology &tmtopo, + Array<BoundingBox> comp_bb, IMeshArena *arena) { constexpr int dbg_level = 0; @@ -1888,6 +1889,12 @@ static Vector<ComponentContainer> find_component_containers(int comp, if (dbg_level > 0) { std::cout << "comp_other = " << comp_other << "\n"; } + if (!bbs_might_intersect(comp_bb[comp], comp_bb[comp_other])) { + if (dbg_level > 0) { + std::cout << "bounding boxes don't overlap\n"; + } + continue; + } int nearest_tri = NO_INDEX; int nearest_tri_close_vert = -1; int nearest_tri_close_edge = -1; @@ -1962,6 +1969,51 @@ static Vector<ComponentContainer> find_component_containers(int comp, } /** + * Populate the per-component bounding boxes, expanding them + * by an appropriate epsilon so that we conservatively will say + * that components could intersect if the BBs overlap. + */ +static void populate_comp_bbs(const Vector<Vector<int>> &components, + const PatchesInfo &pinfo, + const IMesh &im, + Array<BoundingBox> &comp_bb) +{ + const int comp_grainsize = 16; + /* To get a good expansion epsilon, we need to find the maximum + * absolute value of any coordinate. Do it first per component, + * then get the overall max. */ + Array<double> max_abs(components.size(), 0.0); + parallel_for(components.index_range(), comp_grainsize, [&](IndexRange comp_range) { + for (int c : comp_range) { + BoundingBox &bb = comp_bb[c]; + double &maxa = max_abs[c]; + for (int p : components[c]) { + const Patch &patch = pinfo.patch(p); + for (int t : patch.tris()) { + const Face &tri = *im.face(t); + for (const Vert *v : tri) { + bb.combine(v->co); + for (int i = 0; i < 3; ++i) { + maxa = max_dd(maxa, fabs(v->co[i])); + } + } + } + } + } + }); + double all_max_abs = 0.0; + for (int c : components.index_range()) { + all_max_abs = max_dd(all_max_abs, max_abs[c]); + } + constexpr float pad_factor = 10.0f; + float pad = all_max_abs == 0.0 ? FLT_EPSILON : 2 * FLT_EPSILON * all_max_abs; + pad *= pad_factor; + for (int c : components.index_range()) { + comp_bb[c].expand(pad); + } +} + +/** * The cells and patches are supposed to form a bipartite graph. * The graph may be disconnected (if parts of meshes are nested or side-by-side * without intersection with other each other). @@ -2003,19 +2055,23 @@ static void finish_patch_cell_graph(const IMesh &tm, } int tot_components = components.size(); Array<Vector<ComponentContainer>> comp_cont(tot_components); - for (int comp : components.index_range()) { - comp_cont[comp] = find_component_containers( - comp, components, ambient_cell, tm, pinfo, tmtopo, arena); - } - if (dbg_level > 0) { - std::cout << "component containers:\n"; - for (int comp : comp_cont.index_range()) { - std::cout << comp << ": "; - for (const ComponentContainer &cc : comp_cont[comp]) { - std::cout << "[containing_comp=" << cc.containing_component - << ", nearest_cell=" << cc.nearest_cell << ", d2=" << cc.dist_to_cell << "] "; + if (tot_components > 1) { + Array<BoundingBox> comp_bb(tot_components); + populate_comp_bbs(components, pinfo, tm, comp_bb); + for (int comp : components.index_range()) { + comp_cont[comp] = find_component_containers( + comp, components, ambient_cell, tm, pinfo, tmtopo, comp_bb, arena); + } + if (dbg_level > 0) { + std::cout << "component containers:\n"; + for (int comp : comp_cont.index_range()) { + std::cout << comp << ": "; + for (const ComponentContainer &cc : comp_cont[comp]) { + std::cout << "[containing_comp=" << cc.containing_component + << ", nearest_cell=" << cc.nearest_cell << ", d2=" << cc.dist_to_cell << "] "; + } + std::cout << "\n"; } - std::cout << "\n"; } } if (dbg_level > 1) { |