skip assigning vars for inline bmesh flag funcs, just cast.
[blender.git] / source / blender / bmesh / operators / dissolveops.c
1 #include "MEM_guardedalloc.h"
2
3 #include "BKE_utildefines.h"
4
5 #include "bmesh.h"
6 #include "mesh_intern.h"
7 #include "bmesh_private.h"
8 #include "BLI_math.h"
9 #include "BLI_array.h"
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #define FACE_MARK       1
16 #define FACE_ORIG       2
17 #define FACE_NEW        4
18 #define EDGE_MARK       1
19
20 #define VERT_MARK       1
21
22 static int check_hole_in_region(BMesh *bm, BMFace *f) {
23         BMWalker regwalker;
24         BMIter liter2;
25         BMLoop *l2, *l3;
26         BMFace *f2;
27
28         /*checks if there are any unmarked boundary edges in the face region*/
29
30         BMW_Init(&regwalker, bm, BMW_ISLAND, FACE_MARK, 0);
31         f2 = BMW_Begin(&regwalker, f);
32         for (; f2; f2=BMW_Step(&regwalker)) {
33                 l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2);
34                 for (; l2; l2=BMIter_Step(&liter2)) {                   
35                         l3 = bmesh_radial_nextloop(l2);
36                         if (BMO_TestFlag(bm, l3->f, FACE_MARK) 
37                             != BMO_TestFlag(bm, l2->f, FACE_MARK))
38                         {
39                                 if (!BMO_TestFlag(bm, l2->e, EDGE_MARK)) {
40                                         return 0;
41                                 }
42                         }
43                 }
44         }
45         BMW_End(&regwalker);
46
47         return 1;
48 }
49
50 void dissolvefaces_exec(BMesh *bm, BMOperator *op)
51 {
52         BMOIter oiter;
53         BMFace *f, *f2 /* , *nf = NULL */;
54         BLI_array_declare(faces);
55         BLI_array_declare(regions);
56         BMFace ***regions = NULL;
57         BMFace **faces = NULL;
58         BMWalker regwalker;
59         int i;
60
61         BMO_Flag_Buffer(bm, op, "faces", FACE_MARK, BM_FACE);
62         
63         /*collect regions*/
64         BMO_ITER(f, &oiter, bm, op, "faces", BM_FACE) {
65                 if (!BMO_TestFlag(bm, f, FACE_MARK)) continue;
66
67                 BLI_array_empty(faces);
68                 faces = NULL; /*forces different allocation*/
69
70                 /*yay, walk!*/
71                 BMW_Init(&regwalker, bm, BMW_ISLAND, FACE_MARK, 0);
72                 f2 = BMW_Begin(&regwalker, f);
73                 for (; f2; f2=BMW_Step(&regwalker)) {
74                         BLI_array_append(faces, f2);
75                 }                               
76                 BMW_End(&regwalker);
77                 
78                 for (i=0; i<BLI_array_count(faces); i++) {
79                         f2 = faces[i];
80                         BMO_ClearFlag(bm, f2, FACE_MARK);
81                         BMO_SetFlag(bm, f2, FACE_ORIG);
82                 }
83
84                 if (BMO_HasError(bm)) {
85                         BMO_ClearStack(bm);
86                         BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL);
87                         goto cleanup;
88                 }
89                 
90                 BLI_array_append(faces, NULL);
91                 BLI_array_append(regions, faces);
92         }
93         
94         for (i=0; i<BLI_array_count(regions); i++) {
95                 int tot=0;
96                 
97                 faces = regions[i];
98                 if (!faces[0]) {
99                         BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, 
100                                         "Could not find boundary of dissolve region");
101                         goto cleanup;
102                 }
103                 
104                 /**/
105                 while (faces[tot])
106                         tot++;
107                 
108                 f = BM_Join_Faces(bm, faces, tot);
109                 if (!f) {
110                         BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, 
111                                         "Could not create merged face");
112                         goto cleanup;
113                 }
114
115                 /*if making the new face failed (e.g. overlapping test)
116                   unmark the original faces for deletion.*/
117                 BMO_ClearFlag(bm, f, FACE_ORIG);
118                 BMO_SetFlag(bm, f, FACE_NEW);
119
120         }
121
122         BMO_CallOpf(bm, "del geom=%ff context=%d", FACE_ORIG, DEL_FACES);
123         if (BMO_HasError(bm)) goto cleanup;
124
125         BMO_Flag_To_Slot(bm, op, "regionout", FACE_NEW, BM_FACE);
126
127 cleanup:
128         /*free/cleanup*/
129         for (i=0; i<BLI_array_count(regions); i++) {
130                 if (regions[i]) MEM_freeN(regions[i]);
131         }
132
133         BLI_array_free(regions);
134 }
135
136 /*almost identical to dissolve edge, except it cleans up vertices*/
137 void dissolve_edgeloop_exec(BMesh *bm, BMOperator *op)
138 {
139         /* BMOperator fop; */
140         BMOIter oiter;
141         BMIter iter;
142         BMVert *v, **verts = NULL;
143         BLI_array_declare(verts);
144         BMEdge *e;
145         /* BMFace *f; */
146         int i;
147
148         BMO_ITER(e, &oiter, bm, op, "edges", BM_EDGE) {
149                 if (BM_Edge_FaceCount(e) == 2) {
150                         BMO_SetFlag(bm, e->v1, VERT_MARK);
151                         BMO_SetFlag(bm, e->v2, VERT_MARK);
152
153                         BM_Join_TwoFaces(bm, e->l->f,
154                                       ((BMLoop*)e->l->radial_next)->f,
155                                       e);
156                 }
157         }
158
159         BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
160                 if (BMO_TestFlag(bm, v, VERT_MARK) && 
161                         BM_Vert_EdgeCount(v) == 2) 
162                 {
163                         BLI_array_growone(verts);
164                         verts[BLI_array_count(verts)-1] = v;
165                 }
166         }
167
168         /*clean up extreneous 2-valence vertices*/
169         for (i=0; i<BLI_array_count(verts); i++) {
170                 if (verts[i]->e)
171                         BM_Collapse_Vert(bm, verts[i]->e, verts[i], 1.0);
172         }
173         
174         BLI_array_free(verts);
175
176         //BMO_InitOpf(bm, &fop, "dissolvefaces faces=%ff", FACE_MARK);
177         //BMO_Exec_Op(bm, &fop);
178
179         //BMO_CopySlot(op, &fop, "regionout", "regionout");
180
181         //BMO_Finish_Op(bm, &fop);
182 }
183
184
185 void dissolveedges_exec(BMesh *bm, BMOperator *op)
186 {
187         /* BMOperator fop; */
188         BMOIter oiter;
189         /* BMIter iter; */
190         /* BMVert *v; */
191         BMEdge *e;
192         /* BMFace *f; */
193         /* int i; */
194
195         BMO_ITER(e, &oiter, bm, op, "edges", BM_EDGE) {
196                 if (BM_Edge_FaceCount(e) == 2) {
197                         BM_Join_TwoFaces(bm, e->l->f,
198                                       ((BMLoop*)e->l->radial_next)->f,
199                                       e);
200                 }
201         }
202 }
203
204 static int test_extra_verts(BMesh *bm, BMVert *v)
205 {
206         BMIter iter, liter, iter2, iter3;
207         BMFace *f, *f2;
208         BMLoop *l;
209         BMEdge *e;
210         int found;
211
212         /*test faces around verts for verts that would be wronly killed
213           by dissolve faces.*/
214         f = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v);
215         for (; f; f=BMIter_Step(&iter)) {
216                 l=BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
217                 for (; l; l=BMIter_Step(&liter)) {
218                         if (!BMO_TestFlag(bm, l->v, VERT_MARK)) {
219                                 /*if an edge around a vert is a boundary edge,
220                                    then dissolve faces won't destroy it.
221                                    also if it forms a boundary with one
222                                    of the face regions*/
223                                 found = 0;
224                                 e = BMIter_New(&iter2, bm, BM_EDGES_OF_VERT, l->v);
225                                 for (; e; e=BMIter_Step(&iter2)) {
226                                         if (BM_Edge_FaceCount(e)==1) found = 1;
227                                         f2 = BMIter_New(&iter3, bm, BM_FACES_OF_EDGE, e);
228                                         for (; f2; f2=BMIter_Step(&iter3)) {
229                                                 if (!BMO_TestFlag(bm, f2, FACE_MARK)) {
230                                                         found = 1;
231                                                         break;
232                                                 }
233                                         }
234                                         if (found) break;
235                                 }
236                                 if (!found) return 0;
237                         }
238                 }
239         }
240
241         return 1;
242 }
243 void dissolveverts_exec(BMesh *bm, BMOperator *op)
244 {
245         BMOpSlot *vinput;
246         BMIter iter, fiter;
247         BMVert *v;
248         BMFace *f;
249         /* int i; */
250         
251         vinput = BMO_GetSlot(op, "verts");
252         BMO_Flag_Buffer(bm, op, "verts", VERT_MARK, BM_VERT);
253         
254         for (v=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v=BMIter_Step(&iter)) {
255                 if (BMO_TestFlag(bm, v, VERT_MARK)) {
256                         /*check if it's a two-valence vert*/
257                         if (BM_Vert_EdgeCount(v) == 2) {
258
259                                 /*collapse the vert*/
260                                 BM_Collapse_Vert(bm, v->e, v, 0.5f);
261                                 continue;
262                         }
263
264                         f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v);
265                         for (; f; f=BMIter_Step(&fiter)) {
266                                 BMO_SetFlag(bm, f, FACE_ORIG);
267                                 BMO_SetFlag(bm, f, FACE_MARK);
268                         }
269                         
270                         /*check if our additions to the input to face dissolve
271                           will destroy nonmarked vertices.*/
272                         if (!test_extra_verts(bm, v)) {
273                                 f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v);
274                                 for (; f; f=BMIter_Step(&fiter)) {
275                                         if (BMO_TestFlag(bm, f, FACE_ORIG)) {
276                                                 BMO_ClearFlag(bm, f, FACE_MARK);
277                                                 BMO_ClearFlag(bm, f, FACE_ORIG);
278                                         }
279                                 }
280                         } else {
281                                 f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v);
282                                 for (; f; f=BMIter_Step(&fiter)) {
283                                         BMO_ClearFlag(bm, f, FACE_ORIG);
284                                 }
285                         }
286                 }
287         }
288
289         BMO_CallOpf(bm, "dissolvefaces faces=%ff", FACE_MARK);
290         if (BMO_HasError(bm)) {
291                         const char *msg;
292
293                         BMO_GetError(bm, &msg, NULL);
294                         BMO_ClearStack(bm);
295                         BMO_RaiseError(bm, op, BMERR_DISSOLVEVERTS_FAILED,msg);
296         }
297         
298         /*clean up any remaining*/
299         for (v=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v=BMIter_Step(&iter)) {
300                 if (BMO_TestFlag(bm, v, VERT_MARK)) {
301                         if (!BM_Dissolve_Vert(bm, v)) {
302                                 BMO_RaiseError(bm, op, 
303                                         BMERR_DISSOLVEVERTS_FAILED, NULL);
304                                 return;
305                         }
306                 }
307         }
308
309 }
310
311 /*this code is for cleaning up two-edged faces, it shall become
312   it's own function one day.*/
313 #if 0
314                 /*clean up two-edged faces*/
315                 /*basic idea is to keep joining 2-edged faces until their
316                   gone.  this however relies on joining two 2-edged faces
317                   together to work, which doesn't.*/
318                 found3 = 1;
319                 while (found3) {
320                         found3 = 0;
321                         for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); f; f=BMIter_Step(&iter)){
322                                 if (!BM_Validate_Face(bm, f, stderr)) {
323                                         printf("error.\n");
324                                 }
325
326                                 if (f->len == 2) {
327                                         //this design relies on join faces working
328                                         //with two-edged faces properly.
329                                         //commenting this line disables the
330                                         //outermost loop.
331                                         //found3 = 1;
332                                         found2 = 0;
333                                         l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
334                                         fe = l->e;
335                                         for (; l; l=BMIter_Step(&liter)) {
336                                                 f2 = BMIter_New(&fiter, bm,
337                                                                 BM_FACES_OF_EDGE, l->e);
338                                                 for (; f2; f2=BMIter_Step(&fiter)) {
339                                                         if (f2 != f) {
340                                                                 BM_Join_TwoFaces(bm, f, f2, l->e);
341                                                                 found2 = 1;
342                                                                 break;
343                                                         }
344                                                 }
345                                                 if (found2) break;
346                                         }
347
348                                         if (!found2) {
349                                                 bmesh_kf(bm, f);
350                                                 bmesh_ke(bm, fe);
351                                         }
352                                 } /*else if (f->len == 3) {
353                                         BMEdge *ed[3];
354                                         BMVert *vt[3];
355                                         BMLoop *lp[3];
356                                         int i=0;
357
358                                         //check for duplicate edges
359                                         l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
360                                         for (; l; l=BMIter_Step(&liter)) {
361                                                 ed[i] = l->e;   
362                                                 lp[i] = l;
363                                                 vt[i++] = l->v;
364                                         }
365                                         if (vt[0] == vt[1] || vt[0] == vt[2]) {
366                                                 i += 1;
367                                         }
368                                 }*/
369                         }
370                 }
371                 if (oldlen == len) break;
372                 oldlen = len;
373
374 #endif