BMesh: add ability not to delete vertex when collapsing
[blender.git] / source / blender / python / bmesh / bmesh_py_utils.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  * The Original Code is Copyright (C) 2012 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Campbell Barton
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/python/bmesh/bmesh_py_utils.c
27  *  \ingroup pybmesh
28  *
29  * This file defines the 'bmesh.utils' module.
30  * Utility functions for operating on 'bmesh.types'
31  */
32
33 #include <Python.h>
34
35 #include "BLI_utildefines.h"
36
37 #include "MEM_guardedalloc.h"
38
39 #include "../mathutils/mathutils.h"
40
41 #include "bmesh.h"
42 #include "bmesh_py_types.h"
43 #include "bmesh_py_utils.h" /* own include */
44
45
46 PyDoc_STRVAR(bpy_bm_utils_vert_collapse_edge_doc,
47 ".. method:: vert_collapse_edge(vert, edge)\n"
48 "\n"
49 "   Collapse a vertex into an edge.\n"
50 "\n"
51 "   :arg vert: The vert that will be collapsed.\n"
52 "   :type vert: :class:`bmesh.types.BMVert`\n"
53 "   :arg edge: The edge to collapse into.\n"
54 "   :type edge: :class:`bmesh.types.BMEdge`\n"
55 "   :return: The resulting edge from the collapse operation.\n"
56 "   :rtype: :class:`bmesh.types.BMEdge`\n"
57 );
58 static PyObject *bpy_bm_utils_vert_collapse_edge(PyObject *UNUSED(self), PyObject *args)
59 {
60         BPy_BMEdge *py_edge;
61         BPy_BMVert *py_vert;
62
63         BMesh *bm;
64         BMEdge *e_new = NULL;
65
66         if (!PyArg_ParseTuple(args, "O!O!:vert_collapse_edge",
67                               &BPy_BMVert_Type, &py_vert,
68                               &BPy_BMEdge_Type, &py_edge))
69         {
70                 return NULL;
71         }
72
73         BPY_BM_CHECK_OBJ(py_edge);
74         BPY_BM_CHECK_OBJ(py_vert);
75
76         /* this doubles for checking that the verts are in the same mesh */
77         if (!(py_edge->e->v1 == py_vert->v ||
78               py_edge->e->v2 == py_vert->v))
79         {
80                 PyErr_SetString(PyExc_ValueError,
81                                 "vert_collapse_edge(vert, edge): the vertex is not found in the edge");
82                 return NULL;
83         }
84
85         if (BM_vert_edge_count(py_vert->v) > 2) {
86                 PyErr_SetString(PyExc_ValueError,
87                                 "vert_collapse_edge(vert, edge): vert has more than 2 connected edges");
88                 return NULL;
89         }
90
91         bm = py_edge->bm;
92
93         e_new = BM_vert_collapse_edge(bm, py_edge->e, py_vert->v, true, true);
94
95         if (e_new) {
96                 return BPy_BMEdge_CreatePyObject(bm, e_new);
97         }
98         else {
99                 PyErr_SetString(PyExc_ValueError,
100                                 "vert_collapse_edge(vert, edge): no new edge created, internal error");
101                 return NULL;
102         }
103 }
104
105
106 PyDoc_STRVAR(bpy_bm_utils_vert_collapse_faces_doc,
107 ".. method:: vert_collapse_faces(vert, edge, fac, join_faces)\n"
108 "\n"
109 "   Collapses a vertex that has only two manifold edges onto a vertex it shares an edge with.\n"
110 "\n"
111 "   :arg vert: The vert that will be collapsed.\n"
112 "   :type vert: :class:`bmesh.types.BMVert`\n"
113 "   :arg edge: The edge to collapse into.\n"
114 "   :type edge: :class:`bmesh.types.BMEdge`\n"
115 "   :arg fac: The factor to use when merging customdata [0 - 1].\n"
116 "   :type fac: float\n"
117 "   :return: The resulting edge from the collapse operation.\n"
118 "   :rtype: :class:`bmesh.types.BMEdge`\n"
119 );
120 static PyObject *bpy_bm_utils_vert_collapse_faces(PyObject *UNUSED(self), PyObject *args)
121 {
122         BPy_BMEdge *py_edge;
123         BPy_BMVert *py_vert;
124
125         float fac;
126         int do_join_faces;
127
128         BMesh *bm;
129         BMEdge *e_new = NULL;
130
131         if (!PyArg_ParseTuple(args, "O!O!fi:vert_collapse_faces",
132                               &BPy_BMVert_Type, &py_vert,
133                               &BPy_BMEdge_Type, &py_edge,
134                               &fac, &do_join_faces))
135         {
136                 return NULL;
137         }
138
139         BPY_BM_CHECK_OBJ(py_edge);
140         BPY_BM_CHECK_OBJ(py_vert);
141
142         /* this doubles for checking that the verts are in the same mesh */
143         if (!(py_edge->e->v1 == py_vert->v ||
144               py_edge->e->v2 == py_vert->v))
145         {
146                 PyErr_SetString(PyExc_ValueError,
147                                 "vert_collapse_faces(vert, edge): the vertex is not found in the edge");
148                 return NULL;
149         }
150
151         if (BM_vert_edge_count(py_vert->v) > 2) {
152                 PyErr_SetString(PyExc_ValueError,
153                                 "vert_collapse_faces(vert, edge): vert has more than 2 connected edges");
154                 return NULL;
155         }
156
157         bm = py_edge->bm;
158
159         e_new = BM_vert_collapse_faces(bm, py_edge->e, py_vert->v, CLAMPIS(fac, 0.0f, 1.0f), true, do_join_faces, true);
160
161         if (e_new) {
162                 return BPy_BMEdge_CreatePyObject(bm, e_new);
163         }
164         else {
165                 PyErr_SetString(PyExc_ValueError,
166                                 "vert_collapse_faces(vert, edge): no new edge created, internal error");
167                 return NULL;
168         }
169 }
170
171
172 PyDoc_STRVAR(bpy_bm_utils_vert_dissolve_doc,
173 ".. method:: vert_dissolve(vert)\n"
174 "\n"
175 "   Dissolve this vertex (will be removed).\n"
176 "\n"
177 "   :arg vert: The vert to be dissolved.\n"
178 "   :type vert: :class:`bmesh.types.BMVert`\n"
179 "   :return: True when the vertex dissolve is successful.\n"
180 "   :rtype: boolean\n"
181 );
182 static PyObject *bpy_bm_utils_vert_dissolve(PyObject *UNUSED(self), PyObject *args)
183 {
184         BPy_BMVert *py_vert;
185
186         BMesh *bm;
187
188         if (!PyArg_ParseTuple(args, "O!:vert_dissolve",
189                               &BPy_BMVert_Type, &py_vert))
190         {
191                 return NULL;
192         }
193
194         BPY_BM_CHECK_OBJ(py_vert);
195
196         bm = py_vert->bm;
197
198         return PyBool_FromLong((BM_vert_dissolve(bm, py_vert->v)));
199 }
200
201 PyDoc_STRVAR(bpy_bm_utils_vert_separate_doc,
202 ".. method:: vert_separate(vert, edges)\n"
203 "\n"
204 "   Separate this vertex at every edge.\n"
205 "\n"
206 "   :arg vert: The vert to be separated.\n"
207 "   :type vert: :class:`bmesh.types.BMVert`\n"
208 "   :arg edges: The edges to separated.\n"
209 "   :type edges: :class:`bmesh.types.BMEdge`\n"
210 "   :return: The newly separated verts (including the vertex passed).\n"
211 "   :rtype: tuple of :class:`bmesh.types.BMVert`\n"
212 );
213 static PyObject *bpy_bm_utils_vert_separate(PyObject *UNUSED(self), PyObject *args)
214 {
215         BPy_BMVert *py_vert;
216         PyObject *edge_seq;
217
218         BMesh *bm;
219         BMVert **elem;
220         int elem_len;
221
222         /* edges to split */
223         BMEdge **edge_array;
224         Py_ssize_t edge_array_len;
225
226         PyObject *ret;
227
228
229         if (!PyArg_ParseTuple(args, "O!O:vert_separate",
230                               &BPy_BMVert_Type, &py_vert,
231                               &edge_seq))
232         {
233                 return NULL;
234         }
235
236         BPY_BM_CHECK_OBJ(py_vert);
237
238         bm = py_vert->bm;
239
240         edge_array = BPy_BMElem_PySeq_As_Array(&bm, edge_seq, 0, PY_SSIZE_T_MAX,
241                                                &edge_array_len, BM_EDGE,
242                                                true, true, "vert_separate(...)");
243
244         if (edge_array == NULL) {
245                 return NULL;
246         }
247
248         BM_vert_separate(bm, py_vert->v, &elem, &elem_len, edge_array, edge_array_len);
249         /* return collected verts */
250         ret = BPy_BMElem_Array_As_Tuple(bm, (BMHeader **)elem, elem_len);
251         MEM_freeN(elem);
252
253         PyMem_FREE(edge_array);
254
255         return ret;
256 }
257
258
259 PyDoc_STRVAR(bpy_bm_utils_edge_split_doc,
260 ".. method:: edge_split(edge, vert, fac)\n"
261 "\n"
262 "   Split an edge, return the newly created data.\n"
263 "\n"
264 "   :arg edge: The edge to split.\n"
265 "   :type edge: :class:`bmesh.types.BMEdge`\n"
266 "   :arg vert: One of the verts on the edge, defines the split direction.\n"
267 "   :type vert: :class:`bmesh.types.BMVert`\n"
268 "   :arg fac: The point on the edge where the new vert will be created [0 - 1].\n"
269 "   :type fac: float\n"
270 "   :return: The newly created (edge, vert) pair.\n"
271 "   :rtype: tuple\n"
272 );
273 static PyObject *bpy_bm_utils_edge_split(PyObject *UNUSED(self), PyObject *args)
274 {
275         BPy_BMEdge *py_edge;
276         BPy_BMVert *py_vert;
277         float fac;
278
279         BMesh *bm;
280         BMVert *v_new = NULL;
281         BMEdge *e_new = NULL;
282
283         if (!PyArg_ParseTuple(args, "O!O!f:edge_split",
284                               &BPy_BMEdge_Type, &py_edge,
285                               &BPy_BMVert_Type, &py_vert,
286                               &fac))
287         {
288                 return NULL;
289         }
290
291         BPY_BM_CHECK_OBJ(py_edge);
292         BPY_BM_CHECK_OBJ(py_vert);
293
294         /* this doubles for checking that the verts are in the same mesh */
295         if (!(py_edge->e->v1 == py_vert->v ||
296               py_edge->e->v2 == py_vert->v))
297         {
298                 PyErr_SetString(PyExc_ValueError,
299                                 "edge_split(edge, vert): the vertex is not found in the edge");
300                 return NULL;
301         }
302
303         bm = py_edge->bm;
304
305         v_new = BM_edge_split(bm, py_edge->e, py_vert->v, &e_new, CLAMPIS(fac, 0.0f, 1.0f));
306
307         if (v_new && e_new) {
308                 PyObject *ret = PyTuple_New(2);
309                 PyTuple_SET_ITEM(ret, 0, BPy_BMEdge_CreatePyObject(bm, e_new));
310                 PyTuple_SET_ITEM(ret, 1, BPy_BMVert_CreatePyObject(bm, v_new));
311                 return ret;
312         }
313         else {
314                 PyErr_SetString(PyExc_ValueError,
315                                 "edge_split(edge, vert): couldn't split the edge, internal error");
316                 return NULL;
317         }
318 }
319
320
321 PyDoc_STRVAR(bpy_bm_utils_edge_rotate_doc,
322 ".. method:: edge_rotate(edge, ccw=False)\n"
323 "\n"
324 "   Rotate the edge and return the newly created edge.\n"
325 "   If rotating the edge fails, None will be returned.\n"
326 "\n"
327 "   :arg edge: The edge to rotate.\n"
328 "   :type edge: :class:`bmesh.types.BMEdge`\n"
329 "   :arg ccw: When True the edge will be rotated counter clockwise.\n"
330 "   :type ccw: boolean\n"
331 "   :return: The newly rotated edge.\n"
332 "   :rtype: :class:`bmesh.types.BMEdge`\n"
333 );
334 static PyObject *bpy_bm_utils_edge_rotate(PyObject *UNUSED(self), PyObject *args)
335 {
336         BPy_BMEdge *py_edge;
337         int do_ccw = false;
338
339         BMesh *bm;
340         BMEdge *e_new = NULL;
341
342         if (!PyArg_ParseTuple(args, "O!|i:edge_rotate",
343                               &BPy_BMEdge_Type, &py_edge,
344                               &do_ccw))
345         {
346                 return NULL;
347         }
348
349         BPY_BM_CHECK_OBJ(py_edge);
350
351         bm = py_edge->bm;
352
353         e_new = BM_edge_rotate(bm, py_edge->e, do_ccw, 0);
354
355         if (e_new) {
356                 return BPy_BMEdge_CreatePyObject(bm, e_new);
357         }
358         else {
359                 Py_RETURN_NONE;
360         }
361 }
362
363
364 PyDoc_STRVAR(bpy_bm_utils_face_split_doc,
365 ".. method:: face_split(face, vert_a, vert_b, coords=(), use_exist=True, example=None)\n"
366 "\n"
367 "   Face split with optional intermediate points.\n"
368 "\n"
369 "   :arg face: The face to cut.\n"
370 "   :type face: :class:`bmesh.types.BMFace`\n"
371 "   :arg vert_a: First vertex to cut in the face (face must contain the vert).\n"
372 "   :type vert_a: :class:`bmesh.types.BMVert`\n"
373 "   :arg vert_b: Second vertex to cut in the face (face must contain the vert).\n"
374 "   :type vert_b: :class:`bmesh.types.BMVert`\n"
375 "   :arg coords: Optional argument to define points inbetween *vert_a* and *vert_b*.\n"
376 "   :type coords: sequence of float triplets\n"
377 "   :arg use_exist: .Use an existing edge if it exists (Only used when *coords* argument is empty or omitted)\n"
378 "   :type use_exist: boolean\n"
379 "   :arg example: Newly created edge will copy settings from this one.\n"
380 "   :type example: :class:`bmesh.types.BMEdge`\n"
381 "   :return: The newly created face or None on failure.\n"
382 "   :rtype: (:class:`bmesh.types.BMFace`, :class:`bmesh.types.BMLoop`) pair\n"
383 );
384 static PyObject *bpy_bm_utils_face_split(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
385 {
386         static const char *kwlist[] = {"face", "vert_a", "vert_b",
387                                        "coords", "use_exist", "example", NULL};
388
389         BPy_BMFace *py_face;
390         BPy_BMVert *py_vert_a;
391         BPy_BMVert *py_vert_b;
392
393         /* optional */
394         PyObject *py_coords = NULL;
395         int edge_exists = true;
396         BPy_BMEdge *py_edge_example = NULL;
397
398         float *coords;
399         int ncoords = 0;
400
401         BMesh *bm;
402         BMFace *f_new = NULL;
403         BMLoop *l_new = NULL;
404         BMLoop *l_a, *l_b;
405
406         if (!PyArg_ParseTupleAndKeywords(args, kw, "O!O!O!|OiO!:face_split", (char **)kwlist,
407                                          &BPy_BMFace_Type, &py_face,
408                                          &BPy_BMVert_Type, &py_vert_a,
409                                          &BPy_BMVert_Type, &py_vert_b,
410                                          &py_coords,
411                                          &edge_exists,
412                                          &BPy_BMEdge_Type, &py_edge_example))
413         {
414                 return NULL;
415         }
416
417         BPY_BM_CHECK_OBJ(py_face);
418         BPY_BM_CHECK_OBJ(py_vert_a);
419         BPY_BM_CHECK_OBJ(py_vert_b);
420
421         if (py_edge_example) {
422                 BPY_BM_CHECK_OBJ(py_edge_example);
423         }
424
425         /* this doubles for checking that the verts are in the same mesh */
426         if ((l_a = BM_face_vert_share_loop(py_face->f, py_vert_a->v)) &&
427             (l_b = BM_face_vert_share_loop(py_face->f, py_vert_b->v)))
428         {
429                 /* pass */
430         }
431         else {
432                 PyErr_SetString(PyExc_ValueError,
433                                 "face_split(...): one of the verts passed is not found in the face");
434                 return NULL;
435         }
436
437         if (py_vert_a->v == py_vert_b->v) {
438                 PyErr_SetString(PyExc_ValueError,
439                                 "face_split(...): vert arguments must differ");
440                 return NULL;
441         }
442
443         if (py_coords) {
444                 ncoords = mathutils_array_parse_alloc_v(&coords, 3, py_coords, "face_split(...): ");
445                 if (ncoords == -1) {
446                         return NULL;
447                 }
448         }
449
450         /* --- main function body --- */
451         bm = py_face->bm;
452
453         if (ncoords) {
454                 f_new = BM_face_split_n(bm, py_face->f,
455                                         l_a, l_b,
456                                         (float (*)[3])coords, ncoords,
457                                         &l_new, py_edge_example ? py_edge_example->e : NULL);
458                 PyMem_Free(coords);
459         }
460         else {
461                 f_new = BM_face_split(bm, py_face->f,
462                                       l_a, l_b,
463                                       &l_new, py_edge_example ? py_edge_example->e : NULL, edge_exists);
464         }
465
466         if (f_new && l_new) {
467                 PyObject *ret = PyTuple_New(2);
468                 PyTuple_SET_ITEM(ret, 0, BPy_BMFace_CreatePyObject(bm, f_new));
469                 PyTuple_SET_ITEM(ret, 1, BPy_BMLoop_CreatePyObject(bm, l_new));
470                 return ret;
471         }
472         else {
473                 PyErr_SetString(PyExc_ValueError,
474                                 "face_split(...): couldn't split the face, internal error");
475                 return NULL;
476         }
477 }
478
479
480 PyDoc_STRVAR(bpy_bm_utils_face_join_doc,
481 ".. method:: face_join(faces, remove=True)\n"
482 "\n"
483 "   Joins a sequence of faces.\n"
484 "\n"
485 "   :arg faces: Sequence of faces.\n"
486 "   :type faces: :class:`bmesh.types.BMFace`\n"
487 "   :arg remove: Remove the edges and vertices between the faces.\n"
488 "   :type remove: boolean\n"
489 "   :return: The newly created face or None on failure.\n"
490 "   :rtype: :class:`bmesh.types.BMFace`\n"
491 );
492 static PyObject *bpy_bm_utils_face_join(PyObject *UNUSED(self), PyObject *args)
493 {
494         BMesh *bm = NULL;
495         PyObject *py_face_array;
496         BMFace **face_array;
497         Py_ssize_t face_seq_len = 0;
498         BMFace *f_new;
499         int do_remove = true;
500
501         if (!PyArg_ParseTuple(args, "O|i:face_join", &py_face_array, &do_remove)) {
502                 return NULL;
503         }
504
505         face_array = BPy_BMElem_PySeq_As_Array(&bm, py_face_array, 2, PY_SSIZE_T_MAX,
506                                                &face_seq_len, BM_FACE,
507                                                true, true, "face_join(...)");
508
509         if (face_array == NULL) {
510                 return NULL; /* error will be set */
511         }
512
513         /* Go ahead and join the face!
514          * --------------------------- */
515         f_new = BM_faces_join(bm, face_array, (int)face_seq_len, do_remove);
516
517         PyMem_FREE(face_array);
518
519         if (f_new) {
520                 return BPy_BMFace_CreatePyObject(bm, f_new);
521         }
522         else {
523                 Py_RETURN_NONE;
524         }
525 }
526
527
528 PyDoc_STRVAR(bpy_bm_utils_face_vert_separate_doc,
529 ".. method:: face_vert_separate(face, vert)\n"
530 "\n"
531 "   Rip a vertex in a face away and add a new vertex.\n"
532 "\n"
533 "   :arg face: The face to separate.\n"
534 "   :type face: :class:`bmesh.types.BMFace`\n"
535 "   :arg vert: A vertex in the face to separate.\n"
536 "   :type vert: :class:`bmesh.types.BMVert`\n"
537 "   :return vert: The newly created vertex or None of failure.\n"
538 "   :rtype vert: :class:`bmesh.types.BMVert`\n"
539 "\n"
540 "   .. note::\n"
541 "\n"
542 "      This is the same as loop_separate, and has only been added for convenience.\n"
543 );
544 static PyObject *bpy_bm_utils_face_vert_separate(PyObject *UNUSED(self), PyObject *args)
545 {
546         BPy_BMFace *py_face;
547         BPy_BMVert *py_vert;
548
549         BMesh *bm;
550         BMLoop *l;
551         BMVert *v_new;
552
553         if (!PyArg_ParseTuple(args, "O!O!:face_vert_separate",
554                               &BPy_BMFace_Type, &py_face,
555                               &BPy_BMVert_Type, &py_vert))
556         {
557                 return NULL;
558         }
559
560         bm = py_face->bm;
561
562         BPY_BM_CHECK_OBJ(py_face);
563         BPY_BM_CHECK_SOURCE_OBJ(py_vert, bm, "face_vert_separate()");
564
565         l = BM_face_vert_share_loop(py_face->f, py_vert->v);
566
567         if (l == NULL) {
568                 PyErr_SetString(PyExc_ValueError,
569                                 "vertex not found in face");
570                 return NULL;
571         }
572
573         v_new = BM_face_loop_separate(bm, l);
574
575         if (v_new != l->v) {
576                 return BPy_BMVert_CreatePyObject(bm, v_new);
577         }
578         else {
579                 Py_RETURN_NONE;
580         }
581 }
582
583
584 PyDoc_STRVAR(bpy_bm_utils_face_flip_doc,
585 ".. method:: face_flip(faces)\n"
586 "\n"
587 "   Flip the faces direction.\n"
588 "\n"
589 "   :arg face: Face to flip.\n"
590 "   :type face: :class:`bmesh.types.BMFace`\n"
591 );
592 static PyObject *bpy_bm_utils_face_flip(PyObject *UNUSED(self), BPy_BMFace *value)
593 {
594         if (!BPy_BMFace_Check(value)) {
595                 PyErr_Format(PyExc_TypeError,
596                              "face_flip(face): BMFace expected, not '%.200s'",
597                              Py_TYPE(value)->tp_name);
598                 return NULL;
599         }
600
601         BPY_BM_CHECK_OBJ(value);
602
603         BM_face_normal_flip(value->bm, value->f);
604
605         Py_RETURN_NONE;
606 }
607
608
609
610 PyDoc_STRVAR(bpy_bm_utils_loop_separate_doc,
611 ".. method:: loop_separate(loop)\n"
612 "\n"
613 "   Rip a vertex in a face away and add a new vertex.\n"
614 "\n"
615 "   :arg loop: The to separate.\n"
616 "   :type loop: :class:`bmesh.types.BMFace`\n"
617 "   :return vert: The newly created vertex or None of failure.\n"
618 "   :rtype vert: :class:`bmesh.types.BMVert`\n"
619 );
620 static PyObject *bpy_bm_utils_loop_separate(PyObject *UNUSED(self), BPy_BMLoop *value)
621 {
622         BMesh *bm;
623         BMVert *v_new;
624
625         if (!BPy_BMLoop_Check(value)) {
626                 PyErr_Format(PyExc_TypeError,
627                              "loop_separate(loop): BMLoop expected, not '%.200s'",
628                              Py_TYPE(value)->tp_name);
629                 return NULL;
630         }
631
632         BPY_BM_CHECK_OBJ(value);
633
634         bm = value->bm;
635
636         v_new = BM_face_loop_separate(bm, value->l);
637
638         if (v_new != value->l->v) {
639                 return BPy_BMVert_CreatePyObject(bm, v_new);
640         }
641         else {
642                 Py_RETURN_NONE;
643         }
644 }
645
646
647 static struct PyMethodDef BPy_BM_utils_methods[] = {
648         {"vert_collapse_edge",  (PyCFunction)bpy_bm_utils_vert_collapse_edge,  METH_VARARGS, bpy_bm_utils_vert_collapse_edge_doc},
649         {"vert_collapse_faces", (PyCFunction)bpy_bm_utils_vert_collapse_faces, METH_VARARGS, bpy_bm_utils_vert_collapse_faces_doc},
650         {"vert_dissolve",       (PyCFunction)bpy_bm_utils_vert_dissolve,       METH_VARARGS, bpy_bm_utils_vert_dissolve_doc}, /* could use METH_O */
651         {"vert_separate",       (PyCFunction)bpy_bm_utils_vert_separate,       METH_VARARGS, bpy_bm_utils_vert_separate_doc},
652         {"edge_split",          (PyCFunction)bpy_bm_utils_edge_split,          METH_VARARGS, bpy_bm_utils_edge_split_doc},
653         {"edge_rotate",         (PyCFunction)bpy_bm_utils_edge_rotate,         METH_VARARGS, bpy_bm_utils_edge_rotate_doc},
654         {"face_split",          (PyCFunction)bpy_bm_utils_face_split,          METH_VARARGS | METH_KEYWORDS, bpy_bm_utils_face_split_doc},
655         {"face_join",           (PyCFunction)bpy_bm_utils_face_join,           METH_VARARGS, bpy_bm_utils_face_join_doc},
656         {"face_vert_separate",  (PyCFunction)bpy_bm_utils_face_vert_separate,  METH_VARARGS, bpy_bm_utils_face_vert_separate_doc},
657         {"face_flip",           (PyCFunction)bpy_bm_utils_face_flip,           METH_O,       bpy_bm_utils_face_flip_doc},
658         {"loop_separate",       (PyCFunction)bpy_bm_utils_loop_separate,       METH_O,       bpy_bm_utils_loop_separate_doc},
659         {NULL, NULL, 0, NULL}
660 };
661
662
663 PyDoc_STRVAR(BPy_BM_utils_doc,
664 "This module provides access to blenders bmesh data structures."
665 );
666 static struct PyModuleDef BPy_BM_utils_module_def = {
667         PyModuleDef_HEAD_INIT,
668         "bmesh.utils",  /* m_name */
669         BPy_BM_utils_doc,  /* m_doc */
670         0,  /* m_size */
671         BPy_BM_utils_methods,  /* m_methods */
672         NULL,  /* m_reload */
673         NULL,  /* m_traverse */
674         NULL,  /* m_clear */
675         NULL,  /* m_free */
676 };
677
678
679 PyObject *BPyInit_bmesh_utils(void)
680 {
681         PyObject *submodule;
682
683         submodule = PyModule_Create(&BPy_BM_utils_module_def);
684
685         return submodule;
686 }