BMesh: generalize logic for quad/ngon triangulate

Avoid having 2 different code-paths for face triangulation.
This commit is contained in:
Campbell Barton 2015-11-05 06:32:04 +11:00
parent 3152419e7e
commit ce49c70956

@ -796,111 +796,111 @@ void BM_face_triangulate(
/* ensure both are valid or NULL */ /* ensure both are valid or NULL */
BLI_assert((r_faces_new == NULL) == (r_faces_new_tot == NULL)); BLI_assert((r_faces_new == NULL) == (r_faces_new_tot == NULL));
if (f->len == 4) { BLI_assert(f->len > 3);
BMLoop *l_v1, *l_v2;
l_first = BM_FACE_FIRST_LOOP(f);
switch (quad_method) { {
case MOD_TRIANGULATE_QUAD_FIXED:
{
l_v1 = l_first;
l_v2 = l_first->next->next;
break;
}
case MOD_TRIANGULATE_QUAD_ALTERNATE:
{
l_v1 = l_first->next;
l_v2 = l_first->prev;
break;
}
case MOD_TRIANGULATE_QUAD_SHORTEDGE:
case MOD_TRIANGULATE_QUAD_BEAUTY:
default:
{
BMLoop *l_v3, *l_v4;
bool split_24;
l_v1 = l_first->next;
l_v2 = l_first->next->next;
l_v3 = l_first->prev;
l_v4 = l_first;
if (quad_method == MOD_TRIANGULATE_QUAD_SHORTEDGE) {
float d1, d2;
d1 = len_squared_v3v3(l_v4->v->co, l_v2->v->co);
d2 = len_squared_v3v3(l_v1->v->co, l_v3->v->co);
split_24 = ((d2 - d1) > 0.0f);
}
else {
/* first check if the quad is concave on either diagonal */
const int flip_flag = is_quad_flip_v3(l_v1->v->co, l_v2->v->co, l_v3->v->co, l_v4->v->co);
if (UNLIKELY(flip_flag & (1 << 0))) {
split_24 = true;
}
else if (UNLIKELY(flip_flag & (1 << 1))) {
split_24 = false;
}
else {
split_24 = (BM_verts_calc_rotate_beauty(l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) > 0.0f);
}
}
/* named confusingly, l_v1 is in fact the second vertex */
if (split_24) {
l_v1 = l_v4;
//l_v2 = l_v2;
}
else {
//l_v1 = l_v1;
l_v2 = l_v3;
}
break;
}
}
f_new = BM_face_split(bm, f, l_v1, l_v2, &l_new, NULL, true);
copy_v3_v3(f_new->no, f->no);
if (use_tag) {
BM_elem_flag_enable(l_new->e, BM_ELEM_TAG);
BM_elem_flag_enable(f_new, BM_ELEM_TAG);
}
if (r_faces_new) {
r_faces_new[nf_i++] = f_new;
}
if (r_edges_new) {
r_edges_new[ne_i++] = l_new->e;
}
}
else if (f->len > 4) {
float axis_mat[3][3];
float (*projverts)[2] = BLI_array_alloca(projverts, f->len);
BMLoop **loops = BLI_array_alloca(loops, f->len); BMLoop **loops = BLI_array_alloca(loops, f->len);
unsigned int (*tris)[3] = BLI_array_alloca(tris, f->len); unsigned int (*tris)[3] = BLI_array_alloca(tris, f->len);
const int totfilltri = f->len - 2; const int totfilltri = f->len - 2;
const int last_tri = f->len - 3; const int last_tri = f->len - 3;
int i; int i;
axis_dominant_v3_to_m3_negate(axis_mat, f->no); if (f->len == 4) {
/* even though we're not using BLI_polyfill, fill in 'tris' and 'loops'
* so we can share code to handle face creation afterwards. */
BMLoop *l_v1, *l_v2;
for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l_iter = l_iter->next) { l_first = BM_FACE_FIRST_LOOP(f);
loops[i] = l_iter;
mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co); switch (quad_method) {
case MOD_TRIANGULATE_QUAD_FIXED:
{
l_v1 = l_first;
l_v2 = l_first->next->next;
break;
}
case MOD_TRIANGULATE_QUAD_ALTERNATE:
{
l_v1 = l_first->next;
l_v2 = l_first->prev;
break;
}
case MOD_TRIANGULATE_QUAD_SHORTEDGE:
case MOD_TRIANGULATE_QUAD_BEAUTY:
default:
{
BMLoop *l_v3, *l_v4;
bool split_24;
l_v1 = l_first->next;
l_v2 = l_first->next->next;
l_v3 = l_first->prev;
l_v4 = l_first;
if (quad_method == MOD_TRIANGULATE_QUAD_SHORTEDGE) {
float d1, d2;
d1 = len_squared_v3v3(l_v4->v->co, l_v2->v->co);
d2 = len_squared_v3v3(l_v1->v->co, l_v3->v->co);
split_24 = ((d2 - d1) > 0.0f);
}
else {
/* first check if the quad is concave on either diagonal */
const int flip_flag = is_quad_flip_v3(l_v1->v->co, l_v2->v->co, l_v3->v->co, l_v4->v->co);
if (UNLIKELY(flip_flag & (1 << 0))) {
split_24 = true;
}
else if (UNLIKELY(flip_flag & (1 << 1))) {
split_24 = false;
}
else {
split_24 = (BM_verts_calc_rotate_beauty(l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) > 0.0f);
}
}
/* named confusingly, l_v1 is in fact the second vertex */
if (split_24) {
l_v1 = l_v4;
//l_v2 = l_v2;
}
else {
//l_v1 = l_v1;
l_v2 = l_v3;
}
break;
}
}
loops[0] = l_v1;
loops[1] = l_v1->next;
loops[2] = l_v2;
loops[3] = l_v2->next;
ARRAY_SET_ITEMS(tris[0], 0, 1, 2);
ARRAY_SET_ITEMS(tris[1], 0, 2, 3);
} }
else {
float axis_mat[3][3];
float (*projverts)[2] = BLI_array_alloca(projverts, f->len);
BLI_polyfill_calc_arena((const float (*)[2])projverts, f->len, 1, tris, axis_dominant_v3_to_m3_negate(axis_mat, f->no);
pf_arena);
if (use_beauty) { for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l_iter = l_iter->next) {
BLI_polyfill_beautify( loops[i] = l_iter;
(const float (*)[2])projverts, f->len, tris, mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co);
pf_arena, pf_heap, pf_ehash); }
BLI_polyfill_calc_arena((const float (*)[2])projverts, f->len, 1, tris,
pf_arena);
if (use_beauty) {
BLI_polyfill_beautify(
(const float (*)[2])projverts, f->len, tris,
pf_arena, pf_heap, pf_ehash);
}
BLI_memarena_clear(pf_arena);
} }
BLI_memarena_clear(pf_arena);
/* loop over calculated triangles and create new geometry */ /* loop over calculated triangles and create new geometry */
for (i = 0; i < totfilltri; i++) { for (i = 0; i < totfilltri; i++) {
/* the order is reverse, otherwise the normal is flipped */ /* the order is reverse, otherwise the normal is flipped */