Changeset View
Standalone View
source/blender/geometry/intern/mesh_merge_by_distance.cc
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | /* SPDX-License-Identifier: GPL-2.0-or-later */ | |||||||||||||||||||||||
| #include "BLI_array.hh" | #include "BLI_array.hh" | |||||||||||||||||||||||
| #include "BLI_bit_vector.hh" | ||||||||||||||||||||||||
| #include "BLI_index_mask.hh" | #include "BLI_index_mask.hh" | |||||||||||||||||||||||
| #include "BLI_kdtree.h" | #include "BLI_kdtree.h" | |||||||||||||||||||||||
| #include "BLI_math_vector.h" | #include "BLI_math_vector.h" | |||||||||||||||||||||||
| #include "BLI_math_vector.hh" | #include "BLI_math_vector.hh" | |||||||||||||||||||||||
| #include "BLI_offset_indices.hh" | ||||||||||||||||||||||||
| #include "BLI_vector.hh" | #include "BLI_vector.hh" | |||||||||||||||||||||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | |||||||||||||||||||||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | |||||||||||||||||||||||
| #include "BKE_customdata.h" | #include "BKE_customdata.h" | |||||||||||||||||||||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | |||||||||||||||||||||||
| ▲ Show 20 Lines • Show All 441 Lines • ▼ Show 20 Lines | ||||||||||||||||||||||||
| * \param r_vlinks: An uninitialized buffer used to compute groups of WeldEdges attached to each | * \param r_vlinks: An uninitialized buffer used to compute groups of WeldEdges attached to each | |||||||||||||||||||||||
| * weld target vertex. It doesn't need to be passed as a parameter but this is | * weld target vertex. It doesn't need to be passed as a parameter but this is | |||||||||||||||||||||||
| * done to reduce allocations. | * done to reduce allocations. | |||||||||||||||||||||||
| * \return r_edge_dest_map: Map of indices pointing edges that will be merged. | * \return r_edge_dest_map: Map of indices pointing edges that will be merged. | |||||||||||||||||||||||
| * \return r_wedge: Weld edges. `flag` and `edge_dest` members will be set here. | * \return r_wedge: Weld edges. `flag` and `edge_dest` members will be set here. | |||||||||||||||||||||||
| * \return r_edge_kill_len: Number of edges to be destroyed by merging or collapsing. | * \return r_edge_kill_len: Number of edges to be destroyed by merging or collapsing. | |||||||||||||||||||||||
| */ | */ | |||||||||||||||||||||||
| static void weld_edge_find_doubles(int remain_edge_ctx_len, | static void weld_edge_find_doubles(int remain_edge_ctx_len, | |||||||||||||||||||||||
| MutableSpan<int> r_vlinks, | int mvert_num, | |||||||||||||||||||||||
HooglyBoogly: Since `MVert` isn't used anymore, maybe `verts_num` would make more sense. There's a task… | ||||||||||||||||||||||||
| MutableSpan<int> r_edge_dest_map, | MutableSpan<int> r_edge_dest_map, | |||||||||||||||||||||||
| MutableSpan<WeldEdge> r_wedge, | MutableSpan<WeldEdge> r_wedge, | |||||||||||||||||||||||
| int *r_edge_kill_len) | int *r_edge_kill_len) | |||||||||||||||||||||||
| { | { | |||||||||||||||||||||||
| if (remain_edge_ctx_len == 0) { | if (remain_edge_ctx_len == 0) { | |||||||||||||||||||||||
| return; | return; | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| /* Setup Edge Overlap. */ | /* Setup Edge Overlap. */ | |||||||||||||||||||||||
| int edge_double_len = 0; | int edge_double_len = 0; | |||||||||||||||||||||||
| r_vlinks.fill(0); | /* Add +1 to allow calculation of the length of the last group. */ | |||||||||||||||||||||||
| Array<int> v_links(mvert_num + 1, 0); | ||||||||||||||||||||||||
| for (WeldEdge &we : r_wedge) { | for (WeldEdge &we : r_wedge) { | |||||||||||||||||||||||
| if (we.flag == ELEM_COLLAPSED) { | if (we.flag == ELEM_COLLAPSED) { | |||||||||||||||||||||||
| BLI_assert(r_edge_dest_map[we.edge_orig] == ELEM_COLLAPSED); | BLI_assert(r_edge_dest_map[we.edge_orig] == ELEM_COLLAPSED); | |||||||||||||||||||||||
| continue; | continue; | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| BLI_assert(we.vert_a != we.vert_b); | BLI_assert(we.vert_a != we.vert_b); | |||||||||||||||||||||||
| r_vlinks[we.vert_a]++; | v_links[we.vert_a]++; | |||||||||||||||||||||||
| r_vlinks[we.vert_b]++; | v_links[we.vert_b]++; | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| int link_len = 0; | int link_len = 0; | |||||||||||||||||||||||
| for (const int i : IndexRange(r_vlinks.size() - 1)) { | for (const int i : IndexRange(v_links.size() - 1)) { | |||||||||||||||||||||||
| link_len += r_vlinks[i]; | link_len += v_links[i]; | |||||||||||||||||||||||
| r_vlinks[i] = link_len; | v_links[i] = link_len; | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| r_vlinks.last() = link_len; | v_links.last() = link_len; | |||||||||||||||||||||||
| BLI_assert(link_len > 0); | BLI_assert(link_len > 0); | |||||||||||||||||||||||
| Array<int> link_edge_buffer(link_len); | Array<int> link_edge_buffer(link_len); | |||||||||||||||||||||||
| /* Use a reverse for loop to ensure that indexes are assigned in ascending order. */ | /* Use a reverse for loop to ensure that indexes are assigned in ascending order. */ | |||||||||||||||||||||||
| for (int i = r_wedge.size(); i--;) { | for (int i = r_wedge.size(); i--;) { | |||||||||||||||||||||||
| const WeldEdge &we = r_wedge[i]; | const WeldEdge &we = r_wedge[i]; | |||||||||||||||||||||||
| if (we.flag == ELEM_COLLAPSED) { | if (we.flag == ELEM_COLLAPSED) { | |||||||||||||||||||||||
| continue; | continue; | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| int dst_vert_a = we.vert_a; | int dst_vert_a = we.vert_a; | |||||||||||||||||||||||
| int dst_vert_b = we.vert_b; | int dst_vert_b = we.vert_b; | |||||||||||||||||||||||
| link_edge_buffer[--r_vlinks[dst_vert_a]] = i; | link_edge_buffer[--v_links[dst_vert_a]] = i; | |||||||||||||||||||||||
| link_edge_buffer[--r_vlinks[dst_vert_b]] = i; | link_edge_buffer[--v_links[dst_vert_b]] = i; | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| for (const int i : r_wedge.index_range()) { | for (const int i : r_wedge.index_range()) { | |||||||||||||||||||||||
| const WeldEdge &we = r_wedge[i]; | const WeldEdge &we = r_wedge[i]; | |||||||||||||||||||||||
| if (we.edge_dest != OUT_OF_CONTEXT) { | if (we.edge_dest != OUT_OF_CONTEXT) { | |||||||||||||||||||||||
| /* No need to retest edges. | /* No need to retest edges. | |||||||||||||||||||||||
| * (Already includes collapsed edges). */ | * (Already includes collapsed edges). */ | |||||||||||||||||||||||
| continue; | continue; | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| int dst_vert_a = we.vert_a; | int dst_vert_a = we.vert_a; | |||||||||||||||||||||||
| int dst_vert_b = we.vert_b; | int dst_vert_b = we.vert_b; | |||||||||||||||||||||||
| const int link_a = r_vlinks[dst_vert_a]; | const int link_a = v_links[dst_vert_a]; | |||||||||||||||||||||||
| const int link_b = r_vlinks[dst_vert_b]; | const int link_b = v_links[dst_vert_b]; | |||||||||||||||||||||||
| int edges_len_a = r_vlinks[dst_vert_a + 1] - link_a; | int edges_len_a = v_links[dst_vert_a + 1] - link_a; | |||||||||||||||||||||||
| int edges_len_b = r_vlinks[dst_vert_b + 1] - link_b; | int edges_len_b = v_links[dst_vert_b + 1] - link_b; | |||||||||||||||||||||||
| if (edges_len_a <= 1 || edges_len_b <= 1) { | if (edges_len_a <= 1 || edges_len_b <= 1) { | |||||||||||||||||||||||
| continue; | continue; | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| int *edges_ctx_a = &link_edge_buffer[link_a]; | int *edges_ctx_a = &link_edge_buffer[link_a]; | |||||||||||||||||||||||
| int *edges_ctx_b = &link_edge_buffer[link_b]; | int *edges_ctx_b = &link_edge_buffer[link_b]; | |||||||||||||||||||||||
| int edge_orig = we.edge_orig; | int edge_orig = we.edge_orig; | |||||||||||||||||||||||
| ▲ Show 20 Lines • Show All 550 Lines • ▼ Show 20 Lines | #endif | |||||||||||||||||||||||
| r_weld_mesh->loop_kill_len = loop_kill_len; | r_weld_mesh->loop_kill_len = loop_kill_len; | |||||||||||||||||||||||
| #ifdef USE_WELD_DEBUG | #ifdef USE_WELD_DEBUG | |||||||||||||||||||||||
| weld_assert_poly_and_loop_kill_len( | weld_assert_poly_and_loop_kill_len( | |||||||||||||||||||||||
| r_weld_mesh, mloop, mpoly, r_weld_mesh->poly_kill_len, r_weld_mesh->loop_kill_len); | r_weld_mesh, mloop, mpoly, r_weld_mesh->poly_kill_len, r_weld_mesh->loop_kill_len); | |||||||||||||||||||||||
| #endif | #endif | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| static void weld_poly_find_doubles(Span<MLoop> mloop, | static int poly_find_doubles(const OffsetIndices<int> poly_corners_offsets, | |||||||||||||||||||||||
| #ifdef USE_WELD_DEBUG | const int poly_num, | |||||||||||||||||||||||
| const Span<MPoly> mpoly, | const Span<int> corners, | |||||||||||||||||||||||
| #endif | const int corner_index_max, | |||||||||||||||||||||||
| const int mvert_len, | Vector<int> &r_doubles_offsets, | |||||||||||||||||||||||
| MutableSpan<int> r_vlinks, | Array<int> &r_doubles_buffer) | |||||||||||||||||||||||
| WeldMesh *r_weld_mesh) | ||||||||||||||||||||||||
| { | { | |||||||||||||||||||||||
| if (r_weld_mesh->poly_kill_len == r_weld_mesh->wpoly.size()) { | /* Fills the `r_buffer` buffer with the intersection of the arrays in `buffer_a` and `buffer_b`. | |||||||||||||||||||||||
| return; | * `buffer_a` and `buffer_b` have a sequence of sorted, non-repeating indices representing | |||||||||||||||||||||||
| * polygons. */ | ||||||||||||||||||||||||
| const auto intersect = [](const Span<int> buffer_a, const Span<int> buffer_b, int *r_buffer) { | ||||||||||||||||||||||||
| int result_num = 0; | ||||||||||||||||||||||||
| int index_a = 0, index_b = 0; | ||||||||||||||||||||||||
| while (index_a < buffer_a.size() && index_b < buffer_b.size()) { | ||||||||||||||||||||||||
| const int value_a = buffer_a[index_a]; | ||||||||||||||||||||||||
| const int value_b = buffer_b[index_b]; | ||||||||||||||||||||||||
| if (value_a < value_b) { | ||||||||||||||||||||||||
| index_a++; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| else if (value_b < value_a) { | ||||||||||||||||||||||||
| index_b++; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| else { | ||||||||||||||||||||||||
| /* Equality. */ | ||||||||||||||||||||||||
| r_buffer[result_num++] = value_a; | ||||||||||||||||||||||||
| index_a++; | ||||||||||||||||||||||||
| index_b++; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| WeldPoly *wpoly = r_weld_mesh->wpoly.data(); | return result_num; | |||||||||||||||||||||||
| MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop; | }; | |||||||||||||||||||||||
| Span<int> loop_map = r_weld_mesh->loop_map; | ||||||||||||||||||||||||
| int poly_kill_len = r_weld_mesh->poly_kill_len; | ||||||||||||||||||||||||
| int loop_kill_len = r_weld_mesh->loop_kill_len; | ||||||||||||||||||||||||
| /* Setup Polygon Overlap. */ | ||||||||||||||||||||||||
| r_vlinks.fill(0); | /* Add +1 to allow calculation of the length of the last group. */ | |||||||||||||||||||||||
| Array<int> linked_polys_offset(corner_index_max + 1, 0); | ||||||||||||||||||||||||
| for (const WeldPoly &wp : r_weld_mesh->wpoly) { | for (const int elem_index : corners) { | |||||||||||||||||||||||
| WeldLoopOfPolyIter iter; | linked_polys_offset[elem_index]++; | |||||||||||||||||||||||
| if (weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) { | ||||||||||||||||||||||||
| while (weld_iter_loop_of_poly_next(iter)) { | ||||||||||||||||||||||||
| r_vlinks[iter.v]++; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| int link_polys_buffer_len = 0; | ||||||||||||||||||||||||
| for (const int elem_index : IndexRange(corner_index_max)) { | ||||||||||||||||||||||||
| link_polys_buffer_len += linked_polys_offset[elem_index]; | ||||||||||||||||||||||||
| linked_polys_offset[elem_index] = link_polys_buffer_len; | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| linked_polys_offset[corner_index_max] = link_polys_buffer_len; | ||||||||||||||||||||||||
| int link_len = 0; | if (link_polys_buffer_len == 0) { | |||||||||||||||||||||||
| for (const int i : IndexRange(mvert_len)) { | return 0; | |||||||||||||||||||||||
| link_len += r_vlinks[i]; | ||||||||||||||||||||||||
| r_vlinks[i] = link_len; | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| r_vlinks[mvert_len] = link_len; | ||||||||||||||||||||||||
| if (link_len) { | Array<int> linked_polys_buffer(link_polys_buffer_len); | |||||||||||||||||||||||
| Array<int> link_poly_buffer(link_len); | ||||||||||||||||||||||||
| /* Use a reverse for loop to ensure that indexes are assigned in ascending order. */ | /* Use a reverse for loop to ensure that indexes are assigned in ascending order. */ | |||||||||||||||||||||||
| for (int i = r_weld_mesh->wpoly.size(); i--;) { | for (int poly_index = poly_num; poly_index--;) { | |||||||||||||||||||||||
| const WeldPoly &wp = wpoly[i]; | if (poly_corners_offsets[poly_index].size() == 0) { | |||||||||||||||||||||||
| WeldLoopOfPolyIter iter; | continue; | |||||||||||||||||||||||
| if (weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) { | ||||||||||||||||||||||||
| while (weld_iter_loop_of_poly_next(iter)) { | ||||||||||||||||||||||||
| link_poly_buffer[--r_vlinks[iter.v]] = i; | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| for (int corner_index = poly_corners_offsets[poly_index].last(); | ||||||||||||||||||||||||
| corner_index >= poly_corners_offsets[poly_index].first(); | ||||||||||||||||||||||||
| corner_index--) { | ||||||||||||||||||||||||
| const int elem_index = corners[corner_index]; | ||||||||||||||||||||||||
| linked_polys_buffer[--linked_polys_offset[elem_index]] = poly_index; | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| int polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b; | Array<int> doubles_buffer(poly_num); | |||||||||||||||||||||||
| polys_len_b = p_ctx_b = 0; /* silence warnings */ | ||||||||||||||||||||||||
| for (const int i : IndexRange(r_weld_mesh->wpoly.size())) { | Vector<int> doubles_offsets; | |||||||||||||||||||||||
| const WeldPoly &wp = wpoly[i]; | doubles_offsets.reserve((poly_num / 2) + 1); | |||||||||||||||||||||||
| if (wp.poly_dst != OUT_OF_CONTEXT) { | doubles_offsets.append(0); | |||||||||||||||||||||||
| /* No need to retest poly. | ||||||||||||||||||||||||
| * (Already includes collapsed polygons). */ | ||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| WeldLoopOfPolyIter iter; | BitVector<> is_double(poly_num, false); | |||||||||||||||||||||||
| weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr); | ||||||||||||||||||||||||
| weld_iter_loop_of_poly_next(iter); | int doubles_buffer_num = 0; | |||||||||||||||||||||||
| const int link_a = r_vlinks[iter.v]; | int doubles_num = 0; | |||||||||||||||||||||||
| polys_len_a = r_vlinks[iter.v + 1] - link_a; | for (const int poly_index : IndexRange(poly_num)) { | |||||||||||||||||||||||
| if (polys_len_a == 1) { | if (is_double[poly_index]) { | |||||||||||||||||||||||
| BLI_assert(link_poly_buffer[link_a] == i); | ||||||||||||||||||||||||
| continue; | continue; | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| int wp_loop_len = wp.loop_len; | ||||||||||||||||||||||||
| polys_ctx_a = &link_poly_buffer[link_a]; | int corner_num = poly_corners_offsets[poly_index].size(); | |||||||||||||||||||||||
| for (; polys_len_a--; polys_ctx_a++) { | if (corner_num == 0) { | |||||||||||||||||||||||
| p_ctx_a = *polys_ctx_a; | ||||||||||||||||||||||||
| if (p_ctx_a == i) { | ||||||||||||||||||||||||
| continue; | continue; | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| WeldPoly *wp_tmp = &wpoly[p_ctx_a]; | /* Set or overwrite the first slot of the possible group. */ | |||||||||||||||||||||||
| if (wp_tmp->loop_len != wp_loop_len) { | doubles_buffer[doubles_buffer_num] = poly_index; | |||||||||||||||||||||||
| int corner_first = poly_corners_offsets[poly_index].first(); | ||||||||||||||||||||||||
| int elem_index = corners[corner_first]; | ||||||||||||||||||||||||
| int link_offs = linked_polys_offset[elem_index]; | ||||||||||||||||||||||||
| int polys_a_num = linked_polys_offset[elem_index + 1] - link_offs; | ||||||||||||||||||||||||
| if (polys_a_num == 1) { | ||||||||||||||||||||||||
| BLI_assert(linked_polys_buffer[linked_polys_offset[elem_index]] == poly_index); | ||||||||||||||||||||||||
| continue; | continue; | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| WeldLoopOfPolyIter iter_b = iter; | const int *polys_a = &linked_polys_buffer[link_offs]; | |||||||||||||||||||||||
| while (weld_iter_loop_of_poly_next(iter_b)) { | int poly_to_test; | |||||||||||||||||||||||
| const int link_b = r_vlinks[iter_b.v]; | ||||||||||||||||||||||||
| polys_len_b = r_vlinks[iter_b.v + 1] - link_b; | /* Skip polygons with lower index as these have already been checked. */ | |||||||||||||||||||||||
| if (polys_len_b == 1) { | do { | |||||||||||||||||||||||
| BLI_assert(link_poly_buffer[link_b] == i); | poly_to_test = *polys_a; | |||||||||||||||||||||||
| polys_len_b = 0; | polys_a++; | |||||||||||||||||||||||
| polys_a_num--; | ||||||||||||||||||||||||
| } while (poly_to_test != poly_index); | ||||||||||||||||||||||||
| int *isect_result = doubles_buffer.data() + doubles_buffer_num + 1; | ||||||||||||||||||||||||
| for (int corner_index : IndexRange(corner_first + 1, corner_num - 1)) { | ||||||||||||||||||||||||
| elem_index = corners[corner_index]; | ||||||||||||||||||||||||
| link_offs = linked_polys_offset[elem_index]; | ||||||||||||||||||||||||
| int polys_b_num = linked_polys_offset[elem_index + 1] - link_offs; | ||||||||||||||||||||||||
| const int *polys_b = &linked_polys_buffer[link_offs]; | ||||||||||||||||||||||||
| /* Skip polygons with lower index as these have already been checked. */ | ||||||||||||||||||||||||
| do { | ||||||||||||||||||||||||
| poly_to_test = *polys_b; | ||||||||||||||||||||||||
| polys_b++; | ||||||||||||||||||||||||
| polys_b_num--; | ||||||||||||||||||||||||
| } while (poly_to_test != poly_index); | ||||||||||||||||||||||||
| doubles_num = intersect( | ||||||||||||||||||||||||
| Span<int>{polys_a, polys_a_num}, Span<int>{polys_b, polys_b_num}, isect_result); | ||||||||||||||||||||||||
| if (doubles_num == 0) { | ||||||||||||||||||||||||
| break; | break; | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| polys_ctx_b = &link_poly_buffer[link_b]; | /* Intersect the last result. */ | |||||||||||||||||||||||
| for (; polys_len_b; polys_len_b--, polys_ctx_b++) { | polys_a = isect_result; | |||||||||||||||||||||||
| p_ctx_b = *polys_ctx_b; | polys_a_num = doubles_num; | |||||||||||||||||||||||
| if (p_ctx_b < p_ctx_a) { | } | |||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||
| if (doubles_num) { | ||||||||||||||||||||||||
| for (const int poly_double : Span<int>{isect_result, doubles_num}) { | ||||||||||||||||||||||||
| BLI_assert(poly_double > poly_index); | ||||||||||||||||||||||||
| is_double[poly_double].set(); | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| if (p_ctx_b >= p_ctx_a) { | doubles_buffer_num += doubles_num; | |||||||||||||||||||||||
| if (p_ctx_b > p_ctx_a) { | doubles_offsets.append(++doubles_buffer_num); | |||||||||||||||||||||||
| polys_len_b = 0; | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| break; | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| r_doubles_buffer = std::move(doubles_buffer); | ||||||||||||||||||||||||
| r_doubles_offsets = std::move(doubles_offsets); | ||||||||||||||||||||||||
| return doubles_buffer_num - (r_doubles_offsets.size() - 1); | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| if (polys_len_b == 0) { | ||||||||||||||||||||||||
| break; | static void weld_poly_find_doubles(Span<MLoop> mloop, | |||||||||||||||||||||||
| #ifdef USE_WELD_DEBUG | ||||||||||||||||||||||||
| const Span<MPoly> mpoly, | ||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||
| const int medge_len, | ||||||||||||||||||||||||
| WeldMesh *r_weld_mesh) | ||||||||||||||||||||||||
| { | ||||||||||||||||||||||||
| if (r_weld_mesh->poly_kill_len == r_weld_mesh->wpoly.size()) { | ||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
Done Inline Actions
How about this? Seems much simpler, and doesn't have to deal with raw pointers HooglyBoogly: How about this? Seems much simpler, and doesn't have to deal with raw pointers | ||||||||||||||||||||||||
Done Inline ActionsNot sure if it would work. The (*buffer > index) condition returns false and serves to break the loop early. But I submitted another solution which is easier to read. mano-wii: Not sure if it would work. The `(*buffer > index)` condition returns `false` and serves to… | ||||||||||||||||||||||||
Not Done Inline ActionsWhy wouldn't that work? Any reasonable implementation of std::any_of would stop when a false condition was found. I would really suggest avoiding falling back to raw pointers here when we have Span. HooglyBoogly: Why wouldn't that work? Any reasonable implementation of `std::any_of` would stop when a false… | ||||||||||||||||||||||||
Not Done Inline ActionsAgh, I wrote that wrong. Looks like the >= should have been reversed or !std::all_of could be used instead. Still seems nice to use those logic building blocks IMO HooglyBoogly: Agh, I wrote that wrong. Looks like the `>=` should have been reversed or `!std::all_of` could… | ||||||||||||||||||||||||
| WeldPoly *wpoly = r_weld_mesh->wpoly.data(); | ||||||||||||||||||||||||
| MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop; | ||||||||||||||||||||||||
| Span<int> loop_map = r_weld_mesh->loop_map; | ||||||||||||||||||||||||
| int poly_index = 0; | ||||||||||||||||||||||||
| const int poly_len = r_weld_mesh->wpoly.size(); | ||||||||||||||||||||||||
| Array<int> poly_offs(poly_len + 1); | ||||||||||||||||||||||||
| Vector<int> corner_edges; | ||||||||||||||||||||||||
| corner_edges.reserve(mloop.size() - r_weld_mesh->loop_kill_len); | ||||||||||||||||||||||||
| for (const WeldPoly &wp : r_weld_mesh->wpoly) { | ||||||||||||||||||||||||
| poly_offs[poly_index++] = corner_edges.size(); | ||||||||||||||||||||||||
| WeldLoopOfPolyIter iter; | ||||||||||||||||||||||||
| if (!weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) { | ||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| if (polys_len_b == 0) { | ||||||||||||||||||||||||
| if (wp.poly_dst != OUT_OF_CONTEXT) { | ||||||||||||||||||||||||
| continue; | continue; | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| BLI_assert(p_ctx_a > i); | ||||||||||||||||||||||||
| BLI_assert(p_ctx_a == p_ctx_b); | while (weld_iter_loop_of_poly_next(iter)) { | |||||||||||||||||||||||
| BLI_assert(wp_tmp->poly_dst == OUT_OF_CONTEXT); | corner_edges.append(iter.e); | |||||||||||||||||||||||
| BLI_assert(wp_tmp != &wp); | } | |||||||||||||||||||||||
| wp_tmp->poly_dst = wp.poly_orig; | ||||||||||||||||||||||||
| loop_kill_len += wp_tmp->loop_len; | ||||||||||||||||||||||||
| poly_kill_len++; | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| poly_offs[poly_len] = corner_edges.size(); | ||||||||||||||||||||||||
| Vector<int> doubles_offsets; | ||||||||||||||||||||||||
| Array<int> doubles_buffer; | ||||||||||||||||||||||||
| const int doubles_num = poly_find_doubles(OffsetIndices<int>(poly_offs), | ||||||||||||||||||||||||
| poly_len, | ||||||||||||||||||||||||
| corner_edges, | ||||||||||||||||||||||||
| medge_len, | ||||||||||||||||||||||||
| doubles_offsets, | ||||||||||||||||||||||||
| doubles_buffer); | ||||||||||||||||||||||||
| if (doubles_num) { | ||||||||||||||||||||||||
| int loop_kill_num = 0; | ||||||||||||||||||||||||
| OffsetIndices<int> doubles_offset_indices = OffsetIndices<int>(doubles_offsets); | ||||||||||||||||||||||||
| for (const int i : IndexRange(doubles_offset_indices.ranges_num())) { | ||||||||||||||||||||||||
| const int poly_dst = wpoly[doubles_buffer[doubles_offsets[i]]].poly_orig; | ||||||||||||||||||||||||
| for (const int offset : doubles_offset_indices[i].drop_front(1)) { | ||||||||||||||||||||||||
| const int wpoly_index = doubles_buffer[offset]; | ||||||||||||||||||||||||
| WeldPoly &wp = wpoly[wpoly_index]; | ||||||||||||||||||||||||
| BLI_assert(wp.poly_dst == OUT_OF_CONTEXT); | ||||||||||||||||||||||||
| wp.poly_dst = poly_dst; | ||||||||||||||||||||||||
| loop_kill_num += wp.loop_len; | ||||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| r_weld_mesh->poly_kill_len = poly_kill_len; | r_weld_mesh->poly_kill_len += doubles_num; | |||||||||||||||||||||||
| r_weld_mesh->loop_kill_len = loop_kill_len; | r_weld_mesh->loop_kill_len += loop_kill_num; | |||||||||||||||||||||||
| } | ||||||||||||||||||||||||
Done Inline ActionsWithout std::move these are probably resulting in copies (though maybe this whole function is inlined) HooglyBoogly: Without `std::move` these are probably resulting in copies (though maybe this whole function is… | ||||||||||||||||||||||||
| #ifdef USE_WELD_DEBUG | #ifdef USE_WELD_DEBUG | |||||||||||||||||||||||
| weld_assert_poly_and_loop_kill_len( | weld_assert_poly_and_loop_kill_len( | |||||||||||||||||||||||
| r_weld_mesh, mloop, mpoly, r_weld_mesh->poly_kill_len, r_weld_mesh->loop_kill_len); | r_weld_mesh, mloop, mpoly, r_weld_mesh->poly_kill_len, r_weld_mesh->loop_kill_len); | |||||||||||||||||||||||
| #endif | #endif | |||||||||||||||||||||||
| } | } | |||||||||||||||||||||||
| /** \} */ | /** \} */ | |||||||||||||||||||||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | |||||||||||||||||||||||
| /** \name Mesh API | /** \name Mesh API | |||||||||||||||||||||||
| * \{ */ | * \{ */ | |||||||||||||||||||||||
| static void weld_mesh_context_create(const Mesh &mesh, | static void weld_mesh_context_create(const Mesh &mesh, | |||||||||||||||||||||||
| MutableSpan<int> vert_dest_map, | MutableSpan<int> vert_dest_map, | |||||||||||||||||||||||
| const int vert_kill_len, | const int vert_kill_len, | |||||||||||||||||||||||
| MutableSpan<int> r_vert_group_map, | MutableSpan<int> r_vert_group_map, | |||||||||||||||||||||||
| WeldMesh *r_weld_mesh) | WeldMesh *r_weld_mesh) | |||||||||||||||||||||||
| { | { | |||||||||||||||||||||||
| const int mvert_len = mesh.totvert; | ||||||||||||||||||||||||
| const Span<MEdge> edges = mesh.edges(); | const Span<MEdge> edges = mesh.edges(); | |||||||||||||||||||||||
| const Span<MPoly> polys = mesh.polys(); | const Span<MPoly> polys = mesh.polys(); | |||||||||||||||||||||||
| const Span<MLoop> loops = mesh.loops(); | const Span<MLoop> loops = mesh.loops(); | |||||||||||||||||||||||
| Vector<WeldVert> wvert = weld_vert_ctx_alloc_and_setup(vert_dest_map, vert_kill_len); | Vector<WeldVert> wvert = weld_vert_ctx_alloc_and_setup(vert_dest_map, vert_kill_len); | |||||||||||||||||||||||
| r_weld_mesh->vert_kill_len = vert_kill_len; | r_weld_mesh->vert_kill_len = vert_kill_len; | |||||||||||||||||||||||
| Array<int> edge_dest_map(edges.size()); | Array<int> edge_dest_map(edges.size()); | |||||||||||||||||||||||
| Array<int> edge_ctx_map(edges.size()); | Array<int> edge_ctx_map(edges.size()); | |||||||||||||||||||||||
| Vector<WeldEdge> wedge = weld_edge_ctx_alloc_and_find_collapsed( | Vector<WeldEdge> wedge = weld_edge_ctx_alloc_and_find_collapsed( | |||||||||||||||||||||||
| edges, vert_dest_map, edge_dest_map, edge_ctx_map, &r_weld_mesh->edge_kill_len); | edges, vert_dest_map, edge_dest_map, edge_ctx_map, &r_weld_mesh->edge_kill_len); | |||||||||||||||||||||||
| /* Add +1 to allow calculation of the length of the last group. */ | ||||||||||||||||||||||||
| Array<int> v_links(mvert_len + 1); | ||||||||||||||||||||||||
| weld_edge_find_doubles(wedge.size() - r_weld_mesh->edge_kill_len, | weld_edge_find_doubles(wedge.size() - r_weld_mesh->edge_kill_len, | |||||||||||||||||||||||
| v_links, | mesh.totvert, | |||||||||||||||||||||||
| edge_dest_map, | edge_dest_map, | |||||||||||||||||||||||
| wedge, | wedge, | |||||||||||||||||||||||
| &r_weld_mesh->edge_kill_len); | &r_weld_mesh->edge_kill_len); | |||||||||||||||||||||||
| weld_poly_loop_ctx_alloc(polys, loops, vert_dest_map, edge_dest_map, r_weld_mesh); | weld_poly_loop_ctx_alloc(polys, loops, vert_dest_map, edge_dest_map, r_weld_mesh); | |||||||||||||||||||||||
| weld_poly_loop_ctx_setup_collapsed_and_split( | weld_poly_loop_ctx_setup_collapsed_and_split( | |||||||||||||||||||||||
| #ifdef USE_WELD_DEBUG | #ifdef USE_WELD_DEBUG | |||||||||||||||||||||||
| loops, | loops, | |||||||||||||||||||||||
| polys, | polys, | |||||||||||||||||||||||
| #endif | #endif | |||||||||||||||||||||||
| vert_dest_map, | vert_dest_map, | |||||||||||||||||||||||
| wedge.size() - r_weld_mesh->edge_kill_len, | wedge.size() - r_weld_mesh->edge_kill_len, | |||||||||||||||||||||||
| r_weld_mesh); | r_weld_mesh); | |||||||||||||||||||||||
| weld_poly_find_doubles(loops, | weld_poly_find_doubles(loops, | |||||||||||||||||||||||
| #ifdef USE_WELD_DEBUG | #ifdef USE_WELD_DEBUG | |||||||||||||||||||||||
| polys, | polys, | |||||||||||||||||||||||
| #endif | #endif | |||||||||||||||||||||||
| mvert_len, | edges.size(), | |||||||||||||||||||||||
| v_links, | ||||||||||||||||||||||||
| r_weld_mesh); | r_weld_mesh); | |||||||||||||||||||||||
| weld_vert_groups_setup(wvert, | weld_vert_groups_setup(wvert, | |||||||||||||||||||||||
| vert_dest_map, | vert_dest_map, | |||||||||||||||||||||||
Done Inline ActionsLooks like this could be done a bit more simply by using a helper OffsetIndices object above after the vector has been filled. HooglyBoogly: Looks like this could be done a bit more simply by using a helper `OffsetIndices` object above… | ||||||||||||||||||||||||
| vert_kill_len, | vert_kill_len, | |||||||||||||||||||||||
| r_vert_group_map, | r_vert_group_map, | |||||||||||||||||||||||
| r_weld_mesh->vert_groups_buffer, | r_weld_mesh->vert_groups_buffer, | |||||||||||||||||||||||
| r_weld_mesh->vert_groups_offs); | r_weld_mesh->vert_groups_offs); | |||||||||||||||||||||||
Done Inline ActionsUsing a more standard for loop with just one changing variable would make these much more readable in my opinion. It's hard to track what's going on here. Same with the for (; link_len_first--; polys_to_test++) { above. HooglyBoogly: Using a more standard for loop with just one changing variable would make these much more… | ||||||||||||||||||||||||
| weld_edge_groups_setup(edges.size(), | weld_edge_groups_setup(edges.size(), | |||||||||||||||||||||||
| r_weld_mesh->edge_kill_len, | r_weld_mesh->edge_kill_len, | |||||||||||||||||||||||
| wedge, | wedge, | |||||||||||||||||||||||
| edge_ctx_map, | edge_ctx_map, | |||||||||||||||||||||||
| edge_dest_map, | edge_dest_map, | |||||||||||||||||||||||
| r_weld_mesh->edge_groups_buffer, | r_weld_mesh->edge_groups_buffer, | |||||||||||||||||||||||
| r_weld_mesh->edge_groups_offs, | r_weld_mesh->edge_groups_offs, | |||||||||||||||||||||||
| r_weld_mesh->edge_groups_verts); | r_weld_mesh->edge_groups_verts); | |||||||||||||||||||||||
| ▲ Show 20 Lines • Show All 432 Lines • Show Last 20 Lines | ||||||||||||||||||||||||
Since MVert isn't used anymore, maybe verts_num would make more sense. There's a task describing how the _num suffix is meant to be the standard for such variables but I can't find it right now :/