dissolve faces: errors-out on holes, preserves winding, and doesn't delete original...
authorJoseph Eagar <joeedh@gmail.com>
Mon, 9 Mar 2009 09:52:32 +0000 (09:52 +0000)
committerJoseph Eagar <joeedh@gmail.com>
Mon, 9 Mar 2009 09:52:32 +0000 (09:52 +0000)
source/blender/bmesh/bmesh.h
source/blender/bmesh/bmesh_operators.h
source/blender/bmesh/intern/bmesh_construct.c
source/blender/bmesh/intern/bmesh_opdefines.c
source/blender/bmesh/intern/bmesh_queries.c
source/blender/bmesh/intern/bmesh_to_editmesh.c
source/blender/bmesh/intern/editmesh_to_bmesh.c
source/blender/bmesh/operators/dissolveops.c
source/blender/editors/mesh/editmesh_add.c

index 054e81566657ac5af637992c06b78cc677d966a7..7f532843dc93a231aa6ad9c9ac29f095660fa654 100644 (file)
@@ -76,6 +76,7 @@ struct BMLoop;
 #define BM_HIDDEN      (1<<3)
 #define BM_SHARP       (1<<4)
 #define BM_SMOOTH      (1<<5)
 #define BM_HIDDEN      (1<<3)
 #define BM_SHARP       (1<<4)
 #define BM_SMOOTH      (1<<5)
