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