From 32ba51c4a1a4c4a67eee3658b959f9569b7e6f56 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 6 May 2012 18:37:08 +0000 Subject: fix for limited dissolve (after sine intended fixes - not cleaning up before vertex dissolve would skip dissolving some verts that should be dissolved). now do this: - edge dissolve - cleanup (removing edges left over from dissolving faces) cleanup removes verts and NULL vertex input array - dissolve verts which haven't been removed. --- source/blender/bmesh/operators/bmo_dissolve.c | 97 +++++++++++++++++---------- 1 file changed, 61 insertions(+), 36 deletions(-) (limited to 'source/blender/bmesh/operators/bmo_dissolve.c') diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index ae1773af05e..1451625d3bb 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -34,14 +34,14 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define FACE_MARK 1 -#define FACE_ORIG 2 -#define FACE_NEW 4 -#define EDGE_MARK 1 +#define FACE_MARK 1 +#define FACE_ORIG 2 +#define FACE_NEW 4 +#define EDGE_MARK 1 -#define VERT_MARK 1 +#define VERT_MARK 1 -static int UNUSED_FUNCTION(check_hole_in_region)(BMesh *bm, BMFace *f) +static int UNUSED_FUNCTION(check_hole_in_region) (BMesh * bm, BMFace * f) { BMWalker regwalker; BMIter liter2; @@ -60,8 +60,8 @@ static int UNUSED_FUNCTION(check_hole_in_region)(BMesh *bm, BMFace *f) l2 = BM_iter_new(&liter2, bm, BM_LOOPS_OF_FACE, f2); for ( ; l2; l2 = BM_iter_step(&liter2)) { l3 = l2->radial_next; - if ( BMO_elem_flag_test(bm, l3->f, FACE_MARK) != - BMO_elem_flag_test(bm, l2->f, FACE_MARK)) + if (BMO_elem_flag_test(bm, l3->f, FACE_MARK) != + BMO_elem_flag_test(bm, l2->f, FACE_MARK)) { if (!BMO_elem_flag_test(bm, l2->e, EDGE_MARK)) { return FALSE; @@ -433,8 +433,8 @@ void dummy_exec(BMesh *bm, BMOperator *op) fe = l->e; for ( ; l; l = BM_iter_step(&liter)) { f2 = BM_iter_new(&fiter, bm, - BM_FACES_OF_EDGE, l->e); - for ( ; f2; f2 = BM_iter_step(&fiter)) { + BM_FACES_OF_EDGE, l->e); + for (; f2; f2 = BM_iter_step(&fiter)) { if (f2 != f) { BM_faces_join_pair(bm, f, f2, l->e); found2 = 1; @@ -520,23 +520,28 @@ void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op) const float angle_max = (float)M_PI / 2.0f; const float angle_limit = minf(angle_max, BMO_slot_float_get(op, "angle_limit")); DissolveElemWeight *weight_elems = MEM_mallocN(MAX2(einput->len, vinput->len) * - sizeof(DissolveElemWeight), __func__); + sizeof(DissolveElemWeight), __func__); int i, tot_found; BMIter iter; BMEdge *e_iter; BMEdge **earray; + int *vert_reverse_lookup; + + BMEdge **einput_arr = (BMEdge **)einput->data.p; + BMVert **vinput_arr = (BMVert **)vinput->data.p; + /* --- first edges --- */ /* wire -> tag */ - BM_ITER_MESH(e_iter, &iter, bm, BM_EDGES_OF_MESH) { + BM_ITER_MESH (e_iter, &iter, bm, BM_EDGES_OF_MESH) { BM_elem_flag_set(e_iter, BM_ELEM_TAG, BM_edge_is_wire(e_iter)); } /* go through and split edge */ for (i = 0, tot_found = 0; i < einput->len; i++) { - BMEdge *e = ((BMEdge **)einput->data.p)[i]; + BMEdge *e = einput_arr[i]; const float angle = BM_edge_calc_face_angle(e); if (angle < angle_limit) { @@ -573,10 +578,51 @@ void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op) } } + /* prepare for cleanup */ + BM_mesh_elem_index_ensure(bm, BM_VERT); + vert_reverse_lookup = MEM_mallocN(sizeof(int) * bm->totvert, __func__); + fill_vn_i(vert_reverse_lookup, bm->totvert, -1); + for (i = 0, tot_found = 0; i < vinput->len; i++) { + BMVert *v = vinput_arr[i]; + vert_reverse_lookup[BM_elem_index_get(v)] = i; + } + + /* --- cleanup --- */ + earray = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, __func__); + BM_ITER_MESH_INDEX (e_iter, &iter, bm, BM_EDGES_OF_MESH, i) { + earray[i] = e_iter; + } + /* remove all edges/verts left behind from dissolving, NULL'ing the vertex array so we dont re-use */ + for (i = bm->totedge - 1; i != -1; i--) { + e_iter = earray[i]; + + if (BM_edge_is_wire(e_iter) && (BM_elem_flag_test(e_iter, BM_ELEM_TAG) == FALSE)) { + /* edge has become wire */ + int vidx_reverse; + BMVert *v1 = e_iter->v1; + BMVert *v2 = e_iter->v2; + BM_edge_kill(bm, e_iter); + if (v1->e == NULL) { + vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v1)]; + if (vidx_reverse != -1) vinput_arr[vidx_reverse] = NULL; + BM_vert_kill(bm, v1); + } + if (v2->e == NULL) { + vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v2)]; + if (vidx_reverse != -1) vinput_arr[vidx_reverse] = NULL; + BM_vert_kill(bm, v2); + } + } + } + MEM_freeN(vert_reverse_lookup); + + MEM_freeN(earray); + + /* --- second verts --- */ for (i = 0, tot_found = 0; i < vinput->len; i++) { - BMVert *v = ((BMVert **)vinput->data.p)[i]; - const float angle = bm_vert_edge_face_angle(v); + BMVert *v = vinput_arr[i]; + const float angle = v ? bm_vert_edge_face_angle(v) : angle_limit; if (angle < angle_limit) { weight_elems[i].ele = (BMHeader *)v; @@ -609,25 +655,4 @@ void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op) } MEM_freeN(weight_elems); - - /* --- cleanup --- */ - earray = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, __func__); - BM_ITER_MESH_INDEX(e_iter, &iter, bm, BM_EDGES_OF_MESH, i) { - earray[i] = e_iter; - } - /* remove all edges/verts left behind from dissolving */ - for (i = bm->totedge - 1; i != -1; i--) { - e_iter = earray[i]; - - if (BM_edge_is_wire(e_iter) && (BM_elem_flag_test(e_iter, BM_ELEM_TAG) == FALSE)) { - /* edge has become wire */ - BMVert *v1 = e_iter->v1; - BMVert *v2 = e_iter->v2; - BM_edge_kill(bm, e_iter); - if (v1->e == NULL) BM_vert_kill(bm, v1); - if (v2->e == NULL) BM_vert_kill(bm, v2); - } - } - - MEM_freeN(earray); } -- cgit v1.2.3