+#define BM_ACTIVE      (1<<6)
 
 typedef struct BMHeader {
        struct BMHeader *next, *prev;
 
 typedef struct BMHeader {
        struct BMHeader *next, *prev;
index 37225ab342ed6a78b600ae7bfd2881094d4358f2..9b368b2acfdeaaca25dc1c11f5cc9c066bf73626 100644 (file)
@@ -86,6 +86,8 @@ void BMO_Set_Pnt(struct BMOperator *op, int slotcode, void *p);
 void BMO_Set_Vec(struct BMOperator *op, int slotcode, float *vec);
 void BMO_SetFlag(struct BMesh *bm, void *element, int flag);
 void BMO_ClearFlag(struct BMesh *bm, void *element, int flag);
 void BMO_Set_Vec(struct BMOperator *op, int slotcode, float *vec);
 void BMO_SetFlag(struct BMesh *bm, void *element, int flag);
 void BMO_ClearFlag(struct BMesh *bm, void *element, int flag);
+
+/*flags 15 and 16 (1<<14 and 1<<15) are reserved for bmesh api use*/
 int BMO_TestFlag(struct BMesh *bm, void *element, int flag);
 int BMO_CountFlag(struct BMesh *bm, int flag, int type);
 void BMO_Flag_To_Slot(struct BMesh *bm, struct BMOperator *op, int slotcode, int flag, int type);
 int BMO_TestFlag(struct BMesh *bm, void *element, int flag);
 int BMO_CountFlag(struct BMesh *bm, int flag, int type);
 void BMO_Flag_To_Slot(struct BMesh *bm, struct BMOperator *op, int slotcode, int flag, int type);
@@ -340,10 +342,9 @@ void BM_esubdivideflag(struct Object *obedit, struct BMesh *bm, int selflag, flo
               int flag, int numcuts, int seltype);
 void BM_extrudefaceflag(BMesh *bm, int flag);
 
               int flag, int numcuts, int seltype);
 void BM_extrudefaceflag(BMesh *bm, int flag);
 
-/*these next two return 1 if they did anything, or zero otherwise.
+/*this next one return 1 if they did anything, or zero otherwise.
   they're kindof a hackish way to integrate with fkey, until
   such time as fkey is completely bmeshafied.*/
   they're kindof a hackish way to integrate with fkey, until
   such time as fkey is completely bmeshafied.*/
-int BM_DissolveFaces(struct EditMesh *em, int flag);
 /*this doesn't display errors to the user, btw*/
 int BM_ConnectVerts(struct EditMesh *em, int flag);
 
 /*this doesn't display errors to the user, btw*/
 int BM_ConnectVerts(struct EditMesh *em, int flag);
 
index d302a85ec7289566a8e8bd6a68fbdefece77c4b9..f061358c8f8a8a056d1a2d6a4f042d02e43658ec 100644 (file)
@@ -210,20 +210,33 @@ void BM_Face_CopyShared(BMesh *bm, BMFace *f) {
 BMFace *BM_Make_Ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, int nodouble)
 {
        BMVert *vert_buf[VERT_BUF_SIZE];
 BMFace *BM_Make_Ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, int nodouble)
 {
        BMVert *vert_buf[VERT_BUF_SIZE];
-       BMVert **verts = vert_buf;
+       BMVert **verts = vert_buf, *lastv;
        BMFace *f = NULL;
        BMFace *f = NULL;
-       int overlap = 0, i;
+       int overlap = 0, i, j;
 
        if(nodouble){
                if(len > VERT_BUF_SIZE)
                        verts = MEM_callocN(sizeof(BMVert *) * len, "bmesh make ngon vertex array");
 
        if(nodouble){
                if(len > VERT_BUF_SIZE)
                        verts = MEM_callocN(sizeof(BMVert *) * len, "bmesh make ngon vertex array");
-               for(i = 0; i < len; i++){
+               
+               /*if ((edges[i]->v1 == edges[i]->v1) || 
+                  (edges[i]->v1 == edges[i]->v2))
+               {
+                       lastv = edges[i]->v2;
+               } else lastv = edges[i]->v1;
+               verts[0] = lastv;
+
+               for (i=1; i<len; i++) {
+                       if (!BMO_TestFlag
+               }*/
+
+               for(i = 0, j=0; i < len; i++){
                        if(!BMO_TestFlag(bm, edges[i]->v1, BM_EDGEVERT)){
                                BMO_SetFlag(bm, edges[i]->v1, BM_EDGEVERT);
                        if(!BMO_TestFlag(bm, edges[i]->v1, BM_EDGEVERT)){
                                BMO_SetFlag(bm, edges[i]->v1, BM_EDGEVERT);
-                               verts[i] = edges[i]->v1;
-                       } else if(!BMO_TestFlag(bm, edges[i]->v2, BM_EDGEVERT)) {
+                               verts[j++] = edges[i]->v1;
+                       }
+                       if(!BMO_TestFlag(bm, edges[i]->v2, BM_EDGEVERT)) {
                                BMO_SetFlag(bm, edges[i]->v2, BM_EDGEVERT);
                                BMO_SetFlag(bm, edges[i]->v2, BM_EDGEVERT);
-                               verts[i] = edges[i]->v2;
+                               verts[j++] = edges[i]->v2;
                        }
                }
                
                        }
                }
                
index 28cf5d881c80dd5b69a446b0224733d5be8d825c..4fd8239ca05b8e167ffa8f934410014fa7f43afe 100644 (file)
@@ -4,7 +4,7 @@
 #include <stdio.h>
 
 BMOpDefine def_connectverts = {
 #include <stdio.h>
 
 BMOpDefine def_connectverts = {
-       "connectvert",
+       "connectverts",
        {{BMOP_OPSLOT_PNT_BUF, "verts"},
        {BMOP_OPSLOT_PNT_BUF, "edgeout"}},
        connectverts_exec,
        {{BMOP_OPSLOT_PNT_BUF, "verts"},
        {BMOP_OPSLOT_PNT_BUF, "edgeout"}},
        connectverts_exec,
index a38f3992dfeb0c6f52221730510815c0e38c16f3..9bc4fe03fdc3098d968de2494b745e4883d3ae61 100644 (file)
@@ -114,7 +114,7 @@ int BM_Verts_In_Face(BMesh *bm, BMFace *f, BMVert **varr, int len)
        curloop = f->loopbase;
        do{
                if(BMO_TestFlag(bm, curloop->v, BM_OVERLAP)) count++;
        curloop = f->loopbase;
        do{
                if(BMO_TestFlag(bm, curloop->v, BM_OVERLAP)) count++;
-               curloop = ((BMLoop*)(curloop->head.next));
+               curloop = (BMLoop*)(curloop->head.next);
        } while(curloop != f->loopbase);
 
        for(i=0; i < len; i++) BMO_ClearFlag(bm, varr[i], BM_OVERLAP);
        } while(curloop != f->loopbase);
 
        for(i=0; i < len; i++) BMO_ClearFlag(bm, varr[i], BM_OVERLAP);
index 99de531e7cd88391cef872b56b2fc70941e79c2e..12bf0bf5e86908e6858b3e8c22efed7a8147f034 100644 (file)
@@ -167,7 +167,6 @@ static EditFace *bmeshface_to_editface(BMesh *bm, EditMesh *em, BMFace *f, EditV
 
        efa->mat_nr = (unsigned char)f->mat_nr;
 
 
        efa->mat_nr = (unsigned char)f->mat_nr;
 
-
        /*Copy normal*/
        efa->n[0] = f->no[0];
        efa->n[1] = f->no[1];
        /*Copy normal*/
        efa->n[0] = f->no[0];
        efa->n[1] = f->no[1];
@@ -177,6 +176,7 @@ static EditFace *bmeshface_to_editface(BMesh *bm, EditMesh *em, BMFace *f, EditV
        if (f->head.flag & BM_SELECT) efa->f |= SELECT;
        if (f->head.flag & BM_HIDDEN) efa->h = 1;
        if (f->head.flag & BM_SMOOTH) efa->flag |= ME_SMOOTH;
        if (f->head.flag & BM_SELECT) efa->f |= SELECT;
        if (f->head.flag & BM_HIDDEN) efa->h = 1;
        if (f->head.flag & BM_SMOOTH) efa->flag |= ME_SMOOTH;
+       if (f->head.flag & BM_ACTIVE) EM_set_actFace(em, efa);
 
        CustomData_em_copy_data(&bm->pdata, &em->fdata, f->data, &efa->data);
        loops_to_editmesh_corners(bm, &em->fdata, efa->data, f, numCol,numTex);
 
        CustomData_em_copy_data(&bm->pdata, &em->fdata, f->data, &efa->data);
        loops_to_editmesh_corners(bm, &em->fdata, efa->data, f, numCol,numTex);
@@ -231,6 +231,10 @@ EditMesh *bmesh_to_editmesh_intern(BMesh *bm)
 
        EM_fgon_flags(em);
 
 
        EM_fgon_flags(em);
 
+       EM_nvertices_selected(em);
+       EM_nedges_selected(em);
+       EM_nfaces_selected(em);
+
        return em;
 }
 
        return em;
 }
 
index dfe97297161f600f53a9c22d651b54a34861d0f4..b8431f06ff4cd8c31c2fd699d0b53c6ac026739f 100644 (file)
@@ -189,6 +189,8 @@ static BMFace *editface_to_BMFace(BMesh *bm, EditMesh *em, EditFace *efa, int nu
                f->mat_nr = efa->mat_nr;
                if(efa->f & SELECT) BM_Select_Face(bm, f, 1);
                if(efa->h) f->head.flag |= BM_HIDDEN;
                f->mat_nr = efa->mat_nr;
                if(efa->f & SELECT) BM_Select_Face(bm, f, 1);
                if(efa->h) f->head.flag |= BM_HIDDEN;
+
+               if (efa == em->act_face) f->head.flag |= BM_ACTIVE;
                
                CustomData_bmesh_copy_data(&em->fdata, &bm->pdata, efa->data, &f->data);
                editmesh_corners_to_loops(bm, &em->fdata, efa->data, f,numCol,numTex);
                
                CustomData_bmesh_copy_data(&em->fdata, &bm->pdata, efa->data, &f->data);
                editmesh_corners_to_loops(bm, &em->fdata, efa->data, f,numCol,numTex);
@@ -234,7 +236,7 @@ static void fuse_fgon(BMesh *bm, BMFace *f)
 {
        BMFace *sf;
        BMLoop *l;
 {
        BMFace *sf;
        BMLoop *l;
-       int done;
+       int done, act=0;
 
        sf = f;
        done = 0;
 
        sf = f;
        done = 0;
@@ -242,8 +244,12 @@ static void fuse_fgon(BMesh *bm, BMFace *f)
                done = 1;
                l = sf->loopbase;
                do{
                done = 1;
                l = sf->loopbase;
                do{
-                       if(l->e->head.flag & BM_FGON){ 
+                       if(l->e->head.flag & BM_FGON) { 
+                               if (l->f->head.flag & BM_ACTIVE) act = BM_ACTIVE;
+                               if (((BMLoop*)l->radial.next->data)->f->head.flag & BM_ACTIVE) act = BM_ACTIVE;
+
                                sf = BM_Join_Faces(bm,l->f, ((BMLoop*)l->radial.next->data)->f, l->e, 0,0);
                                sf = BM_Join_Faces(bm,l->f, ((BMLoop*)l->radial.next->data)->f, l->e, 0,0);
+                               sf->head.flag |= act;
                                if(sf){
                                        done = 0;
                                        break;
                                if(sf){
                                        done = 0;
                                        break;
index 295fd29afc6d6319eade8ffa79249c916dbba81f..de6aea7bd259c109a8b08089482df09b72aefe96 100644 (file)
 
 #define FACE_MARK      1
 #define FACE_ORIG      2
 
 #define FACE_MARK      1
 #define FACE_ORIG      2
-#define VERT_MARK      1
 #define FACE_NEW       4
 #define FACE_NEW       4
+#define EDGE_MARK      1
+
+#define VERT_MARK      1
+
+static int check_hole_in_region(BMesh *bm, BMFace *f) {
+       BMWalker regwalker;
+       BMIter liter2;
+       BMLoop *l2, *l3;
+       BMFace *f2;
+       
+       /*checks if there are any unmarked boundary edges in the face region*/
+
+       BMW_Init(&regwalker, bm, BMW_ISLAND, FACE_MARK);
+       f2 = BMW_Begin(&regwalker, f);
+       for (; f2; f2=BMW_Step(&regwalker)) {
+               l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2);
+               for (; l2; l2=BMIter_Step(&liter2)) {                   
+                       l3 = bmesh_radial_nextloop(l2);
+                       if (BMO_TestFlag(bm, l3->f, FACE_MARK) 
+                           != BMO_TestFlag(bm, l2->f, FACE_MARK))
+                       {
+                               if (!BMO_TestFlag(bm, l2->e, EDGE_MARK)) {
+                                       return 0;
+                               }
+                       }
+               }
+       }
+       BMW_End(&regwalker);
+
+       return 1;
+}
 
 void dissolvefaces_exec(BMesh *bm, BMOperator *op)
 {
 
 void dissolvefaces_exec(BMesh *bm, BMOperator *op)
 {
@@ -51,6 +81,7 @@ void dissolvefaces_exec(BMesh *bm, BMOperator *op)
                                for (; l; l=BMW_Step(&walker)) {
                                        V_GROW(region);
                                        region[V_COUNT(region)-1] = l;
                                for (; l; l=BMW_Step(&walker)) {
                                        V_GROW(region);
                                        region[V_COUNT(region)-1] = l;
+                                       BMO_SetFlag(bm, l->e, EDGE_MARK);
                                }
                                BMW_End(&walker);
 
                                }
                                BMW_End(&walker);
 
@@ -62,6 +93,14 @@ void dissolvefaces_exec(BMesh *bm, BMOperator *op)
                                
                                if (region == NULL) continue;
 
                                
                                if (region == NULL) continue;
 
+                               /*check for holes in boundary*/
+                               if (!check_hole_in_region(bm, region[0]->f)) {
+                                       BMO_RaiseError(bm, op, 
+                                             BMERR_DISSOLVEFACES_FAILED, 
+                                             "Hole(s) in face region");
+                                       goto cleanup;
+                               }
+                               
                                BMW_Init(&regwalker, bm, BMW_ISLAND, FACE_MARK);
                                f2 = BMW_Begin(&regwalker, region[0]->f);
                                for (; f2; f2=BMW_Step(&regwalker)) {
                                BMW_Init(&regwalker, bm, BMW_ISLAND, FACE_MARK);
                                f2 = BMW_Begin(&regwalker, region[0]->f);
                                for (; f2; f2=BMW_Step(&regwalker)) {
@@ -95,22 +134,11 @@ void dissolvefaces_exec(BMesh *bm, BMOperator *op)
                        edges[V_COUNT(edges)-1] = region[j]->e;
                }
                
                        edges[V_COUNT(edges)-1] = region[j]->e;
                }
                
-               f= BM_Make_Ngon(bm, edges[0]->v1, edges[0]->v2,  edges, j, 0);
-               
-               if (!f) continue;
-
-               /*
-               NOTE: sadly, make ngon's overlap checking option
-                     crashes ;/
-               make ngon can fail, if there was already an existing face.
-               this is desired behaviour, I think, so we'll just silently
-               ignore any possible other error cases.
-               if (!f) {
-                       //raise error
-                       BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL);
-                       goto cleanup;
-               }*/
+               f= BM_Make_Ngon(bm, region[0]->v, region[1]->v,  edges, j, 1);
                
                
+               /*if making the new face failed (e.g. overlapping test)
+                 unmark the original faces for deletion.*/
+               BMO_ClearFlag(bm, f, FACE_ORIG);
                BMO_SetFlag(bm, f, FACE_NEW);
 
                fcopied = 0;
                BMO_SetFlag(bm, f, FACE_NEW);
 
                fcopied = 0;
@@ -155,24 +183,6 @@ cleanup:
        V_FREE(regions);
 }
 
        V_FREE(regions);
 }
 
-/*returns 1 if any faces were dissolved*/
-int BM_DissolveFaces(EditMesh *em, int flag) {
-       BMesh *bm = editmesh_to_bmesh(em);
-       EditMesh *em2;
-       BMOperator op;
-
-       BMO_Init_Op(&op, BMOP_DISSOLVE_FACES);
-       BMO_HeaderFlag_To_Slot(bm, &op, BMOP_DISFACES_FACEIN, flag, BM_FACE);
-       BMO_Exec_Op(bm, &op);
-       BMO_Finish_Op(bm, &op);
-       
-       em2 = bmesh_to_editmesh(bm);
-       set_editMesh(em, em2);
-       MEM_freeN(em2);
-
-       return BMO_GetSlot(&op, BMOP_DISFACES_REGIONOUT)->len > 0;
-}
-
 void dissolveverts_exec(BMesh *bm, BMOperator *op)
 {
        BMOpSlot *vinput;
 void dissolveverts_exec(BMesh *bm, BMOperator *op)
 {
        BMOpSlot *vinput;
@@ -195,8 +205,11 @@ void dissolveverts_exec(BMesh *bm, BMOperator *op)
 
        BMO_CallOpf(bm, "dissolvefaces faces=%ff", FACE_MARK);
        if (BMO_HasError(bm)) {
 
        BMO_CallOpf(bm, "dissolvefaces faces=%ff", FACE_MARK);
        if (BMO_HasError(bm)) {
+                       char *msg;
+
+                       BMO_GetError(bm, &msg, NULL);
                        BMO_ClearStack(bm);
                        BMO_ClearStack(bm);
-                       BMO_RaiseError(bm, op, BMERR_DISSOLVEVERTS_FAILED, NULL);
+                       BMO_RaiseError(bm, op, BMERR_DISSOLVEVERTS_FAILED,msg);
        }
 }
 
        }
 }
 
index 8651abac0a995a500776e52cdb060266e1fb44be..b32c733ad8c9ce63b761babcf48bd0d702b16c4a 100644 (file)
@@ -669,15 +669,42 @@ static void addedgeface_mesh(EditMesh *em, wmOperator *op)
        EditFace *efa;
        short amount=0;
        
        EditFace *efa;
        short amount=0;
        
+       /*return if bmesh vert connect does anything.*/
        if (em->selectmode & SCE_SELECT_VERTEX) {
        if (em->selectmode & SCE_SELECT_VERTEX) {
-               /*return if bmesh vert connect does anything.*/
-               if (BM_ConnectVerts(em, BM_SELECT)) return;
+               BMesh *bm = editmesh_to_bmesh(em);
+               BMOperator bmop;
+               int len, ok;
+
+               BMO_InitOpf(bm, &bmop, "connectverts verts=%hv", BM_SELECT);
+               BMO_Exec_Op(bm, &bmop);
+               BMO_Finish_Op(bm, &bmop);
+
+               ok = EDBM_Finish(bm, em, op, 1);
+               if (!ok) return OPERATOR_CANCELLED;
+
+               len = BMO_GetSlot(&bmop, BM_CONVERTS_EDGEOUT)->len;             
+               if (len) return;        
        }
 
        }
 
+       /*return if bmesh face dissolve finds stuff to
+         dissolve.  this entire tool should be
+         bmeshafied eventually, but until then
+         hacks like this to integrate with it
+         are necassary.*/
        if (em->selectmode & SCE_SELECT_FACE) {
        if (em->selectmode & SCE_SELECT_FACE) {
-               /*return if bmesh face dissolve finds stuff to
-                 dissolve.*/
-               if (BM_DissolveFaces(em, BM_SELECT)) return;
+               BMesh *bm = editmesh_to_bmesh(em);
+               BMOperator bmop;
+               int len, ok;
+
+               BMO_InitOpf(bm, &bmop, "dissolvefaces faces=%hf", BM_SELECT);
+               BMO_Exec_Op(bm, &bmop);
+               BMO_Finish_Op(bm, &bmop);
+
+               ok = EDBM_Finish(bm, em, op, 1);
+               if (!ok) return OPERATOR_CANCELLED;
+
+               len = BMO_GetSlot(&bmop, BMOP_DISFACES_REGIONOUT)->len;         
+               if (len) return;
        }
 
        /* how many selected ? */
        }
 
        /* how many selected ? */