Blender V4.5
MOD_solidify_nonmanifold.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10
11#include "BLI_math_matrix.h"
12#include "BLI_math_vector.h"
13#include "BLI_utildefines.h"
14
15#include "DNA_mesh_types.h"
16#include "DNA_meshdata_types.h"
17#include "DNA_object_types.h"
18
19#include "MEM_guardedalloc.h"
20
21#include "BKE_attribute.hh"
22#include "BKE_customdata.hh"
23#include "BKE_deform.hh"
24#include "BKE_mesh.hh"
25
26#include "MOD_solidify_util.hh" /* Own include. */
27#include "MOD_util.hh"
28
29/* -------------------------------------------------------------------- */
32
36static float project_v3_v3(float r[3], const float a[3])
37{
38 float d = dot_v3v3(r, a);
39 r[0] -= a[0] * d;
40 r[1] -= a[1] * d;
41 r[2] -= a[2] * d;
42 return d;
43}
44
45static float angle_signed_on_axis_normalized_v3v3_v3(const float n[3],
46 const float ref_n[3],
47 const float axis[3])
48{
49 float d = dot_v3v3(n, ref_n);
50 CLAMP(d, -1, 1);
51 float angle = acosf(d);
52 float cross[3];
53 cross_v3_v3v3(cross, n, ref_n);
54 if (dot_v3v3(cross, axis) >= 0) {
55 angle = 2 * M_PI - angle;
56 }
57 return angle;
58}
59
60static float clamp_nonzero(const float value, const float epsilon)
61{
62 BLI_assert(!(epsilon < 0.0f));
63 /* Return closest value with `abs(value) >= epsilon`. */
64 if (value < 0.0f) {
65 return min_ff(value, -epsilon);
66 }
67 return max_ff(value, epsilon);
68}
69
71
72/* -------------------------------------------------------------------- */
75
76/* Data structures for manifold solidify. */
77
78struct NewEdgeRef;
79
80struct NewFaceRef {
83 bool reversed = false;
85};
86
93
98
106
121
123 float angle;
125};
126
127static int comp_float_int_pair(const void *a, const void *b)
128{
129 FaceKeyPair *x = (FaceKeyPair *)a;
131 return int(x->angle > y->angle) - int(x->angle < y->angle);
132}
133
134/* NOLINTNEXTLINE: readability-function-size */
136 const ModifierEvalContext *ctx,
137 Mesh *mesh)
138{
139 using namespace blender;
140 Mesh *result;
142
143 const uint verts_num = uint(mesh->verts_num);
144 const uint edges_num = uint(mesh->edges_num);
145 const uint faces_num = uint(mesh->faces_num);
146
147 if (faces_num == 0 && verts_num != 0) {
148 return mesh;
149 }
150
151 /* Only use material offsets if we have 2 or more materials. */
152 const short mat_nrs = ctx->object->totcol > 1 ? ctx->object->totcol : 1;
153 const short mat_nr_max = mat_nrs - 1;
154 const short mat_ofs = mat_nrs > 1 ? smd->mat_ofs : 0;
155 const short mat_ofs_rim = mat_nrs > 1 ? smd->mat_ofs_rim : 0;
156
157 /* #ofs_front and #ofs_back are the offset from the original
158 * surface along the normal, where #oft_front is along the positive
159 * and #oft_back is along the negative normal. */
160 const float ofs_front = (smd->offset_fac + 1.0f) * 0.5f * smd->offset;
161 const float ofs_back = ofs_front - smd->offset * smd->offset_fac;
162 /* #ofs_front_clamped and #ofs_back_clamped are the same as
163 * #ofs_front and #ofs_back, but never zero. */
164 const float ofs_front_clamped = clamp_nonzero(ofs_front, 1e-5f);
165 const float ofs_back_clamped = clamp_nonzero(ofs_back, 1e-5f);
166 const float offset_fac_vg = smd->offset_fac_vg;
167 const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
168 const float offset = fabsf(smd->offset) * smd->offset_clamp;
169 const bool do_angle_clamp = smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP;
170 /* #do_flip, flips the normals of the result. This is inverted if negative thickness
171 * is used, since simple solidify with negative thickness keeps the faces facing outside. */
172 const bool do_flip = ((smd->flag & MOD_SOLIDIFY_FLIP) != 0) == (smd->offset > 0);
173 const bool do_rim = smd->flag & MOD_SOLIDIFY_RIM;
174 const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) ==
175 0;
176 const bool do_clamp = (smd->offset_clamp != 0.0f);
177
178 const float bevel_convex = smd->bevel_convex;
179
180 const MDeformVert *dvert;
181 const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
182 int defgrp_index;
183 const int shell_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->shell_defgrp_name);
184 const int rim_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->rim_defgrp_name);
185
186 MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
187
188 const bool do_flat_faces = dvert && (smd->flag & MOD_SOLIDIFY_NONMANIFOLD_FLAT_FACES);
189
190 const blender::Span<blender::float3> orig_vert_positions = mesh->vert_positions();
191 const blender::Span<int2> orig_edges = mesh->edges();
192 const blender::OffsetIndices orig_faces = mesh->faces();
193 const blender::Span<int> orig_corner_verts = mesh->corner_verts();
194 const blender::Span<int> orig_corner_edges = mesh->corner_edges();
195
196 /* These might be null. */
197 const float *orig_vert_bweight = static_cast<const float *>(
198 CustomData_get_layer_named(&mesh->vert_data, CD_PROP_FLOAT, "bevel_weight_vert"));
199 const float *orig_edge_bweight = static_cast<const float *>(
200 CustomData_get_layer_named(&mesh->edge_data, CD_PROP_FLOAT, "bevel_weight_edge"));
201 const float *orig_edge_crease = static_cast<const float *>(
202 CustomData_get_layer_named(&mesh->edge_data, CD_PROP_FLOAT, "crease_edge"));
203
204 uint new_verts_num = 0;
205 uint new_edges_num = 0;
206 uint new_loops_num = 0;
207 uint new_faces_num = 0;
208
209#define MOD_SOLIDIFY_EMPTY_TAG uint(-1)
210
211 /* Calculate only face normals. Copied because they are modified directly below. */
212 blender::Array<blender::float3> face_nors = mesh->face_normals_true();
213
214 blender::Array<NewFaceRef> face_sides_arr(faces_num * 2);
215 bool *null_faces = (smd->nonmanifold_offset_mode ==
217 MEM_calloc_arrayN<bool>(faces_num, __func__) :
218 nullptr;
219 uint largest_ngon = 3;
220 /* Calculate face to #NewFaceRef map. */
221 {
222 for (const int i : orig_faces.index_range()) {
223 const blender::IndexRange &face = orig_faces[i];
224 /* Make normals for faces without area (should really be avoided though). */
225 if (len_squared_v3(face_nors[i]) < 0.5f) {
226 const int2 &edge = orig_edges[orig_corner_edges[face.start()]];
227 float edgedir[3];
228 sub_v3_v3v3(edgedir, orig_vert_positions[edge[1]], orig_vert_positions[edge[0]]);
229 if (fabsf(edgedir[2]) < fabsf(edgedir[1])) {
230 face_nors[i][2] = 1.0f;
231 }
232 else {
233 face_nors[i][1] = 1.0f;
234 }
235 if (null_faces) {
236 null_faces[i] = true;
237 }
238 }
239
240 NewEdgeRef **link_edges = MEM_calloc_arrayN<NewEdgeRef *>(uint(face.size()), __func__);
241
242 NewFaceRef new_face_ref_a{};
243 new_face_ref_a.face = face;
244 new_face_ref_a.index = uint(i);
245 new_face_ref_a.reversed = false;
246 new_face_ref_a.link_edges = link_edges;
247 face_sides_arr[i * 2] = std::move(new_face_ref_a);
248
249 link_edges = MEM_calloc_arrayN<NewEdgeRef *>(uint(face.size()), __func__);
250
251 NewFaceRef new_face_ref_b{};
252 new_face_ref_b.face = face;
253 new_face_ref_b.index = uint(i);
254 new_face_ref_b.reversed = true;
255 new_face_ref_b.link_edges = link_edges;
256 face_sides_arr[i * 2 + 1] = std::move(new_face_ref_b);
257
258 if (face.size() > largest_ngon) {
259 largest_ngon = uint(face.size());
260 }
261 /* add to final mesh face count */
262 if (do_shell) {
263 new_faces_num += 2;
264 new_loops_num += uint(face.size() * 2);
265 }
266 }
267 }
268
269 uint *edge_adj_faces_len = MEM_calloc_arrayN<uint>(edges_num, __func__);
270 /* Count for each edge how many faces it has adjacent. */
271 {
272 for (const int64_t i : orig_faces.index_range()) {
273 for (const int64_t edge : orig_corner_edges.slice(orig_faces[i])) {
274 edge_adj_faces_len[edge]++;
275 }
276 }
277 }
278
279 /* Original edge to #NewEdgeRef map. */
280 NewEdgeRef ***orig_edge_data_arr = MEM_calloc_arrayN<NewEdgeRef **>(edges_num, __func__);
281 /* Original edge length cache. */
282 float *orig_edge_lengths = MEM_calloc_arrayN<float>(edges_num, __func__);
283 /* Edge groups for every original vert. */
284 EdgeGroup **orig_vert_groups_arr = MEM_calloc_arrayN<EdgeGroup *>(verts_num, __func__);
285 /* vertex map used to map duplicates. */
286 uint *vm = MEM_malloc_arrayN<uint>(verts_num, __func__);
287 for (uint i = 0; i < verts_num; i++) {
288 vm[i] = i;
289 }
290
291 uint edge_index = 0;
292 uint loop_index = 0;
293 uint face_index = 0;
294
295 bool has_singularities = false;
296
297 /* Vert edge adjacent map. */
298 OldVertEdgeRef **vert_adj_edges = MEM_calloc_arrayN<OldVertEdgeRef *>(verts_num, __func__);
299 /* Original vertex positions (changed for degenerated geometry). */
300 float(*orig_mvert_co)[3] = MEM_malloc_arrayN<float[3]>(verts_num, __func__);
301 /* Fill in the original vertex positions. */
302 for (uint i = 0; i < verts_num; i++) {
303 orig_mvert_co[i][0] = orig_vert_positions[i][0];
304 orig_mvert_co[i][1] = orig_vert_positions[i][1];
305 orig_mvert_co[i][2] = orig_vert_positions[i][2];
306 }
307
308 /* Create edge to #NewEdgeRef map. */
309 {
310 OldEdgeFaceRef **edge_adj_faces = MEM_calloc_arrayN<OldEdgeFaceRef *>(edges_num, __func__);
311
312 /* Create link_faces for edges. */
313 {
314 for (const int64_t i : orig_faces.index_range()) {
315 for (const int64_t corner : orig_faces[i]) {
316 const int vert = orig_corner_verts[corner];
317 const int edge = orig_corner_edges[corner];
318 const bool reversed = orig_edges[edge][1] != vert;
319 OldEdgeFaceRef *old_face_edge_ref = edge_adj_faces[edge];
320 if (old_face_edge_ref == nullptr) {
321 const uint len = edge_adj_faces_len[edge];
322 BLI_assert(len > 0);
323 uint *adj_faces = MEM_malloc_arrayN<uint>(len, __func__);
324 bool *adj_faces_reversed = MEM_malloc_arrayN<bool>(len, __func__);
325 adj_faces[0] = uint(i);
326 for (uint k = 1; k < len; k++) {
327 adj_faces[k] = MOD_SOLIDIFY_EMPTY_TAG;
328 }
329 adj_faces_reversed[0] = reversed;
331 *ref = OldEdgeFaceRef{adj_faces, len, adj_faces_reversed, 1};
332 edge_adj_faces[edge] = ref;
333 }
334 else {
335 for (uint k = 1; k < old_face_edge_ref->faces_len; k++) {
336 if (old_face_edge_ref->faces[k] == MOD_SOLIDIFY_EMPTY_TAG) {
337 old_face_edge_ref->faces[k] = uint(i);
338 old_face_edge_ref->faces_reversed[k] = reversed;
339 break;
340 }
341 }
342 }
343 }
344 }
345 }
346
347 float edgedir[3] = {0, 0, 0};
348 uint *vert_adj_edges_len = MEM_calloc_arrayN<uint>(verts_num, __func__);
349
350 /* Calculate edge lengths and len vert_adj edges. */
351 {
352 bool *face_singularity = MEM_calloc_arrayN<bool>(faces_num, __func__);
353
354 const float merge_tolerance_sqr = smd->merge_tolerance * smd->merge_tolerance;
355 uint *combined_verts = MEM_calloc_arrayN<uint>(verts_num, __func__);
356
357 for (uint i = 0; i < edges_num; i++) {
358 const int2 &edge = orig_edges[i];
359 if (edge_adj_faces_len[i] > 0) {
360 uint v1 = vm[edge[0]];
361 uint v2 = vm[edge[1]];
362 if (v1 == v2) {
363 continue;
364 }
365
366 if (v2 < v1) {
367 std::swap(v1, v2);
368 }
369 sub_v3_v3v3(edgedir, orig_mvert_co[v2], orig_mvert_co[v1]);
370 orig_edge_lengths[i] = len_squared_v3(edgedir);
371
372 if (orig_edge_lengths[i] <= merge_tolerance_sqr) {
373 /* Merge verts. But first check if that would create a higher face count. */
374 /* This check is very slow. It would need the vertex edge links to get
375 * accelerated that are not yet available at this point. */
376 bool can_merge = true;
377 for (uint k = 0; k < edges_num && can_merge; k++) {
378 if (k != i && edge_adj_faces_len[k] > 0 &&
379 (ELEM(vm[orig_edges[k][0]], v1, v2) != ELEM(vm[orig_edges[k][1]], v1, v2)))
380 {
381 for (uint j = 0; j < edge_adj_faces[k]->faces_len && can_merge; j++) {
382 const blender::IndexRange face = orig_faces[edge_adj_faces[k]->faces[j]];
383 uint changes = 0;
384 int cur = face.size() - 1;
385 for (int next = 0; next < face.size() && changes <= 2; next++) {
386 uint cur_v = vm[orig_corner_verts[face[cur]]];
387 uint next_v = vm[orig_corner_verts[face[next]]];
388 changes += (ELEM(cur_v, v1, v2) != ELEM(next_v, v1, v2));
389 cur = next;
390 }
391 can_merge = can_merge && changes <= 2;
392 }
393 }
394 }
395
396 if (!can_merge) {
397 orig_edge_lengths[i] = 0.0f;
398 vert_adj_edges_len[v1]++;
399 vert_adj_edges_len[v2]++;
400 continue;
401 }
402
403 mul_v3_fl(edgedir,
404 (combined_verts[v2] + 1) /
405 float(combined_verts[v1] + combined_verts[v2] + 2));
406 add_v3_v3(orig_mvert_co[v1], edgedir);
407 for (uint j = v2; j < verts_num; j++) {
408 if (vm[j] == v2) {
409 vm[j] = v1;
410 }
411 }
412 vert_adj_edges_len[v1] += vert_adj_edges_len[v2];
413 vert_adj_edges_len[v2] = 0;
414 combined_verts[v1] += combined_verts[v2] + 1;
415
416 if (do_shell) {
417 new_loops_num -= edge_adj_faces_len[i] * 2;
418 }
419
420 edge_adj_faces_len[i] = 0;
421 MEM_freeN(edge_adj_faces[i]->faces);
422 MEM_freeN(edge_adj_faces[i]->faces_reversed);
423 MEM_freeN(edge_adj_faces[i]);
424 edge_adj_faces[i] = nullptr;
425 }
426 else {
427 orig_edge_lengths[i] = sqrtf(orig_edge_lengths[i]);
428 vert_adj_edges_len[v1]++;
429 vert_adj_edges_len[v2]++;
430 }
431 }
432 }
433 /* remove zero faces in a second pass */
434 for (uint i = 0; i < edges_num; i++) {
435 const int2 &edge = orig_edges[i];
436 const uint v1 = vm[edge[0]];
437 const uint v2 = vm[edge[1]];
438 if (v1 == v2 && edge_adj_faces[i]) {
439 /* Remove faces. */
440 for (uint j = 0; j < edge_adj_faces[i]->faces_len; j++) {
441 const uint face = edge_adj_faces[i]->faces[j];
442 if (!face_singularity[face]) {
443 bool is_singularity = true;
444 for (const int vert : orig_corner_verts.slice(orig_faces[face])) {
445 if (vm[vert] != v1) {
446 is_singularity = false;
447 break;
448 }
449 }
450 if (is_singularity) {
451 face_singularity[face] = true;
452 /* remove from final mesh face count */
453 if (do_shell) {
454 new_faces_num -= 2;
455 }
456 }
457 }
458 }
459
460 if (do_shell) {
461 new_loops_num -= edge_adj_faces_len[i] * 2;
462 }
463
464 edge_adj_faces_len[i] = 0;
465 MEM_freeN(edge_adj_faces[i]->faces);
466 MEM_freeN(edge_adj_faces[i]->faces_reversed);
467 MEM_freeN(edge_adj_faces[i]);
468 edge_adj_faces[i] = nullptr;
469 }
470 }
471
472 MEM_freeN(face_singularity);
473 MEM_freeN(combined_verts);
474 }
475
476 /* Create vert_adj_edges for verts. */
477 {
478 for (uint i = 0; i < edges_num; i++) {
479 const int2 &edge = orig_edges[i];
480 if (edge_adj_faces_len[i] > 0) {
481 const int vs[2] = {int(vm[edge[0]]), int(vm[edge[1]])};
482 uint invalid_edge_index = 0;
483 bool invalid_edge_reversed = false;
484 for (uint j = 0; j < 2; j++) {
485 const int vert = vs[j];
486 const uint len = vert_adj_edges_len[vert];
487 if (len > 0) {
488 OldVertEdgeRef *old_edge_vert_ref = vert_adj_edges[vert];
489 if (old_edge_vert_ref == nullptr) {
490 uint *adj_edges = MEM_calloc_arrayN<uint>(len, __func__);
491 adj_edges[0] = i;
492 for (uint k = 1; k < len; k++) {
493 adj_edges[k] = MOD_SOLIDIFY_EMPTY_TAG;
494 }
496 *ref = OldVertEdgeRef{adj_edges, 1};
497 vert_adj_edges[vert] = ref;
498 }
499 else {
500 const uint *f = old_edge_vert_ref->edges;
501 for (uint k = 0; k < len && k <= old_edge_vert_ref->edges_len; k++, f++) {
502 const uint edge = old_edge_vert_ref->edges[k];
503 if (edge == MOD_SOLIDIFY_EMPTY_TAG || k == old_edge_vert_ref->edges_len) {
504 old_edge_vert_ref->edges[k] = i;
505 old_edge_vert_ref->edges_len++;
506 break;
507 }
508 if (vm[orig_edges[edge][0]] == vs[1 - j]) {
509 invalid_edge_index = edge + 1;
510 invalid_edge_reversed = (j == 0);
511 break;
512 }
513 if (vm[orig_edges[edge][1]] == vs[1 - j]) {
514 invalid_edge_index = edge + 1;
515 invalid_edge_reversed = (j == 1);
516 break;
517 }
518 }
519 if (invalid_edge_index) {
520 if (j == 1) {
521 /* Should never actually be executed. */
522 vert_adj_edges[vs[0]]->edges_len--;
523 }
524 break;
525 }
526 }
527 }
528 }
529 /* Remove zero faces that are in shape of an edge. */
530 if (invalid_edge_index) {
531 const uint tmp = invalid_edge_index - 1;
532 invalid_edge_index = i;
533 i = tmp;
534 OldEdgeFaceRef *i_adj_faces = edge_adj_faces[i];
535 OldEdgeFaceRef *invalid_adj_faces = edge_adj_faces[invalid_edge_index];
536 uint j = 0;
537 for (uint k = 0; k < i_adj_faces->faces_len; k++) {
538 for (uint l = 0; l < invalid_adj_faces->faces_len; l++) {
539 if (i_adj_faces->faces[k] == invalid_adj_faces->faces[l] &&
540 i_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG)
541 {
542 i_adj_faces->faces[k] = MOD_SOLIDIFY_EMPTY_TAG;
543 invalid_adj_faces->faces[l] = MOD_SOLIDIFY_EMPTY_TAG;
544 j++;
545 }
546 }
547 }
548 /* remove from final face count */
549 if (do_shell) {
550 new_faces_num -= 2 * j;
551 new_loops_num -= 4 * j;
552 }
553 const uint len = i_adj_faces->faces_len + invalid_adj_faces->faces_len - 2 * j;
554 uint *adj_faces = MEM_malloc_arrayN<uint>(len, __func__);
555 bool *adj_faces_loops_reversed = MEM_malloc_arrayN<bool>(len, __func__);
556 /* Clean merge of adj_faces. */
557 j = 0;
558 for (uint k = 0; k < i_adj_faces->faces_len; k++) {
559 if (i_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG) {
560 adj_faces[j] = i_adj_faces->faces[k];
561 adj_faces_loops_reversed[j++] = i_adj_faces->faces_reversed[k];
562 }
563 }
564 for (uint k = 0; k < invalid_adj_faces->faces_len; k++) {
565 if (invalid_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG) {
566 adj_faces[j] = invalid_adj_faces->faces[k];
567 adj_faces_loops_reversed[j++] = (invalid_edge_reversed !=
568 invalid_adj_faces->faces_reversed[k]);
569 }
570 }
571 BLI_assert(j == len);
572 edge_adj_faces_len[invalid_edge_index] = 0;
573 edge_adj_faces_len[i] = len;
574 MEM_freeN(i_adj_faces->faces);
575 MEM_freeN(i_adj_faces->faces_reversed);
576 i_adj_faces->faces_len = len;
577 i_adj_faces->faces = adj_faces;
578 i_adj_faces->faces_reversed = adj_faces_loops_reversed;
579 i_adj_faces->used += invalid_adj_faces->used;
580 MEM_freeN(invalid_adj_faces->faces);
581 MEM_freeN(invalid_adj_faces->faces_reversed);
582 MEM_freeN(invalid_adj_faces);
583 edge_adj_faces[invalid_edge_index] = i_adj_faces;
584 /* Reset counter to continue. */
585 i = invalid_edge_index;
586 }
587 }
588 }
589 }
590
591 MEM_freeN(vert_adj_edges_len);
592
593 /* Filter duplicate faces. */
594 {
595 const int2 *edge = orig_edges.data();
596 /* Iterate over edges and only check the faces around an edge for duplicates
597 * (performance optimization). */
598 for (uint i = 0; i < edges_num; i++, edge++) {
599 if (edge_adj_faces_len[i] > 0) {
600 const OldEdgeFaceRef *adj_faces = edge_adj_faces[i];
601 uint adj_len = adj_faces->faces_len;
602 /* Not that #adj_len doesn't need to equal edge_adj_faces_len anymore
603 * because #adj_len is shared when a face got collapsed to an edge. */
604 if (adj_len > 1) {
605 /* For each face pair check if they have equal verts. */
606 for (uint j = 0; j < adj_len; j++) {
607 const uint face = adj_faces->faces[j];
608 const int j_loopstart = orig_faces[face].start();
609 const int totloop = orig_faces[face].size();
610 const uint j_first_v = vm[orig_corner_verts[j_loopstart]];
611 for (uint k = j + 1; k < adj_len; k++) {
612 if (orig_faces[adj_faces->faces[k]].size() != totloop) {
613 continue;
614 }
615 /* Find first face first loop vert in second face loops. */
616 const int k_loopstart = orig_faces[adj_faces->faces[k]].start();
617 int l;
618 {
619 const int *corner_vert = &orig_corner_verts[k_loopstart];
620 for (l = 0; l < totloop && vm[*corner_vert] != j_first_v; l++, corner_vert++) {
621 /* Pass. */
622 }
623 }
624 if (l == totloop) {
625 continue;
626 }
627 /* Check if all following loops have equal verts. */
628 const bool reversed = adj_faces->faces_reversed[j] != adj_faces->faces_reversed[k];
629 const int count_dir = reversed ? -1 : 1;
630 bool has_diff = false;
631 for (int m = 0, n = l + totloop; m < totloop && !has_diff; m++, n += count_dir) {
632 const int vert = orig_corner_verts[j_loopstart + m];
633 has_diff = has_diff ||
634 vm[vert] != vm[orig_corner_verts[k_loopstart + n % totloop]];
635 }
636 /* If the faces are equal, discard one (j). */
637 if (!has_diff) {
638 uint del_loops = 0;
639 for (uint m = 0; m < totloop; m++) {
640 const int e = orig_corner_edges[j_loopstart + m];
641 OldEdgeFaceRef *e_adj_faces = edge_adj_faces[e];
642 if (e_adj_faces) {
643 uint face_index = j;
644 uint *e_adj_faces_faces = e_adj_faces->faces;
645 bool *e_adj_faces_reversed = e_adj_faces->faces_reversed;
646 const uint faces_len = e_adj_faces->faces_len;
647 if (e_adj_faces_faces != adj_faces->faces) {
648 /* Find index of e in #adj_faces. */
649 for (face_index = 0;
650 face_index < faces_len && e_adj_faces_faces[face_index] != face;
651 face_index++)
652 {
653 /* Pass. */
654 }
655 /* If not found. */
656 if (face_index == faces_len) {
657 continue;
658 }
659 }
660 else {
661 /* If we shrink #edge_adj_faces[i] we need to update this field. */
662 adj_len--;
663 }
664 memmove(e_adj_faces_faces + face_index,
665 e_adj_faces_faces + face_index + 1,
666 (faces_len - face_index - 1) * sizeof(*e_adj_faces_faces));
667 memmove(e_adj_faces_reversed + face_index,
668 e_adj_faces_reversed + face_index + 1,
669 (faces_len - face_index - 1) * sizeof(*e_adj_faces_reversed));
670 e_adj_faces->faces_len--;
671 if (edge_adj_faces_len[e] > 0) {
672 edge_adj_faces_len[e]--;
673 if (edge_adj_faces_len[e] == 0) {
674 e_adj_faces->used--;
675 edge_adj_faces[e] = nullptr;
676 }
677 }
678 else if (e_adj_faces->used > 1) {
679 for (uint n = 0; n < edges_num; n++) {
680 if (edge_adj_faces[n] == e_adj_faces && edge_adj_faces_len[n] > 0) {
681 edge_adj_faces_len[n]--;
682 if (edge_adj_faces_len[n] == 0) {
683 edge_adj_faces[n]->used--;
684 edge_adj_faces[n] = nullptr;
685 }
686 break;
687 }
688 }
689 }
690 del_loops++;
691 }
692 }
693 if (do_shell) {
694 new_faces_num -= 2;
695 new_loops_num -= 2 * del_loops;
696 }
697 break;
698 }
699 }
700 }
701 }
702 }
703 }
704 }
705
706 /* Create #NewEdgeRef array. */
707 {
708 for (uint i = 0; i < edges_num; i++) {
709 const int2 &edge = orig_edges[i];
710 const uint v1 = vm[edge[0]];
711 const uint v2 = vm[edge[1]];
712 if (edge_adj_faces_len[i] > 0) {
713 if (LIKELY(orig_edge_lengths[i] > FLT_EPSILON)) {
714 sub_v3_v3v3(edgedir, orig_mvert_co[v2], orig_mvert_co[v1]);
715 mul_v3_fl(edgedir, 1.0f / orig_edge_lengths[i]);
716 }
717 else {
718 /* Smart fallback. */
719 /* This makes merging non essential, but correct
720 * merging will still give way better results. */
721 float pos[3];
722 copy_v3_v3(pos, orig_mvert_co[v2]);
723
724 OldVertEdgeRef *link1 = vert_adj_edges[v1];
725 float v1_dir[3];
726 zero_v3(v1_dir);
727 for (int j = 0; j < link1->edges_len; j++) {
728 uint e = link1->edges[j];
729 if (edge_adj_faces_len[e] > 0 && e != i) {
730 uint other_v =
731 vm[vm[orig_edges[e][0]] == v1 ? orig_edges[e][1] : orig_edges[e][0]];
732 sub_v3_v3v3(edgedir, orig_mvert_co[other_v], pos);
733 add_v3_v3(v1_dir, edgedir);
734 }
735 }
736 OldVertEdgeRef *link2 = vert_adj_edges[v2];
737 float v2_dir[3];
738 zero_v3(v2_dir);
739 for (int j = 0; j < link2->edges_len; j++) {
740 uint e = link2->edges[j];
741 if (edge_adj_faces_len[e] > 0 && e != i) {
742 uint other_v =
743 vm[vm[orig_edges[e][0]] == v2 ? orig_edges[e][1] : orig_edges[e][0]];
744 sub_v3_v3v3(edgedir, orig_mvert_co[other_v], pos);
745 add_v3_v3(v2_dir, edgedir);
746 }
747 }
748 sub_v3_v3v3(edgedir, v2_dir, v1_dir);
749 float len = normalize_v3(edgedir);
750 if (len == 0.0f) {
751 edgedir[0] = 0.0f;
752 edgedir[1] = 0.0f;
753 edgedir[2] = 1.0f;
754 }
755 }
756
757 OldEdgeFaceRef *adj_faces = edge_adj_faces[i];
758 const uint adj_len = adj_faces->faces_len;
759 const uint *adj_faces_faces = adj_faces->faces;
760 const bool *adj_faces_reversed = adj_faces->faces_reversed;
761 uint new_edges_len = 0;
762 FaceKeyPair *sorted_faces = MEM_malloc_arrayN<FaceKeyPair>(adj_len, __func__);
763 if (adj_len > 1) {
764 new_edges_len = adj_len;
765 /* Get keys for sorting. */
766 float ref_nor[3] = {0, 0, 0};
767 float nor[3];
768 for (uint j = 0; j < adj_len; j++) {
769 const bool reverse = adj_faces_reversed[j];
770 const uint face_i = adj_faces_faces[j];
771 if (reverse) {
772 negate_v3_v3(nor, face_nors[face_i]);
773 }
774 else {
775 copy_v3_v3(nor, face_nors[face_i]);
776 }
777 float d = 1;
778 if (orig_faces[face_i].size() > 3) {
779 d = project_v3_v3(nor, edgedir);
780 if (LIKELY(d != 0)) {
781 d = normalize_v3(nor);
782 }
783 else {
784 d = 1;
785 }
786 }
787 if (UNLIKELY(d == 0.0f)) {
788 sorted_faces[j].angle = 0.0f;
789 }
790 else if (j == 0) {
791 copy_v3_v3(ref_nor, nor);
792 sorted_faces[j].angle = 0.0f;
793 }
794 else {
795 float angle = angle_signed_on_axis_normalized_v3v3_v3(nor, ref_nor, edgedir);
796 sorted_faces[j].angle = -angle;
797 }
798 sorted_faces[j].face =
799 &face_sides_arr[adj_faces_faces[j] * 2 + (adj_faces_reversed[j] ? 1 : 0)];
800 }
801 /* Sort faces by order around the edge (keep order in faces,
802 * reversed and face_angles the same). */
803 qsort(sorted_faces, adj_len, sizeof(*sorted_faces), comp_float_int_pair);
804 }
805 else {
806 new_edges_len = 2;
807 sorted_faces[0].face =
808 &face_sides_arr[adj_faces_faces[0] * 2 + (adj_faces_reversed[0] ? 1 : 0)];
809 if (do_rim) {
810 /* Only add the loops parallel to the edge for now. */
811 new_loops_num += 2;
812 new_faces_num++;
813 }
814 }
815
816 /* Create a list of new edges and fill it. */
817 NewEdgeRef **new_edges = MEM_malloc_arrayN<NewEdgeRef *>(new_edges_len + 1, __func__);
818 new_edges[new_edges_len] = nullptr;
819 NewFaceRef *faces[2];
820 for (uint j = 0; j < new_edges_len; j++) {
821 float angle;
822 if (adj_len > 1) {
823 const uint next_j = j + 1 == adj_len ? 0 : j + 1;
824 faces[0] = sorted_faces[j].face;
825 faces[1] = sorted_faces[next_j].face->reversed ? sorted_faces[next_j].face - 1 :
826 sorted_faces[next_j].face + 1;
827 angle = sorted_faces[next_j].angle - sorted_faces[j].angle;
828 if (angle < 0) {
829 angle += 2 * M_PI;
830 }
831 }
832 else {
833 faces[0] = sorted_faces[0].face->reversed ? sorted_faces[0].face - j :
834 sorted_faces[0].face + j;
835 faces[1] = nullptr;
836 angle = 0;
837 }
838 NewEdgeRef *edge_data = MEM_mallocN<NewEdgeRef>(__func__);
839 uint edge_data_edge_index = MOD_SOLIDIFY_EMPTY_TAG;
840 if (do_shell || (adj_len == 1 && do_rim)) {
841 edge_data_edge_index = 0;
842 }
843
844 NewEdgeRef new_edge_ref{};
845 new_edge_ref.old_edge = i;
846 new_edge_ref.faces[0] = faces[0];
847 new_edge_ref.faces[1] = faces[1];
848 new_edge_ref.link_edge_groups[0] = nullptr;
849 new_edge_ref.link_edge_groups[1] = nullptr;
850 new_edge_ref.angle = angle;
851 new_edge_ref.new_edge = edge_data_edge_index;
852 *edge_data = new_edge_ref;
853
854 new_edges[j] = edge_data;
855 for (uint k = 0; k < 2; k++) {
856 if (faces[k] != nullptr) {
857 for (int l = 0; l < faces[k]->face.size(); l++) {
858 const int edge = orig_corner_edges[faces[k]->face.start() + l];
859 if (edge_adj_faces[edge] == edge_adj_faces[i]) {
860 if (edge != i && orig_edge_data_arr[edge] == nullptr) {
861 orig_edge_data_arr[edge] = new_edges;
862 }
863 faces[k]->link_edges[l] = edge_data;
864 break;
865 }
866 }
867 }
868 }
869 }
870 MEM_freeN(sorted_faces);
871 orig_edge_data_arr[i] = new_edges;
872 if (do_shell || (adj_len == 1 && do_rim)) {
873 new_edges_num += new_edges_len;
874 }
875 }
876 }
877 }
878
879 for (uint i = 0; i < edges_num; i++) {
880 if (edge_adj_faces[i]) {
881 if (edge_adj_faces[i]->used > 1) {
882 edge_adj_faces[i]->used--;
883 }
884 else {
885 MEM_freeN(edge_adj_faces[i]->faces);
886 MEM_freeN(edge_adj_faces[i]->faces_reversed);
887 MEM_freeN(edge_adj_faces[i]);
888 }
889 }
890 }
891 MEM_freeN(edge_adj_faces);
892 }
893
894 /* Create sorted edge groups for every vert. */
895 {
896 OldVertEdgeRef **adj_edges_ptr = vert_adj_edges;
897 for (uint i = 0; i < verts_num; i++, adj_edges_ptr++) {
898 if (*adj_edges_ptr != nullptr && (*adj_edges_ptr)->edges_len >= 2) {
899 EdgeGroup *edge_groups;
900
901 int eg_index = -1;
902 bool contains_long_groups = false;
903 uint topo_groups = 0;
904
905 /* Initial sorted creation. */
906 {
907 const uint *adj_edges = (*adj_edges_ptr)->edges;
908 const uint tot_adj_edges = (*adj_edges_ptr)->edges_len;
909
910 uint unassigned_edges_len = 0;
911 for (uint j = 0; j < tot_adj_edges; j++) {
912 NewEdgeRef **new_edges = orig_edge_data_arr[adj_edges[j]];
913 /* TODO: check where the null pointer come from,
914 * because there should not be any... */
915 if (new_edges) {
916 /* count the number of new edges around the original vert */
917 while (*new_edges) {
918 unassigned_edges_len++;
919 new_edges++;
920 }
921 }
922 }
923 NewEdgeRef **unassigned_edges = MEM_malloc_arrayN<NewEdgeRef *>(unassigned_edges_len,
924 __func__);
925 for (uint j = 0, k = 0; j < tot_adj_edges; j++) {
926 NewEdgeRef **new_edges = orig_edge_data_arr[adj_edges[j]];
927 if (new_edges) {
928 while (*new_edges) {
929 unassigned_edges[k++] = *new_edges;
930 new_edges++;
931 }
932 }
933 }
934
935 /* An edge group will always contain min 2 edges
936 * so max edge group count can be calculated. */
937 uint edge_groups_len = unassigned_edges_len / 2;
938 edge_groups = MEM_calloc_arrayN<EdgeGroup>(edge_groups_len + 1, __func__);
939
940 uint assigned_edges_len = 0;
941 NewEdgeRef *found_edge = nullptr;
942 uint found_edge_index = 0;
943 bool insert_at_start = false;
944 uint eg_capacity = 5;
945 NewFaceRef *eg_track_faces[2] = {nullptr, nullptr};
946 NewFaceRef *last_open_edge_track = nullptr;
947
948 while (assigned_edges_len < unassigned_edges_len) {
949 found_edge = nullptr;
950 insert_at_start = false;
951 if (eg_index >= 0 && edge_groups[eg_index].edges_len == 0) {
952 /* Called every time a new group was started in the last iteration. */
953 /* Find an unused edge to start the next group
954 * and setup variables to start creating it. */
955 uint j = 0;
956 NewEdgeRef *edge = nullptr;
957 while (!edge && j < unassigned_edges_len) {
958 edge = unassigned_edges[j++];
959 if (edge && last_open_edge_track &&
960 (edge->faces[0] != last_open_edge_track || edge->faces[1] != nullptr))
961 {
962 edge = nullptr;
963 }
964 }
965 if (!edge && last_open_edge_track) {
966 topo_groups++;
967 last_open_edge_track = nullptr;
968 edge_groups[eg_index].topo_group++;
969 j = 0;
970 while (!edge && j < unassigned_edges_len) {
971 edge = unassigned_edges[j++];
972 }
973 }
974 else if (!last_open_edge_track && eg_index > 0) {
975 topo_groups++;
976 edge_groups[eg_index].topo_group++;
977 }
978 BLI_assert(edge != nullptr);
979 found_edge_index = j - 1;
980 found_edge = edge;
981 if (!last_open_edge_track && vm[orig_edges[edge->old_edge][0]] == i) {
982 eg_track_faces[0] = edge->faces[0];
983 eg_track_faces[1] = edge->faces[1];
984 if (edge->faces[1] == nullptr) {
985 last_open_edge_track = edge->faces[0]->reversed ? edge->faces[0] - 1 :
986 edge->faces[0] + 1;
987 }
988 }
989 else {
990 eg_track_faces[0] = edge->faces[1];
991 eg_track_faces[1] = edge->faces[0];
992 }
993 }
994 else if (eg_index >= 0) {
995 NewEdgeRef **edge_ptr = unassigned_edges;
996 for (found_edge_index = 0; found_edge_index < unassigned_edges_len;
997 found_edge_index++, edge_ptr++)
998 {
999 if (*edge_ptr) {
1000 NewEdgeRef *edge = *edge_ptr;
1001 if (edge->faces[0] == eg_track_faces[1]) {
1002 insert_at_start = false;
1003 eg_track_faces[1] = edge->faces[1];
1004 found_edge = edge;
1005 if (edge->faces[1] == nullptr) {
1006 edge_groups[eg_index].is_orig_closed = false;
1007 last_open_edge_track = edge->faces[0]->reversed ? edge->faces[0] - 1 :
1008 edge->faces[0] + 1;
1009 }
1010 break;
1011 }
1012 if (edge->faces[0] == eg_track_faces[0]) {
1013 insert_at_start = true;
1014 eg_track_faces[0] = edge->faces[1];
1015 found_edge = edge;
1016 if (edge->faces[1] == nullptr) {
1017 edge_groups[eg_index].is_orig_closed = false;
1018 }
1019 break;
1020 }
1021 if (edge->faces[1] != nullptr) {
1022 if (edge->faces[1] == eg_track_faces[1]) {
1023 insert_at_start = false;
1024 eg_track_faces[1] = edge->faces[0];
1025 found_edge = edge;
1026 break;
1027 }
1028 if (edge->faces[1] == eg_track_faces[0]) {
1029 insert_at_start = true;
1030 eg_track_faces[0] = edge->faces[0];
1031 found_edge = edge;
1032 break;
1033 }
1034 }
1035 }
1036 }
1037 }
1038 if (found_edge) {
1039 unassigned_edges[found_edge_index] = nullptr;
1040 assigned_edges_len++;
1041 const uint needed_capacity = edge_groups[eg_index].edges_len + 1;
1042 if (needed_capacity > eg_capacity) {
1043 eg_capacity = needed_capacity + 1;
1044 NewEdgeRef **new_eg = MEM_calloc_arrayN<NewEdgeRef *>(eg_capacity, __func__);
1045 if (insert_at_start) {
1046 memcpy(new_eg + 1,
1047 edge_groups[eg_index].edges,
1048 edge_groups[eg_index].edges_len * sizeof(*new_eg));
1049 }
1050 else {
1051 memcpy(new_eg,
1052 edge_groups[eg_index].edges,
1053 edge_groups[eg_index].edges_len * sizeof(*new_eg));
1054 }
1055 MEM_freeN(edge_groups[eg_index].edges);
1056 edge_groups[eg_index].edges = new_eg;
1057 }
1058 else if (insert_at_start) {
1059 memmove(edge_groups[eg_index].edges + 1,
1060 edge_groups[eg_index].edges,
1061 edge_groups[eg_index].edges_len * sizeof(*edge_groups[eg_index].edges));
1062 }
1063 edge_groups[eg_index].edges[insert_at_start ? 0 : edge_groups[eg_index].edges_len] =
1064 found_edge;
1065 edge_groups[eg_index].edges_len++;
1066 if (edge_groups[eg_index].edges[edge_groups[eg_index].edges_len - 1]->faces[1] !=
1067 nullptr)
1068 {
1069 last_open_edge_track = nullptr;
1070 }
1071 if (edge_groups[eg_index].edges_len > 3) {
1072 contains_long_groups = true;
1073 }
1074 }
1075 else {
1076 /* called on first iteration to clean up the eg_index = -1 and start the first group,
1077 * or when the current group is found to be complete (no new found_edge) */
1078 eg_index++;
1079 BLI_assert(eg_index < edge_groups_len);
1080 eg_capacity = 5;
1081 NewEdgeRef **edges = MEM_calloc_arrayN<NewEdgeRef *>(eg_capacity, __func__);
1082
1083 EdgeGroup edge_group{};
1084 edge_group.valid = true;
1085 edge_group.edges = edges;
1086 edge_group.edges_len = 0;
1088 edge_group.is_orig_closed = true;
1089 edge_group.is_even_split = false;
1090 edge_group.split = 0;
1091 edge_group.is_singularity = false;
1092 edge_group.topo_group = topo_groups;
1093 zero_v3(edge_group.co);
1094 zero_v3(edge_group.no);
1095 edge_group.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1096 edge_groups[eg_index] = edge_group;
1097
1098 eg_track_faces[0] = nullptr;
1099 eg_track_faces[1] = nullptr;
1100 }
1101 }
1102 /* #eg_index is the number of groups from here on. */
1103 eg_index++;
1104 /* #topo_groups is the number of topo groups from here on. */
1105 topo_groups++;
1106
1107 MEM_freeN(unassigned_edges);
1108
1109 /* TODO: reshape the edge_groups array to its actual size
1110 * after writing is finished to save on memory. */
1111 }
1112
1113 /* Split of long self intersection groups */
1114 {
1115 uint splits = 0;
1116 if (contains_long_groups) {
1117 uint add_index = 0;
1118 for (uint j = 0; j < eg_index; j++) {
1119 const uint edges_len = edge_groups[j + add_index].edges_len;
1120 if (edges_len > 3) {
1121 bool has_doubles = false;
1122 bool *doubles = MEM_calloc_arrayN<bool>(edges_len, __func__);
1123 EdgeGroup g = edge_groups[j + add_index];
1124 for (uint k = 0; k < edges_len; k++) {
1125 for (uint l = k + 1; l < edges_len; l++) {
1126 if (g.edges[k]->old_edge == g.edges[l]->old_edge) {
1127 doubles[k] = true;
1128 doubles[l] = true;
1129 has_doubles = true;
1130 }
1131 }
1132 }
1133 if (has_doubles) {
1134 const uint prior_splits = splits;
1135 const uint prior_index = add_index;
1136 int unique_start = -1;
1137 int first_unique_end = -1;
1138 int last_split = -1;
1139 int first_split = -1;
1140 bool first_even_split = false;
1141 uint real_k = 0;
1142 while (real_k < edges_len ||
1143 (g.is_orig_closed &&
1144 (real_k <=
1145 (first_unique_end == -1 ? 0 : first_unique_end) + int(edges_len) ||
1146 first_split != last_split)))
1147 {
1148 const uint k = real_k % edges_len;
1149 if (!doubles[k]) {
1150 if (first_unique_end != -1 && unique_start == -1) {
1151 unique_start = int(real_k);
1152 }
1153 }
1154 else if (first_unique_end == -1) {
1155 first_unique_end = int(k);
1156 }
1157 else if (unique_start != -1) {
1158 const uint split = ((uint(unique_start) + real_k + 1) / 2) % edges_len;
1159 const bool is_even_split = ((uint(unique_start) + real_k) & 1);
1160 if (last_split != -1) {
1161 /* Override g on first split (no insert). */
1162 if (prior_splits != splits) {
1163 memmove(edge_groups + j + add_index + 1,
1164 edge_groups + j + add_index,
1165 (uint(eg_index) - j) * sizeof(*edge_groups));
1166 add_index++;
1167 }
1168 if (last_split > split) {
1169 const uint edges_len_group = (split + edges_len) - uint(last_split);
1170 NewEdgeRef **edges = MEM_malloc_arrayN<NewEdgeRef *>(edges_len_group,
1171 __func__);
1172 memcpy(edges,
1173 g.edges + last_split,
1174 (edges_len - uint(last_split)) * sizeof(*edges));
1175 memcpy(edges + (edges_len - uint(last_split)),
1176 g.edges,
1177 split * sizeof(*edges));
1178
1179 EdgeGroup edge_group{};
1180 edge_group.valid = true;
1181 edge_group.edges = edges;
1182 edge_group.edges_len = edges_len_group;
1184 edge_group.is_orig_closed = g.is_orig_closed;
1185 edge_group.is_even_split = is_even_split;
1186 edge_group.split = add_index - prior_index + 1 + uint(!g.is_orig_closed);
1187 edge_group.is_singularity = false;
1188 edge_group.topo_group = g.topo_group;
1189 zero_v3(edge_group.co);
1190 zero_v3(edge_group.no);
1191 edge_group.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1192 edge_groups[j + add_index] = edge_group;
1193 }
1194 else {
1195 const uint edges_len_group = split - uint(last_split);
1196 NewEdgeRef **edges = MEM_malloc_arrayN<NewEdgeRef *>(edges_len_group,
1197 __func__);
1198 memcpy(edges, g.edges + last_split, edges_len_group * sizeof(*edges));
1199
1200 EdgeGroup edge_group{};
1201 edge_group.valid = true;
1202 edge_group.edges = edges;
1203 edge_group.edges_len = edges_len_group;
1205 edge_group.is_orig_closed = g.is_orig_closed;
1206 edge_group.is_even_split = is_even_split;
1207 edge_group.split = add_index - prior_index + 1 + uint(!g.is_orig_closed);
1208 edge_group.is_singularity = false;
1209 edge_group.topo_group = g.topo_group;
1210 zero_v3(edge_group.co);
1211 zero_v3(edge_group.no);
1212 edge_group.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1213 edge_groups[j + add_index] = edge_group;
1214 }
1215 splits++;
1216 }
1217 last_split = int(split);
1218 if (first_split == -1) {
1219 first_split = int(split);
1220 first_even_split = is_even_split;
1221 }
1222 unique_start = -1;
1223 }
1224 real_k++;
1225 }
1226 if (first_split != -1) {
1227 if (!g.is_orig_closed) {
1228 if (prior_splits != splits) {
1229 memmove(edge_groups + (j + prior_index + 1),
1230 edge_groups + (j + prior_index),
1231 (uint(eg_index) + add_index - (j + prior_index)) *
1232 sizeof(*edge_groups));
1233 memmove(edge_groups + (j + add_index + 2),
1234 edge_groups + (j + add_index + 1),
1235 (uint(eg_index) - j) * sizeof(*edge_groups));
1236 add_index++;
1237 }
1238 else {
1239 memmove(edge_groups + (j + add_index + 2),
1240 edge_groups + (j + add_index + 1),
1241 (uint(eg_index) - j - 1) * sizeof(*edge_groups));
1242 }
1243 NewEdgeRef **edges = MEM_malloc_arrayN<NewEdgeRef *>(uint(first_split),
1244 __func__);
1245 memcpy(edges, g.edges, uint(first_split) * sizeof(*edges));
1246
1247 EdgeGroup edge_group_a{};
1248 edge_group_a.valid = true;
1249 edge_group_a.edges = edges;
1250 edge_group_a.edges_len = uint(first_split);
1252 edge_group_a.is_orig_closed = g.is_orig_closed;
1253 edge_group_a.is_even_split = first_even_split;
1254 edge_group_a.split = 1;
1255 edge_group_a.is_singularity = false;
1256 edge_group_a.topo_group = g.topo_group;
1257 zero_v3(edge_group_a.co);
1258 zero_v3(edge_group_a.no);
1259 edge_group_a.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1260 edge_groups[j + prior_index] = edge_group_a;
1261
1262 add_index++;
1263 splits++;
1264 edges = MEM_malloc_arrayN<NewEdgeRef *>(edges_len - uint(last_split),
1265 __func__);
1266 memcpy(edges,
1267 g.edges + last_split,
1268 (edges_len - uint(last_split)) * sizeof(*edges));
1269
1270 EdgeGroup edge_group_b{};
1271 edge_group_b.valid = true;
1272 edge_group_b.edges = edges;
1273 edge_group_b.edges_len = (edges_len - uint(last_split));
1275 edge_group_b.is_orig_closed = g.is_orig_closed;
1276 edge_group_b.is_even_split = false;
1277 edge_group_b.split = add_index - prior_index + 1;
1278 edge_group_b.is_singularity = false;
1279 edge_group_b.topo_group = g.topo_group;
1280 zero_v3(edge_group_b.co);
1281 zero_v3(edge_group_b.no);
1282 edge_group_b.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1283 edge_groups[j + add_index] = edge_group_b;
1284 }
1285 if (prior_splits != splits) {
1286 MEM_freeN(g.edges);
1287 }
1288 }
1289 if (first_unique_end != -1 && prior_splits == splits) {
1290 has_singularities = true;
1291 edge_groups[j + add_index].is_singularity = true;
1292 }
1293 }
1294 MEM_freeN(doubles);
1295 }
1296 }
1297 }
1298 }
1299
1300 orig_vert_groups_arr[i] = edge_groups;
1301 /* Count new edges, loops, faces and add to link_edge_groups. */
1302 {
1303 uint new_verts = 0;
1304 bool contains_open_splits = false;
1305 uint open_edges = 0;
1306 uint contains_splits = 0;
1307 uint last_added = 0;
1308 uint first_added = 0;
1309 bool first_set = false;
1310 for (EdgeGroup *g = edge_groups; g->valid; g++) {
1311 NewEdgeRef **e = g->edges;
1312 for (uint j = 0; j < g->edges_len; j++, e++) {
1313 const uint flip = uint(vm[orig_edges[(*e)->old_edge][1]] == i);
1314 BLI_assert(flip || vm[orig_edges[(*e)->old_edge][0]] == i);
1315 (*e)->link_edge_groups[flip] = g;
1316 }
1317 uint added = 0;
1318 if (do_shell || (do_rim && !g->is_orig_closed)) {
1319 BLI_assert(g->new_vert == MOD_SOLIDIFY_EMPTY_TAG);
1320 g->new_vert = new_verts_num++;
1321 if (do_rim || (do_shell && g->split)) {
1322 new_verts++;
1323 contains_splits += (g->split != 0);
1324 contains_open_splits |= g->split && !g->is_orig_closed;
1325 added = g->split;
1326 }
1327 }
1328 open_edges += uint(added < last_added);
1329 if (!first_set) {
1330 first_set = true;
1331 first_added = added;
1332 }
1333 last_added = added;
1334 if (!(g + 1)->valid || g->topo_group != (g + 1)->topo_group) {
1335 if (new_verts > 2) {
1336 new_faces_num++;
1337 new_edges_num += new_verts;
1338 open_edges += uint(first_added < last_added);
1339 open_edges -= uint(open_edges && !contains_open_splits);
1340 if (do_shell && do_rim) {
1341 new_loops_num += new_verts * 2;
1342 }
1343 else if (do_shell) {
1344 new_loops_num += new_verts * 2 - open_edges;
1345 }
1346 else { // do_rim
1347 new_loops_num += new_verts * 2 + open_edges - contains_splits;
1348 }
1349 }
1350 else if (new_verts == 2) {
1351 new_edges_num++;
1352 new_loops_num += 2u - uint(!(do_rim && do_shell) && contains_open_splits);
1353 }
1354 new_verts = 0;
1355 contains_open_splits = false;
1356 contains_splits = 0;
1357 open_edges = 0;
1358 last_added = 0;
1359 first_added = 0;
1360 first_set = false;
1361 }
1362 }
1363 }
1364 }
1365 }
1366 }
1367
1368 /* Free vert_adj_edges memory. */
1369 {
1370 uint i = 0;
1371 for (OldVertEdgeRef **p = vert_adj_edges; i < verts_num; i++, p++) {
1372 if (*p) {
1373 MEM_freeN((*p)->edges);
1374 MEM_freeN(*p);
1375 }
1376 }
1377 MEM_freeN(vert_adj_edges);
1378 }
1379
1380 /* TODO: create_regions if fix_intersections. */
1381
1382 /* General use pointer for #EdgeGroup iteration. */
1383 EdgeGroup **gs_ptr;
1384
1385 /* Calculate EdgeGroup vertex coordinates. */
1386 {
1387 float *face_weight = nullptr;
1388
1389 if (do_flat_faces) {
1390 face_weight = MEM_malloc_arrayN<float>(faces_num, __func__);
1391
1392 for (const int i : orig_faces.index_range()) {
1393 float scalar_vgroup = 1.0f;
1394 for (const int vert : orig_corner_verts.slice(orig_faces[i])) {
1395 const MDeformVert *dv = &dvert[vert];
1396 if (defgrp_invert) {
1397 scalar_vgroup = min_ff(1.0f - BKE_defvert_find_weight(dv, defgrp_index),
1398 scalar_vgroup);
1399 }
1400 else {
1401 scalar_vgroup = min_ff(BKE_defvert_find_weight(dv, defgrp_index), scalar_vgroup);
1402 }
1403 }
1404 scalar_vgroup = offset_fac_vg + (scalar_vgroup * offset_fac_vg_inv);
1405 face_weight[i] = scalar_vgroup;
1406 }
1407 }
1408
1409 gs_ptr = orig_vert_groups_arr;
1410 for (uint i = 0; i < verts_num; i++, gs_ptr++) {
1411 if (*gs_ptr) {
1412 for (EdgeGroup *g = *gs_ptr; g->valid; g++) {
1413 if (!g->is_singularity) {
1414 float *nor = g->no;
1415 /* During vertex position calculation, the algorithm decides if it wants to disable the
1416 * boundary fix to maintain correct thickness. If the used algorithm does not produce a
1417 * free move direction (move_nor), it can use approximate_free_direction to decide on
1418 * a movement direction based on the connected edges. */
1419 float move_nor[3] = {0, 0, 0};
1420 bool disable_boundary_fix = (smd->nonmanifold_boundary_mode ==
1422 (g->is_orig_closed || g->split));
1423 bool approximate_free_direction = false;
1424 /* Constraints Method. */
1426 NewEdgeRef *first_edge = nullptr;
1427 NewEdgeRef **edge_ptr = g->edges;
1428 /* Contains normal and offset `[nx, ny, nz, ofs]`. */
1429 float(*planes_queue)[4] = MEM_malloc_arrayN<float[4]>(g->edges_len + 1, __func__);
1430 uint queue_index = 0;
1431
1432 float fallback_nor[3];
1433 float fallback_ofs = 0.0f;
1434
1435 const bool cycle = (g->is_orig_closed && !g->split) || g->is_even_split;
1436 for (uint k = 0; k < g->edges_len; k++, edge_ptr++) {
1437 if (!(k & 1) || (!cycle && k == g->edges_len - 1)) {
1438 NewEdgeRef *edge = *edge_ptr;
1439 for (uint l = 0; l < 2; l++) {
1440 NewFaceRef *face = edge->faces[l];
1441 if (face && (first_edge == nullptr ||
1442 (first_edge->faces[0] != face && first_edge->faces[1] != face)))
1443 {
1444 float ofs = face->reversed ? ofs_back_clamped : ofs_front_clamped;
1445 /* Use face_weight here to make faces thinner. */
1446 if (do_flat_faces) {
1447 ofs *= face_weight[face->index];
1448 }
1449
1450 if (!null_faces[face->index]) {
1451 /* And plane to the queue. */
1452 mul_v3_v3fl(planes_queue[queue_index],
1453 face_nors[face->index],
1454 face->reversed ? -1 : 1);
1455 planes_queue[queue_index++][3] = ofs;
1456 }
1457 else {
1458 /* Just use this approximate normal of the null face if there is no other
1459 * normal to use. */
1460 mul_v3_v3fl(fallback_nor, face_nors[face->index], face->reversed ? -1 : 1);
1461 fallback_ofs = ofs;
1462 }
1463 }
1464 }
1465 if ((cycle && k == 0) || (!cycle && k + 3 >= g->edges_len)) {
1466 first_edge = edge;
1467 }
1468 }
1469 }
1470 if (queue_index > 2) {
1471 /* Find the two most different normals. */
1472 float min_p = 2.0f;
1473 uint min_n0 = 0;
1474 uint min_n1 = 0;
1475 for (uint k = 0; k < queue_index; k++) {
1476 for (uint m = k + 1; m < queue_index; m++) {
1477 float p = dot_v3v3(planes_queue[k], planes_queue[m]);
1478 if (p < min_p) {
1479 min_p = p;
1480 min_n0 = k;
1481 min_n1 = m;
1482 }
1483 }
1484 }
1485 /* Put the two found normals, first in the array queue. */
1486 if (min_n1 != 0) {
1487 swap_v4_v4(planes_queue[min_n0], planes_queue[0]);
1488 swap_v4_v4(planes_queue[min_n1], planes_queue[1]);
1489 }
1490 else {
1491 swap_v4_v4(planes_queue[min_n0], planes_queue[1]);
1492 }
1493 /* Find the third most important/different normal. */
1494 min_p = 1.0f;
1495 min_n1 = 2;
1496 float max_p = -1.0f;
1497 for (uint k = 2; k < queue_index; k++) {
1498 max_p = max_ff(dot_v3v3(planes_queue[0], planes_queue[k]),
1499 dot_v3v3(planes_queue[1], planes_queue[k]));
1500 if (max_p <= min_p) {
1501 min_p = max_p;
1502 min_n1 = k;
1503 }
1504 }
1505 swap_v4_v4(planes_queue[min_n1], planes_queue[2]);
1506 }
1507 /* Remove/average duplicate normals in planes_queue. */
1508 while (queue_index > 2) {
1509 uint best_n0 = 0;
1510 uint best_n1 = 0;
1511 float best_p = -1.0f;
1512 float best_ofs_diff = 0.0f;
1513 for (uint k = 0; k < queue_index; k++) {
1514 for (uint m = k + 1; m < queue_index; m++) {
1515 float p = dot_v3v3(planes_queue[m], planes_queue[k]);
1516 float ofs_diff = fabsf(planes_queue[m][3] - planes_queue[k][3]);
1517 if (p > best_p + FLT_EPSILON || (p >= best_p && ofs_diff < best_ofs_diff)) {
1518 best_p = p;
1519 best_ofs_diff = ofs_diff;
1520 best_n0 = k;
1521 best_n1 = m;
1522 }
1523 }
1524 }
1525 /* Make sure there are no equal planes. This threshold is crucial for the
1526 * methods below to work without numerical issues. */
1527 if (best_p < 0.98f) {
1528 break;
1529 }
1530 add_v3_v3(planes_queue[best_n0], planes_queue[best_n1]);
1531 normalize_v3(planes_queue[best_n0]);
1532 planes_queue[best_n0][3] = (planes_queue[best_n0][3] + planes_queue[best_n1][3]) *
1533 0.5f;
1534 queue_index--;
1535 memmove(planes_queue + best_n1,
1536 planes_queue + best_n1 + 1,
1537 (queue_index - best_n1) * sizeof(*planes_queue));
1538 }
1539 const uint size = queue_index;
1540 /* If there is more than 2 planes at this vertex, the boundary fix should be disabled
1541 * to stay at the correct thickness for all the faces. This is not very good in
1542 * practice though, since that will almost always disable the boundary fix. Instead
1543 * introduce a threshold which decides whether the boundary fix can be used without
1544 * major thickness changes. If the following constant is 1.0, it would always
1545 * prioritize correct thickness. At 0.7 the thickness is allowed to change a bit if
1546 * necessary for the fix (~10%). Note this only applies if a boundary fix is used. */
1547 const float boundary_fix_threshold = 0.7f;
1548 if (size > 3) {
1549 /* Use the most general least squares method to find the best position. */
1550 float mat[3][3];
1551 zero_m3(mat);
1552 for (int k = 0; k < 3; k++) {
1553 for (int m = 0; m < size; m++) {
1554 madd_v3_v3fl(mat[k], planes_queue[m], planes_queue[m][k]);
1555 }
1556 /* Add a small epsilon to ensure the invert is going to work.
1557 * This addition makes the inverse more stable and the results
1558 * seem to get more precise. */
1559 mat[k][k] += 5e-5f;
1560 }
1561 /* NOTE: this matrix invert fails if there is less than 3 different normals. */
1562 invert_m3(mat);
1563 zero_v3(nor);
1564 for (int k = 0; k < size; k++) {
1565 madd_v3_v3fl(nor, planes_queue[k], planes_queue[k][3]);
1566 }
1567 mul_v3_m3v3(nor, mat, nor);
1568
1569 if (!disable_boundary_fix) {
1570 /* Figure out if the approximate boundary fix can get use here. */
1571 float greatest_angle_cos = 1.0f;
1572 for (uint k = 0; k < 2; k++) {
1573 for (uint m = 2; m < size; m++) {
1574 float p = dot_v3v3(planes_queue[m], planes_queue[k]);
1575 greatest_angle_cos = std::min(p, greatest_angle_cos);
1576 }
1577 }
1578 if (greatest_angle_cos > boundary_fix_threshold) {
1579 approximate_free_direction = true;
1580 }
1581 else {
1582 disable_boundary_fix = true;
1583 }
1584 }
1585 }
1586 else if (size > 1) {
1587 /* When up to 3 constraint normals are found, there is a simple solution. */
1588 const float stop_explosion = 0.999f - fabsf(smd->offset_fac) * 0.05f;
1589 const float q = dot_v3v3(planes_queue[0], planes_queue[1]);
1590 float d = 1.0f - q * q;
1591 cross_v3_v3v3(move_nor, planes_queue[0], planes_queue[1]);
1592 normalize_v3(move_nor);
1593 if (d > FLT_EPSILON * 10 && q < stop_explosion) {
1594 d = 1.0f / d;
1595 mul_v3_fl(planes_queue[0], (planes_queue[0][3] - planes_queue[1][3] * q) * d);
1596 mul_v3_fl(planes_queue[1], (planes_queue[1][3] - planes_queue[0][3] * q) * d);
1597 }
1598 else {
1599 d = 1.0f / (fabsf(q) + 1.0f);
1600 mul_v3_fl(planes_queue[0], planes_queue[0][3] * d);
1601 mul_v3_fl(planes_queue[1], planes_queue[1][3] * d);
1602 }
1603 add_v3_v3v3(nor, planes_queue[0], planes_queue[1]);
1604 if (size == 3) {
1605 d = dot_v3v3(planes_queue[2], move_nor);
1606 /* The following threshold ignores the third plane if it is almost orthogonal to
1607 * the still free direction. */
1608 if (fabsf(d) > 0.02f) {
1609 float tmp[3];
1610 madd_v3_v3v3fl(tmp, nor, planes_queue[2], -planes_queue[2][3]);
1611 mul_v3_v3fl(tmp, move_nor, dot_v3v3(planes_queue[2], tmp) / d);
1612 sub_v3_v3(nor, tmp);
1613 /* Disable boundary fix if the constraints would be majorly unsatisfied. */
1614 if (fabsf(d) > 1.0f - boundary_fix_threshold) {
1615 disable_boundary_fix = true;
1616 }
1617 }
1618 }
1619 approximate_free_direction = false;
1620 }
1621 else if (size == 1) {
1622 /* Face corner case. */
1623 mul_v3_v3fl(nor, planes_queue[0], planes_queue[0][3]);
1624 if (g->edges_len > 2) {
1625 disable_boundary_fix = true;
1626 approximate_free_direction = true;
1627 }
1628 }
1629 else {
1630 /* Fallback case for null faces. */
1631 mul_v3_v3fl(nor, fallback_nor, fallback_ofs);
1632 disable_boundary_fix = true;
1633 }
1634 MEM_freeN(planes_queue);
1635 }
1636 /* Fixed/Even Method. */
1637 else {
1638 float total_angle = 0;
1639 float total_angle_back = 0;
1640 NewEdgeRef *first_edge = nullptr;
1641 NewEdgeRef **edge_ptr = g->edges;
1642 float face_nor[3];
1643 float nor_back[3] = {0, 0, 0};
1644 bool has_back = false;
1645 bool has_front = false;
1646 bool cycle = (g->is_orig_closed && !g->split) || g->is_even_split;
1647 for (uint k = 0; k < g->edges_len; k++, edge_ptr++) {
1648 if (!(k & 1) || (!cycle && k == g->edges_len - 1)) {
1649 NewEdgeRef *edge = *edge_ptr;
1650 for (uint l = 0; l < 2; l++) {
1651 NewFaceRef *face = edge->faces[l];
1652 if (face && (first_edge == nullptr ||
1653 (first_edge->faces[0] != face && first_edge->faces[1] != face)))
1654 {
1655 float angle = 1.0f;
1656 float ofs = face->reversed ? -ofs_back_clamped : ofs_front_clamped;
1657 /* Use face_weight here to make faces thinner. */
1658 if (do_flat_faces) {
1659 ofs *= face_weight[face->index];
1660 }
1661
1662 if (smd->nonmanifold_offset_mode ==
1664 {
1665 int corner_next = face->face.start();
1666 int corner = corner_next + (face->face.size() - 1);
1667 int corner_prev = corner - 1;
1668
1669 for (int m = 0;
1670 m < face->face.size() && vm[orig_corner_verts[corner]] != i;
1671 m++, corner_next++)
1672 {
1673 corner_prev = corner;
1674 corner = corner_next;
1675 }
1676 angle = angle_v3v3v3(orig_mvert_co[vm[orig_corner_verts[corner_prev]]],
1677 orig_mvert_co[i],
1678 orig_mvert_co[vm[orig_corner_verts[corner_next]]]);
1679 if (face->reversed) {
1680 total_angle_back += angle * ofs * ofs;
1681 }
1682 else {
1683 total_angle += angle * ofs * ofs;
1684 }
1685 }
1686 else {
1687 if (face->reversed) {
1688 total_angle_back++;
1689 }
1690 else {
1691 total_angle++;
1692 }
1693 }
1694 mul_v3_v3fl(face_nor, face_nors[face->index], angle * ofs);
1695 if (face->reversed) {
1696 add_v3_v3(nor_back, face_nor);
1697 has_back = true;
1698 }
1699 else {
1700 add_v3_v3(nor, face_nor);
1701 has_front = true;
1702 }
1703 }
1704 }
1705 if ((cycle && k == 0) || (!cycle && k + 3 >= g->edges_len)) {
1706 first_edge = edge;
1707 }
1708 }
1709 }
1710
1711 /* Set normal length with selected method. */
1713 if (has_front) {
1714 float length_sq = len_squared_v3(nor);
1715 if (LIKELY(length_sq > FLT_EPSILON)) {
1716 mul_v3_fl(nor, total_angle / length_sq);
1717 }
1718 }
1719 if (has_back) {
1720 float length_sq = len_squared_v3(nor_back);
1721 if (LIKELY(length_sq > FLT_EPSILON)) {
1722 mul_v3_fl(nor_back, total_angle_back / length_sq);
1723 }
1724 if (!has_front) {
1725 copy_v3_v3(nor, nor_back);
1726 }
1727 }
1728 if (has_front && has_back) {
1729 float nor_length = len_v3(nor);
1730 float nor_back_length = len_v3(nor_back);
1731 float q = dot_v3v3(nor, nor_back);
1732 if (LIKELY(fabsf(q) > FLT_EPSILON)) {
1733 q /= nor_length * nor_back_length;
1734 }
1735 float d = 1.0f - q * q;
1736 if (LIKELY(d > FLT_EPSILON)) {
1737 d = 1.0f / d;
1738 if (LIKELY(nor_length > FLT_EPSILON)) {
1739 mul_v3_fl(nor, (1 - nor_back_length * q / nor_length) * d);
1740 }
1741 if (LIKELY(nor_back_length > FLT_EPSILON)) {
1742 mul_v3_fl(nor_back, (1 - nor_length * q / nor_back_length) * d);
1743 }
1744 add_v3_v3(nor, nor_back);
1745 }
1746 else {
1747 mul_v3_fl(nor, 0.5f);
1748 mul_v3_fl(nor_back, 0.5f);
1749 add_v3_v3(nor, nor_back);
1750 }
1751 }
1752 }
1753 else {
1754 if (has_front && total_angle > FLT_EPSILON) {
1755 mul_v3_fl(nor, 1.0f / total_angle);
1756 }
1757 if (has_back && total_angle_back > FLT_EPSILON) {
1758 mul_v3_fl(nor_back, 1.0f / total_angle_back);
1759 add_v3_v3(nor, nor_back);
1760 if (has_front && total_angle > FLT_EPSILON) {
1761 mul_v3_fl(nor, 0.5f);
1762 }
1763 }
1764 }
1765 /* Set move_nor for boundary fix. */
1766 if (!disable_boundary_fix && g->edges_len > 2) {
1767 approximate_free_direction = true;
1768 }
1769 else {
1770 disable_boundary_fix = true;
1771 }
1772 }
1773 if (approximate_free_direction) {
1774 /* Set move_nor for boundary fix. */
1775 NewEdgeRef **edge_ptr = g->edges + 1;
1776 float tmp[3];
1777 int k;
1778 for (k = 1; k + 1 < g->edges_len; k++, edge_ptr++) {
1779 const int2 &edge = orig_edges[(*edge_ptr)->old_edge];
1781 tmp, orig_mvert_co[vm[edge[0]] == i ? edge[1] : edge[0]], orig_mvert_co[i]);
1782 add_v3_v3(move_nor, tmp);
1783 }
1784 if (k == 1) {
1785 disable_boundary_fix = true;
1786 }
1787 else {
1788 disable_boundary_fix = normalize_v3(move_nor) == 0.0f;
1789 }
1790 }
1791 /* Fix boundary verts. */
1792 if (!disable_boundary_fix) {
1793 /* Constraint normal, nor * constr_nor == 0 after this fix. */
1794 float constr_nor[3];
1795 const int2 &e0_edge = orig_edges[g->edges[0]->old_edge];
1796 const int2 &e1_edge = orig_edges[g->edges[g->edges_len - 1]->old_edge];
1797 float e0[3];
1798 float e1[3];
1799 sub_v3_v3v3(e0,
1800 orig_mvert_co[vm[e0_edge[0]] == i ? e0_edge[1] : e0_edge[0]],
1801 orig_mvert_co[i]);
1802 sub_v3_v3v3(e1,
1803 orig_mvert_co[vm[e1_edge[0]] == i ? e1_edge[1] : e1_edge[0]],
1804 orig_mvert_co[i]);
1806 cross_v3_v3v3(constr_nor, e0, e1);
1807 normalize_v3(constr_nor);
1808 }
1809 else {
1812 float f0[3];
1813 float f1[3];
1814 if (g->edges[0]->faces[0]->reversed) {
1815 negate_v3_v3(f0, face_nors[g->edges[0]->faces[0]->index]);
1816 }
1817 else {
1818 copy_v3_v3(f0, face_nors[g->edges[0]->faces[0]->index]);
1819 }
1820 if (g->edges[g->edges_len - 1]->faces[0]->reversed) {
1821 negate_v3_v3(f1, face_nors[g->edges[g->edges_len - 1]->faces[0]->index]);
1822 }
1823 else {
1824 copy_v3_v3(f1, face_nors[g->edges[g->edges_len - 1]->faces[0]->index]);
1825 }
1826 float n0[3];
1827 float n1[3];
1828 cross_v3_v3v3(n0, e0, f0);
1829 cross_v3_v3v3(n1, f1, e1);
1830 normalize_v3(n0);
1831 normalize_v3(n1);
1832 add_v3_v3v3(constr_nor, n0, n1);
1833 normalize_v3(constr_nor);
1834 }
1835 float d = dot_v3v3(constr_nor, move_nor);
1836 /* Only allow the thickness to increase about 10 times. */
1837 if (fabsf(d) > 0.1f) {
1838 mul_v3_fl(move_nor, dot_v3v3(constr_nor, nor) / d);
1839 sub_v3_v3(nor, move_nor);
1840 }
1841 }
1842 float scalar_vgroup = 1;
1843 /* Use vertex group. */
1844 if (dvert && !do_flat_faces) {
1845 const MDeformVert *dv = &dvert[i];
1846 if (defgrp_invert) {
1847 scalar_vgroup = 1.0f - BKE_defvert_find_weight(dv, defgrp_index);
1848 }
1849 else {
1850 scalar_vgroup = BKE_defvert_find_weight(dv, defgrp_index);
1851 }
1852 scalar_vgroup = offset_fac_vg + (scalar_vgroup * offset_fac_vg_inv);
1853 }
1854 /* Do clamping. */
1855 if (do_clamp) {
1856 if (do_angle_clamp) {
1857 if (g->edges_len > 2) {
1858 float min_length = 0;
1859 float angle = 0.5f * M_PI;
1860 uint k = 0;
1861 for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) {
1862 float length = orig_edge_lengths[(*p)->old_edge];
1863 float e_ang = (*p)->angle;
1864 angle = std::max(e_ang, angle);
1865 if (length < min_length || k == 0) {
1866 min_length = length;
1867 }
1868 }
1869 float cos_ang = cosf(angle * 0.5f);
1870 if (cos_ang > 0) {
1871 float max_off = min_length * 0.5f / cos_ang;
1872 if (max_off < offset * 0.5f) {
1873 scalar_vgroup *= max_off / offset * 2;
1874 }
1875 }
1876 }
1877 }
1878 else {
1879 float min_length = 0;
1880 uint k = 0;
1881 for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) {
1882 float length = orig_edge_lengths[(*p)->old_edge];
1883 if (length < min_length || k == 0) {
1884 min_length = length;
1885 }
1886 }
1887 if (min_length < offset) {
1888 scalar_vgroup *= min_length / offset;
1889 }
1890 }
1891 }
1892 mul_v3_fl(nor, scalar_vgroup);
1893 add_v3_v3v3(g->co, nor, orig_mvert_co[i]);
1894 }
1895 else {
1896 copy_v3_v3(g->co, orig_mvert_co[i]);
1897 }
1898 }
1899 }
1900 }
1901
1902 if (do_flat_faces) {
1903 MEM_freeN(face_weight);
1904 }
1905 }
1906
1907 MEM_freeN(orig_mvert_co);
1908 if (null_faces) {
1909 MEM_freeN(null_faces);
1910 }
1911
1912 /* TODO: create vertdata for intersection fixes (intersection fixing per topology region). */
1913
1914 /* Correction for adjacent one sided groups around a vert to
1915 * prevent edge duplicates and null faces. */
1916 uint(*singularity_edges)[2] = nullptr;
1917 uint totsingularity = 0;
1918 if (has_singularities) {
1919 has_singularities = false;
1920 uint i = 0;
1921 uint singularity_edges_len = 1;
1922 singularity_edges = MEM_malloc_arrayN<uint[2]>(singularity_edges_len, __func__);
1923 for (NewEdgeRef ***new_edges = orig_edge_data_arr; i < edges_num; i++, new_edges++) {
1924 if (*new_edges && (do_shell || edge_adj_faces_len[i] == 1) && (**new_edges)->old_edge == i) {
1925 for (NewEdgeRef **l = *new_edges; *l; l++) {
1926 if ((*l)->link_edge_groups[0]->is_singularity &&
1927 (*l)->link_edge_groups[1]->is_singularity)
1928 {
1929 const uint v1 = (*l)->link_edge_groups[0]->new_vert;
1930 const uint v2 = (*l)->link_edge_groups[1]->new_vert;
1931 bool exists_already = false;
1932 uint j = 0;
1933 for (uint(*p)[2] = singularity_edges; j < totsingularity; p++, j++) {
1934 if (((*p)[0] == v1 && (*p)[1] == v2) || ((*p)[0] == v2 && (*p)[1] == v1)) {
1935 exists_already = true;
1936 break;
1937 }
1938 }
1939 if (!exists_already) {
1940 has_singularities = true;
1941 if (singularity_edges_len <= totsingularity) {
1942 singularity_edges_len = totsingularity + 1;
1943 singularity_edges = static_cast<uint(*)[2]>(
1944 MEM_reallocN_id(singularity_edges,
1945 singularity_edges_len * sizeof(*singularity_edges),
1946 __func__));
1947 }
1948 singularity_edges[totsingularity][0] = v1;
1949 singularity_edges[totsingularity][1] = v2;
1950 totsingularity++;
1951 if (edge_adj_faces_len[i] == 1 && do_rim) {
1952 new_loops_num -= 2;
1953 new_faces_num--;
1954 }
1955 }
1956 else {
1957 new_edges_num--;
1958 }
1959 }
1960 }
1961 }
1962 }
1963 }
1964
1965 /* Create Mesh *result with proper capacity. */
1967 mesh, int(new_verts_num), int(new_edges_num), int(new_faces_num), int(new_loops_num));
1968
1969 blender::MutableSpan<float3> vert_positions = result->vert_positions_for_write();
1970 blender::MutableSpan<int2> edges = result->edges_for_write();
1971 blender::MutableSpan<int> face_offsets = result->face_offsets_for_write();
1972 blender::MutableSpan<int> corner_verts = result->corner_verts_for_write();
1973 blender::MutableSpan<int> corner_edges = result->corner_edges_for_write();
1974
1975 int *origindex_edge = static_cast<int *>(
1976 CustomData_get_layer_for_write(&result->edge_data, CD_ORIGINDEX, result->edges_num));
1977 int *origindex_face = static_cast<int *>(
1978 CustomData_get_layer_for_write(&result->face_data, CD_ORIGINDEX, result->faces_num));
1979
1980 float *result_edge_bweight = static_cast<float *>(CustomData_get_layer_named_for_write(
1981 &result->edge_data, CD_PROP_FLOAT, "bevel_weight_edge", result->edges_num));
1982 if (!result_edge_bweight && (bevel_convex != 0.0f || orig_vert_bweight != nullptr)) {
1983 result_edge_bweight = static_cast<float *>(CustomData_add_layer_named(&result->edge_data,
1986 result->edges_num,
1987 "bevel_weight_edge"));
1988 }
1989
1990 /* Checks that result has dvert data. */
1991 MDeformVert *dst_dvert = nullptr;
1992 if (shell_defgrp_index != -1 || rim_defgrp_index != -1) {
1993 dst_dvert = result->deform_verts_for_write().data();
1994 }
1995
1996 /* Get vertex crease layer and ensure edge creases are active if vertex creases are found, since
1997 * they will introduce edge creases in the used custom interpolation method. */
1998 const float *vertex_crease = static_cast<const float *>(
1999 CustomData_get_layer_named(&mesh->vert_data, CD_PROP_FLOAT, "crease_vert"));
2000 float *result_edge_crease = nullptr;
2001 if (vertex_crease || orig_edge_crease) {
2002 result_edge_crease = static_cast<float *>(CustomData_get_layer_named_for_write(
2003 &result->edge_data, CD_PROP_FLOAT, "crease_edge", result->edges_num));
2004 if (!result_edge_crease) {
2005 result_edge_crease = (float *)CustomData_add_layer_named(
2006 &result->edge_data, CD_PROP_FLOAT, CD_SET_DEFAULT, result->edges_num, "crease_edge");
2007 }
2008 /* delete all vertex creases in the result if a rim is used. */
2009 if (do_rim) {
2010 CustomData_free_layer_named(&result->vert_data, "crease_vert");
2011 }
2012 }
2013
2014 /* Make_new_verts. */
2015 {
2016 gs_ptr = orig_vert_groups_arr;
2017 for (uint i = 0; i < verts_num; i++, gs_ptr++) {
2018 EdgeGroup *gs = *gs_ptr;
2019 if (gs) {
2020 for (EdgeGroup *g = gs; g->valid; g++) {
2021 if (g->new_vert != MOD_SOLIDIFY_EMPTY_TAG) {
2023 &mesh->vert_data, &result->vert_data, int(i), int(g->new_vert), 1);
2024 copy_v3_v3(vert_positions[g->new_vert], g->co);
2025 }
2026 }
2027 }
2028 }
2029 }
2030
2031 /* Make edges. */
2032 {
2033 uint i = 0;
2034 edge_index += totsingularity;
2035 for (NewEdgeRef ***new_edges = orig_edge_data_arr; i < edges_num; i++, new_edges++) {
2036 if (*new_edges && (do_shell || edge_adj_faces_len[i] == 1) && (**new_edges)->old_edge == i) {
2037 for (NewEdgeRef **l = *new_edges; *l; l++) {
2038 if ((*l)->new_edge != MOD_SOLIDIFY_EMPTY_TAG) {
2039 const uint v1 = (*l)->link_edge_groups[0]->new_vert;
2040 const uint v2 = (*l)->link_edge_groups[1]->new_vert;
2041 uint insert = edge_index;
2042 if (has_singularities && ((*l)->link_edge_groups[0]->is_singularity &&
2043 (*l)->link_edge_groups[1]->is_singularity))
2044 {
2045 uint j = 0;
2046 for (uint(*p)[2] = singularity_edges; j < totsingularity; p++, j++) {
2047 if (((*p)[0] == v1 && (*p)[1] == v2) || ((*p)[0] == v2 && (*p)[1] == v1)) {
2048 insert = j;
2049 break;
2050 }
2051 }
2052 BLI_assert(insert == j);
2053 }
2054 else {
2055 edge_index++;
2056 }
2057 CustomData_copy_data(&mesh->edge_data, &result->edge_data, int(i), int(insert), 1);
2060 edges[insert][0] = v1;
2061 edges[insert][1] = v2;
2062 if (result_edge_crease) {
2063 result_edge_crease[insert] = orig_edge_crease ? orig_edge_crease[(*l)->old_edge] :
2064 0.0f;
2065 }
2066 if (result_edge_bweight) {
2067 result_edge_bweight[insert] = orig_edge_bweight ? orig_edge_bweight[(*l)->old_edge] :
2068 0.0f;
2069 }
2070 if (bevel_convex != 0.0f && (*l)->faces[1] != nullptr) {
2071 result_edge_bweight[insert] = clamp_f(
2072 result_edge_bweight[insert] +
2073 ((*l)->angle > M_PI + FLT_EPSILON ?
2074 clamp_f(bevel_convex, 0.0f, 1.0f) :
2075 ((*l)->angle < M_PI - FLT_EPSILON ? clamp_f(bevel_convex, -1.0f, 0.0f) :
2076 0)),
2077 0.0f,
2078 1.0f);
2079 }
2080 (*l)->new_edge = insert;
2081 }
2082 }
2083 }
2084 }
2085 }
2086 if (singularity_edges) {
2087 MEM_freeN(singularity_edges);
2088 }
2089
2090 /* DEBUG CODE FOR BUG-FIXING (can not be removed because every bug-fix needs this badly!). */
2091#if 0
2092 {
2093 /* this code will output the content of orig_vert_groups_arr.
2094 * in orig_vert_groups_arr these conditions must be met for every vertex:
2095 * - new_edge value should have no duplicates
2096 * - every old_edge value should appear twice
2097 * - every group should have at least two members (edges)
2098 * NOTE: that there can be vertices that only have one group. They are called singularities.
2099 * These vertices will only have one side (there is no way of telling apart front
2100 * from back like on a mobius strip)
2101 */
2102
2103 /* Debug output format:
2104 * <original vertex id>:
2105 * {
2106 * { <old edge id>/<new edge id>, } \
2107 * (tg:<topology group id>)(s:<is split group>,c:<is closed group (before splitting)>)
2108 * }
2109 */
2110 gs_ptr = orig_vert_groups_arr;
2111 for (uint i = 0; i < verts_num; i++, gs_ptr++) {
2112 EdgeGroup *gs = *gs_ptr;
2113 /* check if the vertex is present (may be dissolved because of proximity) */
2114 if (gs) {
2115 printf("%d:\n", i);
2116 for (EdgeGroup *g = gs; g->valid; g++) {
2117 NewEdgeRef **e = g->edges;
2118 for (uint j = 0; j < g->edges_len; j++, e++) {
2119 printf("%u/%d, ", (*e)->old_edge, int(*e)->new_edge);
2120 }
2121 printf("(tg:%u)(s:%u,c:%d)\n", g->topo_group, g->split, g->is_orig_closed);
2122 }
2123 }
2124 }
2125 }
2126#endif
2127 const bke::AttributeAccessor src_attributes = mesh->attributes();
2128 const VArraySpan src_material_index = *src_attributes.lookup<int>("material_index",
2130 bke::MutableAttributeAccessor dst_attributes = result->attributes_for_write();
2131 bke::SpanAttributeWriter dst_material_index = dst_attributes.lookup_or_add_for_write_span<int>(
2132 "material_index", bke::AttrDomain::Face);
2133
2134 /* Make boundary edges/faces. */
2135 {
2136 gs_ptr = orig_vert_groups_arr;
2137 for (uint i = 0; i < verts_num; i++, gs_ptr++) {
2138 EdgeGroup *gs = *gs_ptr;
2139 if (gs) {
2140 EdgeGroup *g = gs;
2141 EdgeGroup *g2 = gs;
2142 EdgeGroup *last_g = nullptr;
2143 EdgeGroup *first_g = nullptr;
2144 float mv_crease = vertex_crease ? vertex_crease[i] : 0.0f;
2145 float mv_bweight = orig_vert_bweight ? orig_vert_bweight[i] : 0.0f;
2146 /* Data calculation cache. */
2147 float max_crease;
2148 float last_max_crease = 0.0f;
2149 float first_max_crease = 0.0f;
2150 float max_bweight;
2151 float last_max_bweight = 0.0f;
2152 float first_max_bweight = 0.0f;
2153 for (uint j = 0; g->valid; g++) {
2154 if ((do_rim && !g->is_orig_closed) || (do_shell && g->split)) {
2155 max_crease = 0;
2156 max_bweight = 0;
2157
2158 BLI_assert(g->edges_len >= 2);
2159
2160 if (g->edges_len == 2) {
2161 if (result_edge_crease) {
2162 if (orig_edge_crease) {
2163 max_crease = min_ff(orig_edge_crease[g->edges[0]->old_edge],
2164 orig_edge_crease[g->edges[1]->old_edge]);
2165 }
2166 else {
2167 max_crease = 0.0f;
2168 }
2169 }
2170 }
2171 else {
2172 for (uint k = 1; k < g->edges_len - 1; k++) {
2173 const uint orig_edge_index = g->edges[k]->old_edge;
2174 if (result_edge_crease) {
2175 if (orig_edge_crease && orig_edge_crease[orig_edge_index] > max_crease) {
2176 max_crease = orig_edge_crease[orig_edge_index];
2177 }
2178 }
2179 if (g->edges[k]->new_edge != MOD_SOLIDIFY_EMPTY_TAG) {
2180 if (result_edge_bweight) {
2181 float bweight = result_edge_bweight[g->edges[k]->new_edge];
2182 max_bweight = std::max(bweight, max_bweight);
2183 }
2184 }
2185 }
2186 }
2187
2188 const float bweight_open_edge =
2189 orig_edge_bweight ?
2190 min_ff(orig_edge_bweight[g->edges[0]->old_edge],
2191 orig_edge_bweight[g->edges[g->edges_len - 1]->old_edge]) :
2192 0.0f;
2193 if (bweight_open_edge > 0) {
2194 max_bweight = min_ff(bweight_open_edge, max_bweight);
2195 }
2196 else {
2197 if (bevel_convex < 0.0f) {
2198 max_bweight = 0;
2199 }
2200 }
2201 if (!first_g) {
2202 first_g = g;
2203 first_max_crease = max_crease;
2204 first_max_bweight = max_bweight;
2205 }
2206 else {
2207 last_g->open_face_edge = edge_index;
2209 &result->edge_data,
2210 int(last_g->edges[0]->old_edge),
2211 int(edge_index),
2212 1);
2213 if (origindex_edge) {
2214 origindex_edge[edge_index] = ORIGINDEX_NONE;
2215 }
2216 edges[edge_index][0] = last_g->new_vert;
2217 edges[edge_index][1] = g->new_vert;
2218 if (result_edge_crease) {
2219 result_edge_crease[edge_index] = max_ff(mv_crease,
2220 min_ff(last_max_crease, max_crease));
2221 }
2222 if (result_edge_bweight) {
2223 result_edge_bweight[edge_index] = max_ff(mv_bweight,
2224 min_ff(last_max_bweight, max_bweight));
2225 }
2226 edge_index++;
2227 }
2228 last_g = g;
2229 last_max_crease = max_crease;
2230 last_max_bweight = max_bweight;
2231 j++;
2232 }
2233 if (!(g + 1)->valid || g->topo_group != (g + 1)->topo_group) {
2234 if (j == 2) {
2235 last_g->open_face_edge = edge_index - 1;
2236 }
2237 if (j > 2) {
2239 &result->edge_data,
2240 int(last_g->edges[0]->old_edge),
2241 int(edge_index),
2242 1);
2243 if (origindex_edge) {
2244 origindex_edge[edge_index] = ORIGINDEX_NONE;
2245 }
2246 last_g->open_face_edge = edge_index;
2247 edges[edge_index][0] = last_g->new_vert;
2248 edges[edge_index][1] = first_g->new_vert;
2249 if (result_edge_crease) {
2250 result_edge_crease[edge_index] = max_ff(mv_crease,
2251 min_ff(last_max_crease, first_max_crease));
2252 }
2253 if (result_edge_bweight) {
2254 result_edge_bweight[edge_index] = max_ff(
2255 mv_bweight, min_ff(last_max_bweight, first_max_bweight));
2256 }
2257 edge_index++;
2258
2259 /* Loop data. */
2260 int *loops_data = MEM_malloc_arrayN<int>(j, __func__);
2261 /* The result material index is from consensus. */
2262 short most_mat_nr = 0;
2263 uint most_mat_nr_face = 0;
2264 uint most_mat_nr_count = 0;
2265 for (short l = 0; l < mat_nrs; l++) {
2266 uint count = 0;
2267 uint face = 0;
2268 uint k = 0;
2269 for (EdgeGroup *g3 = g2; g3->valid && k < j; g3++) {
2270 if ((do_rim && !g3->is_orig_closed) || (do_shell && g3->split)) {
2271 /* Check both far ends in terms of faces of an edge group. */
2272 if ((!src_material_index.is_empty() ?
2273 src_material_index[g3->edges[0]->faces[0]->index] :
2274 0) == l)
2275 {
2276 face = g3->edges[0]->faces[0]->index;
2277 count++;
2278 }
2279 NewEdgeRef *le = g3->edges[g3->edges_len - 1];
2280 if (le->faces[1] &&
2281 (!src_material_index.is_empty() ? src_material_index[le->faces[1]->index] :
2282 0) == l)
2283 {
2284 face = le->faces[1]->index;
2285 count++;
2286 }
2287 else if (!le->faces[1] && (!src_material_index.is_empty() ?
2288 src_material_index[le->faces[0]->index] :
2289 0) == l)
2290 {
2291 face = le->faces[0]->index;
2292 count++;
2293 }
2294 k++;
2295 }
2296 }
2297 if (count > most_mat_nr_count) {
2298 most_mat_nr = l;
2299 most_mat_nr_face = face;
2300 most_mat_nr_count = count;
2301 }
2302 }
2304 &mesh->face_data, &result->face_data, int(most_mat_nr_face), int(face_index), 1);
2305 if (origindex_face) {
2306 origindex_face[face_index] = ORIGINDEX_NONE;
2307 }
2308 face_offsets[face_index] = int(loop_index);
2309 dst_material_index.span[face_index] = most_mat_nr + (g->is_orig_closed || !do_rim ?
2310 0 :
2311 mat_ofs_rim);
2312 CLAMP(dst_material_index.span[face_index], 0, mat_nr_max);
2313 face_index++;
2314
2315 for (uint k = 0; g2->valid && k < j; g2++) {
2316 if ((do_rim && !g2->is_orig_closed) || (do_shell && g2->split)) {
2317 const blender::IndexRange face = g2->edges[0]->faces[0]->face;
2318 for (int l = 0; l < face.size(); l++) {
2319 const int vert = orig_corner_verts[face[l]];
2320 if (vm[vert] == i) {
2321 loops_data[k] = face[l];
2322 break;
2323 }
2324 }
2325 k++;
2326 }
2327 }
2328
2329 if (!do_flip) {
2330 for (uint k = 0; k < j; k++) {
2332 &mesh->corner_data, &result->corner_data, loops_data[k], int(loop_index), 1);
2333 corner_verts[loop_index] = edges[edge_index - j + k][0];
2334 corner_edges[loop_index++] = edge_index - j + k;
2335 }
2336 }
2337 else {
2338 for (uint k = 1; k <= j; k++) {
2340 &result->corner_data,
2341 loops_data[j - k],
2342 int(loop_index),
2343 1);
2344 corner_verts[loop_index] = edges[edge_index - k][1];
2345 corner_edges[loop_index++] = edge_index - k;
2346 }
2347 }
2348 MEM_freeN(loops_data);
2349 }
2350 /* Reset everything for the next face. */
2351 j = 0;
2352 last_g = nullptr;
2353 first_g = nullptr;
2354 last_max_crease = 0;
2355 first_max_crease = 0;
2356 last_max_bweight = 0;
2357 first_max_bweight = 0;
2358 }
2359 }
2360 }
2361 }
2362 }
2363
2364 /* Make boundary faces. */
2365 if (do_rim) {
2366 for (uint i = 0; i < edges_num; i++) {
2367 if (edge_adj_faces_len[i] == 1 && orig_edge_data_arr[i] &&
2368 (*orig_edge_data_arr[i])->old_edge == i)
2369 {
2370 NewEdgeRef **new_edges = orig_edge_data_arr[i];
2371
2372 NewEdgeRef *edge1 = new_edges[0];
2373 NewEdgeRef *edge2 = new_edges[1];
2374 const bool v1_singularity = edge1->link_edge_groups[0]->is_singularity &&
2376 const bool v2_singularity = edge1->link_edge_groups[1]->is_singularity &&
2378 if (v1_singularity && v2_singularity) {
2379 continue;
2380 }
2381
2382 const uint orig_face_index = (*new_edges)->faces[0]->index;
2383 const blender::IndexRange face = (*new_edges)->faces[0]->face;
2385 &result->face_data,
2386 int((*new_edges)->faces[0]->index),
2387 int(face_index),
2388 1);
2389 face_offsets[face_index] = int(loop_index);
2390 dst_material_index.span[face_index] = (!src_material_index.is_empty() ?
2391 src_material_index[orig_face_index] :
2392 0) +
2393 mat_ofs_rim;
2394 CLAMP(dst_material_index.span[face_index], 0, mat_nr_max);
2395 face_index++;
2396
2397 int loop1 = -1;
2398 int loop2 = -1;
2399 const uint old_v1 = vm[orig_edges[edge1->old_edge][0]];
2400 const uint old_v2 = vm[orig_edges[edge1->old_edge][1]];
2401 for (uint j = 0; j < face.size(); j++) {
2402 const int vert = orig_corner_verts[face.start() + j];
2403 if (vm[vert] == old_v1) {
2404 loop1 = face.start() + int(j);
2405 }
2406 else if (vm[vert] == old_v2) {
2407 loop2 = face.start() + int(j);
2408 }
2409 }
2410 BLI_assert(loop1 != -1 && loop2 != -1);
2411 int2 open_face_edge;
2412 uint open_face_edge_index;
2413 if (!do_flip) {
2414 if (rim_defgrp_index != -1) {
2415 BKE_defvert_ensure_index(&dst_dvert[edges[edge1->new_edge][0]], rim_defgrp_index)
2416 ->weight = 1.0f;
2417 }
2419 &mesh->corner_data, &result->corner_data, loop1, int(loop_index), 1);
2420 corner_verts[loop_index] = edges[edge1->new_edge][0];
2421 corner_edges[loop_index++] = edge1->new_edge;
2422
2423 if (!v2_singularity) {
2424 open_face_edge_index = edge1->link_edge_groups[1]->open_face_edge;
2425 if (rim_defgrp_index != -1) {
2426 BKE_defvert_ensure_index(&dst_dvert[edges[edge1->new_edge][1]], rim_defgrp_index)
2427 ->weight = 1.0f;
2428 }
2430 &mesh->corner_data, &result->corner_data, loop2, int(loop_index), 1);
2431 corner_verts[loop_index] = edges[edge1->new_edge][1];
2432 open_face_edge = edges[open_face_edge_index];
2433 if (ELEM(edges[edge2->new_edge][1], open_face_edge[0], open_face_edge[1])) {
2434 corner_edges[loop_index++] = open_face_edge_index;
2435 }
2436 else {
2437 corner_edges[loop_index++] = edge2->link_edge_groups[1]->open_face_edge;
2438 }
2439 }
2440
2441 if (rim_defgrp_index != -1) {
2442 BKE_defvert_ensure_index(&dst_dvert[edges[edge2->new_edge][1]], rim_defgrp_index)
2443 ->weight = 1.0f;
2444 }
2446 &mesh->corner_data, &result->corner_data, loop2, int(loop_index), 1);
2447 corner_verts[loop_index] = edges[edge2->new_edge][1];
2448 corner_edges[loop_index++] = edge2->new_edge;
2449
2450 if (!v1_singularity) {
2451 open_face_edge_index = edge2->link_edge_groups[0]->open_face_edge;
2452 if (rim_defgrp_index != -1) {
2453 BKE_defvert_ensure_index(&dst_dvert[edges[edge2->new_edge][0]], rim_defgrp_index)
2454 ->weight = 1.0f;
2455 }
2457 &mesh->corner_data, &result->corner_data, loop1, int(loop_index), 1);
2458 corner_verts[loop_index] = edges[edge2->new_edge][0];
2459 open_face_edge = edges[open_face_edge_index];
2460 if (ELEM(edges[edge1->new_edge][0], open_face_edge[0], open_face_edge[1])) {
2461 corner_edges[loop_index++] = open_face_edge_index;
2462 }
2463 else {
2464 corner_edges[loop_index++] = edge1->link_edge_groups[0]->open_face_edge;
2465 }
2466 }
2467 }
2468 else {
2469 if (!v1_singularity) {
2470 open_face_edge_index = edge1->link_edge_groups[0]->open_face_edge;
2471 if (rim_defgrp_index != -1) {
2472 BKE_defvert_ensure_index(&dst_dvert[edges[edge1->new_edge][0]], rim_defgrp_index)
2473 ->weight = 1.0f;
2474 }
2476 &mesh->corner_data, &result->corner_data, loop1, int(loop_index), 1);
2477 corner_verts[loop_index] = edges[edge1->new_edge][0];
2478 open_face_edge = edges[open_face_edge_index];
2479 if (ELEM(edges[edge2->new_edge][0], open_face_edge[0], open_face_edge[1])) {
2480 corner_edges[loop_index++] = open_face_edge_index;
2481 }
2482 else {
2483 corner_edges[loop_index++] = edge2->link_edge_groups[0]->open_face_edge;
2484 }
2485 }
2486
2487 if (rim_defgrp_index != -1) {
2488 BKE_defvert_ensure_index(&dst_dvert[edges[edge2->new_edge][0]], rim_defgrp_index)
2489 ->weight = 1.0f;
2490 }
2492 &mesh->corner_data, &result->corner_data, loop1, int(loop_index), 1);
2493 corner_verts[loop_index] = edges[edge2->new_edge][0];
2494 corner_edges[loop_index++] = edge2->new_edge;
2495
2496 if (!v2_singularity) {
2497 open_face_edge_index = edge2->link_edge_groups[1]->open_face_edge;
2498 if (rim_defgrp_index != -1) {
2499 BKE_defvert_ensure_index(&dst_dvert[edges[edge2->new_edge][1]], rim_defgrp_index)
2500 ->weight = 1.0f;
2501 }
2503 &mesh->corner_data, &result->corner_data, loop2, int(loop_index), 1);
2504 corner_verts[loop_index] = edges[edge2->new_edge][1];
2505 open_face_edge = edges[open_face_edge_index];
2506 if (ELEM(edges[edge1->new_edge][1], open_face_edge[0], open_face_edge[1])) {
2507 corner_edges[loop_index++] = open_face_edge_index;
2508 }
2509 else {
2510 corner_edges[loop_index++] = edge1->link_edge_groups[1]->open_face_edge;
2511 }
2512 }
2513
2514 if (rim_defgrp_index != -1) {
2515 BKE_defvert_ensure_index(&dst_dvert[edges[edge1->new_edge][1]], rim_defgrp_index)
2516 ->weight = 1.0f;
2517 }
2519 &mesh->corner_data, &result->corner_data, loop2, int(loop_index), 1);
2520 corner_verts[loop_index] = edges[edge1->new_edge][1];
2521 corner_edges[loop_index++] = edge1->new_edge;
2522 }
2523 }
2524 }
2525 }
2526
2527 /* Make faces. */
2528 if (do_shell) {
2529 uint *face_loops = MEM_malloc_arrayN<uint>(largest_ngon * 2, __func__);
2530 uint *face_verts = MEM_malloc_arrayN<uint>(largest_ngon * 2, __func__);
2531 uint *face_edges = MEM_malloc_arrayN<uint>(largest_ngon * 2, __func__);
2532 for (uint i = 0; i < faces_num * 2; i++) {
2533 NewFaceRef &fr = face_sides_arr[i];
2534 const uint loopstart = uint(fr.face.start());
2535 uint totloop = uint(fr.face.size());
2536 uint valid_edges = 0;
2537 uint k = 0;
2538 while (totloop > 0 && (!fr.link_edges[totloop - 1] ||
2539 fr.link_edges[totloop - 1]->new_edge == MOD_SOLIDIFY_EMPTY_TAG))
2540 {
2541 totloop--;
2542 }
2543 if (totloop > 0) {
2544 NewEdgeRef *prior_edge = fr.link_edges[totloop - 1];
2545 uint prior_flip = uint(vm[orig_edges[prior_edge->old_edge][0]] ==
2546 vm[orig_corner_verts[loopstart + (totloop - 1)]]);
2547 for (uint j = 0; j < totloop; j++) {
2548 NewEdgeRef *new_edge = fr.link_edges[j];
2549 if (new_edge && new_edge->new_edge != MOD_SOLIDIFY_EMPTY_TAG) {
2550 valid_edges++;
2551 const uint flip = uint(vm[orig_edges[new_edge->old_edge][1]] ==
2552 vm[orig_corner_verts[loopstart + j]]);
2553 BLI_assert(flip || vm[orig_edges[new_edge->old_edge][0]] ==
2554 vm[orig_corner_verts[loopstart + j]]);
2555 /* The vert that's in the current loop. */
2556 const uint new_v1 = new_edge->link_edge_groups[flip]->new_vert;
2557 /* The vert that's in the next loop. */
2558 const uint new_v2 = new_edge->link_edge_groups[1 - flip]->new_vert;
2559 if (k == 0 || face_verts[k - 1] != new_v1) {
2560 face_loops[k] = loopstart + j;
2561 if (fr.reversed) {
2562 face_edges[k] = prior_edge->link_edge_groups[prior_flip]->open_face_edge;
2563 }
2564 else {
2565 face_edges[k] = new_edge->link_edge_groups[flip]->open_face_edge;
2566 }
2567 BLI_assert(k == 0 || edges[face_edges[k]][1] == face_verts[k - 1] ||
2568 edges[face_edges[k]][0] == face_verts[k - 1]);
2569 BLI_assert(face_edges[k] == MOD_SOLIDIFY_EMPTY_TAG ||
2570 edges[face_edges[k]][1] == new_v1 || edges[face_edges[k]][0] == new_v1);
2571 face_verts[k++] = new_v1;
2572 }
2573 prior_edge = new_edge;
2574 prior_flip = 1 - flip;
2575 if (j < totloop - 1 || face_verts[0] != new_v2) {
2576 face_loops[k] = loopstart + (j + 1) % totloop;
2577 face_edges[k] = new_edge->new_edge;
2578 face_verts[k++] = new_v2;
2579 }
2580 else {
2581 face_edges[0] = new_edge->new_edge;
2582 }
2583 }
2584 }
2585 if (k > 2 && valid_edges > 2) {
2587 &mesh->face_data, &result->face_data, int(i / 2), int(face_index), 1);
2588 face_offsets[face_index] = int(loop_index);
2589 dst_material_index.span[face_index] = (!src_material_index.is_empty() ?
2590 src_material_index[fr.index] :
2591 0) +
2592 (fr.reversed != do_flip ? mat_ofs : 0);
2593 CLAMP(dst_material_index.span[face_index], 0, mat_nr_max);
2594 if (fr.reversed != do_flip) {
2595 for (int l = int(k) - 1; l >= 0; l--) {
2596 if (shell_defgrp_index != -1) {
2597 BKE_defvert_ensure_index(&dst_dvert[face_verts[l]], shell_defgrp_index)->weight =
2598 1.0f;
2599 }
2601 &result->corner_data,
2602 int(face_loops[l]),
2603 int(loop_index),
2604 1);
2605 corner_verts[loop_index] = face_verts[l];
2606 corner_edges[loop_index++] = face_edges[l];
2607 }
2608 }
2609 else {
2610 uint l = k - 1;
2611 for (uint next_l = 0; next_l < k; next_l++) {
2613 &result->corner_data,
2614 int(face_loops[l]),
2615 int(loop_index),
2616 1);
2617 corner_verts[loop_index] = face_verts[l];
2618 corner_edges[loop_index++] = face_edges[next_l];
2619 l = next_l;
2620 }
2621 }
2622 face_index++;
2623 }
2624 }
2625 }
2626 MEM_freeN(face_loops);
2627 MEM_freeN(face_verts);
2628 MEM_freeN(face_edges);
2629 }
2630 if (edge_index != new_edges_num) {
2632 md,
2633 "Internal Error: edges array wrong size: %u instead of %u",
2634 new_edges_num,
2635 edge_index);
2636 }
2637 if (face_index != new_faces_num) {
2639 md,
2640 "Internal Error: faces array wrong size: %u instead of %u",
2641 new_faces_num,
2642 face_index);
2643 }
2644 if (loop_index != new_loops_num) {
2646 md,
2647 "Internal Error: loops array wrong size: %u instead of %u",
2648 new_loops_num,
2649 loop_index);
2650 }
2651 BLI_assert(edge_index == new_edges_num);
2652 BLI_assert(face_index == new_faces_num);
2653 BLI_assert(loop_index == new_loops_num);
2654
2655 /* Free remaining memory */
2656 {
2657 MEM_freeN(vm);
2658 MEM_freeN(edge_adj_faces_len);
2659 uint i = 0;
2660 for (EdgeGroup **p = orig_vert_groups_arr; i < verts_num; i++, p++) {
2661 if (*p) {
2662 for (EdgeGroup *eg = *p; eg->valid; eg++) {
2663 MEM_freeN(eg->edges);
2664 }
2665 MEM_freeN(*p);
2666 }
2667 }
2668 MEM_freeN(orig_vert_groups_arr);
2669 i = edges_num;
2670 for (NewEdgeRef ***p = orig_edge_data_arr + (edges_num - 1); i > 0; i--, p--) {
2671 if (*p && (**p)->old_edge == i - 1) {
2672 for (NewEdgeRef **l = *p; *l; l++) {
2673 MEM_freeN(*l);
2674 }
2675 MEM_freeN(*p);
2676 }
2677 }
2678 MEM_freeN(orig_edge_data_arr);
2679 MEM_freeN(orig_edge_lengths);
2680 i = 0;
2681 for (NewFaceRef &p : face_sides_arr) {
2682 MEM_freeN(p.link_edges);
2683 }
2684 }
2685
2686#undef MOD_SOLIDIFY_EMPTY_TAG
2687
2688 dst_material_index.finish();
2689
2690 return result;
2691}
2692
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_get_layer_named_for_write(CustomData *data, eCustomDataType type, blender::StringRef name, int totelem)
@ CD_SET_DEFAULT
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
#define ORIGINDEX_NONE
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
bool CustomData_free_layer_named(CustomData *data, blender::StringRef name)
support for deformation groups and hooks.
MDeformWeight * BKE_defvert_ensure_index(MDeformVert *dv, int defgroup)
Definition deform.cc:814
int BKE_id_defgroup_name_index(const ID *id, blender::StringRef name)
Definition deform.cc:538
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:763
Mesh * BKE_mesh_new_nomain_from_template(const Mesh *me_src, int verts_num, int edges_num, int faces_num, int corners_num)
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_kdtree_nd_ insert(KDTree *tree, int index, const float co[KD_DIMS]) ATTR_NONNULL(1
MINLINE float max_ff(float a, float b)
MINLINE float clamp_f(float value, float min, float max)
MINLINE float min_ff(float a, float b)
#define M_PI
void zero_m3(float m[3][3])
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
bool invert_m3(float mat[3][3])
MINLINE void swap_v4_v4(float a[4], float b[4])
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_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
#define CLAMP(a, b, c)
#define UNLIKELY(x)
#define ELEM(...)
#define LIKELY(x)
@ CD_PROP_FLOAT
@ MOD_SOLIDIFY_RIM
@ MOD_SOLIDIFY_FLIP
@ MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP
@ MOD_SOLIDIFY_NONMANIFOLD_FLAT_FACES
@ MOD_SOLIDIFY_VGROUP_INV
@ MOD_SOLIDIFY_NOSHELL
@ MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN
@ MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS
@ MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_FLAT
@ MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_ROUND
@ MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_NONE
Object is a sort of wrapper for general info.
static void split(const char *text, const char *seps, char ***str, int *count)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
Read Guarded memory(de)allocation.
Mesh * MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static int comp_float_int_pair(const void *a, const void *b)
static float angle_signed_on_axis_normalized_v3v3_v3(const float n[3], const float ref_n[3], const float axis[3])
static float clamp_nonzero(const float value, const float epsilon)
#define MOD_SOLIDIFY_EMPTY_TAG
static float project_v3_v3(float r[3], const float a[3])
void MOD_get_vgroup(const Object *ob, const Mesh *mesh, const char *name, const MDeformVert **dvert, int *defgrp_index)
Definition MOD_util.cc:156
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
AttributeSet attributes
constexpr int64_t size() const
constexpr int64_t start() const
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr bool is_empty() const
Definition BLI_span.hh:260
GAttributeReader lookup(const StringRef attribute_id) const
#define cosf(x)
#define acosf(x)
#define fabsf(x)
#define sqrtf(x)
uint pos
uint nor
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
#define printf(...)
float length(VecOp< float, D >) RET
int count
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void *(* MEM_reallocN_id)(void *vmemh, size_t len, const char *str)
Definition mallocn.cc:40
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static ulong * next
static char faces[256]
CustomData edge_data
int edges_num
CustomData corner_data
CustomData face_data
CustomData vert_data
int faces_num
int verts_num
NewFaceRef * faces[2]
struct EdgeGroup * link_edge_groups[2]
NewEdgeRef ** link_edges
blender::IndexRange face
i
Definition text_draw.cc:230
uint len