fix for limited dissolve (after sine intended fixes - not cleaning up before vertex...
authorCampbell Barton <ideasman42@gmail.com>
Sun, 6 May 2012 18:37:08 +0000 (18:37 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sun, 6 May 2012 18:37:08 +0000 (18:37 +0000)
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

index ae1773af05eb1cb8502e9f0214d57c3845590ffe..1451625d3bb143b3195056890797d62d1a3fe0aa 100644 (file)
 
 #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);
 }