bmesh api name change, add _count suffix for BM_*_share functions.
[blender.git] / source / blender / bmesh / intern / bmesh_mods.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/bmesh/intern/bmesh_mods.c
24  *  \ingroup bmesh
25  *
26  * This file contains functions for locally modifying
27  * the topology of existing mesh data. (split, join, flip etc).
28  */
29
30 #include "MEM_guardedalloc.h"
31
32
33 #include "BLI_math.h"
34 #include "BLI_array.h"
35 #include "BLI_smallhash.h"
36
37 #include "BKE_customdata.h"
38
39 #include "bmesh.h"
40 #include "bmesh_private.h"
41
42 /**
43  *                      bmesh_dissolve_disk
44  *
45  *  Turns the face region surrounding a manifold vertex into
46  *  A single polygon.
47  *
48  *
49  * Example:
50  *
51  *          |=========|             |=========|
52  *          |  \   /  |             |         |
53  * Before:  |    V    |      After: |         |
54  *          |  /   \  |             |         |
55  *          |=========|             |=========|
56  *
57  *
58  */
59 #if 1
60 int BM_vert_dissolve(BMesh *bm, BMVert *v)
61 {
62         const int len = BM_vert_edge_count(v);
63         
64         if (len == 1) {
65                 BM_vert_kill(bm, v); /* will kill edges too */
66                 return TRUE;
67         }
68         else if (!BM_vert_is_manifold(bm, v)) {
69                 if (!v->e) {
70                         BM_vert_kill(bm, v);
71                         return TRUE;
72                 }
73                 else if (!v->e->l) {
74                         if (len == 2) {
75                                 return (BM_vert_collapse_edge(bm, v->e, v, TRUE) != NULL);
76                         }
77                         else {
78                                 /* used to kill the vertex here, but it may be connected to faces.
79                                  * so better do nothing */
80                                 return FALSE;
81                         }
82                 }
83                 else {
84                         return FALSE;
85                 }
86         }
87         else if (len == 2 && BM_vert_face_count(v) == 1) {
88                 /* boundry vertex on a face */
89                 return (BM_vert_collapse_edge(bm, v->e, v, TRUE) != NULL);
90         }
91         else {
92                 return BM_disk_dissolve(bm, v);
93         }
94 }
95
96 int BM_disk_dissolve(BMesh *bm, BMVert *v)
97 {
98         BMFace *f, *f2;
99         BMEdge *e, *keepedge = NULL, *baseedge = NULL;
100         int len = 0;
101
102         if (!BM_vert_is_manifold(bm, v)) {
103                 return FALSE;
104         }
105         
106         if (v->e) {
107                 /* v->e we keep, what else */
108                 e = v->e;
109                 do {
110                         e = bmesh_disk_nextedge(e, v);
111                         if (!(BM_edge_share_face_count(e, v->e))) {
112                                 keepedge = e;
113                                 baseedge = v->e;
114                                 break;
115                         }
116                         len++;
117                 } while (e != v->e);
118         }
119         
120         /* this code for handling 2 and 3-valence verts
121          * may be totally bad */
122         if (keepedge == NULL && len == 3) {
123                 /* handle specific case for three-valence.  solve it by
124                  * increasing valence to four.  this may be hackish. .  */
125                 BMLoop *loop = e->l;
126                 if (loop->v == v) loop = loop->next;
127                 if (!BM_face_split(bm, loop->f, v, loop->v, NULL, NULL))
128                         return FALSE;
129
130                 if (!BM_disk_dissolve(bm, v)) {
131                         return FALSE;
132                 }
133                 return TRUE;
134         }
135         else if (keepedge == NULL && len == 2) {
136                 /* collapse the verte */
137                 e = BM_vert_collapse_faces(bm, v->e, v, 1.0, TRUE, TRUE);
138
139                 if (!e) {
140                         return FALSE;
141                 }
142
143                 /* handle two-valenc */
144                 f = e->l->f;
145                 f2 = e->l->radial_next->f;
146
147                 if (f != f2 && !BM_faces_join_pair(bm, f, f2, e)) {
148                         return FALSE;
149                 }
150
151                 return TRUE;
152         }
153
154         if (keepedge) {
155                 int done = 0;
156
157                 while (!done) {
158                         done = 1;
159                         e = v->e;
160                         do {
161                                 f = NULL;
162                                 len = bmesh_radial_length(e->l);
163                                 if (len == 2 && (e != baseedge) && (e != keepedge)) {
164                                         f = BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e);
165                                         /* return if couldn't join faces in manifold
166                                          * conditions */
167                                         //!disabled for testing why bad things happen
168                                         if (!f) {
169                                                 return FALSE;
170                                         }
171                                 }
172
173                                 if (f) {
174                                         done = 0;
175                                         break;
176                                 }
177                                 e = bmesh_disk_nextedge(e, v);
178                         } while (e != v->e);
179                 }
180
181                 /* collapse the verte */
182                 e = BM_vert_collapse_faces(bm, baseedge, v, 1.0, TRUE, TRUE);
183
184                 if (!e) {
185                         return FALSE;
186                 }
187                 
188                 /* get remaining two face */
189                 f = e->l->f;
190                 f2 = e->l->radial_next->f;
191
192                 if (f != f2) {
193                         /* join two remaining face */
194                         if (!BM_faces_join_pair(bm, f, f2, e)) {
195                                 return FALSE;
196                         }
197                 }
198         }
199
200         return TRUE;
201 }
202 #else
203 void BM_disk_dissolve(BMesh *bm, BMVert *v)
204 {
205         BMFace *f;
206         BMEdge *e;
207         BMIter iter;
208         int done, len;
209         
210         if (v->e) {
211                 done = 0;
212                 while (!done) {
213                         done = 1;
214                         
215                         /* loop the edges looking for an edge to dissolv */
216                         for (e = BM_iter_new(&iter, bm, BM_EDGES_OF_VERT, v); e;
217                              e = BM_iter_step(&iter)) {
218                                 f = NULL;
219                                 len = bmesh_cycle_length(&(e->l->radial));
220                                 if (len == 2) {
221                                         f = BM_faces_join_pair(bm, e->l->f, ((BMLoop *)(e->l->radial_next))->f, e);
222                                 }
223                                 if (f) {
224                                         done = 0;
225                                         break;
226                                 }
227                         };
228                 }
229                 BM_vert_collapse_faces(bm, v->e, v, 1.0, TRUE);
230         }
231 }
232 #endif
233
234 /**
235  * BM_faces_join_pair
236  *
237  *  Joins two adjacenct faces togather.
238  *
239  *  Because this method calls to BM_faces_join to do its work, ff a pair
240  *  of faces share multiple edges, the pair of faces will be joined at
241  *  every edge (not just edge e). This part of the functionality might need
242  *  to be reconsidered.
243  *
244  *  If the windings do not match the winding of the new face will follow
245  *  f1's winding (i.e. f2 will be reversed before the join).
246  *
247  * Returns:
248  *       pointer to the combined face
249  */
250
251 BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
252 {
253         BMLoop *l1, *l2;
254         BMEdge *jed = NULL;
255         BMFace *faces[2] = {f1, f2};
256         
257         jed = e;
258         if (!jed) {
259                 BMLoop *l_first;
260                 /* search for an edge that has both these faces in its radial cycl */
261                 l1 = l_first = BM_FACE_FIRST_LOOP(f1);
262                 do {
263                         if (l1->radial_next->f == f2) {
264                                 jed = l1->e;
265                                 break;
266                         }
267                 } while ((l1 = l1->next) != l_first);
268         }
269
270         if (UNLIKELY(!jed)) {
271                 BMESH_ASSERT(0);
272                 return NULL;
273         }
274         
275         l1 = jed->l;
276         
277         if (UNLIKELY(!l1)) {
278                 BMESH_ASSERT(0);
279                 return NULL;
280         }
281         
282         l2 = l1->radial_next;
283         if (l1->v == l2->v) {
284                 bmesh_loop_reverse(bm, f2);
285         }
286
287         f1 = BM_faces_join(bm, faces, 2);
288         
289         return f1;
290 }
291
292 /* connects two verts together, automatically (if very naively) finding the
293  * face they both share (if there is one) and splittling it.  use this at your
294  * own risk, as it doesn't handle the many complex cases it should (like zero-area faces,
295  * multiple faces, etc).
296  *
297  * this is really only meant for cases where you don't know before hand the face
298  * the two verts belong to for splitting (e.g. the subdivision operator).
299  */
300
301 BMEdge *BM_verts_connect(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf)
302 {
303         BMIter iter, iter2;
304         BMVert *v;
305         BMLoop *nl;
306         BMFace *face;
307
308         /* be warned: this can do weird things in some ngon situation, see BM_face_legal_splits */
309         for (face = BM_iter_new(&iter, bm, BM_FACES_OF_VERT, v1); face; face = BM_iter_step(&iter)) {
310                 for (v = BM_iter_new(&iter2, bm, BM_VERTS_OF_FACE, face); v; v = BM_iter_step(&iter2)) {
311                         if (v == v2) {
312                                 face = BM_face_split(bm, face, v1, v2, &nl, NULL);
313
314                                 if (nf) *nf = face;
315                                 return nl->e;
316                         }
317                 }
318         }
319
320         return NULL;
321 }
322
323 /**
324  * BM_face_split
325  *
326  *  Splits a single face into two.
327  *
328  *   f - the original face
329  *   v1 & v2 - vertices which define the split edge, must be different
330  *   nl - pointer which will receive the BMLoop for the split edge in the new face
331  *
332  *  Notes: the
333
334  *  Returns -
335  *        Pointer to the newly created face representing one side of the split
336  *   if the split is successful (and the original original face will be the
337  *   other side). NULL if the split fails.
338  *
339  */
340
341 BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **nl, BMEdge *example)
342 {
343         const int has_mdisp = CustomData_has_layer(&bm->ldata, CD_MDISPS);
344         BMFace *nf, *of;
345
346         BLI_assert(v1 != v2);
347
348         /* do we have a multires layer */
349         if (has_mdisp) {
350                 of = BM_face_copy(bm, f, FALSE, FALSE);
351         }
352         
353 #ifdef USE_BMESH_HOLES
354         nf = bmesh_sfme(bm, f, v1, v2, nl, NULL, example);
355 #else
356         nf = bmesh_sfme(bm, f, v1, v2, nl, example);
357 #endif
358         
359         if (nf) {
360                 BM_elem_attrs_copy(bm, bm, f, nf);
361                 copy_v3_v3(nf->no, f->no);
362
363                 /* handle multires update */
364                 if (has_mdisp && (nf != f)) {
365                         BMLoop *l_iter;
366                         BMLoop *l_first;
367
368                         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
369                         do {
370                                 BM_loop_interp_from_face(bm, l_iter, of, FALSE, TRUE);
371                         } while ((l_iter = l_iter->next) != l_first);
372
373                         l_iter = l_first = BM_FACE_FIRST_LOOP(nf);
374                         do {
375                                 BM_loop_interp_from_face(bm, l_iter, of, FALSE, TRUE);
376                         } while ((l_iter = l_iter->next) != l_first);
377
378                         BM_face_kill(bm, of);
379
380 #if 0
381                         /* BM_face_multires_bounds_smooth doesn't flip displacement correct */
382                         BM_face_multires_bounds_smooth(bm, f);
383                         BM_face_multires_bounds_smooth(bm, nf);
384 #endif
385                 }
386         }
387
388         return nf;
389 }
390
391 /**
392  *                      BM_vert_collapse_faces
393  *
394  *  Collapses a vertex that has only two manifold edges
395  *  onto a vertex it shares an edge with. Fac defines
396  *  the amount of interpolation for Custom Data.
397  *
398  *  Note that this is not a general edge collapse function.
399  *
400  * Note this function is very close to 'BM_vert_collapse_edge', both collapse
401  * a vertex and return a new edge. Except this takes a factor and merges
402  * custom data.
403  *
404  *  BMESH_TODO:
405  *    Insert error checking for KV valance.
406  *
407  * @param fac The factor along the edge
408  * @param join_faces When true the faces around the vertex will be joined
409  * otherwise collapse the vertex by merging the 2 edges this vert touches into one.
410  *  @returns The New Edge
411  */
412
413 BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *ke, BMVert *kv, float fac,
414                                const short join_faces, const short kill_degenerate_faces)
415 {
416         BMEdge *ne = NULL;
417         BMVert *tv = bmesh_edge_getothervert(ke, kv);
418
419         BMEdge *e2;
420         BMVert *tv2;
421
422         BMIter iter;
423         BMLoop *l_iter = NULL, *kvloop = NULL, *tvloop = NULL;
424
425         void *src[2];
426         float w[2];
427
428         /* Only intended to be called for 2-valence vertices */
429         BLI_assert(bmesh_disk_count(kv) <= 2);
430
431
432         /* first modify the face loop data  */
433         w[0] = 1.0f - fac;
434         w[1] = fac;
435
436         if (ke->l) {
437                 l_iter = ke->l;
438                 do {
439                         if (l_iter->v == tv && l_iter->next->v == kv) {
440                                 tvloop = l_iter;
441                                 kvloop = l_iter->next;
442
443                                 src[0] = kvloop->head.data;
444                                 src[1] = tvloop->head.data;
445                                 CustomData_bmesh_interp(&bm->ldata, src, w, NULL, 2, kvloop->head.data);
446                         }
447                 } while ((l_iter = l_iter->radial_next) != ke->l);
448         }
449
450         /* now interpolate the vertex data */
451         BM_data_interp_from_verts(bm, kv, tv, kv, fac);
452
453         e2 = bmesh_disk_nextedge(ke, kv);
454         tv2 = BM_edge_other_vert(e2, kv);
455
456         if (join_faces) {
457                 BMFace **faces = NULL, *f;
458                 BLI_array_staticdeclare(faces, 8);
459
460                 BM_ITER(f, &iter, bm, BM_FACES_OF_VERT, kv) {
461                         BLI_array_append(faces, f);
462                 }
463
464                 if (BLI_array_count(faces) >= 2) {
465                         BMFace *f2 = BM_faces_join(bm, faces, BLI_array_count(faces));
466                         if (f2) {
467                                 BMLoop *nl = NULL;
468                                 if (BM_face_split(bm, f2, tv, tv2, &nl, NULL)) {
469                                         ne = nl->e;
470                                 }
471                         }
472                 }
473
474                 BLI_array_free(faces);
475         }
476         else {
477                 /* single face or no faces */
478                 /* same as BM_vert_collapse_edge() however we already
479                  * have vars to perform this operation so dont call. */
480                 ne = bmesh_jekv(bm, ke, kv, TRUE);
481                 /* ne = BM_edge_exists(tv, tv2); */ /* same as return above */
482
483                 if (kill_degenerate_faces) {
484                         BMIter fiter;
485                         BMFace *f;
486                         BMVert *verts[2] = {ne->v1, ne->v2};
487                         int i;
488                         for (i = 0; i < 2; i++) {
489                                 BM_ITER(f, &fiter, bm, BM_FACES_OF_VERT, verts[i]) {
490                                         if (f->len < 3) {
491                                                 BM_face_kill(bm, f);
492                                         }
493                                 }
494                         }
495                 }
496         }
497
498         return ne;
499 }
500
501
502 /**
503  *                      BM_vert_collapse_edge
504  *
505  * Collapses a vertex onto another vertex it shares an edge with.
506  *
507  * Returns -
508  * The New Edge
509  */
510
511 BMEdge *BM_vert_collapse_edge(BMesh *bm, BMEdge *ke, BMVert *kv,
512                               const short kill_degenerate_faces)
513 {
514         /* nice example implementation but we want loops to have their customdata
515          * accounted for */
516 #if 0
517         BMEdge *ne = NULL;
518
519         /* Collapse between 2 edges */
520
521         /* in this case we want to keep all faces and not join them,
522          * rather just get rid of the veretex - see bug [#28645] */
523         BMVert *tv  = bmesh_edge_getothervert(ke, kv);
524         if (tv) {
525                 BMEdge *e2 = bmesh_disk_nextedge(ke, kv);
526                 if (e2) {
527                         BMVert *tv2 = BM_edge_other_vert(e2, kv);
528                         if (tv2) {
529                                 /* only action, other calls here only get the edge to return */
530                                 ne = bmesh_jekv(bm, ke, kv);
531
532                                 /* ne = BM_edge_exists(tv, tv2); */ /* same as return above */
533                         }
534                 }
535         }
536
537         return ne;
538 #else
539         /* with these args faces are never joined, same as above
540          * but account for loop customdata */
541         return BM_vert_collapse_faces(bm, ke, kv, 1.0f, FALSE, kill_degenerate_faces);
542 #endif
543 }
544
545 #undef DO_V_INTERP
546
547 /**
548  *                      BM_split_edge
549  *
550  *      Splits an edge. v should be one of the vertices in e and
551  *  defines the direction of the splitting operation for interpolation
552  *  purposes.
553  *
554  *  Returns -
555  *      the new vert
556  */
557
558 BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **ne, float percent)
559 {
560         BMVert *nv, *v2;
561         BMFace **oldfaces = NULL;
562         BMEdge *dummy;
563         BLI_array_staticdeclare(oldfaces, 32);
564         SmallHash hash;
565
566         /* we need this for handling multire */
567         if (!ne)
568                 ne = &dummy;
569
570         /* do we have a multires layer */
571         if (CustomData_has_layer(&bm->ldata, CD_MDISPS) && e->l) {
572                 BMLoop *l;
573                 int i;
574                 
575                 l = e->l;
576                 do {
577                         BLI_array_append(oldfaces, l->f);
578                         l = l->radial_next;
579                 } while (l != e->l);
580                 
581                 /* create a hash so we can differentiate oldfaces from new face */
582                 BLI_smallhash_init(&hash);
583                 
584                 for (i = 0; i < BLI_array_count(oldfaces); i++) {
585                         oldfaces[i] = BM_face_copy(bm, oldfaces[i], TRUE, TRUE);
586                         BLI_smallhash_insert(&hash, (intptr_t)oldfaces[i], NULL);
587                 }
588         }
589
590         v2 = bmesh_edge_getothervert(e, v);
591         nv = bmesh_semv(bm, v, e, ne);
592         if (nv == NULL) {
593                 return NULL;
594         }
595
596         sub_v3_v3v3(nv->co, v2->co, v->co);
597         madd_v3_v3v3fl(nv->co, v->co, nv->co, percent);
598
599         if (ne) {
600                 (*ne)->head.hflag = e->head.hflag;
601                 BM_elem_attrs_copy(bm, bm, e, *ne);
602         }
603
604         /* v->nv->v2 */
605         BM_data_interp_face_vert_edge(bm, v2, v, nv, e, percent);
606         BM_data_interp_from_verts(bm, v, v2, nv, percent);
607
608         if (CustomData_has_layer(&bm->ldata, CD_MDISPS) && e->l && nv) {
609                 int i, j;
610
611                 /* interpolate new/changed loop data from copied old face */
612                 for (j = 0; j < 2; j++) {
613                         for (i = 0; i < BLI_array_count(oldfaces); i++) {
614                                 BMEdge *e1 = j ? *ne : e;
615                                 BMLoop *l, *l2;
616                                 
617                                 l = e1->l;
618
619                                 if (UNLIKELY(!l)) {
620                                         BMESH_ASSERT(0);
621                                         break;
622                                 }
623                                 
624                                 do {
625                                         if (!BLI_smallhash_haskey(&hash, (intptr_t)l->f)) {
626                                                 BMLoop *l2_first;
627
628                                                 l2 = l2_first = BM_FACE_FIRST_LOOP(l->f);
629                                                 do {
630                                                         BM_loop_interp_multires(bm, l2, oldfaces[i]);
631                                                 } while ((l2 = l2->next) != l2_first);
632                                         }
633                                         l = l->radial_next;
634                                 } while (l != e1->l);
635                         }
636                 }
637                 
638                 /* destroy the old face */
639                 for (i = 0; i < BLI_array_count(oldfaces); i++) {
640                         BM_face_verts_kill(bm, oldfaces[i]);
641                 }
642                 
643                 /* fix boundaries a bit, doesn't work too well quite ye */
644 #if 0
645                 for (j = 0; j < 2; j++) {
646                         BMEdge *e1 = j ? *ne : e;
647                         BMLoop *l, *l2;
648                         
649                         l = e1->l;
650                         if (UNLIKELY(!l)) {
651                                 BMESH_ASSERT(0);
652                                 break;
653                         }
654                         
655                         do {
656                                 BM_face_multires_bounds_smooth(bm, l->f);
657                                 l = l->radial_next;
658                         } while (l != e1->l);
659                 }
660 #endif
661                 
662                 BLI_array_free(oldfaces);
663                 BLI_smallhash_release(&hash);
664         }
665         
666         return nv;
667 }
668
669 BMVert  *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts)
670 {
671         int i;
672         float percent;
673         BMVert *nv = NULL;
674         
675         for (i = 0; i < numcuts; i++) {
676                 percent = 1.0f / (float)(numcuts + 1 - i);
677                 nv = BM_edge_split(bm, e, e->v2, NULL, percent);
678         }
679         return nv;
680 }
681
682 int BM_face_validate(BMesh *bm, BMFace *face, FILE *err)
683 {
684         BMIter iter;
685         BLI_array_declare(verts);
686         BMVert **verts = NULL;
687         BMLoop *l;
688         int ret = 1, i, j;
689         
690         if (face->len == 2) {
691                 fprintf(err, "warning: found two-edged face. face ptr: %p\n", face);
692                 fflush(err);
693         }
694
695         for (l = BM_iter_new(&iter, bm, BM_LOOPS_OF_FACE, face); l; l = BM_iter_step(&iter)) {
696                 BLI_array_growone(verts);
697                 verts[BLI_array_count(verts) - 1] = l->v;
698                 
699                 if (l->e->v1 == l->e->v2) {
700                         fprintf(err, "Found bmesh edge with identical verts!\n");
701                         fprintf(err, "  edge ptr: %p, vert: %p\n",  l->e, l->e->v1);
702                         fflush(err);
703                         ret = 0;
704                 }
705         }
706
707         for (i = 0; i < BLI_array_count(verts); i++) {
708                 for (j = 0; j < BLI_array_count(verts); j++) {
709                         if (j == i) {
710                                 continue;
711                         }
712
713                         if (verts[i] == verts[j]) {
714                                 fprintf(err, "Found duplicate verts in bmesh face!\n");
715                                 fprintf(err, "  face ptr: %p, vert: %p\n", face, verts[i]);
716                                 fflush(err);
717                                 ret = 0;
718                         }
719                 }
720         }
721         
722         BLI_array_free(verts);
723         return ret;
724 }
725
726 /*
727  *         BM Rotate Edge
728  *
729  * Spins an edge topologically, either counter-clockwise or clockwise.
730  * If ccw is true, the edge is spun counter-clockwise, otherwise it is
731  * spun clockwise.
732  *
733  * Returns the spun edge.  Note that this works by dissolving the edge
734  * then re-creating it, so the returned edge won't have the same pointer
735  * address as the original one.
736  *
737  * Returns NULL on error (e.g., if the edge isn't surrounded by exactly
738  * two faces).
739  */
740 BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, int ccw)
741 {
742         BMVert *v1, *v2;
743         BMLoop *l, *l1, *l2, *nl;
744         BMFace *f;
745         BMIter liter;
746
747         v1 = e->v1;
748         v2 = e->v2;
749
750         if (BM_edge_face_count(e) != 2)
751                 return NULL;
752
753         /* If either of e's vertices has valence 2, then
754          * dissolving the edge would leave a spur, so not allowed */
755         if (BM_vert_edge_count(e->v1) == 2 || BM_vert_edge_count(e->v2) == 2)
756                 return NULL;
757
758         f = BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e);
759
760         if (f == NULL)
761                 return NULL;
762
763         BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
764                 if (l->v == v1)
765                         l1 = l;
766                 else if (l->v == v2)
767                         l2 = l;
768         }
769         
770         if (ccw) {
771                 l1 = l1->prev;
772                 l2 = l2->prev;
773         }
774         else {
775                 l1 = l1->next;
776                 l2 = l2->next;
777         }
778
779         if (!BM_face_split(bm, f, l1->v, l2->v, &nl, NULL))
780                 return NULL;
781
782         return nl->e;
783 }
784
785 BMVert *BM_vert_rip ( BMesh *bm, BMFace *sf, BMVert *sv)
786 {
787         return bmesh_urmv(bm, sf, sv);
788 }