Blender V4.3
bmesh_decimate_collapse.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
11#include <cstddef>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_alloca.h"
16#include "BLI_heap.h"
17#include "BLI_linklist.h"
18#include "BLI_math_geom.h"
19#include "BLI_math_vector.h"
20#include "BLI_memarena.h"
21#include "BLI_polyfill_2d.h"
23#include "BLI_quadric.h"
25
26#include "BKE_customdata.hh"
27
28#include "bmesh.hh"
29#include "bmesh_decimate.hh" /* own include */
30
32
33#define USE_SYMMETRY
34#ifdef USE_SYMMETRY
35# include "BLI_kdtree.h"
36#endif
37
38/* defines for testing */
39#define USE_CUSTOMDATA
40#define USE_TRIANGULATE
42#define USE_VERT_NORMAL_INTERP
43
45#define USE_TOPOLOGY_FALLBACK
46#ifdef USE_TOPOLOGY_FALLBACK
48# define TOPOLOGY_FALLBACK_EPS 1e-12f
49#endif
50
51#define BOUNDARY_PRESERVE_WEIGHT 100.0f
56#define OPTIMIZE_EPS 1e-8
57#define COST_INVALID FLT_MAX
58
60 CD_DO_VERT = (1 << 0),
61 CD_DO_EDGE = (1 << 1),
62 CD_DO_LOOP = (1 << 2),
63};
65
66/* BMesh Helper Functions
67 * ********************** */
68
69
72static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
73{
74 BMIter iter;
75 BMFace *f;
76 BMEdge *e;
77
78 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
79 BMLoop *l_first;
80 BMLoop *l_iter;
81
82 float center[3];
83 double plane_db[4];
84 Quadric q;
85
87 copy_v3db_v3fl(plane_db, f->no);
88 plane_db[3] = -dot_v3db_v3fl(plane_db, center);
89
90 BLI_quadric_from_plane(&q, plane_db);
91
92 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
93 do {
94 BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(l_iter->v)], &q);
95 } while ((l_iter = l_iter->next) != l_first);
96 }
97
98 /* boundary edges */
101 float edge_vector[3];
102 float edge_plane[3];
103 double edge_plane_db[4];
104 sub_v3_v3v3(edge_vector, e->v2->co, e->v1->co);
105 f = e->l->f;
106
107 cross_v3_v3v3(edge_plane, edge_vector, f->no);
108 copy_v3db_v3fl(edge_plane_db, edge_plane);
109
110 if (normalize_v3_db(edge_plane_db) > double(FLT_EPSILON)) {
111 Quadric q;
112 float center[3];
113
114 mid_v3_v3v3(center, e->v1->co, e->v2->co);
115
116 edge_plane_db[3] = -dot_v3db_v3fl(edge_plane_db, center);
117 BLI_quadric_from_plane(&q, edge_plane_db);
119
120 BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(e->v1)], &q);
121 BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(e->v2)], &q);
122 }
123 }
124 }
125}
126
127static void bm_decim_calc_target_co_db(BMEdge *e, double optimize_co[3], const Quadric *vquadrics)
128{
129 /* compute an edge contraction target for edge 'e'
130 * this is computed by summing its vertices quadrics and
131 * optimizing the result. */
132 Quadric q;
133
135 &q, &vquadrics[BM_elem_index_get(e->v1)], &vquadrics[BM_elem_index_get(e->v2)]);
136
137 if (BLI_quadric_optimize(&q, optimize_co, OPTIMIZE_EPS)) {
138 /* all is good */
139 return;
140 }
141
142 optimize_co[0] = 0.5 * (double(e->v1->co[0]) + double(e->v2->co[0]));
143 optimize_co[1] = 0.5 * (double(e->v1->co[1]) + double(e->v2->co[1]));
144 optimize_co[2] = 0.5 * (double(e->v1->co[2]) + double(e->v2->co[2]));
145}
146
147static void bm_decim_calc_target_co_fl(BMEdge *e, float optimize_co[3], const Quadric *vquadrics)
148{
149 double optimize_co_db[3];
150 bm_decim_calc_target_co_db(e, optimize_co_db, vquadrics);
151 copy_v3fl_v3db(optimize_co, optimize_co_db);
152}
153
154static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_co[3])
155{
156 BMIter liter;
157 BMLoop *l;
158 uint i;
159
160 for (i = 0; i < 2; i++) {
161 /* loop over both verts */
162 BMVert *v = *((&e->v1) + i);
163
164 BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
165 if (l->e != e && l->prev->e != e) {
166 const float *co_prev = l->prev->v->co;
167 const float *co_next = l->next->v->co;
168 float cross_exist[3];
169 float cross_optim[3];
170
171#if 1
172 /* line between the two outer verts, re-use for both cross products */
173 float vec_other[3];
174 /* before collapse */
175 float vec_exist[3];
176 /* after collapse */
177 float vec_optim[3];
178
179 sub_v3_v3v3(vec_other, co_prev, co_next);
180 sub_v3_v3v3(vec_exist, co_prev, v->co);
181 sub_v3_v3v3(vec_optim, co_prev, optimize_co);
182
183 cross_v3_v3v3(cross_exist, vec_other, vec_exist);
184 cross_v3_v3v3(cross_optim, vec_other, vec_optim);
185
186 /* avoid normalize */
187 if (dot_v3v3(cross_exist, cross_optim) <=
188 (len_squared_v3(cross_exist) + len_squared_v3(cross_optim)) * 0.01f)
189 {
190 return true;
191 }
192#else
193 normal_tri_v3(cross_exist, v->co, co_prev, co_next);
194 normal_tri_v3(cross_optim, optimize_co, co_prev, co_next);
195
196 /* use a small value rather than zero so we don't flip a face in multiple steps
197 * (first making it zero area, then flipping again) */
198 if (dot_v3v3(cross_exist, cross_optim) <= FLT_EPSILON) {
199 // printf("no flip\n");
200 return true;
201 }
202#endif
203 }
204 }
205 }
206
207 return false;
208}
209
210#ifdef USE_TOPOLOGY_FALLBACK
218{
219 return fabsf(dot_v3v3(e->v1->no, e->v2->no)) /
220 min_ff(-len_squared_v3v3(e->v1->co, e->v2->co), -FLT_EPSILON);
221}
223{
224 return fabsf(dot_v3v3(e->v1->no, e->v2->no)) /
225 min_ff(-len_v3v3(e->v1->co, e->v2->co), -FLT_EPSILON);
226}
227
228#endif /* USE_TOPOLOGY_FALLBACK */
229
231 const Quadric *vquadrics,
232 const float *vweights,
233 const float vweight_factor,
234 Heap *eheap,
235 HeapNode **eheap_table)
236{
237 float cost;
238
239 if (UNLIKELY(vweights && ((vweights[BM_elem_index_get(e->v1)] == 0.0f) ||
240 (vweights[BM_elem_index_get(e->v2)] == 0.0f))))
241 {
242 goto clear;
243 }
244
245 /* Check we can collapse, some edges we better not touch. */
246 if (BM_edge_is_boundary(e)) {
247 if (e->l->f->len == 3) {
248 /* Pass. */
249 }
250 else {
251 /* Only collapse triangles. */
252 goto clear;
253 }
254 }
255 else if (BM_edge_is_manifold(e)) {
256 if ((e->l->f->len == 3) && (e->l->radial_next->f->len == 3)) {
257 /* Pass. */
258 }
259 else {
260 /* Only collapse triangles. */
261 goto clear;
262 }
263 }
264 else {
265 goto clear;
266 }
267 /* End sanity check. */
268
269 {
270 double optimize_co[3];
271 bm_decim_calc_target_co_db(e, optimize_co, vquadrics);
272
273 const Quadric *q1, *q2;
274 q1 = &vquadrics[BM_elem_index_get(e->v1)];
275 q2 = &vquadrics[BM_elem_index_get(e->v2)];
276
277 cost = (BLI_quadric_evaluate(q1, optimize_co) + BLI_quadric_evaluate(q2, optimize_co));
278 }
279
280 /* NOTE: 'cost' shouldn't be negative but happens sometimes with small values.
281 * this can cause faces that make up a flat surface to over-collapse, see #37121. */
282 cost = fabsf(cost);
283
284#ifdef USE_TOPOLOGY_FALLBACK
285 if (UNLIKELY(cost < TOPOLOGY_FALLBACK_EPS)) {
286 /* subtract existing cost to further differentiate edges from one another
287 *
288 * keep topology cost below 0.0 so their values don't interfere with quadric cost,
289 * (and they get handled first). */
290 if (vweights == nullptr) {
292 }
293 else {
294 /* with weights we need to use the real length so we can scale them properly */
295 const float e_weight = (vweights[BM_elem_index_get(e->v1)] +
296 vweights[BM_elem_index_get(e->v2)]);
298 /* NOTE: this is rather arbitrary max weight is 2 here,
299 * allow for skipping edges 4x the length, based on weights */
300 if (e_weight) {
301 cost *= 1.0f + (e_weight * vweight_factor);
302 }
303
304 BLI_assert(cost <= 0.0f);
305 }
306 }
307 else
308#endif
309 if (vweights)
310 {
311 const float e_weight = 2.0f - (vweights[BM_elem_index_get(e->v1)] +
312 vweights[BM_elem_index_get(e->v2)]);
313 if (e_weight) {
314 cost += (BM_edge_calc_length(e) * (e_weight * vweight_factor));
315 }
316 }
317
318 BLI_heap_insert_or_update(eheap, &eheap_table[BM_elem_index_get(e)], cost, e);
319 return;
320
321clear:
322 if (eheap_table[BM_elem_index_get(e)]) {
323 BLI_heap_remove(eheap, eheap_table[BM_elem_index_get(e)]);
324 }
325 eheap_table[BM_elem_index_get(e)] = nullptr;
326}
327
328/* use this for degenerate cases - add back to the heap with an invalid cost,
329 * this way it may be calculated again if surrounding geometry changes */
330static void bm_decim_invalid_edge_cost_single(BMEdge *e, Heap *eheap, HeapNode **eheap_table)
331{
332 BLI_assert(eheap_table[BM_elem_index_get(e)] == nullptr);
333 eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, COST_INVALID, e);
334}
335
337 const Quadric *vquadrics,
338 const float *vweights,
339 const float vweight_factor,
340 Heap *eheap,
341 HeapNode **eheap_table)
342{
343 BMIter iter;
344 BMEdge *e;
345 uint i;
346
348 /* keep sanity check happy */
349 eheap_table[i] = nullptr;
350 bm_decim_build_edge_cost_single(e, vquadrics, vweights, vweight_factor, eheap, eheap_table);
351 }
352}
353
354#ifdef USE_SYMMETRY
355
357 /* pre-flipped coords */
358 float e_v1_co[3], e_v2_co[3];
359 /* Use to compare the correct endpoints in case v1/v2 are swapped. */
360 float e_dir[3];
361
363
364 /* same for all */
366 float limit_sq;
367};
368
369static bool bm_edge_symmetry_check_cb(void *user_data,
370 int index,
371 const float[3] /*co*/,
372 float /*dist_sq*/)
373{
374 KD_Symmetry_Data *sym_data = static_cast<KD_Symmetry_Data *>(user_data);
375 BMEdge *e_other = sym_data->etable[index];
376 float e_other_dir[3];
377
378 sub_v3_v3v3(e_other_dir, e_other->v2->co, e_other->v1->co);
379
380 if (dot_v3v3(e_other_dir, sym_data->e_dir) > 0.0f) {
381 if ((len_squared_v3v3(sym_data->e_v1_co, e_other->v1->co) > sym_data->limit_sq) ||
382 (len_squared_v3v3(sym_data->e_v2_co, e_other->v2->co) > sym_data->limit_sq))
383 {
384 return true;
385 }
386 }
387 else {
388 if ((len_squared_v3v3(sym_data->e_v1_co, e_other->v2->co) > sym_data->limit_sq) ||
389 (len_squared_v3v3(sym_data->e_v2_co, e_other->v1->co) > sym_data->limit_sq))
390 {
391 return true;
392 }
393 }
394
395 /* exit on first-hit, this is OK since the search range is very small */
396 sym_data->e_found_index = index;
397 return false;
398}
399
400static int *bm_edge_symmetry_map(BMesh *bm, uint symmetry_axis, float limit)
401{
402 KD_Symmetry_Data sym_data;
403 BMIter iter;
404 BMEdge *e, **etable;
405 uint i;
406 int *edge_symmetry_map;
407 const float limit_sq = square_f(limit);
408 KDTree_3d *tree;
409
410 tree = BLI_kdtree_3d_new(bm->totedge);
411
412 etable = static_cast<BMEdge **>(MEM_mallocN(sizeof(*etable) * bm->totedge, __func__));
413 edge_symmetry_map = static_cast<int *>(
414 MEM_mallocN(sizeof(*edge_symmetry_map) * bm->totedge, __func__));
415
417 float co[3];
418 mid_v3_v3v3(co, e->v1->co, e->v2->co);
419 BLI_kdtree_3d_insert(tree, i, co);
420 etable[i] = e;
421 edge_symmetry_map[i] = -1;
422 }
423
424 BLI_kdtree_3d_balance(tree);
425
426 sym_data.etable = etable;
427 sym_data.limit_sq = limit_sq;
428
430 if (edge_symmetry_map[i] == -1) {
431 float co[3];
432 mid_v3_v3v3(co, e->v1->co, e->v2->co);
433 co[symmetry_axis] *= -1.0f;
434
435 copy_v3_v3(sym_data.e_v1_co, e->v1->co);
436 copy_v3_v3(sym_data.e_v2_co, e->v2->co);
437 sym_data.e_v1_co[symmetry_axis] *= -1.0f;
438 sym_data.e_v2_co[symmetry_axis] *= -1.0f;
439 sub_v3_v3v3(sym_data.e_dir, sym_data.e_v2_co, sym_data.e_v1_co);
440 sym_data.e_found_index = -1;
441
442 BLI_kdtree_3d_range_search_cb(tree, co, limit, bm_edge_symmetry_check_cb, &sym_data);
443
444 if (sym_data.e_found_index != -1) {
445 const int i_other = sym_data.e_found_index;
446 edge_symmetry_map[i] = i_other;
447 edge_symmetry_map[i_other] = i;
448 }
449 }
450 }
451
452 MEM_freeN(etable);
453 BLI_kdtree_3d_free(tree);
454
455 return edge_symmetry_map;
456}
457#endif /* USE_SYMMETRY */
458
459#ifdef USE_TRIANGULATE
460/* Temp Triangulation
461 * ****************** */
462
476 BMFace *f_base,
477 LinkNode **r_faces_double,
478 int *r_edges_tri_tot,
479
480 MemArena *pf_arena,
481 /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
482 Heap *pf_heap)
483{
484 const int f_base_len = f_base->len;
485 int faces_array_tot = f_base_len - 3;
486 int edges_array_tot = f_base_len - 3;
487 BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
488 BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot);
489 const int quad_method = 0, ngon_method = 0; /* beauty */
490
491 bool has_cut = false;
492
493 const int f_index = BM_elem_index_get(f_base);
494
496 f_base,
497 faces_array,
498 &faces_array_tot,
499 edges_array,
500 &edges_array_tot,
501 r_faces_double,
502 quad_method,
503 ngon_method,
504 false,
505 pf_arena,
506 pf_heap);
507
508 for (int i = 0; i < edges_array_tot; i++) {
509 BMLoop *l_iter, *l_first;
510 l_iter = l_first = edges_array[i]->l;
511 do {
512 BM_elem_index_set(l_iter, f_index); /* set_dirty */
513 has_cut = true;
514 } while ((l_iter = l_iter->radial_next) != l_first);
515 }
516
517 for (int i = 0; i < faces_array_tot; i++) {
518 BM_face_normal_update(faces_array[i]);
519 }
520
521 *r_edges_tri_tot += edges_array_tot;
522
523 return has_cut;
524}
525
526static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot)
527{
528 BMIter iter;
529 BMFace *f;
530 bool has_ngon = false;
531 bool has_cut = false;
532
534
535 /* first clear loop index values */
536 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
537 BMLoop *l_iter;
538 BMLoop *l_first;
539
540 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
541 do {
542 BM_elem_index_set(l_iter, -1); /* set_dirty */
543 } while ((l_iter = l_iter->next) != l_first);
544
545 has_ngon |= (f->len > 4);
546 }
547
549
550 {
551 MemArena *pf_arena;
552 Heap *pf_heap;
553
554 LinkNode *faces_double = nullptr;
555
556 if (has_ngon) {
557 pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
559 }
560 else {
561 pf_arena = nullptr;
562 pf_heap = nullptr;
563 }
564
565 /* Adding new faces as we loop over faces
566 * is normally best avoided, however in this case its not so bad because any face touched twice
567 * will already be triangulated. */
568 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
569 if (f->len > 3) {
570 has_cut |= bm_face_triangulate(bm,
571 f,
572 &faces_double,
573 r_edges_tri_tot,
574
575 pf_arena,
576 pf_heap);
577 }
578 }
579
580 while (faces_double) {
581 LinkNode *next = faces_double->next;
582 BM_face_kill(bm, static_cast<BMFace *>(faces_double->link));
583 MEM_freeN(faces_double);
584 faces_double = next;
585 }
586
587 if (has_ngon) {
588 BLI_memarena_free(pf_arena);
589 BLI_heap_free(pf_heap, nullptr);
590 }
591
593
594 if (has_cut) {
595 /* now triangulation is done we need to correct index values */
597 }
598 }
599
600 return has_cut;
601}
602
603static void bm_decim_triangulate_end(BMesh *bm, const int edges_tri_tot)
604{
605 /* decimation finished, now re-join */
606 BMIter iter;
607 BMEdge *e;
608
609 /* we need to collect before merging for ngons since the loops indices will be lost */
610 BMEdge **edges_tri = static_cast<BMEdge **>(
611 MEM_mallocN(std::min(edges_tri_tot, bm->totedge) * sizeof(*edges_tri), __func__));
612 STACK_DECLARE(edges_tri);
613
614 STACK_INIT(edges_tri, std::min(edges_tri_tot, bm->totedge));
615
616 /* boundary edges */
617 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
618 BMLoop *l_a, *l_b;
619 if (BM_edge_loop_pair(e, &l_a, &l_b)) {
620 const int l_a_index = BM_elem_index_get(l_a);
621 if (l_a_index != -1) {
622 const int l_b_index = BM_elem_index_get(l_b);
623 if (l_a_index == l_b_index) {
624 if (l_a->v != l_b->v) { /* if this is the case, faces have become flipped */
625 /* check we are not making a degenerate quad */
626
627# define CAN_LOOP_MERGE(l) \
628 (BM_loop_is_manifold(l) && ((l)->v != (l)->radial_next->v) && \
629 (l_a_index == BM_elem_index_get(l)) && (l_a_index == BM_elem_index_get((l)->radial_next)))
630
631 if ((l_a->f->len == 3 && l_b->f->len == 3) && !CAN_LOOP_MERGE(l_a->next) &&
634 {
635 BMVert *vquad[4] = {
636 e->v1,
637 BM_vert_in_edge(e, l_a->next->v) ? l_a->prev->v : l_a->next->v,
638 e->v2,
639 BM_vert_in_edge(e, l_b->next->v) ? l_b->prev->v : l_b->next->v,
640 };
641
642 BLI_assert(ELEM(vquad[0], vquad[1], vquad[2], vquad[3]) == false);
643 BLI_assert(ELEM(vquad[1], vquad[0], vquad[2], vquad[3]) == false);
644 BLI_assert(ELEM(vquad[2], vquad[1], vquad[0], vquad[3]) == false);
645 BLI_assert(ELEM(vquad[3], vquad[1], vquad[2], vquad[0]) == false);
646
647 if (!is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) {
648 continue;
649 }
650 }
651# undef CAN_LOOP_MERGE
652
653 /* highly unlikely to fail, but prevents possible double-ups */
654 STACK_PUSH(edges_tri, e);
655 }
656 }
657 }
658 }
659 }
660
661 for (int i = 0; i < STACK_SIZE(edges_tri); i++) {
662 BMLoop *l_a, *l_b;
663 e = edges_tri[i];
664 if (BM_edge_loop_pair(e, &l_a, &l_b)) {
665 BMFace *f_array[2] = {l_a->f, l_b->f};
666 BM_faces_join(bm, f_array, 2, false);
667 if (e->l == nullptr) {
668 BM_edge_kill(bm, e);
669 }
670 }
671 }
672 MEM_freeN(edges_tri);
673}
674
675#endif /* USE_TRIANGULATE */
676
677/* Edge Collapse Functions
678 * *********************** */
679
680#ifdef USE_CUSTOMDATA
681
686 BMesh *bm, BMLoop *l, BMVert *v_clear, BMVert *v_other, const float customdata_fac)
687{
688 /* Disable seam check - the seam check would have to be done per layer,
689 * its not really that important. */
690 // #define USE_SEAM
691 /* these don't need to be updated, since they will get removed when the edge collapses */
692 BMLoop *l_clear, *l_other;
693 const bool is_manifold = BM_edge_is_manifold(l->e);
694 int side;
695
696 /* first find the loop of 'v_other' that's attached to the face of 'l' */
697 if (l->v == v_clear) {
698 l_clear = l;
699 l_other = l->next;
700 }
701 else {
702 l_clear = l->next;
703 l_other = l;
704 }
705
706 BLI_assert(l_clear->v == v_clear);
707 BLI_assert(l_other->v == v_other);
708 /* quiet warnings for release */
709 (void)v_other;
710
711 /* now we have both corners of the face 'l->f' */
712 for (side = 0; side < 2; side++) {
713# ifdef USE_SEAM
714 bool is_seam = false;
715# endif
716 void *src[2];
717 BMFace *f_exit = is_manifold ? l->radial_next->f : nullptr;
718 BMEdge *e_prev = l->e;
719 BMLoop *l_first;
720 BMLoop *l_iter;
721 float w[2];
722
723 if (side == 0) {
724 l_iter = l_first = l_clear;
725 src[0] = l_clear->head.data;
726 src[1] = l_other->head.data;
727
728 w[0] = customdata_fac;
729 w[1] = 1.0f - customdata_fac;
730 }
731 else {
732 l_iter = l_first = l_other;
733 src[0] = l_other->head.data;
734 src[1] = l_clear->head.data;
735
736 w[0] = 1.0f - customdata_fac;
737 w[1] = customdata_fac;
738 }
739
740 // print_v2("weights", w);
741
742 /* WATCH IT! - should NOT reference (_clear or _other) vars for this while loop */
743
744 /* walk around the fan using 'e_prev' */
745 while (((l_iter = BM_vert_step_fan_loop(l_iter, &e_prev)) != l_first) && (l_iter != nullptr)) {
746 int i;
747 /* quit once we hit the opposite face, if we have one */
748 if (f_exit && UNLIKELY(f_exit == l_iter->f)) {
749 break;
750 }
751
752# ifdef USE_SEAM
753 /* break out unless we find a match */
754 is_seam = true;
755# endif
756
757 /* ok. we have a loop. now be smart with it! */
758 for (i = 0; i < bm->ldata.totlayer; i++) {
760 const int offset = bm->ldata.layers[i].offset;
761 const int type = bm->ldata.layers[i].type;
762 const void *cd_src[2] = {
763 POINTER_OFFSET(src[0], offset),
764 POINTER_OFFSET(src[1], offset),
765 };
766 void *cd_iter = POINTER_OFFSET(l_iter->head.data, offset);
767
768 /* detect seams */
769 if (CustomData_data_equals(eCustomDataType(type), cd_src[0], cd_iter)) {
771 cd_src,
772 w,
773 nullptr,
774 ARRAY_SIZE(cd_src),
775 POINTER_OFFSET(l_iter->head.data, offset),
776 i);
777# ifdef USE_SEAM
778 is_seam = false;
779# endif
780 }
781 }
782 }
783
784# ifdef USE_SEAM
785 if (is_seam) {
786 break;
787 }
788# endif
789 }
790 }
791
792 // #undef USE_SEAM
793}
794#endif /* USE_CUSTOMDATA */
795
806{
809 if (e->l) {
811 if (e->l != e->l->radial_next) {
812 BM_elem_flag_enable(e->l->radial_next->f, BM_ELEM_TAG);
813 }
814 }
815}
816
818{
821 if (e->l) {
823 if (e->l != e->l->radial_next) {
824 BM_elem_flag_disable(e->l->radial_next->f, BM_ELEM_TAG);
825 }
826 }
827}
828
830{
831 /* is the edge or one of its faces tagged? */
833 (e->l &&
835 (e->l != e->l->radial_next && BM_elem_flag_test(e->l->radial_next->f, BM_ELEM_TAG)))));
836}
837
838/* takes the edges loop */
840{
841#if 0
842 /* less optimized version of check below */
844#else
845 /* if the edge is a boundary it points to itself, else this must be a manifold */
846 return LIKELY(l) && LIKELY(l->radial_next->radial_next == l);
847#endif
848}
849
851{
852 /* simply check that there is no overlap between faces and edges of each vert,
853 * (excluding the 2 faces attached to 'e' and 'e' itself) */
854
855 BMEdge *e_iter;
856
857 /* clear flags on both disks */
858 e_iter = e_first;
859 do {
860 if (!bm_edge_is_manifold_or_boundary(e_iter->l)) {
861 return true;
862 }
863 bm_edge_tag_disable(e_iter);
864 } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v1)) != e_first);
865
866 e_iter = e_first;
867 do {
868 if (!bm_edge_is_manifold_or_boundary(e_iter->l)) {
869 return true;
870 }
871 bm_edge_tag_disable(e_iter);
872 } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v2)) != e_first);
873
874 /* now enable one side... */
875 e_iter = e_first;
876 do {
877 bm_edge_tag_enable(e_iter);
878 } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v1)) != e_first);
879
880 /* ... except for the edge we will collapse, we know that's shared,
881 * disable this to avoid false positive. We could be smart and never enable these
882 * face/edge tags in the first place but easier to do this */
883 // bm_edge_tag_disable(e_first);
884 /* do inline... */
885 {
886#if 0
887 BMIter iter;
888 BMIter liter;
889 BMLoop *l;
890 BMVert *v;
891 BM_ITER_ELEM (l, &liter, e_first, BM_LOOPS_OF_EDGE) {
893 BM_ITER_ELEM (v, &iter, l->f, BM_VERTS_OF_FACE) {
895 }
896 }
897#else
898 /* we know each face is a triangle, no looping/iterators needed here */
899
900 BMLoop *l_radial;
901 BMLoop *l_face;
902
903 l_radial = e_first->l;
904 l_face = l_radial;
905 BLI_assert(l_face->f->len == 3);
907 BM_elem_flag_disable((l_face = l_radial)->v, BM_ELEM_TAG);
908 BM_elem_flag_disable((l_face = l_face->next)->v, BM_ELEM_TAG);
910 l_face = l_radial->radial_next;
911 if (l_radial != l_face) {
912 BLI_assert(l_face->f->len == 3);
914 BM_elem_flag_disable((l_face = l_radial->radial_next)->v, BM_ELEM_TAG);
915 BM_elem_flag_disable((l_face = l_face->next)->v, BM_ELEM_TAG);
917 }
918#endif
919 }
920
921 /* and check for overlap */
922 e_iter = e_first;
923 do {
924 if (bm_edge_tag_test(e_iter)) {
925 return true;
926 }
927 } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v2)) != e_first);
928
929 return false;
930}
931
943 BMEdge *e_clear,
944 BMVert *v_clear,
945 int r_e_clear_other[2],
946#ifdef USE_SYMMETRY
947 int *edge_symmetry_map,
948#endif
949#ifdef USE_CUSTOMDATA
950 const CD_UseFlag customdata_flag,
951 const float customdata_fac
952#else
953 const CD_UseFlag /*customdata_flag*/,
954 const float /*customdata_fac*/
955#endif
956)
957{
958 BMVert *v_other;
959
960 v_other = BM_edge_other_vert(e_clear, v_clear);
961 BLI_assert(v_other != nullptr);
962
963 if (BM_edge_is_manifold(e_clear)) {
964 BMLoop *l_a, *l_b;
965 BMEdge *e_a_other[2], *e_b_other[2];
966 bool ok;
967
968 ok = BM_edge_loop_pair(e_clear, &l_a, &l_b);
969
970 BLI_assert(ok == true);
971 BLI_assert(l_a->f->len == 3);
972 BLI_assert(l_b->f->len == 3);
974
975 /* keep 'v_clear' 0th */
976 if (BM_vert_in_edge(l_a->prev->e, v_clear)) {
977 e_a_other[0] = l_a->prev->e;
978 e_a_other[1] = l_a->next->e;
979 }
980 else {
981 e_a_other[1] = l_a->prev->e;
982 e_a_other[0] = l_a->next->e;
983 }
984
985 if (BM_vert_in_edge(l_b->prev->e, v_clear)) {
986 e_b_other[0] = l_b->prev->e;
987 e_b_other[1] = l_b->next->e;
988 }
989 else {
990 e_b_other[1] = l_b->prev->e;
991 e_b_other[0] = l_b->next->e;
992 }
993
994/* we could assert this case, but better just bail out */
995#if 0
996 BLI_assert(e_a_other[0] != e_b_other[0]);
997 BLI_assert(e_a_other[0] != e_b_other[1]);
998 BLI_assert(e_b_other[0] != e_a_other[0]);
999 BLI_assert(e_b_other[0] != e_a_other[1]);
1000#endif
1001 /* not totally common but we want to avoid */
1002 if (ELEM(e_a_other[0], e_b_other[0], e_b_other[1]) ||
1003 ELEM(e_a_other[1], e_b_other[0], e_b_other[1]))
1004 {
1005 return false;
1006 }
1007
1008 BLI_assert(BM_edge_share_vert(e_a_other[0], e_b_other[0]));
1009 BLI_assert(BM_edge_share_vert(e_a_other[1], e_b_other[1]));
1010
1011 r_e_clear_other[0] = BM_elem_index_get(e_a_other[0]);
1012 r_e_clear_other[1] = BM_elem_index_get(e_b_other[0]);
1013
1014#ifdef USE_CUSTOMDATA
1015 /* before killing, do customdata */
1016 if (customdata_flag & CD_DO_VERT) {
1017 BM_data_interp_from_verts(bm, v_other, v_clear, v_other, customdata_fac);
1018 }
1019 if (customdata_flag & CD_DO_EDGE) {
1020 BM_data_interp_from_edges(bm, e_a_other[1], e_a_other[0], e_a_other[1], customdata_fac);
1021 BM_data_interp_from_edges(bm, e_b_other[1], e_b_other[0], e_b_other[1], customdata_fac);
1022 }
1023 if (customdata_flag & CD_DO_LOOP) {
1024 bm_edge_collapse_loop_customdata(bm, e_clear->l, v_clear, v_other, customdata_fac);
1026 bm, e_clear->l->radial_next, v_clear, v_other, customdata_fac);
1027 }
1028#endif
1029
1030 BM_edge_kill(bm, e_clear);
1031
1032 v_other->head.hflag |= v_clear->head.hflag;
1033 BM_vert_splice(bm, v_other, v_clear);
1034
1035 e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag;
1036 e_b_other[1]->head.hflag |= e_b_other[0]->head.hflag;
1037 BM_edge_splice(bm, e_a_other[1], e_a_other[0]);
1038 BM_edge_splice(bm, e_b_other[1], e_b_other[0]);
1039
1040#ifdef USE_SYMMETRY
1041 /* update mirror map */
1042 if (edge_symmetry_map) {
1043 if (edge_symmetry_map[r_e_clear_other[0]] != -1) {
1044 edge_symmetry_map[edge_symmetry_map[r_e_clear_other[0]]] = BM_elem_index_get(e_a_other[1]);
1045 }
1046 if (edge_symmetry_map[r_e_clear_other[1]] != -1) {
1047 edge_symmetry_map[edge_symmetry_map[r_e_clear_other[1]]] = BM_elem_index_get(e_b_other[1]);
1048 }
1049 }
1050#endif
1051
1052 // BM_mesh_validate(bm);
1053
1054 return true;
1055 }
1056 if (BM_edge_is_boundary(e_clear)) {
1057 /* same as above but only one triangle */
1058 BMLoop *l_a;
1059 BMEdge *e_a_other[2];
1060
1061 l_a = e_clear->l;
1062
1063 BLI_assert(l_a->f->len == 3);
1064
1065 /* keep 'v_clear' 0th */
1066 if (BM_vert_in_edge(l_a->prev->e, v_clear)) {
1067 e_a_other[0] = l_a->prev->e;
1068 e_a_other[1] = l_a->next->e;
1069 }
1070 else {
1071 e_a_other[1] = l_a->prev->e;
1072 e_a_other[0] = l_a->next->e;
1073 }
1074
1075 r_e_clear_other[0] = BM_elem_index_get(e_a_other[0]);
1076 r_e_clear_other[1] = -1;
1077
1078#ifdef USE_CUSTOMDATA
1079 /* before killing, do customdata */
1080 if (customdata_flag & CD_DO_VERT) {
1081 BM_data_interp_from_verts(bm, v_other, v_clear, v_other, customdata_fac);
1082 }
1083 if (customdata_flag & CD_DO_EDGE) {
1084 BM_data_interp_from_edges(bm, e_a_other[1], e_a_other[0], e_a_other[1], customdata_fac);
1085 }
1086 if (customdata_flag & CD_DO_LOOP) {
1087 bm_edge_collapse_loop_customdata(bm, e_clear->l, v_clear, v_other, customdata_fac);
1088 }
1089#endif
1090
1091 BM_edge_kill(bm, e_clear);
1092
1093 v_other->head.hflag |= v_clear->head.hflag;
1094 BM_vert_splice(bm, v_other, v_clear);
1095
1096 e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag;
1097 BM_edge_splice(bm, e_a_other[1], e_a_other[0]);
1098
1099#ifdef USE_SYMMETRY
1100 /* update mirror map */
1101 if (edge_symmetry_map) {
1102 if (edge_symmetry_map[r_e_clear_other[0]] != -1) {
1103 edge_symmetry_map[edge_symmetry_map[r_e_clear_other[0]]] = BM_elem_index_get(e_a_other[1]);
1104 }
1105 }
1106#endif
1107
1108 // BM_mesh_validate(bm);
1109
1110 return true;
1111 }
1112 return false;
1113}
1114
1121 BMEdge *e,
1122 Quadric *vquadrics,
1123 float *vweights,
1124 const float vweight_factor,
1125 Heap *eheap,
1126 HeapNode **eheap_table,
1127#ifdef USE_SYMMETRY
1128 int *edge_symmetry_map,
1129#endif
1130 const CD_UseFlag customdata_flag,
1131 float optimize_co[3],
1132 bool optimize_co_calc)
1133{
1134 int e_clear_other[2];
1135 BMVert *v_other = e->v1;
1136 const int v_other_index = BM_elem_index_get(e->v1);
1137 /* the vert is removed so only store the index */
1138 const int v_clear_index = BM_elem_index_get(e->v2);
1139 float customdata_fac;
1140
1141#ifdef USE_VERT_NORMAL_INTERP
1142 float v_clear_no[3];
1143 copy_v3_v3(v_clear_no, e->v2->no);
1144#endif
1145
1146 /* when false, use without degenerate checks */
1147 if (optimize_co_calc) {
1148 /* disallow collapsing which results in degenerate cases */
1150 /* add back with a high cost */
1151 bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
1152 return false;
1153 }
1154
1155 bm_decim_calc_target_co_fl(e, optimize_co, vquadrics);
1156
1157 /* check if this would result in an overlapping face */
1158 if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) {
1159 /* add back with a high cost */
1160 bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
1161 return false;
1162 }
1163 }
1164
1165 /* use for customdata merging */
1166 if (LIKELY(compare_v3v3(e->v1->co, e->v2->co, FLT_EPSILON) == false)) {
1167 customdata_fac = line_point_factor_v3(optimize_co, e->v1->co, e->v2->co);
1168#if 0
1169 /* simple test for stupid collapse */
1170 if (customdata_fac < 0.0 - FLT_EPSILON || customdata_fac > 1.0f + FLT_EPSILON) {
1171 return false;
1172 }
1173#endif
1174 }
1175 else {
1176 /* avoid divide by zero */
1177 customdata_fac = 0.5f;
1178 }
1179
1180 if (bm_edge_collapse(bm,
1181 e,
1182 e->v2,
1183 e_clear_other,
1184#ifdef USE_SYMMETRY
1185 edge_symmetry_map,
1186#endif
1187 customdata_flag,
1188 customdata_fac))
1189 {
1190 /* update collapse info */
1191 int i;
1192
1193 if (vweights) {
1194 float v_other_weight = interpf(
1195 vweights[v_other_index], vweights[v_clear_index], customdata_fac);
1196 CLAMP(v_other_weight, 0.0f, 1.0f);
1197 vweights[v_other_index] = v_other_weight;
1198 }
1199
1200 /* paranoid safety check */
1201 e = nullptr;
1202
1203 copy_v3_v3(v_other->co, optimize_co);
1204
1205 /* remove eheap */
1206 for (i = 0; i < 2; i++) {
1207 /* highly unlikely 'eheap_table[ke_other[i]]' would be nullptr, but do for sanity sake */
1208 if ((e_clear_other[i] != -1) && (eheap_table[e_clear_other[i]] != nullptr)) {
1209 BLI_heap_remove(eheap, eheap_table[e_clear_other[i]]);
1210 eheap_table[e_clear_other[i]] = nullptr;
1211 }
1212 }
1213
1214 /* update vertex quadric, add kept vertex from killed vertex */
1215 BLI_quadric_add_qu_qu(&vquadrics[v_other_index], &vquadrics[v_clear_index]);
1216
1217/* update connected normals */
1218
1219/* in fact face normals are not used for progressive updates, no need to update them */
1220// BM_vert_normal_update_all(v);
1221#ifdef USE_VERT_NORMAL_INTERP
1222 interp_v3_v3v3(v_other->no, v_other->no, v_clear_no, customdata_fac);
1223 normalize_v3(v_other->no);
1224#else
1225 BM_vert_normal_update(v_other);
1226#endif
1227
1228 /* update error costs and the eheap */
1229 if (LIKELY(v_other->e)) {
1230 BMEdge *e_iter;
1231 BMEdge *e_first;
1232 e_iter = e_first = v_other->e;
1233 do {
1234 BLI_assert(BM_edge_find_double(e_iter) == nullptr);
1236 e_iter, vquadrics, vweights, vweight_factor, eheap, eheap_table);
1237 } while ((e_iter = bmesh_disk_edge_next(e_iter, v_other)) != e_first);
1238 }
1239
1240/* this block used to be disabled,
1241 * but enable now since surrounding faces may have been
1242 * set to COST_INVALID because of a face overlap that no longer occurs */
1243#if 1
1244 /* optional, update edges around the vertex face fan */
1245 {
1246 BMIter liter;
1247 BMLoop *l;
1248 BM_ITER_ELEM (l, &liter, v_other, BM_LOOPS_OF_VERT) {
1249 if (l->f->len == 3) {
1250 BMEdge *e_outer;
1251 if (BM_vert_in_edge(l->prev->e, l->v)) {
1252 e_outer = l->next->e;
1253 }
1254 else {
1255 e_outer = l->prev->e;
1256 }
1257
1258 BLI_assert(BM_vert_in_edge(e_outer, l->v) == false);
1259
1261 e_outer, vquadrics, vweights, vweight_factor, eheap, eheap_table);
1262 }
1263 }
1264 }
1265 /* end optional update */
1266 return true;
1267#endif
1268 }
1269 /* add back with a high cost */
1270 bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
1271 return false;
1272}
1273
1274/* Main Decimate Function
1275 * ********************** */
1276
1278 const float factor,
1279 float *vweights,
1280 float vweight_factor,
1281 const bool do_triangulate,
1282 const int symmetry_axis,
1283 const float symmetry_eps)
1284{
1285 /* edge heap */
1286 Heap *eheap;
1287 /* edge index aligned table pointing to the eheap */
1288 HeapNode **eheap_table;
1289 /* vert index aligned quadrics */
1290 Quadric *vquadrics;
1291 int tot_edge_orig;
1292 int face_tot_target;
1293
1294 CD_UseFlag customdata_flag = CD_UseFlag(0);
1295
1296#ifdef USE_SYMMETRY
1297 bool use_symmetry = (symmetry_axis != -1);
1298 int *edge_symmetry_map;
1299#endif
1300
1301#ifdef USE_TRIANGULATE
1302 int edges_tri_tot = 0;
1303 /* temp convert quads to triangles */
1304 bool use_triangulate = bm_decim_triangulate_begin(bm, &edges_tri_tot);
1305#else
1306 UNUSED_VARS(do_triangulate);
1307#endif
1308
1309 /* Allocate variables. */
1310 vquadrics = static_cast<Quadric *>(MEM_callocN(sizeof(Quadric) * bm->totvert, __func__));
1311 /* Since some edges may be degenerate, we might be over allocating a little here. */
1312 eheap = BLI_heap_new_ex(bm->totedge);
1313 eheap_table = static_cast<HeapNode **>(MEM_mallocN(sizeof(HeapNode *) * bm->totedge, __func__));
1314 tot_edge_orig = bm->totedge;
1315
1316 /* build initial edge collapse cost data */
1317 bm_decim_build_quadrics(bm, vquadrics);
1318
1319 bm_decim_build_edge_cost(bm, vquadrics, vweights, vweight_factor, eheap, eheap_table);
1320
1321 face_tot_target = bm->totface * factor;
1323
1324#ifdef USE_SYMMETRY
1325 edge_symmetry_map = (use_symmetry) ? bm_edge_symmetry_map(bm, symmetry_axis, symmetry_eps) :
1326 nullptr;
1327#else
1328 UNUSED_VARS(symmetry_axis, symmetry_eps);
1329#endif
1330
1331#ifdef USE_CUSTOMDATA
1332 /* initialize customdata flag, we only need math for loops */
1334 customdata_flag |= CD_DO_VERT;
1335 }
1337 customdata_flag |= CD_DO_EDGE;
1338 }
1339 if (CustomData_has_math(&bm->ldata)) {
1340 customdata_flag |= CD_DO_LOOP;
1341 }
1342#endif
1343
1344/* iterative edge collapse and maintain the eheap */
1345#ifdef USE_SYMMETRY
1346 if (use_symmetry == false)
1347#endif
1348 {
1349 /* simple non-mirror case */
1350 while ((bm->totface > face_tot_target) && (BLI_heap_is_empty(eheap) == false) &&
1351 (BLI_heap_top_value(eheap) != COST_INVALID))
1352 {
1353 // const float value = BLI_heap_node_value(BLI_heap_top(eheap));
1354 BMEdge *e = static_cast<BMEdge *>(BLI_heap_pop_min(eheap));
1355 float optimize_co[3];
1356 /* handy to detect corruptions elsewhere */
1357 BLI_assert(BM_elem_index_get(e) < tot_edge_orig);
1358
1359 /* Under normal conditions won't be accessed again,
1360 * but nullptr just in case so we don't use freed node. */
1361 eheap_table[BM_elem_index_get(e)] = nullptr;
1362
1364 e,
1365 vquadrics,
1366 vweights,
1367 vweight_factor,
1368 eheap,
1369 eheap_table,
1370#ifdef USE_SYMMETRY
1371 edge_symmetry_map,
1372#endif
1373 customdata_flag,
1374 optimize_co,
1375 true);
1376 }
1377 }
1378#ifdef USE_SYMMETRY
1379 else {
1380 while ((bm->totface > face_tot_target) && (BLI_heap_is_empty(eheap) == false) &&
1381 (BLI_heap_top_value(eheap) != COST_INVALID))
1382 {
1383 /* NOTE:
1384 * - `eheap_table[e_index_mirr]` is only removed from the heap at the last moment
1385 * since its possible (in theory) for collapsing `e` to remove `e_mirr`.
1386 * - edges sharing a vertex are ignored, so the pivot vertex isn't moved to one side.
1387 */
1388
1389 BMEdge *e = static_cast<BMEdge *>(BLI_heap_pop_min(eheap));
1390 const int e_index = BM_elem_index_get(e);
1391 const int e_index_mirr = edge_symmetry_map[e_index];
1392 BMEdge *e_mirr = nullptr;
1393 float optimize_co[3];
1394 char e_invalidate = 0;
1395
1396 BLI_assert(e_index < tot_edge_orig);
1397
1398 eheap_table[e_index] = nullptr;
1399
1400 if (e_index_mirr != -1) {
1401 if (e_index_mirr == e_index) {
1402 /* pass */
1403 }
1404 else if (eheap_table[e_index_mirr]) {
1405 e_mirr = static_cast<BMEdge *>(BLI_heap_node_ptr(eheap_table[e_index_mirr]));
1406 /* for now ignore edges with a shared vertex */
1407 if (BM_edge_share_vert_check(e, e_mirr)) {
1408 /* ignore permanently!
1409 * Otherwise we would keep re-evaluating and attempting to collapse. */
1410 // e_invalidate |= (1 | 2);
1411 goto invalidate;
1412 }
1413 }
1414 else {
1415 /* mirror edge can't be operated on (happens with asymmetrical meshes) */
1416 e_invalidate |= 1;
1417 goto invalidate;
1418 }
1419 }
1420
1421 /* when false, use without degenerate checks */
1422 {
1423 /* run both before checking (since they invalidate surrounding geometry) */
1424 bool ok_a, ok_b;
1425
1427 ok_b = e_mirr ? !bm_edge_collapse_is_degenerate_topology(e_mirr) : true;
1428
1429 /* disallow collapsing which results in degenerate cases */
1430
1431 if (UNLIKELY(!ok_a || !ok_b)) {
1432 e_invalidate |= (1 | (e_mirr ? 2 : 0));
1433 goto invalidate;
1434 }
1435
1436 bm_decim_calc_target_co_fl(e, optimize_co, vquadrics);
1437
1438 if (e_index_mirr == e_index) {
1439 optimize_co[symmetry_axis] = 0.0f;
1440 }
1441
1442 /* check if this would result in an overlapping face */
1443 if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) {
1444 e_invalidate |= (1 | (e_mirr ? 2 : 0));
1445 goto invalidate;
1446 }
1447 }
1448
1450 e,
1451 vquadrics,
1452 vweights,
1453 vweight_factor,
1454 eheap,
1455 eheap_table,
1456 edge_symmetry_map,
1457 customdata_flag,
1458 optimize_co,
1459 false))
1460 {
1461 if (e_mirr && (eheap_table[e_index_mirr])) {
1462 BLI_assert(e_index_mirr != e_index);
1463 BLI_heap_remove(eheap, eheap_table[e_index_mirr]);
1464 eheap_table[e_index_mirr] = nullptr;
1465 optimize_co[symmetry_axis] *= -1.0f;
1467 e_mirr,
1468 vquadrics,
1469 vweights,
1470 vweight_factor,
1471 eheap,
1472 eheap_table,
1473 edge_symmetry_map,
1474 customdata_flag,
1475 optimize_co,
1476 false);
1477 }
1478 }
1479 else {
1480 if (e_mirr && (eheap_table[e_index_mirr])) {
1481 e_invalidate |= 2;
1482 goto invalidate;
1483 }
1484 }
1485
1486 BLI_assert(e_invalidate == 0);
1487 continue;
1488
1489 invalidate:
1490 if (e_invalidate & 1) {
1491 bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
1492 }
1493
1494 if (e_invalidate & 2) {
1495 BLI_assert(eheap_table[e_index_mirr] != nullptr);
1496 BLI_heap_remove(eheap, eheap_table[e_index_mirr]);
1497 eheap_table[e_index_mirr] = nullptr;
1498 bm_decim_invalid_edge_cost_single(e_mirr, eheap, eheap_table);
1499 }
1500 }
1501
1502 MEM_freeN((void *)edge_symmetry_map);
1503 }
1504#endif /* USE_SYMMETRY */
1505
1506#ifdef USE_TRIANGULATE
1507 if (do_triangulate == false) {
1508 /* its possible we only had triangles, skip this step in that case */
1509 if (LIKELY(use_triangulate)) {
1510 /* temp convert quads to triangles */
1511 bm_decim_triangulate_end(bm, edges_tri_tot);
1512 }
1513 }
1514#endif
1515
1516 /* free vars */
1517 MEM_freeN(vquadrics);
1518 MEM_freeN(eheap_table);
1519 BLI_heap_free(eheap, nullptr);
1520
1521 /* testing only */
1522 // BM_mesh_validate(bm);
1523
1524 /* quiet release build warning */
1525 (void)tot_edge_orig;
1526}
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_layer_has_math(const CustomData *data, int layer_n)
bool CustomData_has_interp(const CustomData *data)
bool CustomData_data_equals(eCustomDataType type, const void *data1, const void *data2)
bool CustomData_has_math(const CustomData *data)
void CustomData_bmesh_interp_n(CustomData *data, const void **src_blocks, const float *weights, const float *sub_weights, int count, void *dst_block_ofs, int n)
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:25
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition BLI_heap.c:192
void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr) ATTR_NONNULL(1
Heap * BLI_heap_new_ex(unsigned int reserve_num) ATTR_WARN_UNUSED_RESULT
Definition BLI_heap.c:172
void void bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1)
Definition BLI_heap.c:269
float BLI_heap_top_value(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition BLI_heap.c:284
void * BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1)
Definition BLI_heap.c:291
void * BLI_heap_node_ptr(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition BLI_heap.c:352
HeapNode * BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1)
Definition BLI_heap.c:235
void void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1
A KD-tree for nearest neighbor search.
MINLINE float min_ff(float a, float b)
MINLINE float square_f(float a)
MINLINE float interpf(float target, float origin, float t)
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:39
MINLINE double normalize_v3_db(double n[3])
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE double dot_v3db_v3fl(const double a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition math_vector.c:36
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3fl_v3db(float r[3], const double a[3])
MINLINE void copy_v3db_v3fl(double r[3], const float a[3])
MINLINE bool compare_v3v3(const float v1[3], const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3(float n[3])
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
#define BLI_POLYFILL_ARENA_SIZE
#define BLI_POLYFILL_ALLOC_NGON_RESERVE
void BLI_quadric_mul(Quadric *a, double scalar)
Definition quadric.c:125
bool BLI_quadric_optimize(const Quadric *q, double v[3], double epsilon)
Definition quadric.c:142
void BLI_quadric_from_plane(Quadric *q, const double v[4])
Definition quadric.c:31
double BLI_quadric_evaluate(const Quadric *q, const double v[3])
Definition quadric.c:130
void BLI_quadric_add_qu_qu(Quadric *a, const Quadric *b)
Definition quadric.c:115
void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b)
Definition quadric.c:120
unsigned int uint
#define CLAMP(a, b, c)
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define ENUM_OPERATORS(_type, _max)
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define ELEM(...)
#define POINTER_OFFSET(v, ofs)
#define LIKELY(x)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_SIZE(stack)
#define STACK_INIT(stack, stack_num)
typedef double(DMatrix)[4][4]
Read Guarded memory(de)allocation.
@ BM_LOOP
@ BM_ELEM_TAG
#define BM_ALL
#define BM_FACE_FIRST_LOOP(p)
BMFace * BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
Join Connected Faces.
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
Splice Edge.
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
Splice Vert.
void BM_face_kill(BMesh *bm, BMFace *f)
void BM_edge_kill(BMesh *bm, BMEdge *e)
static void bm_edge_tag_enable(BMEdge *e)
static void bm_decim_invalid_edge_cost_single(BMEdge *e, Heap *eheap, HeapNode **eheap_table)
static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
static void bm_decim_build_edge_cost(BMesh *bm, const Quadric *vquadrics, const float *vweights, const float vweight_factor, Heap *eheap, HeapNode **eheap_table)
#define TOPOLOGY_FALLBACK_EPS
#define USE_CUSTOMDATA
static void bm_edge_tag_disable(BMEdge *e)
static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_co[3])
void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, float vweight_factor, const bool do_triangulate, const int symmetry_axis, const float symmetry_eps)
BM_mesh_decimate.
static void bm_decim_triangulate_end(BMesh *bm, const int edges_tri_tot)
static void bm_decim_calc_target_co_fl(BMEdge *e, float optimize_co[3], const Quadric *vquadrics)
static bool bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_e_clear_other[2], int *edge_symmetry_map, const CD_UseFlag customdata_flag, const float customdata_fac)
static bool bm_face_triangulate(BMesh *bm, BMFace *f_base, LinkNode **r_faces_double, int *r_edges_tri_tot, MemArena *pf_arena, Heap *pf_heap)
#define BOUNDARY_PRESERVE_WEIGHT
static void bm_decim_build_edge_cost_single(BMEdge *e, const Quadric *vquadrics, const float *vweights, const float vweight_factor, Heap *eheap, HeapNode **eheap_table)
#define COST_INVALID
#define CAN_LOOP_MERGE(l)
BLI_INLINE int bm_edge_is_manifold_or_boundary(BMLoop *l)
static float bm_decim_build_edge_cost_single__topology(BMEdge *e)
static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot)
#define USE_SYMMETRY
static bool bm_edge_symmetry_check_cb(void *user_data, int index, const float[3], float)
static bool bm_decim_edge_collapse(BMesh *bm, BMEdge *e, Quadric *vquadrics, float *vweights, const float vweight_factor, Heap *eheap, HeapNode **eheap_table, int *edge_symmetry_map, const CD_UseFlag customdata_flag, float optimize_co[3], bool optimize_co_calc)
static void bm_decim_calc_target_co_db(BMEdge *e, double optimize_co[3], const Quadric *vquadrics)
#define OPTIMIZE_EPS
static int * bm_edge_symmetry_map(BMesh *bm, uint symmetry_axis, float limit)
static float bm_decim_build_edge_cost_single_squared__topology(BMEdge *e)
static bool bm_edge_tag_test(BMEdge *e)
static void bm_edge_collapse_loop_customdata(BMesh *bm, BMLoop *l, BMVert *v_clear, BMVert *v_other, const float customdata_fac)
static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
#define BM_elem_index_get(ele)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
void BM_data_interp_from_edges(BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, const float fac)
Data, Interpolate From Edges.
void BM_data_interp_from_verts(BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac)
Data, Interpolate From Verts.
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_FACE
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_EDGE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void BM_vert_normal_update(BMVert *v)
void BM_face_normal_update(BMFace *f)
void BM_face_triangulate(BMesh *bm, BMFace *f, BMFace **r_faces_new, int *r_faces_new_tot, BMEdge **r_edges_new, int *r_edges_new_tot, LinkNode **r_faces_double, const int quad_method, const int ngon_method, const bool use_tag, MemArena *pf_arena, Heap *pf_heap)
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
BMVert * BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
BMLoop * BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
BMEdge * BM_edge_find_double(BMEdge *e)
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2)
float BM_edge_calc_length(const BMEdge *e)
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
ATTR_WARN_UNUSED_RESULT const BMVert * v
BLI_INLINE BMEdge * bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
SIMD_FORCE_INLINE void invalidate()
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
#define fabsf(x)
KDTree_3d * tree
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
static ulong * next
static void clear(Message &msg)
Definition msgfmt.cc:218
BMHeader head
BMVert * v1
BMVert * v2
struct BMLoop * l
float no[3]
void * data
BMHeader head
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
float co[3]
struct BMEdge * e
float no[3]
BMHeader head
int totvert
char elem_index_dirty
CustomData vdata
int totedge
CustomData edata
CustomData ldata
int totface
CustomDataLayer * layers
void * link
struct LinkNode * next