1 #include "MEM_guardedalloc.h"
3 #include "BKE_utildefines.h"
6 #include "mesh_intern.h"
7 #include "bmesh_private.h"
8 #include "BLI_arithb.h"
21 static int check_hole_in_region(BMesh *bm, BMFace *f) {
27 /*checks if there are any unmarked boundary edges in the face region*/
29 BMW_Init(®walker, bm, BMW_ISLAND, FACE_MARK);
30 f2 = BMW_Begin(®walker, f);
31 for (; f2; f2=BMW_Step(®walker)) {
32 l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2);
33 for (; l2; l2=BMIter_Step(&liter2)) {
34 l3 = bmesh_radial_nextloop(l2);
35 if (BMO_TestFlag(bm, l3->f, FACE_MARK)
36 != BMO_TestFlag(bm, l2->f, FACE_MARK))
38 if (!BMO_TestFlag(bm, l2->e, EDGE_MARK)) {
49 void dissolvefaces_exec(BMesh *bm, BMOperator *op)
54 BMFace *f, *f2, *nf = NULL;
57 BMLoop ***regions = NULL;
58 BMLoop **region = NULL;
59 BMWalker walker, regwalker;
62 BMO_Flag_Buffer(bm, op, BMOP_DISFACES_FACEIN, FACE_MARK);
65 f = BMO_IterNew(&oiter, bm, op, BMOP_DISFACES_FACEIN);
66 for (; f; f=BMO_IterStep(&oiter)) {
67 if (!BMO_TestFlag(bm, f, FACE_MARK)) continue;
69 l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
70 for (; l; l=BMIter_Step(&liter)) {
71 l2 = bmesh_radial_nextloop(l);
72 if (l2!=l && BMO_TestFlag(bm, l2->f, FACE_MARK))
74 if (BM_FacesAroundEdge(l->e) <= 2) {
76 region = NULL; /*forces different allocation*/
79 BMW_Init(&walker, bm, BMW_ISLANDBOUND, FACE_MARK);
80 l = BMW_Begin(&walker, l);
81 for (; l; l=BMW_Step(&walker)) {
83 region[V_COUNT(region)-1] = l;
84 BMO_SetFlag(bm, l->e, EDGE_MARK);
88 if (BMO_HasError(bm)) {
90 BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL);
94 if (region == NULL) continue;
96 /*check for holes in boundary*/
97 if (!check_hole_in_region(bm, region[0]->f)) {
98 BMO_RaiseError(bm, op,
99 BMERR_DISSOLVEFACES_FAILED,
100 "Hole(s) in face region");
104 BMW_Init(®walker, bm, BMW_ISLAND, FACE_MARK);
105 f2 = BMW_Begin(®walker, region[0]->f);
106 for (; f2; f2=BMW_Step(®walker)) {
107 BMO_ClearFlag(bm, f2, FACE_MARK);
108 BMO_SetFlag(bm, f2, FACE_ORIG);
112 if (BMO_HasError(bm)) {
114 BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL);
120 regions[V_COUNT(regions)-1] = region;
121 region[V_COUNT(region)-1] = NULL;
127 for (i=0; i<V_COUNT(regions); i++) {
128 BMEdge **edges = NULL;
132 for (j=0; region[j]; j++) {
134 edges[V_COUNT(edges)-1] = region[j]->e;
137 f= BM_Make_Ngon(bm, region[0]->v, region[1]->v, edges, j, 1);
139 /*if making the new face failed (e.g. overlapping test)
140 unmark the original faces for deletion.*/
141 BMO_ClearFlag(bm, f, FACE_ORIG);
142 BMO_SetFlag(bm, f, FACE_NEW);
145 l=BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
146 for (; l; l=BMIter_Step(&liter)) {
147 /*ensure winding is identical*/
148 l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_LOOP, l);
149 for (; l2; l2=BMIter_Step(&liter2)) {
150 if (BMO_TestFlag(bm, l2->f, FACE_ORIG)) {
152 bmesh_loop_reverse(bm, l2->f);
157 /*copy over attributes*/
158 l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_LOOP, l);
159 for (; l2; l2=BMIter_Step(&liter2)) {
160 if (BMO_TestFlag(bm, l2->f, FACE_ORIG)) {
162 BM_Copy_Attributes(bm, bm, l2->f, f);
165 BM_Copy_Attributes(bm, bm, l2, l);
172 BMO_CallOpf(bm, "del geom=%ff context=%d", FACE_ORIG, DEL_FACES);
173 if (BMO_HasError(bm)) return;
175 BMO_Flag_To_Slot(bm, op, BMOP_DISFACES_REGIONOUT, FACE_NEW, BM_FACE);
179 for (i=0; i<V_COUNT(regions); i++) {
180 if (regions[i]) V_FREE(regions[i]);
186 void dissolveverts_exec(BMesh *bm, BMOperator *op)
193 vinput = BMO_GetSlot(op, BMOP_DISVERTS_VERTIN);
195 BMO_Flag_Buffer(bm, op, BMOP_DISVERTS_VERTIN, VERT_MARK);
197 for (v=BMIter_New(&iter, bm, BM_VERTS, NULL); v; v=BMIter_Step(&iter)) {
198 if (BMO_TestFlag(bm, v, VERT_MARK)) {
199 f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v);
200 for (; f; f=BMIter_Step(&fiter)) {
201 BMO_SetFlag(bm, f, FACE_MARK);
206 BMO_CallOpf(bm, "dissolvefaces faces=%ff", FACE_MARK);
207 if (BMO_HasError(bm)) {
210 BMO_GetError(bm, &msg, NULL);
212 BMO_RaiseError(bm, op, BMERR_DISSOLVEVERTS_FAILED,msg);
216 /*this code is for cleaning up two-edged faces, it shall become
217 it's own function one day.*/
219 /*clean up two-edged faces*/
220 /*basic idea is to keep joining 2-edged faces until their
221 gone. this however relies on joining two 2-edged faces
222 together to work, which doesn't.*/
226 for (f=BMIter_New(&iter, bm, BM_FACES, NULL); f; f=BMIter_Step(&iter)){
227 if (!BM_Validate_Face(bm, f, stderr)) {
232 //this design relies on join faces working
233 //with two-edged faces properly.
234 //commenting this line disables the
238 l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
240 for (; l; l=BMIter_Step(&liter)) {
241 f2 = BMIter_New(&fiter, bm,
242 BM_FACES_OF_EDGE, l->e);
243 for (; f2; f2=BMIter_Step(&fiter)) {
245 BM_Join_Faces(bm, f, f2, l->e,
258 } /*else if (f->len == 3) {
264 //check for duplicate edges
265 l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
266 for (; l; l=BMIter_Step(&liter)) {
271 if (vt[0] == vt[1] || vt[0] == vt[2]) {
277 if (oldlen == len) break;