23#ifdef USE_WELD_DEBUG_TIME
27# pragma optimize("t", on)
34#define OUT_OF_CONTEXT int(-1)
36#define ELEM_COLLAPSED int(-2)
38#define ELEM_MERGED int(-2)
150static void weld_assert_edge_kill_len(
Span<int> edge_dest_map,
const int expected_kill_len)
153 for (
const int edge_orig : edge_dest_map.index_range()) {
161static void weld_assert_poly_and_loop_kill_len(WeldMesh *weld_mesh,
162 const int expected_faces_kill_len,
163 const int expected_loop_kill_len)
165 const Span<int> corner_verts = weld_mesh->corner_verts;
166 const Span<int> corner_edges = weld_mesh->corner_edges;
167 const OffsetIndices<int> faces = weld_mesh->faces;
170 int loop_kills = corner_verts.size();
171 for (
const int i : faces.index_range()) {
172 int poly_ctx = weld_mesh->face_map[i];
174 const WeldPoly *wp = &weld_mesh->wpoly[poly_ctx];
175 WeldLoopOfPolyIter iter;
192 int remain = wp->loop_len;
193 int l = wp->loop_start;
196 int loop_ctx = weld_mesh->loop_map[
l];
198 const WeldLoop *wl = &weld_mesh->wloop[loop_ctx];
213 loop_kills -= faces[i].size();
217 for (
const int i : weld_mesh->wpoly.index_range().take_back(weld_mesh->wpoly_new_len)) {
218 const WeldPoly &wp = weld_mesh->wpoly[i];
223 int remain = wp.loop_len;
224 int l = wp.loop_start;
227 int loop_ctx = weld_mesh->loop_map[
l];
229 const WeldLoop *wl = &weld_mesh->wloop[loop_ctx];
243 BLI_assert(poly_kills == expected_faces_kill_len);
244 BLI_assert(loop_kills == expected_loop_kill_len);
247static void weld_assert_poly_no_vert_repetition(
const WeldPoly *wp,
248 Span<WeldLoop> wloop,
249 const Span<int> corner_verts,
250 const Span<int> corner_edges,
254 if (wp->loop_len == 0) {
259 Array<int, 64>
verts(wp->loop_len);
260 WeldLoopOfPolyIter iter;
262 iter, *wp, wloop, corner_verts, corner_edges, loop_map,
nullptr))
274 for (i = 0; i < wp->loop_len; i++) {
276 for (
int j = i + 1; j < wp->loop_len; j++) {
297 const int vert_kill_len)
300 wvert.
reserve(std::min<int>(2 * vert_kill_len, vert_dest_map.
size()));
304 const int vert_dest = vert_dest_map[i];
307 if (vert_dest_map[vert_dest] != vert_dest) {
311 vert_dest_map[vert_dest] = vert_dest;
333 int *r_edge_collapsed_len)
336 int edge_collapsed_len = 0;
341 for (
const int i : edges.index_range()) {
342 int v1 = edges[i][0];
343 int v2 = edges[i][1];
344 int v_dest_1 = vert_dest_map[v1];
345 int v_dest_2 = vert_dest_map[
v2];
354 if (vert_a == vert_b) {
356 edge_collapsed_len++;
359 wedge.
append({i, vert_a, vert_b});
360 r_edge_dest_map[i] = i;
364 *r_edge_collapsed_len = edge_collapsed_len;
380 int *r_edge_double_kill_len)
383 int edge_double_kill_len = 0;
386 *r_edge_double_kill_len = edge_double_kill_len;
393 for (
const WeldEdge &we : weld_edges) {
396 v_links[we.vert_a]++;
397 v_links[we.vert_b]++;
402 link_len += v_links[i];
403 v_links[i] = link_len;
405 v_links.
last() = link_len;
411 for (
int i = weld_edges.
size(); i--;) {
414 int dst_vert_a = we.
vert_a;
415 int dst_vert_b = we.
vert_b;
417 link_edge_buffer[--v_links[dst_vert_a]] = i;
418 link_edge_buffer[--v_links[dst_vert_b]] = i;
429 int dst_vert_a = we.
vert_a;
430 int dst_vert_b = we.
vert_b;
432 const int link_a = v_links[dst_vert_a];
433 const int link_b = v_links[dst_vert_b];
435 int edges_len_a = v_links[dst_vert_a + 1] - link_a;
436 int edges_len_b = v_links[dst_vert_b + 1] - link_b;
439 if (edges_len_a <= 1 || edges_len_b <= 1) {
446 int *edges_ctx_a = &link_edge_buffer[link_a];
447 int *edges_ctx_b = &link_edge_buffer[link_b];
449 const int edge_double_len_prev = edge_double_kill_len;
450 for (; edges_len_a--; edges_ctx_a++) {
451 int e_ctx_a = *edges_ctx_a;
455 while (edges_len_b && *edges_ctx_b < e_ctx_a) {
459 if (edges_len_b == 0) {
462 int e_ctx_b = *edges_ctx_b;
463 if (e_ctx_a == e_ctx_b) {
464 const WeldEdge &we_b = weld_edges[e_ctx_b];
469 r_edge_dest_map[we_b.
edge_orig] = edge_orig;
470 edge_double_kill_len++;
473 if (edge_double_len_prev == edge_double_kill_len) {
480 *r_edge_double_kill_len = edge_double_kill_len;
500 int loop_ctx = loop_map[
l];
502 const WeldLoop *wl = &wloop[loop_ctx];
518 if (wl->
vert == iter.
v) {
561 iter.
group = group_buffer;
588 int max_ctx_poly_len = 4;
596 int maybe_new_poly = 0;
598 for (
const int i : faces.index_range()) {
599 const int loopstart = faces[i].start();
600 const int totloop = faces[i].size();
601 const int loop_end = loopstart + totloop - 1;
602 int v_first = corner_verts[loopstart];
603 int v_dest_first = vert_dest_map[v_first];
606 int v_next = v_first;
607 int v_dest_next = v_dest_first;
608 bool is_vert_next_ctx = is_vert_first_ctx;
610 int prev_wloop_len = wloop_len;
611 for (
const int loop_orig : faces[i]) {
613 int v_dest = v_dest_next;
614 bool is_vert_ctx = is_vert_next_ctx;
617 if (loop_orig != loop_end) {
618 loop_next = loop_orig + 1;
619 v_next = corner_verts[loop_next];
620 v_dest_next = vert_dest_map[v_next];
624 loop_next = loopstart;
626 v_dest_next = v_dest_first;
627 is_vert_next_ctx = is_vert_first_ctx;
630 if (is_vert_ctx || is_vert_next_ctx) {
631 int e = corner_edges[loop_orig];
632 int e_dest = edge_dest_map[
e];
637 wl.
vert = is_vert_ctx ? v_dest :
v;
638 wl.
edge = is_edge_ctx ? e_dest :
e;
642 loop_map[loop_orig] = wloop_len++;
649 if (wloop_len != prev_wloop_len) {
650 int loop_ctx_len = wloop_len - prev_wloop_len;
663 wp.loop_len = totloop;
666 face_map[i] = wpoly_len++;
667 if (totloop > 5 && loop_ctx_len > 1) {
671 int max_new = std::min((totloop / 3), loop_ctx_len) - 1;
672 maybe_new_poly += max_new;
683 r_weld_mesh->
wloop = std::move(wloop);
684 r_weld_mesh->
wpoly = std::move(wpoly);
686 r_weld_mesh->
loop_map = std::move(loop_map);
687 r_weld_mesh->
face_map = std::move(face_map);
698 if (poly_loop_len < 3) {
708 int loop_ctx_a = loop_map[loop_end];
712 int loop_ctx_a = loop_map[la];
722 int vert_a = wla->
vert;
735 int loop_ctx_b = loop_map[lb];
746 int vert_b = wlb->
vert;
747 if (vert_a != vert_b) {
755 int dist_b = poly_loop_len - dist_a;
758 if (dist_a == 1 || dist_b == 1) {
762 else if (dist_a == 2 && dist_b == 2) {
778 *r_loop_kill += loop_kill;
796 else if (dist_b == 2) {
803 r_wp->
loop_end = loop_end = lb_prev;
805 poly_loop_len = dist_a;
809 r_weld_mesh->
wpoly.increase_size_by_unchecked(1);
821 new_test->loop_len = dist_a;
824 dist_a, vert_dest_map, new_test, r_weld_mesh, r_poly_kill, r_loop_kill);
829 poly_loop_len = dist_b;
837 }
while (lb_prev != loop_end);
840 if (la == loop_end) {
845 }
while (la != loop_end);
847 *r_loop_kill += loop_kill;
849 r_wp->loop_len = poly_loop_len;
850 weld_assert_poly_no_vert_repetition(
851 r_wp, wloop, r_weld_mesh->corner_verts, r_weld_mesh->corner_edges, r_weld_mesh->
loop_map);
867 if (remain_edge_ctx_len == 0) {
883 int face_kill_len = 0;
884 int loop_kill_len = 0;
890 for (
const int i : wpoly_original_range) {
894 bool chang_loop_start =
false;
897 int loop_ctx = loop_map[
l];
904 const int edge_dest = wl->
edge;
907 if (poly_loop_len == 3) {
916 chang_loop_start =
true;
923 if (chang_loop_start) {
925 chang_loop_start =
false;
942 wp.loop_len = poly_loop_len;
945 int loop_ctx = loop_map[loop_orig];
960 wl = &wloop[loop_ctx];
966 poly_loop_len, vert_dest_map, &wp, r_weld_mesh, &face_kill_len, &loop_kill_len);
974 weld_assert_poly_and_loop_kill_len(
982 const int corner_index_max,
994 int index_a = 0, index_b = 0;
995 while (index_a < buffer_a.
size() && index_b < buffer_b.
size()) {
996 const int value_a = buffer_a[index_a];
997 const int value_b = buffer_b[index_b];
998 if (value_a < value_b) {
1001 else if (value_b < value_a) {
1009 if (!is_double[value_a]) {
1010 r_buffer[result_num++] = value_a;
1021 Array<int> linked_faces_offset(corner_index_max + 1, 0);
1023 for (
const int elem_index : corners) {
1024 linked_faces_offset[elem_index]++;
1027 int link_faces_buffer_len = 0;
1028 for (
const int elem_index :
IndexRange(corner_index_max)) {
1029 link_faces_buffer_len += linked_faces_offset[elem_index];
1030 linked_faces_offset[elem_index] = link_faces_buffer_len;
1032 linked_faces_offset[corner_index_max] = link_faces_buffer_len;
1034 if (link_faces_buffer_len == 0) {
1038 Array<int> linked_faces_buffer(link_faces_buffer_len);
1041 for (
int face_index = poly_num; face_index--;) {
1042 if (poly_corners_offsets[face_index].is_empty()) {
1046 for (
int corner_index = poly_corners_offsets[face_index].last();
1047 corner_index >= poly_corners_offsets[face_index].first();
1050 const int elem_index = corners[corner_index];
1051 linked_faces_buffer[--linked_faces_offset[elem_index]] = face_index;
1058 doubles_offsets.
reserve((poly_num / 2) + 1);
1059 doubles_offsets.
append(0);
1063 int doubles_buffer_num = 0;
1064 int doubles_num = 0;
1065 for (
const int face_index :
IndexRange(poly_num)) {
1066 if (is_double[face_index]) {
1070 int corner_num = poly_corners_offsets[face_index].
size();
1071 if (corner_num == 0) {
1076 doubles_buffer[doubles_buffer_num] = face_index;
1078 int corner_first = poly_corners_offsets[face_index].first();
1079 int elem_index = corners[corner_first];
1080 int link_offs = linked_faces_offset[elem_index];
1081 int faces_a_num = linked_faces_offset[elem_index + 1] - link_offs;
1082 if (faces_a_num == 1) {
1083 BLI_assert(linked_faces_buffer[linked_faces_offset[elem_index]] == face_index);
1087 const int *faces_a = &linked_faces_buffer[link_offs];
1092 poly_to_test = *faces_a;
1095 }
while (poly_to_test != face_index);
1097 int *isect_result = doubles_buffer.
data() + doubles_buffer_num + 1;
1100 for (
int corner_index :
IndexRange(corner_first + 1, corner_num - 1)) {
1101 elem_index = corners[corner_index];
1102 link_offs = linked_faces_offset[elem_index];
1103 int faces_b_num = linked_faces_offset[elem_index + 1] - link_offs;
1104 const int *faces_b = &linked_faces_buffer[link_offs];
1108 poly_to_test = *faces_b;
1111 }
while (poly_to_test != face_index);
1118 if (doubles_num == 0) {
1123 faces_a = isect_result;
1124 faces_a_num = doubles_num;
1128 for (
const int poly_double :
Span<int>{isect_result, doubles_num}) {
1130 is_double[poly_double].set();
1132 doubles_buffer_num += doubles_num;
1133 doubles_offsets.
append(++doubles_buffer_num);
1135 if ((doubles_buffer_num + 1) == poly_num) {
1143 r_doubles_buffer = std::move(doubles_buffer);
1144 r_doubles_offsets = std::move(doubles_offsets);
1145 return doubles_buffer_num - (r_doubles_offsets.
size() - 1);
1150 const int medge_len,
1162 const int face_len = r_weld_mesh->
wpoly.size();
1168 poly_offs_[face_index++] = new_corner_edges.
size();
1172 iter, wp, wloop, corner_verts, corner_edges, loop_map,
nullptr))
1182 new_corner_edges.
append(iter.
e);
1186 poly_offs_[face_len] = new_corner_edges.
size();
1192 poly_offs, face_len, new_corner_edges, medge_len, doubles_offsets, doubles_buffer);
1195 int loop_kill_num = 0;
1198 for (
const int i : doubles_offset_indices.
index_range()) {
1199 const int poly_dst = wpoly[doubles_buffer[doubles_offsets[i]]].
poly_orig;
1201 for (
const int offset : doubles_offset_indices[i].drop_front(1)) {
1202 const int wpoly_index = doubles_buffer[offset];
1207 loop_kill_num += poly_offs[wpoly_index].
size();
1215#ifdef USE_WELD_DEBUG
1216 weld_assert_poly_and_loop_kill_len(
1229 const int vert_kill_len,
1230 const bool get_doubles,
1235 const Span<int> corner_verts = mesh.corner_verts();
1236 const Span<int> corner_edges = mesh.corner_edges();
1244#ifdef USE_WELD_DEBUG
1245 r_weld_mesh->corner_verts = corner_verts;
1246 r_weld_mesh->corner_edges = corner_edges;
1247 r_weld_mesh->faces =
faces;
1250 int edge_collapsed_len, edge_double_kill_len;
1252 edges, vert_dest_map, r_weld_mesh->
edge_dest_map, &edge_collapsed_len);
1256 r_weld_mesh->
edge_kill_len = edge_collapsed_len + edge_double_kill_len;
1258#ifdef USE_WELD_DEBUG
1304 r_groups_offsets.
fill(0);
1309 for (
const int elem_orig : double_elems) {
1310 const int elem_dest = dest_map[elem_orig];
1311 r_groups_offsets[elem_dest]++;
1316 offs += r_groups_offsets[i];
1317 r_groups_offsets[i] = offs;
1319 r_groups_offsets.
last() = offs;
1325 for (
int i = double_elems.
size(); i--;) {
1326 const int elem_orig = double_elems[i];
1327 const int elem_dest = dest_map[elem_orig];
1328 r_groups_buffer[--r_groups_offsets[elem_dest]] = elem_orig;
1349 for (src_i = 0; src_i < source->
totlayer; src_i++) {
1355 while (dest_i < dest->totlayer && dest->
layers[dest_i].
type < type) {
1376 for (j = 0; j <
count; j++) {
1378 vs_flag |= vs->
flag;
1388 void *v_dst =
POINTER_OFFSET(dst_data,
size_t(dest_index) * size);
1389 for (j = 0; j <
count; j++) {
1391 type, v_dst,
POINTER_OFFSET(src_data,
size_t(src_indices[j]) * size));
1406 float fac = 1.0f /
count;
1408 for (dest_i = 0; dest_i < dest->
totlayer; dest_i++) {
1420 void *dst_data = layer_dst->
data;
1421 void *v_dst =
POINTER_OFFSET(dst_data,
size_t(dest_index) * size);
1446 const int dest_size,
1447 const bool do_mix_data,
1452 const int source_size = dest_map.
size();
1460 groups_offs_ = r_final_map;
1468 bool finalize_map =
false;
1470 for (
int i = 0; i < source_size; i++) {
1471 const int source_index = i;
1474 r_final_map[i] = dest_index +
count;
1480 dest_index +=
count;
1482 if (i == source_size) {
1485 if (dest_map[i] == i) {
1487 const IndexRange grp_buffer_range = groups_offs[i];
1490 &groups_buffer[grp_buffer_range.
start()],
1491 grp_buffer_range.
size(),
1497 r_final_map[i] = dest_index;
1505 const int elem_dest = dest_map[i];
1507 BLI_assert(dest_map[elem_dest] == elem_dest);
1508 if (elem_dest < i) {
1509 r_final_map[i] = r_final_map[elem_dest];
1514 r_final_map[i] = -elem_dest;
1515 finalize_map =
true;
1522 if (r_final_map[i] < 0) {
1523 r_final_map[i] = r_final_map[-r_final_map[i]];
1541 const int removed_vertex_count,
1542 const bool do_mix_data)
1544#ifdef USE_WELD_DEBUG_TIME
1549 const Span<int> src_corner_verts = mesh.corner_verts();
1550 const Span<int> src_corner_edges = mesh.corner_edges();
1551 const int totvert = mesh.verts_num;
1552 const int totedge = mesh.edges_num;
1557 const int result_nverts = totvert - weld_mesh.
vert_kill_len;
1558 const int result_nedges = totedge - weld_mesh.
edge_kill_len;
1563 &mesh, result_nverts, result_nedges, result_nfaces, result_nloops);
1593 for (
int2 &edge : dst_edges) {
1594 edge[0] = vert_final_map[edge[0]];
1595 edge[1] = vert_final_map[edge[1]];
1607 const int loop_start = loop_cur;
1608 const int poly_ctx = weld_mesh.
face_map[i];
1610 int mp_loop_len = src_faces[i].
size();
1612 &mesh.corner_data, &result->corner_data, src_faces[i].start(), loop_cur, mp_loop_len);
1613 for (; mp_loop_len--; loop_cur++) {
1614 dst_corner_verts[loop_cur] = vert_final_map[dst_corner_verts[loop_cur]];
1615 dst_corner_edges[loop_cur] = edge_final_map[dst_corner_edges[loop_cur]];
1627 group_buffer.
data()))
1637 &result->corner_data,
1638 group_buffer.
data(),
1641 dst_corner_verts[loop_cur] = vert_final_map[iter.
v];
1642 dst_corner_edges[loop_cur] = edge_final_map[iter.
e];
1648 dst_face_offsets[r_i] = loop_start;
1653 for (
const int i : weld_mesh.
wpoly.index_range().take_back(weld_mesh.
wpoly_new_len)) {
1655 const int loop_start = loop_cur;
1663 group_buffer.
data()))
1673 &mesh.corner_data, &result->corner_data, group_buffer.
data(), iter.
group_len, loop_cur);
1674 dst_corner_verts[loop_cur] = vert_final_map[iter.
v];
1675 dst_corner_edges[loop_cur] = edge_final_map[iter.
e];
1679 dst_face_offsets[r_i] = loop_start;
1699 const float merge_distance)
1703 KDTree_3d *
tree = BLI_kdtree_3d_new(selection.size());
1706 selection.foreach_index([&](
const int64_t i) { BLI_kdtree_3d_insert(
tree, i, positions[i]); });
1708 BLI_kdtree_3d_balance(
tree);
1709 const int vert_kill_len = BLI_kdtree_3d_calc_duplicates_fast(
1710 tree, merge_distance,
true, vert_dest_map.
data());
1711 BLI_kdtree_3d_free(
tree);
1713 if (vert_kill_len == 0) {
1714 return std::nullopt;
1727 const float merge_distance,
1728 const bool only_loose_edges)
1733 int vert_kill_len = 0;
1741 for (
const int i : positions.index_range()) {
1746 const float merge_dist_sq =
square_f(merge_distance);
1752 if (only_loose_edges) {
1753 loose_edges = &mesh.loose_edges();
1754 if (loose_edges->
count == 0) {
1759 for (
const int i : edges.index_range()) {
1760 int v1 = edges[i][0];
1761 int v2 = edges[i][1];
1766 while (v1 != vert_dest_map[v1]) {
1767 v1 = vert_dest_map[v1];
1769 while (
v2 != vert_dest_map[
v2]) {
1770 v2 = vert_dest_map[
v2];
1775 if (!selection.is_empty() && (!selection[v1] || !selection[
v2])) {
1787 if (dist_sq <= merge_dist_sq) {
1793 vert_dest_map[
v2] = v1;
1798 if (vert_kill_len == 0) {
1799 return std::nullopt;
1802 for (
const int i :
IndexRange(mesh.verts_num)) {
1803 if (i == vert_dest_map[i]) {
1809 v = vert_dest_map[
v];
1811 vert_dest_map[
v] =
v;
1812 vert_dest_map[i] =
v;
1821 int vert_dest_map_len,
1822 const bool do_mix_vert_data)
CustomData interface, see also DNA_customdata_types.h.
int CustomData_sizeof(eCustomDataType type)
bool CustomData_layer_has_interp(const CustomData *data, int layer_n)
void CustomData_interp(const CustomData *source, CustomData *dest, const int *src_indices, const float *weights, const float *sub_weights, int count, int dest_index)
bool CustomData_layer_has_math(const CustomData *data, int layer_n)
void CustomData_copy_layer_type_data(const CustomData *source, CustomData *destination, eCustomDataType type, int source_index, int destination_index, int count)
void CustomData_data_multiply(eCustomDataType type, void *data, float fac)
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
void CustomData_data_add(eCustomDataType type, void *data1, const void *data2)
Mesh * BKE_mesh_new_nomain_from_template(const Mesh *me_src, int verts_num, int edges_num, int faces_num, int corners_num)
A KD-tree for nearest neighbor search.
MINLINE float square_f(float a)
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void range_vn_i(int *array_tar, int size, int start)
#define SCOPED_TIMER(name)
#define UNUSED_VARS_NDEBUG(...)
#define POINTER_OFFSET(v, ofs)
#define IN_RANGE_INCL(a, b, c)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
__forceinline BoundBox intersect(const BoundBox &a, const BoundBox &b)
const T & last(const int64_t n=0) const
IndexRange index_range() const
void reinitialize(const int64_t new_size)
constexpr int64_t size() const
constexpr int64_t start() const
constexpr int64_t size() const
constexpr void fill(const T &value) const
constexpr IndexRange index_range() const
constexpr T & last(const int64_t n=0) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
void append(const T &value)
const T & last(const int64_t n=0) const
void reserve(const int64_t min_capacity)
void increase_size_by_unchecked(const int64_t n) noexcept
IndexRange index_range() const
static int poly_find_doubles(const OffsetIndices< int > poly_corners_offsets, const int poly_num, const Span< int > corners, const int corner_index_max, Vector< int > &r_doubles_offsets, Array< int > &r_doubles_buffer)
std::optional< Mesh * > mesh_merge_by_distance_connected(const Mesh &mesh, Span< bool > selection, float merge_distance, bool only_loose_edges)
static void weld_poly_split_recursive(int poly_loop_len, Span< int > vert_dest_map, WeldPoly *r_wp, WeldMesh *r_weld_mesh, int *r_poly_kill, int *r_loop_kill)
static Vector< WeldEdge > weld_edge_ctx_alloc_and_find_collapsed(Span< int2 > edges, Span< int > vert_dest_map, MutableSpan< int > r_edge_dest_map, int *r_edge_collapsed_len)
static void weld_poly_find_doubles(const Span< int > corner_verts, const Span< int > corner_edges, const int medge_len, WeldMesh *r_weld_mesh)
static void weld_edge_find_doubles(Span< WeldEdge > weld_edges, int mvert_num, MutableSpan< int > r_edge_dest_map, int *r_edge_double_kill_len)
static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter &iter)
static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter &iter, const WeldPoly &wp, Span< WeldLoop > wloop, const Span< int > corner_verts, const Span< int > corner_edges, Span< int > loop_map, int *group_buffer)
static void merge_customdata_all(const CustomData *source, CustomData *dest, Span< int > dest_map, Span< int > double_elems, const int dest_size, const bool do_mix_data, Array< int > &r_final_map)
Applies to CustomData *dest the values in CustomData *source.
std::optional< Mesh * > mesh_merge_by_distance_all(const Mesh &mesh, const IndexMask &selection, float merge_distance)
static void weld_poly_loop_ctx_setup_collapsed_and_split(const int remain_edge_ctx_len, WeldMesh *r_weld_mesh)
static Mesh * create_merged_mesh(const Mesh &mesh, MutableSpan< int > vert_dest_map, const int removed_vertex_count, const bool do_mix_data)
void debug_randomize_mesh_order(Mesh *mesh)
static void merge_groups_create(Span< int > dest_map, Span< int > double_elems, MutableSpan< int > r_groups_offsets, Array< int > &r_groups_buffer)
Create groups to merge.
Mesh * mesh_merge_verts(const Mesh &mesh, MutableSpan< int > vert_dest_map, int vert_dest_map_len, const bool do_mix_data)
static Vector< int > weld_vert_ctx_alloc_and_setup(MutableSpan< int > vert_dest_map, const int vert_kill_len)
static void weld_mesh_context_create(const Mesh &mesh, MutableSpan< int > vert_dest_map, const int vert_kill_len, const bool get_doubles, WeldMesh *r_weld_mesh)
static void weld_poly_loop_ctx_alloc(const OffsetIndices< int > faces, const Span< int > corner_verts, const Span< int > corner_edges, WeldMesh *r_weld_mesh)
static void customdata_weld(const CustomData *source, CustomData *dest, const int *src_indices, int count, int dest_index)
blender::BitVector is_loose_bits
Vector< int > double_verts
Vector< int > double_edges
Array< int > edge_dest_map
Span< int > vert_dest_map