2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * Contributor(s): Campbell Barton
20 * ***** END GPL LICENSE BLOCK *****
23 /** \file blender/bmesh/tools/bmesh_decimate_collapse.c
26 * BMesh decimator that uses an edge collapse method.
31 #include "MEM_guardedalloc.h"
33 #include "DNA_scene_types.h"
36 #include "BLI_quadric.h"
39 #include "BKE_customdata.h"
42 #include "bmesh_decimate.h" /* own include */
44 #include "../intern/bmesh_structure.h"
46 /* defines for testing */
47 #define USE_CUSTOMDATA
48 #define USE_TRIANGULATE
49 #define USE_VERT_NORMAL_INTERP /* has the advantage that flipped faces don't mess up vertex normals */
51 /* these checks are for rare cases that we can't avoid since they are valid meshes still */
52 #define USE_SAFETY_CHECKS
54 #define BOUNDARY_PRESERVE_WEIGHT 100.0f
55 #define OPTIMIZE_EPS 0.01f /* FLT_EPSILON is too small, see [#33106] */
56 #define COST_INVALID FLT_MAX
58 typedef enum CD_UseFlag {
59 CD_DO_VERT = (1 << 0),
60 CD_DO_EDGE = (1 << 1),
65 /* BMesh Helper Functions
66 * ********************** */
69 * \param vquadrics must be calloc'd
71 static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
77 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
81 const float *co = BM_FACE_FIRST_LOOP(f)->v->co;
82 const float *no = f->no;
83 const float offset = -dot_v3v3(no, co);
86 BLI_quadric_from_v3_dist(&q, no, offset);
88 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
90 BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(l_iter->v)], &q);
91 } while ((l_iter = l_iter->next) != l_first);
95 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
96 if (UNLIKELY(BM_edge_is_boundary(e))) {
99 sub_v3_v3v3(edge_vector, e->v2->co, e->v1->co);
101 cross_v3_v3v3(edge_cross, edge_vector, f->no);
103 if (normalize_v3(edge_cross) > FLT_EPSILON) {
105 BLI_quadric_from_v3_dist(&q, edge_cross, -dot_v3v3(edge_cross, e->v1->co));
106 BLI_quadric_mul(&q, BOUNDARY_PRESERVE_WEIGHT);
108 BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(e->v1)], &q);
109 BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(e->v2)], &q);
116 static void bm_decim_calc_target_co(BMEdge *e, float optimize_co[3],
117 const Quadric *vquadrics)
119 /* compute an edge contraction target for edge 'e'
120 * this is computed by summing it's vertices quadrics and
121 * optimizing the result. */
124 BLI_quadric_add_qu_ququ(&q,
125 &vquadrics[BM_elem_index_get(e->v1)],
126 &vquadrics[BM_elem_index_get(e->v2)]);
129 if (BLI_quadric_optimize(&q, optimize_co, OPTIMIZE_EPS)) {
130 return; /* all is good */
133 mid_v3_v3v3(optimize_co, e->v1->co, e->v2->co);
137 static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_co[3])
143 for (i = 0; i < 2; i++) {
144 /* loop over both verts */
145 BMVert *v = *((&e->v1) + i);
147 BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
148 if (l->e != e && l->prev->e != e) {
149 float *co_prev = l->prev->v->co;
150 float *co_next = l->next->v->co;
151 float cross_exist[3];
152 float cross_optim[3];
155 float vec_other[3]; /* line between the two outer verts, re-use for both cross products */
156 float vec_exist[3]; /* before collapse */
157 float vec_optim[3]; /* after collapse */
159 sub_v3_v3v3(vec_other, co_prev, co_next);
160 sub_v3_v3v3(vec_exist, co_prev, v->co);
161 sub_v3_v3v3(vec_optim, co_prev, optimize_co);
163 cross_v3_v3v3(cross_exist, vec_other, vec_exist);
164 cross_v3_v3v3(cross_optim, vec_other, vec_optim);
166 /* normalize isn't really needed, but ensures the value at a unit we can compare against */
167 normalize_v3(cross_exist);
168 normalize_v3(cross_optim);
170 normal_tri_v3(cross_exist, v->co, co_prev, co_next);
171 normal_tri_v3(cross_optim, optimize_co, co_prev, co_next);
174 /* use a small value rather then zero so we don't flip a face in multiple steps
175 * (first making it zero area, then flipping again) */
176 if (dot_v3v3(cross_exist, cross_optim) <= FLT_EPSILON) {
177 //printf("no flip\n");
187 static void bm_decim_build_edge_cost_single(BMEdge *e,
188 const Quadric *vquadrics, const float *vweights,
189 Heap *eheap, HeapNode **eheap_table)
191 const Quadric *q1, *q2;
192 float optimize_co[3];
195 if (eheap_table[BM_elem_index_get(e)]) {
196 BLI_heap_remove(eheap, eheap_table[BM_elem_index_get(e)]);
199 /* check we can collapse, some edges we better not touch */
200 if (BM_edge_is_boundary(e)) {
201 if (e->l->f->len == 3) {
205 /* only collapse tri's */
206 eheap_table[BM_elem_index_get(e)] = NULL;
210 else if (BM_edge_is_manifold(e)) {
211 if ((e->l->f->len == 3) && (e->l->radial_next->f->len == 3)) {
215 /* only collapse tri's */
216 eheap_table[BM_elem_index_get(e)] = NULL;
221 eheap_table[BM_elem_index_get(e)] = NULL;
226 if ((vweights[BM_elem_index_get(e->v1)] >= BM_MESH_DECIM_WEIGHT_MAX) &&
227 (vweights[BM_elem_index_get(e->v2)] >= BM_MESH_DECIM_WEIGHT_MAX))
229 /* skip collapsing this edge */
230 eheap_table[BM_elem_index_get(e)] = NULL;
234 /* end sanity check */
237 bm_decim_calc_target_co(e, optimize_co, vquadrics);
239 q1 = &vquadrics[BM_elem_index_get(e->v1)];
240 q2 = &vquadrics[BM_elem_index_get(e->v2)];
242 if (vweights == NULL) {
243 cost = (BLI_quadric_evaluate(q1, optimize_co) +
244 BLI_quadric_evaluate(q2, optimize_co));
247 /* add 1.0 so planar edges are still weighted against */
248 cost = (((BLI_quadric_evaluate(q1, optimize_co) + 1.0f) * vweights[BM_elem_index_get(e->v1)]) +
249 ((BLI_quadric_evaluate(q2, optimize_co) + 1.0f) * vweights[BM_elem_index_get(e->v2)]));
251 // print("COST %.12f\n");
253 /* note, 'cost' shouldn't be negative but happens sometimes with small values.
254 * this can cause faces that make up a flat surface to over-collapse, see [#37121] */
256 eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, cost, e);
260 /* use this for degenerate cases - add back to the heap with an invalid cost,
261 * this way it may be calculated again if surrounding geometry changes */
262 static void bm_decim_invalid_edge_cost_single(BMEdge *e,
263 Heap *eheap, HeapNode **eheap_table)
265 BLI_assert(eheap_table[BM_elem_index_get(e)] == NULL);
266 eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, COST_INVALID, e);
269 static void bm_decim_build_edge_cost(BMesh *bm,
270 const Quadric *vquadrics, const float *vweights,
271 Heap *eheap, HeapNode **eheap_table)
277 BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
278 eheap_table[i] = NULL; /* keep sanity check happy */
279 bm_decim_build_edge_cost_single(e, vquadrics, vweights, eheap, eheap_table);
283 #ifdef USE_TRIANGULATE
284 /* Temp Triangulation
285 * ****************** */
288 * To keep things simple we can only collapse edges on triangulated data
289 * (limitation with edge collapse and error calculation functions).
291 * But to avoid annoying users by only giving triangle results, we can
292 * triangulate, keeping a reference between the faces, then join after
293 * if the edges don't collapse, this will also allow more choices when
294 * collapsing edges so even has some advantage over decimating quads
297 * \return true if any faces were triangulated.
300 static bool bm_decim_triangulate_begin(BMesh *bm)
304 // bool has_quad; // could optimize this a little
305 bool has_cut = false;
307 BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
309 /* first clear loop index values */
310 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
314 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
316 BM_elem_index_set(l_iter, -1);
317 } while ((l_iter = l_iter->next) != l_first);
319 // has_quad |= (f->len == 4)
322 /* adding new faces as we loop over faces
323 * is normally best avoided, however in this case its not so bad because any face touched twice
324 * will already be triangulated*/
325 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
331 BMLoop *l_iter = BM_FACE_FIRST_LOOP(f);
333 f_l[0] = l_iter; l_iter = l_iter->next;
334 f_l[1] = l_iter; l_iter = l_iter->next;
335 f_l[2] = l_iter; l_iter = l_iter->next;
339 if (len_squared_v3v3(f_l[0]->v->co, f_l[2]->v->co) <
340 len_squared_v3v3(f_l[1]->v->co, f_l[3]->v->co))
350 #ifdef USE_SAFETY_CHECKS
351 if (BM_edge_exists(l_a->v, l_b->v) == NULL)
357 /* warning, NO_DOUBLE option here isn't handled as nice as it could be
358 * - if there is a quad that has a free standing edge joining it along
359 * where we want to split the face, there isnt a good way we can handle this.
360 * currently that edge will get removed when joining the tris back into a quad. */
361 f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false);
364 /* the value of this doesn't matter, only that the 2 loops match and have unique values */
365 const int f_index = BM_elem_index_get(f);
367 /* since we just split theres only ever 2 loops */
368 BLI_assert(BM_edge_is_manifold(l_new->e));
370 BM_elem_index_set(l_new, f_index);
371 BM_elem_index_set(l_new->radial_next, f_index);
373 BM_face_normal_update(f);
374 BM_face_normal_update(f_new);
382 BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
385 /* now triangulation is done we need to correct index values */
386 BM_mesh_elem_index_ensure(bm, BM_EDGE | BM_FACE);
392 static void bm_decim_triangulate_end(BMesh *bm)
394 /* decimation finished, now re-join */
399 BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
401 if (BM_edge_loop_pair(e, &l_a, &l_b)) {
402 const int l_a_index = BM_elem_index_get(l_a);
403 if (l_a_index != -1) {
404 const int l_b_index = BM_elem_index_get(l_b);
405 if (l_a_index == l_b_index) {
406 if (LIKELY(l_a->f->len == 3 && l_b->f->len == 3)) {
407 if (l_a->v != l_b->v) { /* if this is the case, faces have become flipped */
408 /* check we are not making a degenerate quad */
411 BM_vert_in_edge(e, l_a->next->v) ? l_a->prev->v : l_a->next->v,
413 BM_vert_in_edge(e, l_b->next->v) ? l_b->prev->v : l_b->next->v,
416 BLI_assert(ELEM3(vquad[0], vquad[1], vquad[2], vquad[3]) == false);
417 BLI_assert(ELEM3(vquad[1], vquad[0], vquad[2], vquad[3]) == false);
418 BLI_assert(ELEM3(vquad[2], vquad[1], vquad[0], vquad[3]) == false);
419 BLI_assert(ELEM3(vquad[3], vquad[1], vquad[2], vquad[0]) == false);
421 if (is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) {
422 /* highly unlikely to fail, but prevents possible double-ups */
423 BMFace *f[2] = {l_a->f, l_b->f};
424 BM_faces_join(bm, f, 2, true);
434 #endif /* USE_TRIANGULATE */
436 /* Edge Collapse Functions
437 * *********************** */
439 #ifdef USE_CUSTOMDATA
442 * \param v is the target to merge into.
444 static void bm_edge_collapse_loop_customdata(BMesh *bm, BMLoop *l, BMVert *v_clear, BMVert *v_other,
445 const float customdata_fac)
447 /* disable seam check - the seam check would have to be done per layer, its not really that important */
449 /* these don't need to be updated, since they will get removed when the edge collapses */
450 BMLoop *l_clear, *l_other;
451 const bool is_manifold = BM_edge_is_manifold(l->e);
454 /* l defines the vert to collapse into */
456 /* first find the loop of 'v_other' thats attached to the face of 'l' */
457 if (l->v == v_clear) {
466 BLI_assert(l_clear->v == v_clear);
467 BLI_assert(l_other->v == v_other);
468 (void)v_other; /* quiet warnings for release */
470 /* now we have both corners of the face 'l->f' */
471 for (side = 0; side < 2; side++) {
473 bool is_seam = false;
476 BMFace *f_exit = is_manifold ? l->radial_next->f : NULL;
477 BMEdge *e_prev = l->e;
483 l_iter = l_first = l_clear;
484 src[0] = l_clear->head.data;
485 src[1] = l_other->head.data;
487 w[0] = customdata_fac;
488 w[1] = 1.0f - customdata_fac;
491 l_iter = l_first = l_other;
492 src[0] = l_other->head.data;
493 src[1] = l_clear->head.data;
495 w[0] = 1.0f - customdata_fac;
496 w[1] = customdata_fac;
499 // print_v2("weights", w);
501 /* WATCH IT! - should NOT reference (_clear or _other) vars for this while loop */
503 /* walk around the fan using 'e_prev' */
504 while (((l_iter = BM_vert_step_fan_loop(l_iter, &e_prev)) != l_first) && (l_iter != NULL)) {
506 /* quit once we hit the opposite face, if we have one */
507 if (f_exit && UNLIKELY(f_exit == l_iter->f)) {
512 /* break out unless we find a match */
516 /* ok. we have a loop. now be smart with it! */
517 for (i = 0; i < bm->ldata.totlayer; i++) {
518 if (CustomData_layer_has_math(&bm->ldata, i)) {
519 const int offset = bm->ldata.layers[i].offset;
520 const int type = bm->ldata.layers[i].type;
521 void *cd_src[2] = {(char *)src[0] + offset,
522 (char *)src[1] + offset};
523 void *cd_iter = (char *)l_iter->head.data + offset;
526 if (CustomData_data_equals(type, cd_src[0], cd_iter)) {
527 CustomData_bmesh_interp_n(&bm->ldata, cd_src, w, NULL, 2, l_iter->head.data, i);
546 #endif /* USE_CUSTOMDATA */
549 * Check if the collapse will result in a degenerate mesh,
550 * that is - duplicate edges or faces.
552 * This situation could be checked for when calculating collapse cost
553 * however its quite slow and a degenerate collapse could eventuate
554 * after the cost is calculated, so instead, check just before collapsing.
557 static void bm_edge_tag_enable(BMEdge *e)
559 BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
560 BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
562 BM_elem_flag_enable(e->l->f, BM_ELEM_TAG);
563 if (e->l != e->l->radial_next) {
564 BM_elem_flag_enable(e->l->radial_next->f, BM_ELEM_TAG);
569 static void bm_edge_tag_disable(BMEdge *e)
571 BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
572 BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
574 BM_elem_flag_disable(e->l->f, BM_ELEM_TAG);
575 if (e->l != e->l->radial_next) {
576 BM_elem_flag_disable(e->l->radial_next->f, BM_ELEM_TAG);
581 static int bm_edge_tag_test(BMEdge *e)
583 /* is the edge or one of its faces tagged? */
584 return (BM_elem_flag_test(e->v1, BM_ELEM_TAG) ||
585 BM_elem_flag_test(e->v2, BM_ELEM_TAG) ||
586 (e->l && (BM_elem_flag_test(e->l->f, BM_ELEM_TAG) ||
587 (e->l != e->l->radial_next &&
588 BM_elem_flag_test(e->l->radial_next->f, BM_ELEM_TAG))))
592 /* takes the edges loop */
593 BLI_INLINE int bm_edge_is_manifold_or_boundary(BMLoop *l)
596 /* less optimized version of check below */
597 return (BM_edge_is_manifold(l->e) || BM_edge_is_boundary(l->e);
599 /* if the edge is a boundary it points to its self, else this must be a manifold */
600 return LIKELY(l) && LIKELY(l->radial_next->radial_next == l);
604 static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
606 /* simply check that there is no overlap between faces and edges of each vert,
607 * (excluding the 2 faces attached to 'e' and 'e' its self) */
611 /* clear flags on both disks */
614 if (!bm_edge_is_manifold_or_boundary(e_iter->l)) {
617 bm_edge_tag_disable(e_iter);
618 } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v1)) != e_first);
622 if (!bm_edge_is_manifold_or_boundary(e_iter->l)) {
625 bm_edge_tag_disable(e_iter);
626 } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v2)) != e_first);
628 /* now enable one side... */
631 bm_edge_tag_enable(e_iter);
632 } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v1)) != e_first);
634 /* ... except for the edge we will collapse, we know thats shared,
635 * disable this to avoid false positive. We could be smart and never enable these
636 * face/edge tags in the first place but easier to do this */
637 // bm_edge_tag_disable(e_first);
645 BM_ITER_ELEM (l, &liter, e_first, BM_LOOPS_OF_EDGE) {
646 BM_elem_flag_disable(l->f, BM_ELEM_TAG);
647 BM_ITER_ELEM (v, &iter, l->f, BM_VERTS_OF_FACE) {
648 BM_elem_flag_disable(v, BM_ELEM_TAG);
652 /* we know each face is a triangle, no looping/iterators needed here */
657 l_radial = e_first->l;
659 BLI_assert(l_face->f->len == 3);
660 BM_elem_flag_disable(l_face->f, BM_ELEM_TAG);
661 BM_elem_flag_disable((l_face = l_radial)->v, BM_ELEM_TAG);
662 BM_elem_flag_disable((l_face = l_face->next)->v, BM_ELEM_TAG);
663 BM_elem_flag_disable(( l_face->next)->v, BM_ELEM_TAG);
664 l_face = l_radial->radial_next;
665 if (l_radial != l_face) {
666 BLI_assert(l_face->f->len == 3);
667 BM_elem_flag_disable(l_face->f, BM_ELEM_TAG);
668 BM_elem_flag_disable((l_face = l_radial->radial_next)->v, BM_ELEM_TAG);
669 BM_elem_flag_disable((l_face = l_face->next)->v, BM_ELEM_TAG);
670 BM_elem_flag_disable(( l_face->next)->v, BM_ELEM_TAG);
675 /* and check for overlap */
678 if (bm_edge_tag_test(e_iter)) {
681 } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v2)) != e_first);
687 * special, highly limited edge collapse function
688 * intended for speed over flexibility.
689 * can only collapse edges connected to (1, 2) tris.
691 * Important - dont add vert/edge/face data on collapsing!
693 * \param e_clear_other let caller know what edges we remove besides \a e_clear
694 * \param customdata_flag merge factor, scales from 0 - 1 ('v_clear' -> 'v_other')
696 static bool bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_e_clear_other[2],
697 #ifdef USE_CUSTOMDATA
698 const CD_UseFlag customdata_flag,
699 const float customdata_fac
701 const CD_UseFlag UNUSED(customdata_flag),
702 const float UNUSED(customdata_fac)
708 v_other = BM_edge_other_vert(e_clear, v_clear);
709 BLI_assert(v_other != NULL);
711 if (BM_edge_is_manifold(e_clear)) {
713 BMEdge *e_a_other[2], *e_b_other[2];
716 ok = BM_edge_loop_pair(e_clear, &l_a, &l_b);
718 BLI_assert(ok == true);
719 BLI_assert(l_a->f->len == 3);
720 BLI_assert(l_b->f->len == 3);
722 /* keep 'v_clear' 0th */
723 if (BM_vert_in_edge(l_a->prev->e, v_clear)) {
724 e_a_other[0] = l_a->prev->e;
725 e_a_other[1] = l_a->next->e;
728 e_a_other[1] = l_a->prev->e;
729 e_a_other[0] = l_a->next->e;
732 if (BM_vert_in_edge(l_b->prev->e, v_clear)) {
733 e_b_other[0] = l_b->prev->e;
734 e_b_other[1] = l_b->next->e;
737 e_b_other[1] = l_b->prev->e;
738 e_b_other[0] = l_b->next->e;
741 /* we could assert this case, but better just bail out */
743 BLI_assert(e_a_other[0] != e_b_other[0]);
744 BLI_assert(e_a_other[0] != e_b_other[1]);
745 BLI_assert(e_b_other[0] != e_a_other[0]);
746 BLI_assert(e_b_other[0] != e_a_other[1]);
748 /* not totally common but we want to avoid */
749 if (ELEM(e_a_other[0], e_b_other[0], e_b_other[1]) ||
750 ELEM(e_a_other[1], e_b_other[0], e_b_other[1]))
755 BLI_assert(BM_edge_share_vert(e_a_other[0], e_b_other[0]));
756 BLI_assert(BM_edge_share_vert(e_a_other[1], e_b_other[1]));
758 r_e_clear_other[0] = BM_elem_index_get(e_a_other[0]);
759 r_e_clear_other[1] = BM_elem_index_get(e_b_other[0]);
761 #ifdef USE_CUSTOMDATA
762 /* before killing, do customdata */
763 if (customdata_flag & CD_DO_VERT) {
764 BM_data_interp_from_verts(bm, v_other, v_clear, v_other, customdata_fac);
766 if (customdata_flag & CD_DO_EDGE) {
767 BM_data_interp_from_edges(bm, e_a_other[1], e_a_other[0], e_a_other[1], customdata_fac);
768 BM_data_interp_from_edges(bm, e_b_other[1], e_b_other[0], e_b_other[1], customdata_fac);
770 if (customdata_flag & CD_DO_LOOP) {
771 bm_edge_collapse_loop_customdata(bm, e_clear->l, v_clear, v_other, customdata_fac);
772 bm_edge_collapse_loop_customdata(bm, e_clear->l->radial_next, v_clear, v_other, customdata_fac);
776 BM_edge_kill(bm, e_clear);
778 v_other->head.hflag |= v_clear->head.hflag;
779 BM_vert_splice(bm, v_clear, v_other);
781 e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag;
782 e_b_other[1]->head.hflag |= e_b_other[0]->head.hflag;
783 BM_edge_splice(bm, e_a_other[0], e_a_other[1]);
784 BM_edge_splice(bm, e_b_other[0], e_b_other[1]);
786 // BM_mesh_validate(bm);
790 else if (BM_edge_is_boundary(e_clear)) {
791 /* same as above but only one triangle */
793 BMEdge *e_a_other[2];
797 BLI_assert(l_a->f->len == 3);
799 /* keep 'v_clear' 0th */
800 if (BM_vert_in_edge(l_a->prev->e, v_clear)) {
801 e_a_other[0] = l_a->prev->e;
802 e_a_other[1] = l_a->next->e;
805 e_a_other[1] = l_a->prev->e;
806 e_a_other[0] = l_a->next->e;
809 r_e_clear_other[0] = BM_elem_index_get(e_a_other[0]);
810 r_e_clear_other[1] = -1;
812 #ifdef USE_CUSTOMDATA
813 /* before killing, do customdata */
814 if (customdata_flag & CD_DO_VERT) {
815 BM_data_interp_from_verts(bm, v_other, v_clear, v_other, customdata_fac);
817 if (customdata_flag & CD_DO_EDGE) {
818 BM_data_interp_from_edges(bm, e_a_other[1], e_a_other[0], e_a_other[1], customdata_fac);
820 if (customdata_flag & CD_DO_LOOP) {
821 bm_edge_collapse_loop_customdata(bm, e_clear->l, v_clear, v_other, customdata_fac);
825 BM_edge_kill(bm, e_clear);
827 v_other->head.hflag |= v_clear->head.hflag;
828 BM_vert_splice(bm, v_clear, v_other);
830 e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag;
831 BM_edge_splice(bm, e_a_other[0], e_a_other[1]);
833 // BM_mesh_validate(bm);
843 /* collapse e the edge, removing e->v2 */
844 static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e,
845 Quadric *vquadrics, float *vweights,
846 Heap *eheap, HeapNode **eheap_table,
847 const CD_UseFlag customdata_flag)
849 int e_clear_other[2];
850 BMVert *v_other = e->v1;
851 int v_clear_index = BM_elem_index_get(e->v2); /* the vert is removed so only store the index */
852 float optimize_co[3];
853 float customdata_fac;
855 #ifdef USE_VERT_NORMAL_INTERP
857 copy_v3_v3(v_clear_no, e->v2->no);
860 /* disallow collapsing which results in degenerate cases */
861 if (UNLIKELY(bm_edge_collapse_is_degenerate_topology(e))) {
862 bm_decim_invalid_edge_cost_single(e, eheap, eheap_table); /* add back with a high cost */
866 bm_decim_calc_target_co(e, optimize_co, vquadrics);
868 /* check if this would result in an overlapping face */
869 if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) {
870 bm_decim_invalid_edge_cost_single(e, eheap, eheap_table); /* add back with a high cost */
874 /* use for customdata merging */
875 if (LIKELY(compare_v3v3(e->v1->co, e->v2->co, FLT_EPSILON) == false)) {
876 customdata_fac = line_point_factor_v3(optimize_co, e->v1->co, e->v2->co);
878 /* simple test for stupid collapse */
879 if (customdata_fac < 0.0 - FLT_EPSILON || customdata_fac > 1.0f + FLT_EPSILON) {
885 /* avoid divide by zero */
886 customdata_fac = 0.5f;
889 if (bm_edge_collapse(bm, e, e->v2, e_clear_other, customdata_flag, customdata_fac)) {
890 /* update collapse info */
894 vweights[BM_elem_index_get(v_other)] += vweights[v_clear_index];
897 e = NULL; /* paranoid safety check */
899 copy_v3_v3(v_other->co, optimize_co);
902 for (i = 0; i < 2; i++) {
903 /* highly unlikely 'eheap_table[ke_other[i]]' would be NULL, but do for sanity sake */
904 if ((e_clear_other[i] != -1) && (eheap_table[e_clear_other[i]] != NULL)) {
905 BLI_heap_remove(eheap, eheap_table[e_clear_other[i]]);
906 eheap_table[e_clear_other[i]] = NULL;
910 /* update vertex quadric, add kept vertex from killed vertex */
911 BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(v_other)], &vquadrics[v_clear_index]);
913 /* update connected normals */
915 /* in fact face normals are not used for progressive updates, no need to update them */
916 // BM_vert_normal_update_all(v);
917 #ifdef USE_VERT_NORMAL_INTERP
918 interp_v3_v3v3(v_other->no, v_other->no, v_clear_no, customdata_fac);
919 normalize_v3(v_other->no);
921 BM_vert_normal_update(v_other);
925 /* update error costs and the eheap */
926 if (LIKELY(v_other->e)) {
929 e_iter = e_first = v_other->e;
931 BLI_assert(BM_edge_find_double(e_iter) == NULL);
932 bm_decim_build_edge_cost_single(e_iter, vquadrics, vweights, eheap, eheap_table);
933 } while ((e_iter = bmesh_disk_edge_next(e_iter, v_other)) != e_first);
936 /* this block used to be disabled,
937 * but enable now since surrounding faces may have been
938 * set to COST_INVALID because of a face overlap that no longer occurs */
940 /* optional, update edges around the vertex face fan */
944 BM_ITER_ELEM (l, &liter, v_other, BM_LOOPS_OF_VERT) {
945 if (l->f->len == 3) {
947 if (BM_vert_in_edge(l->prev->e, l->v))
948 e_outer = l->next->e;
950 e_outer = l->prev->e;
952 BLI_assert(BM_vert_in_edge(e_outer, l->v) == false);
954 bm_decim_build_edge_cost_single(e_outer, vquadrics, vweights, eheap, eheap_table);
958 /* end optional update */
962 /* add back with a high cost */
963 bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
968 /* Main Decimate Function
969 * ********************** */
972 * \brief BM_mesh_decimate
974 * \param factor face count multiplier [0 - 1]
975 * \param vweights Optional array of vertex aligned weights [0 - 1],
976 * a vertex group is the usual source for this.
978 void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, const bool do_triangulate)
980 Heap *eheap; /* edge heap */
981 HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */
982 Quadric *vquadrics; /* vert index aligned quadrics */
985 bool use_triangulate;
987 CD_UseFlag customdata_flag = 0;
989 #ifdef USE_TRIANGULATE
990 /* temp convert quads to triangles */
991 use_triangulate = bm_decim_triangulate_begin(bm);
996 vquadrics = MEM_callocN(sizeof(Quadric) * bm->totvert, __func__);
997 /* since some edges may be degenerate, we might be over allocing a little here */
998 eheap = BLI_heap_new_ex(bm->totedge);
999 eheap_table = MEM_mallocN(sizeof(HeapNode *) * bm->totedge, __func__);
1000 tot_edge_orig = bm->totedge;
1003 /* build initial edge collapse cost data */
1004 bm_decim_build_quadrics(bm, vquadrics);
1006 bm_decim_build_edge_cost(bm, vquadrics, vweights, eheap, eheap_table);
1008 face_tot_target = bm->totface * factor;
1009 bm->elem_index_dirty |= BM_FACE | BM_EDGE | BM_VERT;
1012 #ifdef USE_CUSTOMDATA
1013 /* initialize customdata flag, we only need math for loops */
1014 if (CustomData_has_interp(&bm->vdata)) customdata_flag |= CD_DO_VERT;
1015 if (CustomData_has_interp(&bm->edata)) customdata_flag |= CD_DO_EDGE;
1016 if (CustomData_has_math(&bm->ldata)) customdata_flag |= CD_DO_LOOP;
1019 /* iterative edge collapse and maintain the eheap */
1020 while ((bm->totface > face_tot_target) &&
1021 (BLI_heap_is_empty(eheap) == false) &&
1022 (BLI_heap_node_value(BLI_heap_top(eheap)) != COST_INVALID))
1024 // const float value = BLI_heap_node_value(BLI_heap_top(eheap));
1025 BMEdge *e = BLI_heap_popmin(eheap);
1026 BLI_assert(BM_elem_index_get(e) < tot_edge_orig); /* handy to detect corruptions elsewhere */
1028 // printf("COST %.10f\n", value);
1030 /* under normal conditions wont be accessed again,
1031 * but NULL just incase so we don't use freed node */
1032 eheap_table[BM_elem_index_get(e)] = NULL;
1034 bm_decim_edge_collapse(bm, e, vquadrics, vweights, eheap, eheap_table, customdata_flag);
1038 #ifdef USE_TRIANGULATE
1039 if (do_triangulate == false) {
1040 /* its possible we only had triangles, skip this step in that case */
1041 if (LIKELY(use_triangulate)) {
1042 /* temp convert quads to triangles */
1043 bm_decim_triangulate_end(bm);
1049 MEM_freeN(vquadrics);
1050 MEM_freeN(eheap_table);
1051 BLI_heap_free(eheap, NULL);
1054 // BM_mesh_validate(bm);
1056 (void)tot_edge_orig; /* quiet release build warning */