Blender V5.0
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 const bke::AttributeAccessor orig_attributes = mesh->attributes();
196
197 /* These might be null. */
198 const VArraySpan orig_vert_bweight = *orig_attributes.lookup<float>("bevel_weight_vert",
200 const VArraySpan orig_edge_bweight = *orig_attributes.lookup<float>("bevel_weight_edge",
202 const VArraySpan orig_edge_crease = *orig_attributes.lookup<float>("crease_edge",
204
205 uint new_verts_num = 0;
206 uint new_edges_num = 0;
207 uint new_loops_num = 0;
208 uint new_faces_num = 0;
209
210#define MOD_SOLIDIFY_EMPTY_TAG uint(-1)
211
212 /* Calculate only face normals. Copied because they are modified directly below. */
213 blender::Array<blender::float3> face_nors = mesh->face_normals_true();
214
215 blender::Array<NewFaceRef> face_sides_arr(faces_num * 2);
216 bool *null_faces = (smd->nonmanifold_offset_mode ==
218 MEM_calloc_arrayN<bool>(faces_num, __func__) :
219 nullptr;
220 uint largest_ngon = 3;
221 /* Calculate face to #NewFaceRef map. */
222 {
223 for (const int i : orig_faces.index_range()) {
224 const blender::IndexRange &face = orig_faces[i];
225 /* Make normals for faces without area (should really be avoided though). */
226 if (len_squared_v3(face_nors[i]) < 0.5f) {
227 const int2 &edge = orig_edges[orig_corner_edges[face.start()]];
228 float edgedir[3];
229 sub_v3_v3v3(edgedir, orig_vert_positions[edge[1]], orig_vert_positions[edge[0]]);
230 if (fabsf(edgedir[2]) < fabsf(edgedir[1])) {
231 face_nors[i][2] = 1.0f;
232 }
233 else {
234 face_nors[i][1] = 1.0f;
235 }
236 if (null_faces) {
237 null_faces[i] = true;
238 }
239 }
240
241 NewEdgeRef **link_edges = MEM_calloc_arrayN<NewEdgeRef *>(uint(face.size()), __func__);
242
243 NewFaceRef new_face_ref_a{};
244 new_face_ref_a.face = face;
245 new_face_ref_a.index = uint(i);
246 new_face_ref_a.reversed = false;
247 new_face_ref_a.link_edges = link_edges;
248 face_sides_arr[i * 2] = std::move(new_face_ref_a);
249
250 link_edges = MEM_calloc_arrayN<NewEdgeRef *>(uint(face.size()), __func__);
251
252 NewFaceRef new_face_ref_b{};
253 new_face_ref_b.face = face;
254 new_face_ref_b.index = uint(i);
255 new_face_ref_b.reversed = true;
256 new_face_ref_b.link_edges = link_edges;
257 face_sides_arr[i * 2 + 1] = std::move(new_face_ref_b);
258
259 if (face.size() > largest_ngon) {
260 largest_ngon = uint(face.size());
261 }
262 /* add to final mesh face count */
263 if (do_shell) {
264 new_faces_num += 2;
265 new_loops_num += uint(face.size() * 2);
266 }
267 }
268 }
269
270 uint *edge_adj_faces_len = MEM_calloc_arrayN<uint>(edges_num, __func__);
271 /* Count for each edge how many faces it has adjacent. */
272 {
273 for (const int64_t i : orig_faces.index_range()) {
274 for (const int64_t edge : orig_corner_edges.slice(orig_faces[i])) {
275 edge_adj_faces_len[edge]++;
276 }
277 }
278 }
279
280 /* Original edge to #NewEdgeRef map. */
281 NewEdgeRef ***orig_edge_data_arr = MEM_calloc_arrayN<NewEdgeRef **>(edges_num, __func__);
282 /* Original edge length cache. */
283 float *orig_edge_lengths = MEM_calloc_arrayN<float>(edges_num, __func__);
284 /* Edge groups for every original vert. */
285 EdgeGroup **orig_vert_groups_arr = MEM_calloc_arrayN<EdgeGroup *>(verts_num, __func__);
286 /* vertex map used to map duplicates. */
287 uint *vm = MEM_malloc_arrayN<uint>(verts_num, __func__);
288 for (uint i = 0; i < verts_num; i++) {
289 vm[i] = i;
290 }
291
292 uint edge_index = 0;
293 uint loop_index = 0;
294 uint face_index = 0;
295
296 bool has_singularities = false;
297
298 /* Vert edge adjacent map. */
299 OldVertEdgeRef **vert_adj_edges = MEM_calloc_arrayN<OldVertEdgeRef *>(verts_num, __func__);
300 /* Original vertex positions (changed for degenerated geometry). */
301 float (*orig_mvert_co)[3] = MEM_malloc_arrayN<float[3]>(verts_num, __func__);
302 /* Fill in the original vertex positions. */
303 for (uint i = 0; i < verts_num; i++) {
304 orig_mvert_co[i][0] = orig_vert_positions[i][0];
305 orig_mvert_co[i][1] = orig_vert_positions[i][1];
306 orig_mvert_co[i][2] = orig_vert_positions[i][2];
307 }
308
309 /* Create edge to #NewEdgeRef map. */
310 {
311 OldEdgeFaceRef **edge_adj_faces = MEM_calloc_arrayN<OldEdgeFaceRef *>(edges_num, __func__);
312
313 /* Create link_faces for edges. */
314 {
315 for (const int64_t i : orig_faces.index_range()) {
316 for (const int64_t corner : orig_faces[i]) {
317 const int vert = orig_corner_verts[corner];
318 const int edge = orig_corner_edges[corner];
319 const bool reversed = orig_edges[edge][1] != vert;
320 OldEdgeFaceRef *old_face_edge_ref = edge_adj_faces[edge];
321 if (old_face_edge_ref == nullptr) {
322 const uint len = edge_adj_faces_len[edge];
323 BLI_assert(len > 0);
324 uint *adj_faces = MEM_malloc_arrayN<uint>(len, __func__);
325 bool *adj_faces_reversed = MEM_malloc_arrayN<bool>(len, __func__);
326 adj_faces[0] = uint(i);
327 for (uint k = 1; k < len; k++) {
328 adj_faces[k] = MOD_SOLIDIFY_EMPTY_TAG;
329 }
330 adj_faces_reversed[0] = reversed;
332 *ref = OldEdgeFaceRef{adj_faces, len, adj_faces_reversed, 1};
333 edge_adj_faces[edge] = ref;
334 }
335 else {
336 for (uint k = 1; k < old_face_edge_ref->faces_len; k++) {
337 if (old_face_edge_ref->faces[k] == MOD_SOLIDIFY_EMPTY_TAG) {
338 old_face_edge_ref->faces[k] = uint(i);
339 old_face_edge_ref->faces_reversed[k] = reversed;
340 break;
341 }
342 }
343 }
344 }
345 }
346 }
347
348 float edgedir[3] = {0, 0, 0};
349 uint *vert_adj_edges_len = MEM_calloc_arrayN<uint>(verts_num, __func__);
350
351 /* Calculate edge lengths and len vert_adj edges. */
352 {
353 bool *face_singularity = MEM_calloc_arrayN<bool>(faces_num, __func__);
354
355 const float merge_tolerance_sqr = smd->merge_tolerance * smd->merge_tolerance;
356 uint *combined_verts = MEM_calloc_arrayN<uint>(verts_num, __func__);
357
358 for (uint i = 0; i < edges_num; i++) {
359 const int2 &edge = orig_edges[i];
360 if (edge_adj_faces_len[i] > 0) {
361 uint v1 = vm[edge[0]];
362 uint v2 = vm[edge[1]];
363 if (v1 == v2) {
364 continue;
365 }
366
367 if (v2 < v1) {
368 std::swap(v1, v2);
369 }
370 sub_v3_v3v3(edgedir, orig_mvert_co[v2], orig_mvert_co[v1]);
371 orig_edge_lengths[i] = len_squared_v3(edgedir);
372
373 if (orig_edge_lengths[i] <= merge_tolerance_sqr) {
374 /* Merge verts. But first check if that would create a higher face count. */
375 /* This check is very slow. It would need the vertex edge links to get
376 * accelerated that are not yet available at this point. */
377 bool can_merge = true;
378 for (uint k = 0; k < edges_num && can_merge; k++) {
379 if (k != i && edge_adj_faces_len[k] > 0 &&
380 (ELEM(vm[orig_edges[k][0]], v1, v2) != ELEM(vm[orig_edges[k][1]], v1, v2)))
381 {
382 for (uint j = 0; j < edge_adj_faces[k]->faces_len && can_merge; j++) {
383 const blender::IndexRange face = orig_faces[edge_adj_faces[k]->faces[j]];
384 uint changes = 0;
385 int cur = face.size() - 1;
386 for (int next = 0; next < face.size() && changes <= 2; next++) {
387 uint cur_v = vm[orig_corner_verts[face[cur]]];
388 uint next_v = vm[orig_corner_verts[face[next]]];
389 changes += (ELEM(cur_v, v1, v2) != ELEM(next_v, v1, v2));
390 cur = next;
391 }
392 can_merge = can_merge && changes <= 2;
393 }
394 }
395 }
396
397 if (!can_merge) {
398 orig_edge_lengths[i] = 0.0f;
399 vert_adj_edges_len[v1]++;
400 vert_adj_edges_len[v2]++;
401 continue;
402 }
403
404 mul_v3_fl(edgedir,
405 (combined_verts[v2] + 1) /
406 float(combined_verts[v1] + combined_verts[v2] + 2));
407 add_v3_v3(orig_mvert_co[v1], edgedir);
408 for (uint j = v2; j < verts_num; j++) {
409 if (vm[j] == v2) {
410 vm[j] = v1;
411 }
412 }
413 vert_adj_edges_len[v1] += vert_adj_edges_len[v2];
414 vert_adj_edges_len[v2] = 0;
415 combined_verts[v1] += combined_verts[v2] + 1;
416
417 if (do_shell) {
418 new_loops_num -= edge_adj_faces_len[i] * 2;
419 }
420
421 edge_adj_faces_len[i] = 0;
422 MEM_freeN(edge_adj_faces[i]->faces);
423 MEM_freeN(edge_adj_faces[i]->faces_reversed);
424 MEM_freeN(edge_adj_faces[i]);
425 edge_adj_faces[i] = nullptr;
426 }
427 else {
428 orig_edge_lengths[i] = sqrtf(orig_edge_lengths[i]);
429 vert_adj_edges_len[v1]++;
430 vert_adj_edges_len[v2]++;
431 }
432 }
433 }
434 /* remove zero faces in a second pass */
435 for (uint i = 0; i < edges_num; i++) {
436 const int2 &edge = orig_edges[i];
437 const uint v1 = vm[edge[0]];
438 const uint v2 = vm[edge[1]];
439 if (v1 == v2 && edge_adj_faces[i]) {
440 /* Remove faces. */
441 for (uint j = 0; j < edge_adj_faces[i]->faces_len; j++) {
442 const uint face = edge_adj_faces[i]->faces[j];
443 if (!face_singularity[face]) {
444 bool is_singularity = true;
445 for (const int vert : orig_corner_verts.slice(orig_faces[face])) {
446 if (vm[vert] != v1) {
447 is_singularity = false;
448 break;
449 }
450 }
451 if (is_singularity) {
452 face_singularity[face] = true;
453 /* remove from final mesh face count */
454 if (do_shell) {
455 new_faces_num -= 2;
456 }
457 }
458 }
459 }
460
461 if (do_shell) {
462 new_loops_num -= edge_adj_faces_len[i] * 2;
463 }
464
465 edge_adj_faces_len[i] = 0;
466 MEM_freeN(edge_adj_faces[i]->faces);
467 MEM_freeN(edge_adj_faces[i]->faces_reversed);
468 MEM_freeN(edge_adj_faces[i]);
469 edge_adj_faces[i] = nullptr;
470 }
471 }
472
473 MEM_freeN(face_singularity);
474 MEM_freeN(combined_verts);
475 }
476
477 /* Create vert_adj_edges for verts. */
478 {
479 for (uint i = 0; i < edges_num; i++) {
480 const int2 &edge = orig_edges[i];
481 if (edge_adj_faces_len[i] > 0) {
482 const int vs[2] = {int(vm[edge[0]]), int(vm[edge[1]])};
483 uint invalid_edge_index = 0;
484 bool invalid_edge_reversed = false;
485 for (uint j = 0; j < 2; j++) {
486 const int vert = vs[j];
487 const uint len = vert_adj_edges_len[vert];
488 if (len > 0) {
489 OldVertEdgeRef *old_edge_vert_ref = vert_adj_edges[vert];
490 if (old_edge_vert_ref == nullptr) {
491 uint *adj_edges = MEM_calloc_arrayN<uint>(len, __func__);
492 adj_edges[0] = i;
493 for (uint k = 1; k < len; k++) {
494 adj_edges[k] = MOD_SOLIDIFY_EMPTY_TAG;
495 }
497 *ref = OldVertEdgeRef{adj_edges, 1};
498 vert_adj_edges[vert] = ref;
499 }
500 else {
501 const uint *f = old_edge_vert_ref->edges;
502 for (uint k = 0; k < len && k <= old_edge_vert_ref->edges_len; k++, f++) {
503 const uint edge = old_edge_vert_ref->edges[k];
504 if (edge == MOD_SOLIDIFY_EMPTY_TAG || k == old_edge_vert_ref->edges_len) {
505 old_edge_vert_ref->edges[k] = i;
506 old_edge_vert_ref->edges_len++;
507 break;
508 }
509 if (vm[orig_edges[edge][0]] == vs[1 - j]) {
510 invalid_edge_index = edge + 1;
511 invalid_edge_reversed = (j == 0);
512 break;
513 }
514 if (vm[orig_edges[edge][1]] == vs[1 - j]) {
515 invalid_edge_index = edge + 1;
516 invalid_edge_reversed = (j == 1);
517 break;
518 }
519 }
520 if (invalid_edge_index) {
521 if (j == 1) {
522 /* Should never actually be executed. */
523 vert_adj_edges[vs[0]]->edges_len--;
524 }
525 break;
526 }
527 }
528 }
529 }
530 /* Remove zero faces that are in shape of an edge. */
531 if (invalid_edge_index) {
532 const uint tmp = invalid_edge_index - 1;
533 invalid_edge_index = i;
534 i = tmp;
535 OldEdgeFaceRef *i_adj_faces = edge_adj_faces[i];
536 OldEdgeFaceRef *invalid_adj_faces = edge_adj_faces[invalid_edge_index];
537 uint j = 0;
538 for (uint k = 0; k < i_adj_faces->faces_len; k++) {
539 for (uint l = 0; l < invalid_adj_faces->faces_len; l++) {
540 if (i_adj_faces->faces[k] == invalid_adj_faces->faces[l] &&
541 i_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG)
542 {
543 i_adj_faces->faces[k] = MOD_SOLIDIFY_EMPTY_TAG;
544 invalid_adj_faces->faces[l] = MOD_SOLIDIFY_EMPTY_TAG;
545 j++;
546 }
547 }
548 }
549 /* remove from final face count */
550 if (do_shell) {
551 new_faces_num -= 2 * j;
552 new_loops_num -= 4 * j;
553 }
554 const uint len = i_adj_faces->faces_len + invalid_adj_faces->faces_len - 2 * j;
555 uint *adj_faces = MEM_malloc_arrayN<uint>(len, __func__);
556 bool *adj_faces_loops_reversed = MEM_malloc_arrayN<bool>(len, __func__);
557 /* Clean merge of adj_faces. */
558 j = 0;
559 for (uint k = 0; k < i_adj_faces->faces_len; k++) {
560 if (i_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG) {
561 adj_faces[j] = i_adj_faces->faces[k];
562 adj_faces_loops_reversed[j++] = i_adj_faces->faces_reversed[k];
563 }
564 }
565 for (uint k = 0; k < invalid_adj_faces->faces_len; k++) {
566 if (invalid_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG) {
567 adj_faces[j] = invalid_adj_faces->faces[k];
568 adj_faces_loops_reversed[j++] = (invalid_edge_reversed !=
569 invalid_adj_faces->faces_reversed[k]);
570 }
571 }
572 BLI_assert(j == len);
573 edge_adj_faces_len[invalid_edge_index] = 0;
574 edge_adj_faces_len[i] = len;
575 MEM_freeN(i_adj_faces->faces);
576 MEM_freeN(i_adj_faces->faces_reversed);
577 i_adj_faces->faces_len = len;
578 i_adj_faces->faces = adj_faces;
579 i_adj_faces->faces_reversed = adj_faces_loops_reversed;
580 i_adj_faces->used += invalid_adj_faces->used;
581 MEM_freeN(invalid_adj_faces->faces);
582 MEM_freeN(invalid_adj_faces->faces_reversed);
583 MEM_freeN(invalid_adj_faces);
584 edge_adj_faces[invalid_edge_index] = i_adj_faces;
585 /* Reset counter to continue. */
586 i = invalid_edge_index;
587 }
588 }
589 }
590 }
591
592 MEM_freeN(vert_adj_edges_len);
593
594 /* Filter duplicate faces. */
595 {
596 const int2 *edge = orig_edges.data();
597 /* Iterate over edges and only check the faces around an edge for duplicates
598 * (performance optimization). */
599 for (uint i = 0; i < edges_num; i++, edge++) {
600 if (edge_adj_faces_len[i] > 0) {
601 const OldEdgeFaceRef *adj_faces = edge_adj_faces[i];
602 uint adj_len = adj_faces->faces_len;
603 /* Not that #adj_len doesn't need to equal edge_adj_faces_len anymore
604 * because #adj_len is shared when a face got collapsed to an edge. */
605 if (adj_len > 1) {
606 /* For each face pair check if they have equal verts. */
607 for (uint j = 0; j < adj_len; j++) {
608 const uint face = adj_faces->faces[j];
609 const int j_loopstart = orig_faces[face].start();
610 const int totloop = orig_faces[face].size();
611 const uint j_first_v = vm[orig_corner_verts[j_loopstart]];
612 for (uint k = j + 1; k < adj_len; k++) {
613 if (orig_faces[adj_faces->faces[k]].size() != totloop) {
614 continue;
615 }
616 /* Find first face first loop vert in second face loops. */
617 const int k_loopstart = orig_faces[adj_faces->faces[k]].start();
618 int l;
619 {
620 const int *corner_vert = &orig_corner_verts[k_loopstart];
621 for (l = 0; l < totloop && vm[*corner_vert] != j_first_v; l++, corner_vert++) {
622 /* Pass. */
623 }
624 }
625 if (l == totloop) {
626 continue;
627 }
628 /* Check if all following loops have equal verts. */
629 const bool reversed = adj_faces->faces_reversed[j] != adj_faces->faces_reversed[k];
630 const int count_dir = reversed ? -1 : 1;
631 bool has_diff = false;
632 for (int m = 0, n = l + totloop; m < totloop && !has_diff; m++, n += count_dir) {
633 const int vert = orig_corner_verts[j_loopstart + m];
634 has_diff = has_diff ||
635 vm[vert] != vm[orig_corner_verts[k_loopstart + n % totloop]];
636 }
637 /* If the faces are equal, discard one (j). */
638 if (!has_diff) {
639 uint del_loops = 0;
640 for (uint m = 0; m < totloop; m++) {
641 const int e = orig_corner_edges[j_loopstart + m];
642 OldEdgeFaceRef *e_adj_faces = edge_adj_faces[e];
643 if (e_adj_faces) {
644 uint face_index = j;
645 uint *e_adj_faces_faces = e_adj_faces->faces;
646 bool *e_adj_faces_reversed = e_adj_faces->faces_reversed;
647 const uint faces_len = e_adj_faces->faces_len;
648 if (e_adj_faces_faces != adj_faces->faces) {
649 /* Find index of e in #adj_faces. */
650 for (face_index = 0;
651 face_index < faces_len && e_adj_faces_faces[face_index] != face;
652 face_index++)
653 {
654 /* Pass. */
655 }
656 /* If not found. */
657 if (face_index == faces_len) {
658 continue;
659 }
660 }
661 else {
662 /* If we shrink #edge_adj_faces[i] we need to update this field. */
663 adj_len--;
664 }
665 memmove(e_adj_faces_faces + face_index,
666 e_adj_faces_faces + face_index + 1,
667 (faces_len - face_index - 1) * sizeof(*e_adj_faces_faces));
668 memmove(e_adj_faces_reversed + face_index,
669 e_adj_faces_reversed + face_index + 1,
670 (faces_len - face_index - 1) * sizeof(*e_adj_faces_reversed));
671 e_adj_faces->faces_len--;
672 if (edge_adj_faces_len[e] > 0) {
673 edge_adj_faces_len[e]--;
674 if (edge_adj_faces_len[e] == 0) {
675 e_adj_faces->used--;
676 edge_adj_faces[e] = nullptr;
677 }
678 }
679 else if (e_adj_faces->used > 1) {
680 for (uint n = 0; n < edges_num; n++) {
681 if (edge_adj_faces[n] == e_adj_faces && edge_adj_faces_len[n] > 0) {
682 edge_adj_faces_len[n]--;
683 if (edge_adj_faces_len[n] == 0) {
684 edge_adj_faces[n]->used--;
685 edge_adj_faces[n] = nullptr;
686 }
687 break;
688 }
689 }
690 }
691 del_loops++;
692 }
693 }
694 if (do_shell) {
695 new_faces_num -= 2;
696 new_loops_num -= 2 * del_loops;
697 }
698 break;
699 }
700 }
701 }
702 }
703 }
704 }
705 }
706
707 /* Create #NewEdgeRef array. */
708 {
709 for (uint i = 0; i < edges_num; i++) {
710 const int2 &edge = orig_edges[i];
711 const uint v1 = vm[edge[0]];
712 const uint v2 = vm[edge[1]];
713 if (edge_adj_faces_len[i] > 0) {
714 if (LIKELY(orig_edge_lengths[i] > FLT_EPSILON)) {
715 sub_v3_v3v3(edgedir, orig_mvert_co[v2], orig_mvert_co[v1]);
716 mul_v3_fl(edgedir, 1.0f / orig_edge_lengths[i]);
717 }
718 else {
719 /* Smart fallback. */
720 /* This makes merging non essential, but correct
721 * merging will still give way better results. */
722 float pos[3];
723 copy_v3_v3(pos, orig_mvert_co[v2]);
724
725 OldVertEdgeRef *link1 = vert_adj_edges[v1];
726 float v1_dir[3];
727 zero_v3(v1_dir);
728 for (int j = 0; j < link1->edges_len; j++) {
729 uint e = link1->edges[j];
730 if (edge_adj_faces_len[e] > 0 && e != i) {
731 uint other_v =
732 vm[vm[orig_edges[e][0]] == v1 ? orig_edges[e][1] : orig_edges[e][0]];
733 sub_v3_v3v3(edgedir, orig_mvert_co[other_v], pos);
734 add_v3_v3(v1_dir, edgedir);
735 }
736 }
737 OldVertEdgeRef *link2 = vert_adj_edges[v2];
738 float v2_dir[3];
739 zero_v3(v2_dir);
740 for (int j = 0; j < link2->edges_len; j++) {
741 uint e = link2->edges[j];
742 if (edge_adj_faces_len[e] > 0 && e != i) {
743 uint other_v =
744 vm[vm[orig_edges[e][0]] == v2 ? orig_edges[e][1] : orig_edges[e][0]];
745 sub_v3_v3v3(edgedir, orig_mvert_co[other_v], pos);
746 add_v3_v3(v2_dir, edgedir);
747 }
748 }
749 sub_v3_v3v3(edgedir, v2_dir, v1_dir);
750 float len = normalize_v3(edgedir);
751 if (len == 0.0f) {
752 edgedir[0] = 0.0f;
753 edgedir[1] = 0.0f;
754 edgedir[2] = 1.0f;
755 }
756 }
757
758 OldEdgeFaceRef *adj_faces = edge_adj_faces[i];
759 const uint adj_len = adj_faces->faces_len;
760 const uint *adj_faces_faces = adj_faces->faces;
761 const bool *adj_faces_reversed = adj_faces->faces_reversed;
762 uint new_edges_len = 0;
763 FaceKeyPair *sorted_faces = MEM_malloc_arrayN<FaceKeyPair>(adj_len, __func__);
764 if (adj_len > 1) {
765 new_edges_len = adj_len;
766 /* Get keys for sorting. */
767 float ref_nor[3] = {0, 0, 0};
768 float nor[3];
769 for (uint j = 0; j < adj_len; j++) {
770 const bool reverse = adj_faces_reversed[j];
771 const uint face_i = adj_faces_faces[j];
772 if (reverse) {
773 negate_v3_v3(nor, face_nors[face_i]);
774 }
775 else {
776 copy_v3_v3(nor, face_nors[face_i]);
777 }
778 float d = 1;
779 if (orig_faces[face_i].size() > 3) {
780 d = project_v3_v3(nor, edgedir);
781 if (LIKELY(d != 0)) {
782 d = normalize_v3(nor);
783 }
784 else {
785 d = 1;
786 }
787 }
788 if (UNLIKELY(d == 0.0f)) {
789 sorted_faces[j].angle = 0.0f;
790 }
791 else if (j == 0) {
792 copy_v3_v3(ref_nor, nor);
793 sorted_faces[j].angle = 0.0f;
794 }
795 else {
796 float angle = angle_signed_on_axis_normalized_v3v3_v3(nor, ref_nor, edgedir);
797 sorted_faces[j].angle = -angle;
798 }
799 sorted_faces[j].face =
800 &face_sides_arr[adj_faces_faces[j] * 2 + (adj_faces_reversed[j] ? 1 : 0)];
801 }
802 /* Sort faces by order around the edge (keep order in faces,
803 * reversed and face_angles the same). */
804 qsort(sorted_faces, adj_len, sizeof(*sorted_faces), comp_float_int_pair);
805 }
806 else {
807 new_edges_len = 2;
808 sorted_faces[0].face =
809 &face_sides_arr[adj_faces_faces[0] * 2 + (adj_faces_reversed[0] ? 1 : 0)];
810 if (do_rim) {
811 /* Only add the loops parallel to the edge for now. */
812 new_loops_num += 2;
813 new_faces_num++;
814 }
815 }
816
817 /* Create a list of new edges and fill it. */
818 NewEdgeRef **new_edges = MEM_malloc_arrayN<NewEdgeRef *>(new_edges_len + 1, __func__);
819 new_edges[new_edges_len] = nullptr;
820 NewFaceRef *faces[2];
821 for (uint j = 0; j < new_edges_len; j++) {
822 float angle;
823 if (adj_len > 1) {
824 const uint next_j = j + 1 == adj_len ? 0 : j + 1;
825 faces[0] = sorted_faces[j].face;
826 faces[1] = sorted_faces[next_j].face->reversed ? sorted_faces[next_j].face - 1 :
827 sorted_faces[next_j].face + 1;
828 angle = sorted_faces[next_j].angle - sorted_faces[j].angle;
829 if (angle < 0) {
830 angle += 2 * M_PI;
831 }
832 }
833 else {
834 faces[0] = sorted_faces[0].face->reversed ? sorted_faces[0].face - j :
835 sorted_faces[0].face + j;
836 faces[1] = nullptr;
837 angle = 0;
838 }
839 NewEdgeRef *edge_data = MEM_mallocN<NewEdgeRef>(__func__);
840 uint edge_data_edge_index = MOD_SOLIDIFY_EMPTY_TAG;
841 if (do_shell || (adj_len == 1 && do_rim)) {
842 edge_data_edge_index = 0;
843 }
844
845 NewEdgeRef new_edge_ref{};
846 new_edge_ref.old_edge = i;
847 new_edge_ref.faces[0] = faces[0];
848 new_edge_ref.faces[1] = faces[1];
849 new_edge_ref.link_edge_groups[0] = nullptr;
850 new_edge_ref.link_edge_groups[1] = nullptr;
851 new_edge_ref.angle = angle;
852 new_edge_ref.new_edge = edge_data_edge_index;
853 *edge_data = new_edge_ref;
854
855 new_edges[j] = edge_data;
856 for (uint k = 0; k < 2; k++) {
857 if (faces[k] != nullptr) {
858 for (int l = 0; l < faces[k]->face.size(); l++) {
859 const int edge = orig_corner_edges[faces[k]->face.start() + l];
860 if (edge_adj_faces[edge] == edge_adj_faces[i]) {
861 if (edge != i && orig_edge_data_arr[edge] == nullptr) {
862 orig_edge_data_arr[edge] = new_edges;
863 }
864 faces[k]->link_edges[l] = edge_data;
865 break;
866 }
867 }
868 }
869 }
870 }
871 MEM_freeN(sorted_faces);
872 orig_edge_data_arr[i] = new_edges;
873 if (do_shell || (adj_len == 1 && do_rim)) {
874 new_edges_num += new_edges_len;
875 }
876 }
877 }
878 }
879
880 for (uint i = 0; i < edges_num; i++) {
881 if (edge_adj_faces[i]) {
882 if (edge_adj_faces[i]->used > 1) {
883 edge_adj_faces[i]->used--;
884 }
885 else {
886 MEM_freeN(edge_adj_faces[i]->faces);
887 MEM_freeN(edge_adj_faces[i]->faces_reversed);
888 MEM_freeN(edge_adj_faces[i]);
889 }
890 }
891 }
892 MEM_freeN(edge_adj_faces);
893 }
894
895 /* Create sorted edge groups for every vert. */
896 {
897 OldVertEdgeRef **adj_edges_ptr = vert_adj_edges;
898 for (uint i = 0; i < verts_num; i++, adj_edges_ptr++) {
899 if (*adj_edges_ptr != nullptr && (*adj_edges_ptr)->edges_len >= 2) {
900 EdgeGroup *edge_groups;
901
902 int eg_index = -1;
903 bool contains_long_groups = false;
904 uint topo_groups = 0;
905
906 /* Initial sorted creation. */
907 {
908 const uint *adj_edges = (*adj_edges_ptr)->edges;
909 const uint tot_adj_edges = (*adj_edges_ptr)->edges_len;
910
911 uint unassigned_edges_len = 0;
912 for (uint j = 0; j < tot_adj_edges; j++) {
913 NewEdgeRef **new_edges = orig_edge_data_arr[adj_edges[j]];
914 /* TODO: check where the null pointer come from,
915 * because there should not be any... */
916 if (new_edges) {
917 /* count the number of new edges around the original vert */
918 while (*new_edges) {
919 unassigned_edges_len++;
920 new_edges++;
921 }
922 }
923 }
924 NewEdgeRef **unassigned_edges = MEM_malloc_arrayN<NewEdgeRef *>(unassigned_edges_len,
925 __func__);
926 for (uint j = 0, k = 0; j < tot_adj_edges; j++) {
927 NewEdgeRef **new_edges = orig_edge_data_arr[adj_edges[j]];
928 if (new_edges) {
929 while (*new_edges) {
930 unassigned_edges[k++] = *new_edges;
931 new_edges++;
932 }
933 }
934 }
935
936 /* An edge group will always contain min 2 edges
937 * so max edge group count can be calculated. */
938 uint edge_groups_len = unassigned_edges_len / 2;
939 edge_groups = MEM_calloc_arrayN<EdgeGroup>(edge_groups_len + 1, __func__);
940
941 uint assigned_edges_len = 0;
942 NewEdgeRef *found_edge = nullptr;
943 uint found_edge_index = 0;
944 bool insert_at_start = false;
945 uint eg_capacity = 5;
946 NewFaceRef *eg_track_faces[2] = {nullptr, nullptr};
947 NewFaceRef *last_open_edge_track = nullptr;
948
949 while (assigned_edges_len < unassigned_edges_len) {
950 found_edge = nullptr;
951 insert_at_start = false;
952 if (eg_index >= 0 && edge_groups[eg_index].edges_len == 0) {
953 /* Called every time a new group was started in the last iteration. */
954 /* Find an unused edge to start the next group
955 * and setup variables to start creating it. */
956 uint j = 0;
957 NewEdgeRef *edge = nullptr;
958 while (!edge && j < unassigned_edges_len) {
959 edge = unassigned_edges[j++];
960 if (edge && last_open_edge_track &&
961 (edge->faces[0] != last_open_edge_track || edge->faces[1] != nullptr))
962 {
963 edge = nullptr;
964 }
965 }
966 if (!edge && last_open_edge_track) {
967 topo_groups++;
968 last_open_edge_track = nullptr;
969 edge_groups[eg_index].topo_group++;
970 j = 0;
971 while (!edge && j < unassigned_edges_len) {
972 edge = unassigned_edges[j++];
973 }
974 }
975 else if (!last_open_edge_track && eg_index > 0) {
976 topo_groups++;
977 edge_groups[eg_index].topo_group++;
978 }
979 BLI_assert(edge != nullptr);
980 found_edge_index = j - 1;
981 found_edge = edge;
982 if (!last_open_edge_track && vm[orig_edges[edge->old_edge][0]] == i) {
983 eg_track_faces[0] = edge->faces[0];
984 eg_track_faces[1] = edge->faces[1];
985 if (edge->faces[1] == nullptr) {
986 last_open_edge_track = edge->faces[0]->reversed ? edge->faces[0] - 1 :
987 edge->faces[0] + 1;
988 }
989 }
990 else {
991 eg_track_faces[0] = edge->faces[1];
992 eg_track_faces[1] = edge->faces[0];
993 }
994 }
995 else if (eg_index >= 0) {
996 NewEdgeRef **edge_ptr = unassigned_edges;
997 for (found_edge_index = 0; found_edge_index < unassigned_edges_len;
998 found_edge_index++, edge_ptr++)
999 {
1000 if (*edge_ptr) {
1001 NewEdgeRef *edge = *edge_ptr;
1002 if (edge->faces[0] == eg_track_faces[1]) {
1003 insert_at_start = false;
1004 eg_track_faces[1] = edge->faces[1];
1005 found_edge = edge;
1006 if (edge->faces[1] == nullptr) {
1007 edge_groups[eg_index].is_orig_closed = false;
1008 last_open_edge_track = edge->faces[0]->reversed ? edge->faces[0] - 1 :
1009 edge->faces[0] + 1;
1010 }
1011 break;
1012 }
1013 if (edge->faces[0] == eg_track_faces[0]) {
1014 insert_at_start = true;
1015 eg_track_faces[0] = edge->faces[1];
1016 found_edge = edge;
1017 if (edge->faces[1] == nullptr) {
1018 edge_groups[eg_index].is_orig_closed = false;
1019 }
1020 break;
1021 }
1022 if (edge->faces[1] != nullptr) {
1023 if (edge->faces[1] == eg_track_faces[1]) {
1024 insert_at_start = false;
1025 eg_track_faces[1] = edge->faces[0];
1026 found_edge = edge;
1027 break;
1028 }
1029 if (edge->faces[1] == eg_track_faces[0]) {
1030 insert_at_start = true;
1031 eg_track_faces[0] = edge->faces[0];
1032 found_edge = edge;
1033 break;
1034 }
1035 }
1036 }
1037 }
1038 }
1039 if (found_edge) {
1040 unassigned_edges[found_edge_index] = nullptr;
1041 assigned_edges_len++;
1042 const uint needed_capacity = edge_groups[eg_index].edges_len + 1;
1043 if (needed_capacity > eg_capacity) {
1044 eg_capacity = needed_capacity + 1;
1045 NewEdgeRef **new_eg = MEM_calloc_arrayN<NewEdgeRef *>(eg_capacity, __func__);
1046 if (insert_at_start) {
1047 memcpy(new_eg + 1,
1048 edge_groups[eg_index].edges,
1049 edge_groups[eg_index].edges_len * sizeof(*new_eg));
1050 }
1051 else {
1052 memcpy(new_eg,
1053 edge_groups[eg_index].edges,
1054 edge_groups[eg_index].edges_len * sizeof(*new_eg));
1055 }
1056 MEM_freeN(edge_groups[eg_index].edges);
1057 edge_groups[eg_index].edges = new_eg;
1058 }
1059 else if (insert_at_start) {
1060 memmove(edge_groups[eg_index].edges + 1,
1061 edge_groups[eg_index].edges,
1062 edge_groups[eg_index].edges_len * sizeof(*edge_groups[eg_index].edges));
1063 }
1064 edge_groups[eg_index].edges[insert_at_start ? 0 : edge_groups[eg_index].edges_len] =
1065 found_edge;
1066 edge_groups[eg_index].edges_len++;
1067 if (edge_groups[eg_index].edges[edge_groups[eg_index].edges_len - 1]->faces[1] !=
1068 nullptr)
1069 {
1070 last_open_edge_track = nullptr;
1071 }
1072 if (edge_groups[eg_index].edges_len > 3) {
1073 contains_long_groups = true;
1074 }
1075 }
1076 else {
1077 /* called on first iteration to clean up the eg_index = -1 and start the first group,
1078 * or when the current group is found to be complete (no new found_edge) */
1079 eg_index++;
1080 BLI_assert(eg_index < edge_groups_len);
1081 eg_capacity = 5;
1082 NewEdgeRef **edges = MEM_calloc_arrayN<NewEdgeRef *>(eg_capacity, __func__);
1083
1084 EdgeGroup edge_group{};
1085 edge_group.valid = true;
1086 edge_group.edges = edges;
1087 edge_group.edges_len = 0;
1089 edge_group.is_orig_closed = true;
1090 edge_group.is_even_split = false;
1091 edge_group.split = 0;
1092 edge_group.is_singularity = false;
1093 edge_group.topo_group = topo_groups;
1094 zero_v3(edge_group.co);
1095 zero_v3(edge_group.no);
1096 edge_group.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1097 edge_groups[eg_index] = edge_group;
1098
1099 eg_track_faces[0] = nullptr;
1100 eg_track_faces[1] = nullptr;
1101 }
1102 }
1103 /* #eg_index is the number of groups from here on. */
1104 eg_index++;
1105 /* #topo_groups is the number of topo groups from here on. */
1106 topo_groups++;
1107
1108 MEM_freeN(unassigned_edges);
1109
1110 /* TODO: reshape the edge_groups array to its actual size
1111 * after writing is finished to save on memory. */
1112 }
1113
1114 /* Split of long self intersection groups */
1115 {
1116 uint splits = 0;
1117 if (contains_long_groups) {
1118 uint add_index = 0;
1119 for (uint j = 0; j < eg_index; j++) {
1120 const uint edges_len = edge_groups[j + add_index].edges_len;
1121 if (edges_len > 3) {
1122 bool has_doubles = false;
1123 bool *doubles = MEM_calloc_arrayN<bool>(edges_len, __func__);
1124 EdgeGroup g = edge_groups[j + add_index];
1125 for (uint k = 0; k < edges_len; k++) {
1126 for (uint l = k + 1; l < edges_len; l++) {
1127 if (g.edges[k]->old_edge == g.edges[l]->old_edge) {
1128 doubles[k] = true;
1129 doubles[l] = true;
1130 has_doubles = true;
1131 }
1132 }
1133 }
1134 if (has_doubles) {
1135 const uint prior_splits = splits;
1136 const uint prior_index = add_index;
1137 int unique_start = -1;
1138 int first_unique_end = -1;
1139 int last_split = -1;
1140 int first_split = -1;
1141 bool first_even_split = false;
1142 uint real_k = 0;
1143 while (real_k < edges_len ||
1144 (g.is_orig_closed &&
1145 (real_k <=
1146 (first_unique_end == -1 ? 0 : first_unique_end) + int(edges_len) ||
1147 first_split != last_split)))
1148 {
1149 const uint k = real_k % edges_len;
1150 if (!doubles[k]) {
1151 if (first_unique_end != -1 && unique_start == -1) {
1152 unique_start = int(real_k);
1153 }
1154 }
1155 else if (first_unique_end == -1) {
1156 first_unique_end = int(k);
1157 }
1158 else if (unique_start != -1) {
1159 const uint split = ((uint(unique_start) + real_k + 1) / 2) % edges_len;
1160 const bool is_even_split = ((uint(unique_start) + real_k) & 1);
1161 if (last_split != -1) {
1162 /* Override g on first split (no insert). */
1163 if (prior_splits != splits) {
1164 memmove(edge_groups + j + add_index + 1,
1165 edge_groups + j + add_index,
1166 (uint(eg_index) - j) * sizeof(*edge_groups));
1167 add_index++;
1168 }
1169 if (last_split > split) {
1170 const uint edges_len_group = (split + edges_len) - uint(last_split);
1171 NewEdgeRef **edges = MEM_malloc_arrayN<NewEdgeRef *>(edges_len_group,
1172 __func__);
1173 memcpy(edges,
1174 g.edges + last_split,
1175 (edges_len - uint(last_split)) * sizeof(*edges));
1176 memcpy(edges + (edges_len - uint(last_split)),
1177 g.edges,
1178 split * sizeof(*edges));
1179
1180 EdgeGroup edge_group{};
1181 edge_group.valid = true;
1182 edge_group.edges = edges;
1183 edge_group.edges_len = edges_len_group;
1185 edge_group.is_orig_closed = g.is_orig_closed;
1186 edge_group.is_even_split = is_even_split;
1187 edge_group.split = add_index - prior_index + 1 + uint(!g.is_orig_closed);
1188 edge_group.is_singularity = false;
1189 edge_group.topo_group = g.topo_group;
1190 zero_v3(edge_group.co);
1191 zero_v3(edge_group.no);
1192 edge_group.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1193 edge_groups[j + add_index] = edge_group;
1194 }
1195 else {
1196 const uint edges_len_group = split - uint(last_split);
1197 NewEdgeRef **edges = MEM_malloc_arrayN<NewEdgeRef *>(edges_len_group,
1198 __func__);
1199 memcpy(edges, g.edges + last_split, edges_len_group * sizeof(*edges));
1200
1201 EdgeGroup edge_group{};
1202 edge_group.valid = true;
1203 edge_group.edges = edges;
1204 edge_group.edges_len = edges_len_group;
1206 edge_group.is_orig_closed = g.is_orig_closed;
1207 edge_group.is_even_split = is_even_split;
1208 edge_group.split = add_index - prior_index + 1 + uint(!g.is_orig_closed);
1209 edge_group.is_singularity = false;
1210 edge_group.topo_group = g.topo_group;
1211 zero_v3(edge_group.co);
1212 zero_v3(edge_group.no);
1213 edge_group.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1214 edge_groups[j + add_index] = edge_group;
1215 }
1216 splits++;
1217 }
1218 last_split = int(split);
1219 if (first_split == -1) {
1220 first_split = int(split);
1221 first_even_split = is_even_split;
1222 }
1223 unique_start = -1;
1224 }
1225 real_k++;
1226 }
1227 if (first_split != -1) {
1228 if (!g.is_orig_closed) {
1229 if (prior_splits != splits) {
1230 memmove(edge_groups + (j + prior_index + 1),
1231 edge_groups + (j + prior_index),
1232 (uint(eg_index) + add_index - (j + prior_index)) *
1233 sizeof(*edge_groups));
1234 memmove(edge_groups + (j + add_index + 2),
1235 edge_groups + (j + add_index + 1),
1236 (uint(eg_index) - j) * sizeof(*edge_groups));
1237 add_index++;
1238 }
1239 else {
1240 memmove(edge_groups + (j + add_index + 2),
1241 edge_groups + (j + add_index + 1),
1242 (uint(eg_index) - j - 1) * sizeof(*edge_groups));
1243 }
1244 NewEdgeRef **edges = MEM_malloc_arrayN<NewEdgeRef *>(uint(first_split),
1245 __func__);
1246 memcpy(edges, g.edges, uint(first_split) * sizeof(*edges));
1247
1248 EdgeGroup edge_group_a{};
1249 edge_group_a.valid = true;
1250 edge_group_a.edges = edges;
1251 edge_group_a.edges_len = uint(first_split);
1253 edge_group_a.is_orig_closed = g.is_orig_closed;
1254 edge_group_a.is_even_split = first_even_split;
1255 edge_group_a.split = 1;
1256 edge_group_a.is_singularity = false;
1257 edge_group_a.topo_group = g.topo_group;
1258 zero_v3(edge_group_a.co);
1259 zero_v3(edge_group_a.no);
1260 edge_group_a.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1261 edge_groups[j + prior_index] = edge_group_a;
1262
1263 add_index++;
1264 splits++;
1265 edges = MEM_malloc_arrayN<NewEdgeRef *>(edges_len - uint(last_split),
1266 __func__);
1267 memcpy(edges,
1268 g.edges + last_split,
1269 (edges_len - uint(last_split)) * sizeof(*edges));
1270
1271 EdgeGroup edge_group_b{};
1272 edge_group_b.valid = true;
1273 edge_group_b.edges = edges;
1274 edge_group_b.edges_len = (edges_len - uint(last_split));
1276 edge_group_b.is_orig_closed = g.is_orig_closed;
1277 edge_group_b.is_even_split = false;
1278 edge_group_b.split = add_index - prior_index + 1;
1279 edge_group_b.is_singularity = false;
1280 edge_group_b.topo_group = g.topo_group;
1281 zero_v3(edge_group_b.co);
1282 zero_v3(edge_group_b.no);
1283 edge_group_b.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1284 edge_groups[j + add_index] = edge_group_b;
1285 }
1286 if (prior_splits != splits) {
1287 MEM_freeN(g.edges);
1288 }
1289 }
1290 if (first_unique_end != -1 && prior_splits == splits) {
1291 has_singularities = true;
1292 edge_groups[j + add_index].is_singularity = true;
1293 }
1294 }
1295 MEM_freeN(doubles);
1296 }
1297 }
1298 }
1299 }
1300
1301 orig_vert_groups_arr[i] = edge_groups;
1302 /* Count new edges, loops, faces and add to link_edge_groups. */
1303 {
1304 uint new_verts = 0;
1305 bool contains_open_splits = false;
1306 uint open_edges = 0;
1307 uint contains_splits = 0;
1308 uint last_added = 0;
1309 uint first_added = 0;
1310 bool first_set = false;
1311 for (EdgeGroup *g = edge_groups; g->valid; g++) {
1312 NewEdgeRef **e = g->edges;
1313 for (uint j = 0; j < g->edges_len; j++, e++) {
1314 const uint flip = uint(vm[orig_edges[(*e)->old_edge][1]] == i);
1315 BLI_assert(flip || vm[orig_edges[(*e)->old_edge][0]] == i);
1316 (*e)->link_edge_groups[flip] = g;
1317 }
1318 uint added = 0;
1319 if (do_shell || (do_rim && !g->is_orig_closed)) {
1320 BLI_assert(g->new_vert == MOD_SOLIDIFY_EMPTY_TAG);
1321 g->new_vert = new_verts_num++;
1322 if (do_rim || (do_shell && g->split)) {
1323 new_verts++;
1324 contains_splits += (g->split != 0);
1325 contains_open_splits |= g->split && !g->is_orig_closed;
1326 added = g->split;
1327 }
1328 }
1329 open_edges += uint(added < last_added);
1330 if (!first_set) {
1331 first_set = true;
1332 first_added = added;
1333 }
1334 last_added = added;
1335 if (!(g + 1)->valid || g->topo_group != (g + 1)->topo_group) {
1336 if (new_verts > 2) {
1337 new_faces_num++;
1338 new_edges_num += new_verts;
1339 open_edges += uint(first_added < last_added);
1340 open_edges -= uint(open_edges && !contains_open_splits);
1341 if (do_shell && do_rim) {
1342 new_loops_num += new_verts * 2;
1343 }
1344 else if (do_shell) {
1345 new_loops_num += new_verts * 2 - open_edges;
1346 }
1347 else { // do_rim
1348 new_loops_num += new_verts * 2 + open_edges - contains_splits;
1349 }
1350 }
1351 else if (new_verts == 2) {
1352 new_edges_num++;
1353 new_loops_num += 2u - uint(!(do_rim && do_shell) && contains_open_splits);
1354 }
1355 new_verts = 0;
1356 contains_open_splits = false;
1357 contains_splits = 0;
1358 open_edges = 0;
1359 last_added = 0;
1360 first_added = 0;
1361 first_set = false;
1362 }
1363 }
1364 }
1365 }
1366 }
1367 }
1368
1369 /* Free vert_adj_edges memory. */
1370 {
1371 uint i = 0;
1372 for (OldVertEdgeRef **p = vert_adj_edges; i < verts_num; i++, p++) {
1373 if (*p) {
1374 MEM_freeN((*p)->edges);
1375 MEM_freeN(*p);
1376 }
1377 }
1378 MEM_freeN(vert_adj_edges);
1379 }
1380
1381 /* TODO: create_regions if fix_intersections. */
1382
1383 /* General use pointer for #EdgeGroup iteration. */
1384 EdgeGroup **gs_ptr;
1385
1386 /* Calculate EdgeGroup vertex coordinates. */
1387 {
1388 float *face_weight = nullptr;
1389
1390 if (do_flat_faces) {
1391 face_weight = MEM_malloc_arrayN<float>(faces_num, __func__);
1392
1393 for (const int i : orig_faces.index_range()) {
1394 float scalar_vgroup = 1.0f;
1395 for (const int vert : orig_corner_verts.slice(orig_faces[i])) {
1396 const MDeformVert *dv = &dvert[vert];
1397 if (defgrp_invert) {
1398 scalar_vgroup = min_ff(1.0f - BKE_defvert_find_weight(dv, defgrp_index),
1399 scalar_vgroup);
1400 }
1401 else {
1402 scalar_vgroup = min_ff(BKE_defvert_find_weight(dv, defgrp_index), scalar_vgroup);
1403 }
1404 }
1405 scalar_vgroup = offset_fac_vg + (scalar_vgroup * offset_fac_vg_inv);
1406 face_weight[i] = scalar_vgroup;
1407 }
1408 }
1409
1410 gs_ptr = orig_vert_groups_arr;
1411 for (uint i = 0; i < verts_num; i++, gs_ptr++) {
1412 if (*gs_ptr) {
1413 for (EdgeGroup *g = *gs_ptr; g->valid; g++) {
1414 if (!g->is_singularity) {
1415 float *nor = g->no;
1416 /* During vertex position calculation, the algorithm decides if it wants to disable the
1417 * boundary fix to maintain correct thickness. If the used algorithm does not produce a
1418 * free move direction (move_nor), it can use approximate_free_direction to decide on
1419 * a movement direction based on the connected edges. */
1420 float move_nor[3] = {0, 0, 0};
1421 bool disable_boundary_fix = (smd->nonmanifold_boundary_mode ==
1423 (g->is_orig_closed || g->split));
1424 bool approximate_free_direction = false;
1425 /* Constraints Method. */
1427 NewEdgeRef *first_edge = nullptr;
1428 NewEdgeRef **edge_ptr = g->edges;
1429 /* Contains normal and offset `[nx, ny, nz, ofs]`. */
1430 float (*planes_queue)[4] = MEM_malloc_arrayN<float[4]>(g->edges_len + 1, __func__);
1431 uint queue_index = 0;
1432
1433 float fallback_nor[3];
1434 float fallback_ofs = 0.0f;
1435
1436 const bool cycle = (g->is_orig_closed && !g->split) || g->is_even_split;
1437 for (uint k = 0; k < g->edges_len; k++, edge_ptr++) {
1438 if (!(k & 1) || (!cycle && k == g->edges_len - 1)) {
1439 NewEdgeRef *edge = *edge_ptr;
1440 for (uint l = 0; l < 2; l++) {
1441 NewFaceRef *face = edge->faces[l];
1442 if (face && (first_edge == nullptr ||
1443 (first_edge->faces[0] != face && first_edge->faces[1] != face)))
1444 {
1445 float ofs = face->reversed ? ofs_back_clamped : ofs_front_clamped;
1446 /* Use face_weight here to make faces thinner. */
1447 if (do_flat_faces) {
1448 ofs *= face_weight[face->index];
1449 }
1450
1451 if (!null_faces[face->index]) {
1452 /* And plane to the queue. */
1453 mul_v3_v3fl(planes_queue[queue_index],
1454 face_nors[face->index],
1455 face->reversed ? -1 : 1);
1456 planes_queue[queue_index++][3] = ofs;
1457 }
1458 else {
1459 /* Just use this approximate normal of the null face if there is no other
1460 * normal to use. */
1461 mul_v3_v3fl(fallback_nor, face_nors[face->index], face->reversed ? -1 : 1);
1462 fallback_ofs = ofs;
1463 }
1464 }
1465 }
1466 if ((cycle && k == 0) || (!cycle && k + 3 >= g->edges_len)) {
1467 first_edge = edge;
1468 }
1469 }
1470 }
1471 if (queue_index > 2) {
1472 /* Find the two most different normals. */
1473 float min_p = 2.0f;
1474 uint min_n0 = 0;
1475 uint min_n1 = 0;
1476 for (uint k = 0; k < queue_index; k++) {
1477 for (uint m = k + 1; m < queue_index; m++) {
1478 float p = dot_v3v3(planes_queue[k], planes_queue[m]);
1479 if (p < min_p) {
1480 min_p = p;
1481 min_n0 = k;
1482 min_n1 = m;
1483 }
1484 }
1485 }
1486 /* Put the two found normals, first in the array queue. */
1487 if (min_n1 != 0) {
1488 swap_v4_v4(planes_queue[min_n0], planes_queue[0]);
1489 swap_v4_v4(planes_queue[min_n1], planes_queue[1]);
1490 }
1491 else {
1492 swap_v4_v4(planes_queue[min_n0], planes_queue[1]);
1493 }
1494 /* Find the third most important/different normal. */
1495 min_p = 1.0f;
1496 min_n1 = 2;
1497 float max_p = -1.0f;
1498 for (uint k = 2; k < queue_index; k++) {
1499 max_p = max_ff(dot_v3v3(planes_queue[0], planes_queue[k]),
1500 dot_v3v3(planes_queue[1], planes_queue[k]));
1501 if (max_p <= min_p) {
1502 min_p = max_p;
1503 min_n1 = k;
1504 }
1505 }
1506 swap_v4_v4(planes_queue[min_n1], planes_queue[2]);
1507 }
1508 /* Remove/average duplicate normals in planes_queue. */
1509 while (queue_index > 2) {
1510 uint best_n0 = 0;
1511 uint best_n1 = 0;
1512 float best_p = -1.0f;
1513 float best_ofs_diff = 0.0f;
1514 for (uint k = 0; k < queue_index; k++) {
1515 for (uint m = k + 1; m < queue_index; m++) {
1516 float p = dot_v3v3(planes_queue[m], planes_queue[k]);
1517 float ofs_diff = fabsf(planes_queue[m][3] - planes_queue[k][3]);
1518 if (p > best_p + FLT_EPSILON || (p >= best_p && ofs_diff < best_ofs_diff)) {
1519 best_p = p;
1520 best_ofs_diff = ofs_diff;
1521 best_n0 = k;
1522 best_n1 = m;
1523 }
1524 }
1525 }
1526 /* Make sure there are no equal planes. This threshold is crucial for the
1527 * methods below to work without numerical issues. */
1528 if (best_p < 0.98f) {
1529 break;
1530 }
1531 add_v3_v3(planes_queue[best_n0], planes_queue[best_n1]);
1532 normalize_v3(planes_queue[best_n0]);
1533 planes_queue[best_n0][3] = (planes_queue[best_n0][3] + planes_queue[best_n1][3]) *
1534 0.5f;
1535 queue_index--;
1536 memmove(planes_queue + best_n1,
1537 planes_queue + best_n1 + 1,
1538 (queue_index - best_n1) * sizeof(*planes_queue));
1539 }
1540 const uint size = queue_index;
1541 /* If there is more than 2 planes at this vertex, the boundary fix should be disabled
1542 * to stay at the correct thickness for all the faces. This is not very good in
1543 * practice though, since that will almost always disable the boundary fix. Instead
1544 * introduce a threshold which decides whether the boundary fix can be used without
1545 * major thickness changes. If the following constant is 1.0, it would always
1546 * prioritize correct thickness. At 0.7 the thickness is allowed to change a bit if
1547 * necessary for the fix (~10%). Note this only applies if a boundary fix is used. */
1548 const float boundary_fix_threshold = 0.7f;
1549 if (size > 3) {
1550 /* Use the most general least squares method to find the best position. */
1551 float mat[3][3];
1552 zero_m3(mat);
1553 for (int k = 0; k < 3; k++) {
1554 for (int m = 0; m < size; m++) {
1555 madd_v3_v3fl(mat[k], planes_queue[m], planes_queue[m][k]);
1556 }
1557 /* Add a small epsilon to ensure the invert is going to work.
1558 * This addition makes the inverse more stable and the results
1559 * seem to get more precise. */
1560 mat[k][k] += 5e-5f;
1561 }
1562 /* NOTE: this matrix invert fails if there is less than 3 different normals. */
1563 invert_m3(mat);
1564 zero_v3(nor);
1565 for (int k = 0; k < size; k++) {
1566 madd_v3_v3fl(nor, planes_queue[k], planes_queue[k][3]);
1567 }
1568 mul_v3_m3v3(nor, mat, nor);
1569
1570 if (!disable_boundary_fix) {
1571 /* Figure out if the approximate boundary fix can get use here. */
1572 float greatest_angle_cos = 1.0f;
1573 for (uint k = 0; k < 2; k++) {
1574 for (uint m = 2; m < size; m++) {
1575 float p = dot_v3v3(planes_queue[m], planes_queue[k]);
1576 greatest_angle_cos = std::min(p, greatest_angle_cos);
1577 }
1578 }
1579 if (greatest_angle_cos > boundary_fix_threshold) {
1580 approximate_free_direction = true;
1581 }
1582 else {
1583 disable_boundary_fix = true;
1584 }
1585 }
1586 }
1587 else if (size > 1) {
1588 /* When up to 3 constraint normals are found, there is a simple solution. */
1589 const float stop_explosion = 0.999f - fabsf(smd->offset_fac) * 0.05f;
1590 const float q = dot_v3v3(planes_queue[0], planes_queue[1]);
1591 float d = 1.0f - q * q;
1592 cross_v3_v3v3(move_nor, planes_queue[0], planes_queue[1]);
1593 normalize_v3(move_nor);
1594 if (d > FLT_EPSILON * 10 && q < stop_explosion) {
1595 d = 1.0f / d;
1596 mul_v3_fl(planes_queue[0], (planes_queue[0][3] - planes_queue[1][3] * q) * d);
1597 mul_v3_fl(planes_queue[1], (planes_queue[1][3] - planes_queue[0][3] * q) * d);
1598 }
1599 else {
1600 d = 1.0f / (fabsf(q) + 1.0f);
1601 mul_v3_fl(planes_queue[0], planes_queue[0][3] * d);
1602 mul_v3_fl(planes_queue[1], planes_queue[1][3] * d);
1603 }
1604 add_v3_v3v3(nor, planes_queue[0], planes_queue[1]);
1605 if (size == 3) {
1606 d = dot_v3v3(planes_queue[2], move_nor);
1607 /* The following threshold ignores the third plane if it is almost orthogonal to
1608 * the still free direction. */
1609 if (fabsf(d) > 0.02f) {
1610 float tmp[3];
1611 madd_v3_v3v3fl(tmp, nor, planes_queue[2], -planes_queue[2][3]);
1612 mul_v3_v3fl(tmp, move_nor, dot_v3v3(planes_queue[2], tmp) / d);
1613 sub_v3_v3(nor, tmp);
1614 /* Disable boundary fix if the constraints would be majorly unsatisfied. */
1615 if (fabsf(d) > 1.0f - boundary_fix_threshold) {
1616 disable_boundary_fix = true;
1617 }
1618 }
1619 }
1620 approximate_free_direction = false;
1621 }
1622 else if (size == 1) {
1623 /* Face corner case. */
1624 mul_v3_v3fl(nor, planes_queue[0], planes_queue[0][3]);
1625 if (g->edges_len > 2) {
1626 disable_boundary_fix = true;
1627 approximate_free_direction = true;
1628 }
1629 }
1630 else {
1631 /* Fallback case for null faces. */
1632 mul_v3_v3fl(nor, fallback_nor, fallback_ofs);
1633 disable_boundary_fix = true;
1634 }
1635 MEM_freeN(planes_queue);
1636 }
1637 /* Fixed/Even Method. */
1638 else {
1639 float total_angle = 0;
1640 float total_angle_back = 0;
1641 NewEdgeRef *first_edge = nullptr;
1642 NewEdgeRef **edge_ptr = g->edges;
1643 float face_nor[3];
1644 float nor_back[3] = {0, 0, 0};
1645 bool has_back = false;
1646 bool has_front = false;
1647 bool cycle = (g->is_orig_closed && !g->split) || g->is_even_split;
1648 for (uint k = 0; k < g->edges_len; k++, edge_ptr++) {
1649 if (!(k & 1) || (!cycle && k == g->edges_len - 1)) {
1650 NewEdgeRef *edge = *edge_ptr;
1651 for (uint l = 0; l < 2; l++) {
1652 NewFaceRef *face = edge->faces[l];
1653 if (face && (first_edge == nullptr ||
1654 (first_edge->faces[0] != face && first_edge->faces[1] != face)))
1655 {
1656 float angle = 1.0f;
1657 float ofs = face->reversed ? -ofs_back_clamped : ofs_front_clamped;
1658 /* Use face_weight here to make faces thinner. */
1659 if (do_flat_faces) {
1660 ofs *= face_weight[face->index];
1661 }
1662
1663 if (smd->nonmanifold_offset_mode ==
1665 {
1666 int corner_next = face->face.start();
1667 int corner = corner_next + (face->face.size() - 1);
1668 int corner_prev = corner - 1;
1669
1670 for (int m = 0;
1671 m < face->face.size() && vm[orig_corner_verts[corner]] != i;
1672 m++, corner_next++)
1673 {
1674 corner_prev = corner;
1675 corner = corner_next;
1676 }
1677 angle = angle_v3v3v3(orig_mvert_co[vm[orig_corner_verts[corner_prev]]],
1678 orig_mvert_co[i],
1679 orig_mvert_co[vm[orig_corner_verts[corner_next]]]);
1680 if (face->reversed) {
1681 total_angle_back += angle * ofs * ofs;
1682 }
1683 else {
1684 total_angle += angle * ofs * ofs;
1685 }
1686 }
1687 else {
1688 if (face->reversed) {
1689 total_angle_back++;
1690 }
1691 else {
1692 total_angle++;
1693 }
1694 }
1695 mul_v3_v3fl(face_nor, face_nors[face->index], angle * ofs);
1696 if (face->reversed) {
1697 add_v3_v3(nor_back, face_nor);
1698 has_back = true;
1699 }
1700 else {
1701 add_v3_v3(nor, face_nor);
1702 has_front = true;
1703 }
1704 }
1705 }
1706 if ((cycle && k == 0) || (!cycle && k + 3 >= g->edges_len)) {
1707 first_edge = edge;
1708 }
1709 }
1710 }
1711
1712 /* Set normal length with selected method. */
1714 if (has_front) {
1715 float length_sq = len_squared_v3(nor);
1716 if (LIKELY(length_sq > FLT_EPSILON)) {
1717 mul_v3_fl(nor, total_angle / length_sq);
1718 }
1719 }
1720 if (has_back) {
1721 float length_sq = len_squared_v3(nor_back);
1722 if (LIKELY(length_sq > FLT_EPSILON)) {
1723 mul_v3_fl(nor_back, total_angle_back / length_sq);
1724 }
1725 if (!has_front) {
1726 copy_v3_v3(nor, nor_back);
1727 }
1728 }
1729 if (has_front && has_back) {
1730 float nor_length = len_v3(nor);
1731 float nor_back_length = len_v3(nor_back);
1732 float q = dot_v3v3(nor, nor_back);
1733 if (LIKELY(fabsf(q) > FLT_EPSILON)) {
1734 q /= nor_length * nor_back_length;
1735 }
1736 float d = 1.0f - q * q;
1737 if (LIKELY(d > FLT_EPSILON)) {
1738 d = 1.0f / d;
1739 if (LIKELY(nor_length > FLT_EPSILON)) {
1740 mul_v3_fl(nor, (1 - nor_back_length * q / nor_length) * d);
1741 }
1742 if (LIKELY(nor_back_length > FLT_EPSILON)) {
1743 mul_v3_fl(nor_back, (1 - nor_length * q / nor_back_length) * d);
1744 }
1745 add_v3_v3(nor, nor_back);
1746 }
1747 else {
1748 mul_v3_fl(nor, 0.5f);
1749 mul_v3_fl(nor_back, 0.5f);
1750 add_v3_v3(nor, nor_back);
1751 }
1752 }
1753 }
1754 else {
1755 if (has_front && total_angle > FLT_EPSILON) {
1756 mul_v3_fl(nor, 1.0f / total_angle);
1757 }
1758 if (has_back && total_angle_back > FLT_EPSILON) {
1759 mul_v3_fl(nor_back, 1.0f / total_angle_back);
1760 add_v3_v3(nor, nor_back);
1761 if (has_front && total_angle > FLT_EPSILON) {
1762 mul_v3_fl(nor, 0.5f);
1763 }
1764 }
1765 }
1766 /* Set move_nor for boundary fix. */
1767 if (!disable_boundary_fix && g->edges_len > 2) {
1768 approximate_free_direction = true;
1769 }
1770 else {
1771 disable_boundary_fix = true;
1772 }
1773 }
1774 if (approximate_free_direction) {
1775 /* Set move_nor for boundary fix. */
1776 NewEdgeRef **edge_ptr = g->edges + 1;
1777 float tmp[3];
1778 int k;
1779 for (k = 1; k + 1 < g->edges_len; k++, edge_ptr++) {
1780 const int2 &edge = orig_edges[(*edge_ptr)->old_edge];
1782 tmp, orig_mvert_co[vm[edge[0]] == i ? edge[1] : edge[0]], orig_mvert_co[i]);
1783 add_v3_v3(move_nor, tmp);
1784 }
1785 if (k == 1) {
1786 disable_boundary_fix = true;
1787 }
1788 else {
1789 disable_boundary_fix = normalize_v3(move_nor) == 0.0f;
1790 }
1791 }
1792 /* Fix boundary verts. */
1793 if (!disable_boundary_fix) {
1794 /* Constraint normal, nor * constr_nor == 0 after this fix. */
1795 float constr_nor[3];
1796 const int2 &e0_edge = orig_edges[g->edges[0]->old_edge];
1797 const int2 &e1_edge = orig_edges[g->edges[g->edges_len - 1]->old_edge];
1798 float e0[3];
1799 float e1[3];
1800 sub_v3_v3v3(e0,
1801 orig_mvert_co[vm[e0_edge[0]] == i ? e0_edge[1] : e0_edge[0]],
1802 orig_mvert_co[i]);
1803 sub_v3_v3v3(e1,
1804 orig_mvert_co[vm[e1_edge[0]] == i ? e1_edge[1] : e1_edge[0]],
1805 orig_mvert_co[i]);
1807 cross_v3_v3v3(constr_nor, e0, e1);
1808 normalize_v3(constr_nor);
1809 }
1810 else {
1813 float f0[3];
1814 float f1[3];
1815 if (g->edges[0]->faces[0]->reversed) {
1816 negate_v3_v3(f0, face_nors[g->edges[0]->faces[0]->index]);
1817 }
1818 else {
1819 copy_v3_v3(f0, face_nors[g->edges[0]->faces[0]->index]);
1820 }
1821 if (g->edges[g->edges_len - 1]->faces[0]->reversed) {
1822 negate_v3_v3(f1, face_nors[g->edges[g->edges_len - 1]->faces[0]->index]);
1823 }
1824 else {
1825 copy_v3_v3(f1, face_nors[g->edges[g->edges_len - 1]->faces[0]->index]);
1826 }
1827 float n0[3];
1828 float n1[3];
1829 cross_v3_v3v3(n0, e0, f0);
1830 cross_v3_v3v3(n1, f1, e1);
1831 normalize_v3(n0);
1832 normalize_v3(n1);
1833 add_v3_v3v3(constr_nor, n0, n1);
1834 normalize_v3(constr_nor);
1835 }
1836 float d = dot_v3v3(constr_nor, move_nor);
1837 /* Only allow the thickness to increase about 10 times. */
1838 if (fabsf(d) > 0.1f) {
1839 mul_v3_fl(move_nor, dot_v3v3(constr_nor, nor) / d);
1840 sub_v3_v3(nor, move_nor);
1841 }
1842 }
1843 float scalar_vgroup = 1;
1844 /* Use vertex group. */
1845 if (dvert && !do_flat_faces) {
1846 const MDeformVert *dv = &dvert[i];
1847 if (defgrp_invert) {
1848 scalar_vgroup = 1.0f - BKE_defvert_find_weight(dv, defgrp_index);
1849 }
1850 else {
1851 scalar_vgroup = BKE_defvert_find_weight(dv, defgrp_index);
1852 }
1853 scalar_vgroup = offset_fac_vg + (scalar_vgroup * offset_fac_vg_inv);
1854 }
1855 /* Do clamping. */
1856 if (do_clamp) {
1857 if (do_angle_clamp) {
1858 if (g->edges_len > 2) {
1859 float min_length = 0;
1860 float angle = 0.5f * M_PI;
1861 uint k = 0;
1862 for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) {
1863 float length = orig_edge_lengths[(*p)->old_edge];
1864 float e_ang = (*p)->angle;
1865 angle = std::max(e_ang, angle);
1866 if (length < min_length || k == 0) {
1867 min_length = length;
1868 }
1869 }
1870 float cos_ang = cosf(angle * 0.5f);
1871 if (cos_ang > 0) {
1872 float max_off = min_length * 0.5f / cos_ang;
1873 if (max_off < offset * 0.5f) {
1874 scalar_vgroup *= max_off / offset * 2;
1875 }
1876 }
1877 }
1878 }
1879 else {
1880 float min_length = 0;
1881 uint k = 0;
1882 for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) {
1883 float length = orig_edge_lengths[(*p)->old_edge];
1884 if (length < min_length || k == 0) {
1885 min_length = length;
1886 }
1887 }
1888 if (min_length < offset) {
1889 scalar_vgroup *= min_length / offset;
1890 }
1891 }
1892 }
1893 mul_v3_fl(nor, scalar_vgroup);
1894 add_v3_v3v3(g->co, nor, orig_mvert_co[i]);
1895 }
1896 else {
1897 copy_v3_v3(g->co, orig_mvert_co[i]);
1898 }
1899 }
1900 }
1901 }
1902
1903 if (do_flat_faces) {
1904 MEM_freeN(face_weight);
1905 }
1906 }
1907
1908 MEM_freeN(orig_mvert_co);
1909 if (null_faces) {
1910 MEM_freeN(null_faces);
1911 }
1912
1913 /* TODO: create vertdata for intersection fixes (intersection fixing per topology region). */
1914
1915 /* Correction for adjacent one sided groups around a vert to
1916 * prevent edge duplicates and null faces. */
1917 uint(*singularity_edges)[2] = nullptr;
1918 uint totsingularity = 0;
1919 if (has_singularities) {
1920 has_singularities = false;
1921 uint i = 0;
1922 uint singularity_edges_len = 1;
1923 singularity_edges = MEM_malloc_arrayN<uint[2]>(singularity_edges_len, __func__);
1924 for (NewEdgeRef ***new_edges = orig_edge_data_arr; i < edges_num; i++, new_edges++) {
1925 if (*new_edges && (do_shell || edge_adj_faces_len[i] == 1) && (**new_edges)->old_edge == i) {
1926 for (NewEdgeRef **l = *new_edges; *l; l++) {
1927 if ((*l)->link_edge_groups[0]->is_singularity &&
1928 (*l)->link_edge_groups[1]->is_singularity)
1929 {
1930 const uint v1 = (*l)->link_edge_groups[0]->new_vert;
1931 const uint v2 = (*l)->link_edge_groups[1]->new_vert;
1932 bool exists_already = false;
1933 uint j = 0;
1934 for (uint(*p)[2] = singularity_edges; j < totsingularity; p++, j++) {
1935 if (((*p)[0] == v1 && (*p)[1] == v2) || ((*p)[0] == v2 && (*p)[1] == v1)) {
1936 exists_already = true;
1937 break;
1938 }
1939 }
1940 if (!exists_already) {
1941 has_singularities = true;
1942 if (singularity_edges_len <= totsingularity) {
1943 singularity_edges_len = totsingularity + 1;
1944 singularity_edges = static_cast<uint(*)[2]>(
1945 MEM_reallocN_id(singularity_edges,
1946 singularity_edges_len * sizeof(*singularity_edges),
1947 __func__));
1948 }
1949 singularity_edges[totsingularity][0] = v1;
1950 singularity_edges[totsingularity][1] = v2;
1951 totsingularity++;
1952 if (edge_adj_faces_len[i] == 1 && do_rim) {
1953 new_loops_num -= 2;
1954 new_faces_num--;
1955 }
1956 }
1957 else {
1958 new_edges_num--;
1959 }
1960 }
1961 }
1962 }
1963 }
1964 }
1965
1966 /* Create Mesh *result with proper capacity. */
1968 mesh, int(new_verts_num), int(new_edges_num), int(new_faces_num), int(new_loops_num));
1969
1970 blender::MutableSpan<float3> vert_positions = result->vert_positions_for_write();
1971 blender::MutableSpan<int2> edges = result->edges_for_write();
1972 blender::MutableSpan<int> face_offsets = result->face_offsets_for_write();
1973 blender::MutableSpan<int> corner_verts = result->corner_verts_for_write();
1974 blender::MutableSpan<int> corner_edges = result->corner_edges_for_write();
1975 bke::MutableAttributeAccessor result_attributes = result->attributes_for_write();
1976
1977 int *origindex_edge = static_cast<int *>(
1978 CustomData_get_layer_for_write(&result->edge_data, CD_ORIGINDEX, result->edges_num));
1979 int *origindex_face = static_cast<int *>(
1980 CustomData_get_layer_for_write(&result->face_data, CD_ORIGINDEX, result->faces_num));
1981
1982 bke::SpanAttributeWriter<float> result_edge_bweight;
1983 if (orig_attributes.contains("bevel_weight_edge") ||
1984 (bevel_convex != 0.0f || !orig_vert_bweight.is_empty()))
1985 {
1986 result_edge_bweight = result_attributes.lookup_or_add_for_write_span<float>(
1987 "bevel_weight_edge", blender::bke::AttrDomain::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 VArraySpan vertex_crease = *orig_attributes.lookup<float>("crease_vert",
2000 bke::SpanAttributeWriter<float> result_edge_crease;
2001
2002 if (!vertex_crease.is_empty() || !orig_edge_crease.is_empty()) {
2003 result_edge_crease = result_attributes.lookup_or_add_for_write_span<float>(
2004 "crease_edge", blender::bke::AttrDomain::Edge);
2005 /* delete all vertex creases in the result if a rim is used. */
2006 if (do_rim) {
2007 result_attributes.remove("crease_vert");
2008 }
2009 }
2010
2011 /* Make_new_verts. */
2012 {
2013 gs_ptr = orig_vert_groups_arr;
2014 for (uint i = 0; i < verts_num; i++, gs_ptr++) {
2015 EdgeGroup *gs = *gs_ptr;
2016 if (gs) {
2017 for (EdgeGroup *g = gs; g->valid; g++) {
2018 if (g->new_vert != MOD_SOLIDIFY_EMPTY_TAG) {
2020 &mesh->vert_data, &result->vert_data, int(i), int(g->new_vert), 1);
2021 copy_v3_v3(vert_positions[g->new_vert], g->co);
2022 }
2023 }
2024 }
2025 }
2026 }
2027
2028 /* Make edges. */
2029 {
2030 uint i = 0;
2031 edge_index += totsingularity;
2032 for (NewEdgeRef ***new_edges = orig_edge_data_arr; i < edges_num; i++, new_edges++) {
2033 if (*new_edges && (do_shell || edge_adj_faces_len[i] == 1) && (**new_edges)->old_edge == i) {
2034 for (NewEdgeRef **l = *new_edges; *l; l++) {
2035 if ((*l)->new_edge != MOD_SOLIDIFY_EMPTY_TAG) {
2036 const uint v1 = (*l)->link_edge_groups[0]->new_vert;
2037 const uint v2 = (*l)->link_edge_groups[1]->new_vert;
2038 uint insert = edge_index;
2039 if (has_singularities && ((*l)->link_edge_groups[0]->is_singularity &&
2040 (*l)->link_edge_groups[1]->is_singularity))
2041 {
2042 uint j = 0;
2043 for (uint(*p)[2] = singularity_edges; j < totsingularity; p++, j++) {
2044 if (((*p)[0] == v1 && (*p)[1] == v2) || ((*p)[0] == v2 && (*p)[1] == v1)) {
2045 insert = j;
2046 break;
2047 }
2048 }
2049 BLI_assert(insert == j);
2050 }
2051 else {
2052 edge_index++;
2053 }
2054 CustomData_copy_data(&mesh->edge_data, &result->edge_data, int(i), int(insert), 1);
2057 edges[insert][0] = v1;
2058 edges[insert][1] = v2;
2059 if (result_edge_crease) {
2060 result_edge_crease.span[insert] = !orig_edge_crease.is_empty() ?
2061 orig_edge_crease[(*l)->old_edge] :
2062 0.0f;
2063 }
2064 if (result_edge_bweight) {
2065 result_edge_bweight.span[insert] = !orig_edge_bweight.is_empty() ?
2066 orig_edge_bweight[(*l)->old_edge] :
2067 0.0f;
2068 if (bevel_convex != 0.0f && (*l)->faces[1] != nullptr) {
2069 result_edge_bweight.span[insert] = clamp_f(
2070 result_edge_bweight.span[insert] +
2071 ((*l)->angle > M_PI + FLT_EPSILON ?
2072 clamp_f(bevel_convex, 0.0f, 1.0f) :
2073 ((*l)->angle < M_PI - FLT_EPSILON ?
2074 clamp_f(bevel_convex, -1.0f, 0.0f) :
2075 0)),
2076 0.0f,
2077 1.0f);
2078 }
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 VArraySpan src_material_index = *orig_attributes.lookup<int>("material_index",
2129 bke::SpanAttributeWriter dst_material_index =
2130 result_attributes.lookup_or_add_for_write_span<int>("material_index", bke::AttrDomain::Face);
2131
2132 /* Make boundary edges/faces. */
2133 {
2134 gs_ptr = orig_vert_groups_arr;
2135 for (uint i = 0; i < verts_num; i++, gs_ptr++) {
2136 EdgeGroup *gs = *gs_ptr;
2137 if (gs) {
2138 EdgeGroup *g = gs;
2139 EdgeGroup *g2 = gs;
2140 EdgeGroup *last_g = nullptr;
2141 EdgeGroup *first_g = nullptr;
2142 float mv_crease = !vertex_crease.is_empty() ? vertex_crease[i] : 0.0f;
2143 float mv_bweight = !orig_vert_bweight.is_empty() ? orig_vert_bweight[i] : 0.0f;
2144 /* Data calculation cache. */
2145 float max_crease;
2146 float last_max_crease = 0.0f;
2147 float first_max_crease = 0.0f;
2148 float max_bweight;
2149 float last_max_bweight = 0.0f;
2150 float first_max_bweight = 0.0f;
2151 for (uint j = 0; g->valid; g++) {
2152 if ((do_rim && !g->is_orig_closed) || (do_shell && g->split)) {
2153 max_crease = 0;
2154 max_bweight = 0;
2155
2156 BLI_assert(g->edges_len >= 2);
2157
2158 if (g->edges_len == 2) {
2159 if (result_edge_crease) {
2160 if (!orig_edge_crease.is_empty()) {
2161 max_crease = min_ff(orig_edge_crease[g->edges[0]->old_edge],
2162 orig_edge_crease[g->edges[1]->old_edge]);
2163 }
2164 else {
2165 max_crease = 0.0f;
2166 }
2167 }
2168 }
2169 else {
2170 for (uint k = 1; k < g->edges_len - 1; k++) {
2171 const uint orig_edge_index = g->edges[k]->old_edge;
2172 if (result_edge_crease) {
2173 if (!orig_edge_crease.is_empty() &&
2174 orig_edge_crease[orig_edge_index] > max_crease)
2175 {
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.span[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.is_empty() ?
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.span[edge_index] = max_ff(mv_crease,
2220 min_ff(last_max_crease, max_crease));
2221 }
2222 if (result_edge_bweight) {
2223 result_edge_bweight.span[edge_index] = max_ff(
2224 mv_bweight, 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.span[edge_index] = max_ff(
2251 mv_crease, min_ff(last_max_crease, first_max_crease));
2252 }
2253 if (result_edge_bweight) {
2254 result_edge_bweight.span[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 result_edge_bweight.finish();
2690 result_edge_crease.finish();
2691
2692 return result;
2693}
2694
CustomData interface, see also DNA_customdata_types.h.
#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)
support for deformation groups and hooks.
MDeformWeight * BKE_defvert_ensure_index(MDeformVert *dv, int defgroup)
Definition deform.cc:825
int BKE_id_defgroup_name_index(const ID *id, blender::StringRef name)
Definition deform.cc:549
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:774
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)
@ 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
@ MOD_SOLIDIFY_RIM
@ MOD_SOLIDIFY_FLIP
@ MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP
@ MOD_SOLIDIFY_NONMANIFOLD_FLAT_FACES
@ MOD_SOLIDIFY_VGROUP_INV
@ MOD_SOLIDIFY_NOSHELL
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
bool contains(StringRef attribute_id) const
GAttributeReader lookup(const StringRef attribute_id) const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bool remove(const StringRef attribute_id)
nullptr float
#define acosf(x)
uint pos
uint nor
#define printf(...)
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
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]
#define fabsf
#define sqrtf
#define cosf
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