42 #include "../intern/bmesh_structure.h"
50 #define USE_CUSTOMDATA
51 #define USE_TRIANGULATE
53 #define USE_VERT_NORMAL_INTERP
56 #define USE_TOPOLOGY_FALLBACK
57 #ifdef USE_TOPOLOGY_FALLBACK
59 # define TOPOLOGY_FALLBACK_EPS 1e-12f
62 #define BOUNDARY_PRESERVE_WEIGHT 100.0f
67 #define OPTIMIZE_EPS 1e-8
68 #define COST_INVALID FLT_MAX
105 }
while ((l_iter = l_iter->
next) != l_first);
111 float edge_vector[3];
113 double edge_plane_db[4];
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]);
159 double optimize_co_db[3];
170 for (i = 0; i < 2; i++) {
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];
197 if (
dot_v3v3(cross_exist, cross_optim) <=
207 if (
dot_v3v3(cross_exist, cross_optim) <= FLT_EPSILON) {
219 #ifdef USE_TOPOLOGY_FALLBACK
241 const float *vweights,
242 const float vweight_factor,
255 if (
e->l->f->len == 3) {
264 if ((
e->l->f->len == 3) && (
e->l->radial_next->f->len == 3)) {
278 double optimize_co[3];
292 #ifdef USE_TOPOLOGY_FALLBACK
298 if (vweights ==
NULL) {
309 cost *= 1.0f + (e_weight * vweight_factor);
345 const float *vweights,
346 const float vweight_factor,
356 eheap_table[i] =
NULL;
378 const float UNUSED(co[3]),
383 float e_other_dir[3];
411 int *edge_symmetry_map;
423 BLI_kdtree_3d_insert(
tree, i, co);
425 edge_symmetry_map[i] = -1;
428 BLI_kdtree_3d_balance(
tree);
434 if (edge_symmetry_map[i] == -1) {
437 co[symmetry_axis] *= -1.0f;
441 sym_data.
e_v1_co[symmetry_axis] *= -1.0f;
442 sym_data.
e_v2_co[symmetry_axis] *= -1.0f;
450 edge_symmetry_map[i] = i_other;
451 edge_symmetry_map[i_other] = i;
457 BLI_kdtree_3d_free(
tree);
459 return edge_symmetry_map;
463 #ifdef USE_TRIANGULATE
482 int *r_edges_tri_tot,
486 struct Heap *pf_heap)
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;
493 const int quad_method = 0, ngon_method = 0;
495 bool has_cut =
false;
512 for (
int i = 0; i < edges_array_tot; i++) {
514 l_iter = l_first = edges_array[i]->
l;
518 }
while ((l_iter = l_iter->
radial_next) != l_first);
521 for (
int i = 0; i < faces_array_tot; i++) {
525 *r_edges_tri_tot += edges_array_tot;
534 bool has_quad =
false;
535 bool has_ngon =
false;
536 bool has_cut =
false;
548 }
while ((l_iter = l_iter->
next) != l_first);
550 has_quad |= (f->
len > 3);
551 has_ngon |= (f->
len > 4);
586 while (faces_double) {
627 if (l_a_index != -1) {
629 if (l_a_index == l_b_index) {
630 if (l_a->
v !=
l_b->
v) {
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)))
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);
652 if (!
is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) {
656 # undef CAN_LOOP_MERGE
666 for (
int i = 0; i <
STACK_SIZE(edges_tri); i++) {
685 #ifdef USE_CUSTOMDATA
697 BMLoop *l_clear, *l_other;
702 if (
l->
v == v_clear) {
717 for (side = 0; side < 2; side++) {
719 bool is_seam =
false;
729 l_iter = l_first = l_clear;
733 w[0] = customdata_fac;
734 w[1] = 1.0f - customdata_fac;
737 l_iter = l_first = l_other;
741 w[0] = 1.0f - customdata_fac;
742 w[1] = customdata_fac;
753 if (f_exit &&
UNLIKELY(f_exit == l_iter->
f)) {
767 const void *cd_src[2] = {
816 if (
e->l !=
e->l->radial_next) {
828 if (
e->l !=
e->l->radial_next) {
908 l_radial = e_first->
l;
916 if (l_radial != l_face) {
950 int r_e_clear_other[2],
952 int *edge_symmetry_map,
956 const float customdata_fac
959 const float UNUSED(customdata_fac)
970 BMEdge *e_a_other[2], *e_b_other[2];
982 e_a_other[0] = l_a->
prev->
e;
983 e_a_other[1] = l_a->
next->
e;
986 e_a_other[1] = l_a->
prev->
e;
987 e_a_other[0] = l_a->
next->
e;
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])) {
1018 #ifdef USE_CUSTOMDATA
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]);
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]);
1071 e_a_other[0] = l_a->
prev->
e;
1072 e_a_other[1] = l_a->
next->
e;
1075 e_a_other[1] = l_a->
prev->
e;
1076 e_a_other[0] = l_a->
next->
e;
1080 r_e_clear_other[1] = -1;
1082 #ifdef USE_CUSTOMDATA
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]);
1128 const float vweight_factor,
1132 int *edge_symmetry_map,
1135 float optimize_co[3],
1136 bool optimize_co_calc)
1138 int e_clear_other[2];
1143 float customdata_fac;
1145 #ifdef USE_VERT_NORMAL_INTERP
1146 float v_clear_no[3];
1151 if (optimize_co_calc) {
1174 if (customdata_fac < 0.0 - FLT_EPSILON || customdata_fac > 1.0f + FLT_EPSILON) {
1181 customdata_fac = 0.5f;
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;
1209 for (i = 0; i < 2; i++) {
1211 if ((e_clear_other[i] != -1) && (eheap_table[e_clear_other[i]] !=
NULL)) {
1213 eheap_table[e_clear_other[i]] =
NULL;
1224 #ifdef USE_VERT_NORMAL_INTERP
1235 e_iter = e_first = v_other->
e;
1239 e_iter, vquadrics, vweights, vweight_factor, eheap, eheap_table);
1252 if (
l->
f->
len == 3) {
1264 e_outer, vquadrics, vweights, vweight_factor, eheap, eheap_table);
1292 float vweight_factor,
1293 const bool do_triangulate,
1294 const int symmetry_axis,
1295 const float symmetry_eps)
1304 int face_tot_target;
1309 bool use_symmetry = (symmetry_axis != -1);
1310 int *edge_symmetry_map;
1313 #ifdef USE_TRIANGULATE
1314 int edges_tri_tot = 0;
1343 #ifdef USE_CUSTOMDATA
1358 if (use_symmetry ==
false)
1366 float optimize_co[3];
1402 const int e_index_mirr = edge_symmetry_map[e_index];
1404 float optimize_co[3];
1405 char e_invalidate = 0;
1409 eheap_table[e_index] =
NULL;
1411 if (e_index_mirr != -1) {
1412 if (e_index_mirr == e_index) {
1415 else if (eheap_table[e_index_mirr]) {
1443 e_invalidate |= (1 | (e_mirr ? 2 : 0));
1449 if (e_index_mirr == e_index) {
1450 optimize_co[symmetry_axis] = 0.0f;
1455 e_invalidate |= (1 | (e_mirr ? 2 : 0));
1471 if (e_mirr && (eheap_table[e_index_mirr])) {
1474 eheap_table[e_index_mirr] =
NULL;
1475 optimize_co[symmetry_axis] *= -1.0f;
1490 if (e_mirr && (eheap_table[e_index_mirr])) {
1500 if (e_invalidate & 1) {
1504 if (e_invalidate & 2) {
1507 eheap_table[e_index_mirr] =
NULL;
1516 #ifdef USE_TRIANGULATE
1517 if (do_triangulate ==
false) {
1519 if (
LIKELY(use_triangulate)) {
1535 (void)tot_edge_orig;
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_has_math(const struct CustomData *data)
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)
bool CustomData_data_equals(int type, const void *data1, const void *data2)
bool CustomData_has_interp(const struct CustomData *data)
bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
#define BLI_array_alloca(arr, realsize)
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Heap * BLI_heap_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT
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)
void * BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1)
float BLI_heap_top_value(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
HeapNode * BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1)
void * BLI_heap_node_ptr(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
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])
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])
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)
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])
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
struct MemArena * BLI_memarena_new(const size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2) ATTR_MALLOC
#define BLI_POLYFILL_ARENA_SIZE
#define BLI_POLYFILL_ALLOC_NGON_RESERVE
void BLI_quadric_mul(Quadric *a, const double scalar)
bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon)
void BLI_quadric_from_plane(Quadric *q, const double v[4])
double BLI_quadric_evaluate(const Quadric *q, const double v[3])
void BLI_quadric_add_qu_qu(Quadric *a, const Quadric *b)
void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b)
#define UNUSED_VARS_NDEBUG(...)
#define POINTER_OFFSET(v, ofs)
#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
#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
static int * bm_edge_symmetry_map(BMesh *bm, uint symmetry_axis, float limit)
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 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)
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)
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)
#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, Interp 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, Interp 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)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
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)
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2)
BMVert * BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
float BM_edge_calc_length(const BMEdge *e)
BMLoop * BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
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.
void(* MEM_freeN)(void *vmemh)
void *(* MEM_callocN)(size_t len, const char *str)
void *(* MEM_mallocN)(size_t len, const char *str)
static void clear(Message *msg)
struct BMLoop * radial_next