Merge branch 'master' into blender2.8
[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 #include "BLI_math_base.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "../mathutils/mathutils.h"
41
42 #include "bmesh.h"
43 #include "bmesh_py_types.h"
44 #include "bmesh_py_utils.h" /* own include */
45
46 #include "../generic/py_capi_utils.h"
47 #include "../generic/python_utildefines.h"
48
49
50 PyDoc_STRVAR(bpy_bm_utils_vert_collapse_edge_doc,
51 ".. method:: vert_collapse_edge(vert, edge)\n"
52 "\n"
53 "   Collapse a vertex into an edge.\n"
54 "\n"
55 "   :arg vert: The vert that will be collapsed.\n"
56 "   :type vert: :class:`bmesh.types.BMVert`\n"
57 "   :arg edge: The edge to collapse into.\n"
58 "   :type edge: :class:`bmesh.types.BMEdge`\n"
59 "   :return: The resulting edge from the collapse operation.\n"
60 "   :rtype: :class:`bmesh.types.BMEdge`\n"
61 );
62 static PyObject *bpy_bm_utils_vert_collapse_edge(PyObject *UNUSED(self), PyObject *args)
63 {
64         BPy_BMEdge *py_edge;
65         BPy_BMVert *py_vert;
66
67         BMesh *bm;
68         BMEdge *e_new = NULL;
69
70         if (!PyArg_ParseTuple(args, "O!O!:vert_collapse_edge",
71                               &BPy_BMVert_Type, &py_vert,
72                               &BPy_BMEdge_Type, &py_edge))
73         {
74                 return NULL;
75         }
76
77         BPY_BM_CHECK_OBJ(py_edge);
78         BPY_BM_CHECK_OBJ(py_vert);
79
80         /* this doubles for checking that the verts are in the same mesh */
81         if (!(py_edge->e->v1 == py_vert->v ||
82               py_edge->e->v2 == py_vert->v))
83         {
84                 PyErr_SetString(PyExc_ValueError,
85                                 "vert_collapse_edge(vert, edge): the vertex is not found in the edge");
86                 return NULL;
87         }
88
89         if (BM_vert_edge_count_is_over(py_vert->v, 2)) {
90                 PyErr_SetString(PyExc_ValueError,
91                                 "vert_collapse_edge(vert, edge): vert has more than 2 connected edges");
92                 return NULL;
93         }
94
95         bm = py_edge->bm;
96
97         e_new = BM_vert_collapse_edge(bm, py_edge->e, py_vert->v, true, true);
98
99         if (e_new) {
100                 return BPy_BMEdge_CreatePyObject(bm, e_new);
101         }
102         else {
103                 PyErr_SetString(PyExc_ValueError,
104                                 "vert_collapse_edge(vert, edge): no new edge created, internal error");
105                 return NULL;
106         }
107 }
108
109
110 PyDoc_STRVAR(bpy_bm_utils_vert_collapse_faces_doc,
111 ".. method:: vert_collapse_faces(vert, edge, fac, join_faces)\n"
112 "\n"
113 "   Collapses a vertex that has only two manifold edges onto a vertex it shares an edge with.\n"
114 "\n"
115 "   :arg vert: The vert that will be collapsed.\n"
116 "   :type vert: :class:`bmesh.types.BMVert`\n"
117 "   :arg edge: The edge to collapse into.\n"
118 "   :type edge: :class:`bmesh.types.BMEdge`\n"
119 "   :arg fac: The factor to use when merging customdata [0 - 1].\n"
120 "   :type fac: float\n"
121 "   :return: The resulting edge from the collapse operation.\n"
122 "   :rtype: :class:`bmesh.types.BMEdge`\n"
123 );
124 static PyObject *bpy_bm_utils_vert_collapse_faces(PyObject *UNUSED(self), PyObject *args)
125 {
126         BPy_BMEdge *py_edge;
127         BPy_BMVert *py_vert;
128
129         float fac;
130         int do_join_faces;
131
132         BMesh *bm;
133         BMEdge *e_new = NULL;
134
135         if (!PyArg_ParseTuple(args, "O!O!fi:vert_collapse_faces",
136                               &BPy_BMVert_Type, &py_vert,
137                               &BPy_BMEdge_Type, &py_edge,
138                               &fac, &do_join_faces))
139         {
140                 return NULL;
141         }
142
143         BPY_BM_CHECK_OBJ(py_edge);
144         BPY_BM_CHECK_OBJ(py_vert);
145
146         /* this doubles for checking that the verts are in the same mesh */
147         if (!(py_edge->e->v1 == py_vert->v ||
148               py_edge->e->v2 == py_vert->v))
149         {
150                 PyErr_SetString(PyExc_ValueError,
151                                 "vert_collapse_faces(vert, edge): the vertex is not found in the edge");
152                 return NULL;
153         }
154
155         if (BM_vert_edge_count_is_over(py_vert->v, 2)) {
156                 PyErr_SetString(PyExc_ValueError,
157                                 "vert_collapse_faces(vert, edge): vert has more than 2 connected edges");
158                 return NULL;
159         }
160
161         bm = py_edge->bm;
162
163         e_new = BM_vert_collapse_faces(bm, py_edge->e, py_vert->v, clamp_f(fac, 0.0f, 1.0f), true, do_join_faces, true);
164
165         if (e_new) {
166                 return BPy_BMEdge_CreatePyObject(bm, e_new);
167         }
168         else {
169                 PyErr_SetString(PyExc_ValueError,
170                                 "vert_collapse_faces(vert, edge): no new edge created, internal error");
171                 return NULL;
172         }
173 }
174
175
176 PyDoc_STRVAR(bpy_bm_utils_vert_dissolve_doc,
177 ".. method:: vert_dissolve(vert)\n"
178 "\n"
179 "   Dissolve this vertex (will be removed).\n"
180 "\n"
181 "   :arg vert: The vert to be dissolved.\n"
182 "   :type vert: :class:`bmesh.types.BMVert`\n"
183 "   :return: True when the vertex dissolve is successful.\n"
184 "   :rtype: boolean\n"
185 );
186 static PyObject *bpy_bm_utils_vert_dissolve(PyObject *UNUSED(self), PyObject *args)
187 {
188         BPy_BMVert *py_vert;
189
190         BMesh *bm;
191
192         if (!PyArg_ParseTuple(args, "O!:vert_dissolve",
193                               &BPy_BMVert_Type, &py_vert))
194         {
195                 return NULL;
196         }
197
198         BPY_BM_CHECK_OBJ(py_vert);
199
200         bm = py_vert->bm;
201
202         return PyBool_FromLong((BM_vert_dissolve(bm, py_vert->v)));
203 }
204
205 PyDoc_STRVAR(bpy_bm_utils_vert_splice_doc,
206 ".. method:: vert_splice(vert, vert_target)\n"
207 "\n"
208 "   Splice vert into vert_target.\n"
209 "\n"
210 "   :arg vert: The vertex to be removed.\n"
211 "   :type vert: :class:`bmesh.types.BMVert`\n"
212 "   :arg vert_target: The vertex to use.\n"
213 "   :type vert_target: :class:`bmesh.types.BMVert`\n"
214 "\n"
215 "   .. note:: The verts mustn't share an edge or face.\n"
216 );
217 static PyObject *bpy_bm_utils_vert_splice(PyObject *UNUSED(self), PyObject *args)
218 {
219         BPy_BMVert *py_vert;
220         BPy_BMVert *py_vert_target;
221
222         BMesh *bm;
223
224         bool ok;
225
226         if (!PyArg_ParseTuple(args, "O!O!:vert_splice",
227                               &BPy_BMVert_Type, &py_vert,
228                               &BPy_BMVert_Type, &py_vert_target))
229         {
230                 return NULL;
231         }
232
233         BPY_BM_CHECK_OBJ(py_vert);
234         BPY_BM_CHECK_OBJ(py_vert_target);
235
236         bm = py_vert->bm;
237         BPY_BM_CHECK_SOURCE_OBJ(bm, "vert_splice", py_vert_target);
238
239         if (py_vert->v == py_vert_target->v) {
240                 PyErr_SetString(PyExc_ValueError,
241                                 "vert_splice(...): vert arguments match");
242                 return NULL;
243         }
244
245         if (BM_edge_exists(py_vert->v, py_vert_target->v)) {
246                 PyErr_SetString(PyExc_ValueError,
247                                 "vert_splice(...): verts can't share an edge");
248                 return NULL;
249         }
250
251         if (BM_vert_pair_share_face_check(py_vert->v, py_vert_target->v)) {
252                 PyErr_SetString(PyExc_ValueError,
253                                 "vert_splice(...): verts can't share a face");
254                 return NULL;
255         }
256
257         /* should always succeed */
258         ok = BM_vert_splice(bm, py_vert_target->v, py_vert->v);
259         BLI_assert(ok == true);
260         UNUSED_VARS_NDEBUG(ok);
261
262         Py_RETURN_NONE;
263 }
264
265 PyDoc_STRVAR(bpy_bm_utils_vert_separate_doc,
266 ".. method:: vert_separate(vert, edges)\n"
267 "\n"
268 "   Separate this vertex at every edge.\n"
269 "\n"
270 "   :arg vert: The vert to be separated.\n"
271 "   :type vert: :class:`bmesh.types.BMVert`\n"
272 "   :arg edges: The edges to separated.\n"
273 "   :type edges: :class:`bmesh.types.BMEdge`\n"
274 "   :return: The newly separated verts (including the vertex passed).\n"
275 "   :rtype: tuple of :class:`bmesh.types.BMVert`\n"
276 );
277 static PyObject *bpy_bm_utils_vert_separate(PyObject *UNUSED(self), PyObject *args)
278 {
279         BPy_BMVert *py_vert;
280         PyObject *edge_seq;
281
282         BMesh *bm;
283         BMVert **elem;
284         int elem_len;
285
286         /* edges to split */
287         BMEdge **edge_array;
288         Py_ssize_t edge_array_len;
289
290         PyObject *ret;
291
292
293         if (!PyArg_ParseTuple(args, "O!O:vert_separate",
294                               &BPy_BMVert_Type, &py_vert,
295                               &edge_seq))
296         {
297                 return NULL;
298         }
299
300         BPY_BM_CHECK_OBJ(py_vert);
301
302         bm = py_vert->bm;
303
304         edge_array = BPy_BMElem_PySeq_As_Array(&bm, edge_seq, 0, PY_SSIZE_T_MAX,
305                                                &edge_array_len, BM_EDGE,
306                                                true, true, "vert_separate(...)");
307
308         if (edge_array == NULL) {
309                 return NULL;
310         }
311
312         BM_vert_separate(bm, py_vert->v, edge_array, edge_array_len, false, &elem, &elem_len);
313         /* return collected verts */
314         ret = BPy_BMVert_Array_As_Tuple(bm, elem, elem_len);
315         MEM_freeN(elem);
316
317         PyMem_FREE(edge_array);
318
319         return ret;
320 }
321
322
323 PyDoc_STRVAR(bpy_bm_utils_edge_split_doc,
324 ".. method:: edge_split(edge, vert, fac)\n"
325 "\n"
326 "   Split an edge, return the newly created data.\n"
327 "\n"
328 "   :arg edge: The edge to split.\n"
329 "   :type edge: :class:`bmesh.types.BMEdge`\n"
330 "   :arg vert: One of the verts on the edge, defines the split direction.\n"
331 "   :type vert: :class:`bmesh.types.BMVert`\n"
332 "   :arg fac: The point on the edge where the new vert will be created [0 - 1].\n"
333 "   :type fac: float\n"
334 "   :return: The newly created (edge, vert) pair.\n"
335 "   :rtype: tuple\n"
336 );
337 static PyObject *bpy_bm_utils_edge_split(PyObject *UNUSED(self), PyObject *args)
338 {
339         BPy_BMEdge *py_edge;
340         BPy_BMVert *py_vert;
341         float fac;
342
343         BMesh *bm;
344         BMVert *v_new = NULL;
345         BMEdge *e_new = NULL;
346
347         if (!PyArg_ParseTuple(args, "O!O!f:edge_split",
348                               &BPy_BMEdge_Type, &py_edge,
349                               &BPy_BMVert_Type, &py_vert,
350                               &fac))
351         {
352                 return NULL;
353         }
354
355         BPY_BM_CHECK_OBJ(py_edge);
356         BPY_BM_CHECK_OBJ(py_vert);
357
358         /* this doubles for checking that the verts are in the same mesh */
359         if (!(py_edge->e->v1 == py_vert->v ||
360               py_edge->e->v2 == py_vert->v))
361         {
362                 PyErr_SetString(PyExc_ValueError,
363                                 "edge_split(edge, vert): the vertex is not found in the edge");
364                 return NULL;
365         }
366
367         bm = py_edge->bm;
368
369         v_new = BM_edge_split(bm, py_edge->e, py_vert->v, &e_new, clamp_f(fac, 0.0f, 1.0f));
370
371         if (v_new && e_new) {
372                 PyObject *ret = PyTuple_New(2);
373                 PyTuple_SET_ITEMS(ret,
374                         BPy_BMEdge_CreatePyObject(bm, e_new),
375                         BPy_BMVert_CreatePyObject(bm, v_new));
376                 return ret;
377         }
378         else {
379                 PyErr_SetString(PyExc_ValueError,
380                                 "edge_split(edge, vert): couldn't split the edge, internal error");
381                 return NULL;
382         }
383 }
384
385
386 PyDoc_STRVAR(bpy_bm_utils_edge_rotate_doc,
387 ".. method:: edge_rotate(edge, ccw=False)\n"
388 "\n"
389 "   Rotate the edge and return the newly created edge.\n"
390 "   If rotating the edge fails, None will be returned.\n"
391 "\n"
392 "   :arg edge: The edge to rotate.\n"
393 "   :type edge: :class:`bmesh.types.BMEdge`\n"
394 "   :arg ccw: When True the edge will be rotated counter clockwise.\n"
395 "   :type ccw: boolean\n"
396 "   :return: The newly rotated edge.\n"
397 "   :rtype: :class:`bmesh.types.BMEdge`\n"
398 );
399 static PyObject *bpy_bm_utils_edge_rotate(PyObject *UNUSED(self), PyObject *args)
400 {
401         BPy_BMEdge *py_edge;
402         bool do_ccw = false;
403
404         BMesh *bm;
405         BMEdge *e_new = NULL;
406
407         if (!PyArg_ParseTuple(
408                 args, "O!|O&:edge_rotate",
409                 &BPy_BMEdge_Type, &py_edge,
410                 PyC_ParseBool, &do_ccw))
411         {
412                 return NULL;
413         }
414
415         BPY_BM_CHECK_OBJ(py_edge);
416
417         bm = py_edge->bm;
418
419         e_new = BM_edge_rotate(bm, py_edge->e, do_ccw, 0);
420
421         if (e_new) {
422                 return BPy_BMEdge_CreatePyObject(bm, e_new);
423         }
424         else {
425                 Py_RETURN_NONE;
426         }
427 }
428
429
430 PyDoc_STRVAR(bpy_bm_utils_face_split_doc,
431 ".. method:: face_split(face, vert_a, vert_b, coords=(), use_exist=True, example=None)\n"
432 "\n"
433 "   Face split with optional intermediate points.\n"
434 "\n"
435 "   :arg face: The face to cut.\n"
436 "   :type face: :class:`bmesh.types.BMFace`\n"
437 "   :arg vert_a: First vertex to cut in the face (face must contain the vert).\n"
438 "   :type vert_a: :class:`bmesh.types.BMVert`\n"
439 "   :arg vert_b: Second vertex to cut in the face (face must contain the vert).\n"
440 "   :type vert_b: :class:`bmesh.types.BMVert`\n"
441 "   :arg coords: Optional argument to define points inbetween *vert_a* and *vert_b*.\n"
442 "   :type coords: sequence of float triplets\n"
443 "   :arg use_exist: .Use an existing edge if it exists (Only used when *coords* argument is empty or omitted)\n"
444 "   :type use_exist: boolean\n"
445 "   :arg example: Newly created edge will copy settings from this one.\n"
446 "   :type example: :class:`bmesh.types.BMEdge`\n"
447 "   :return: The newly created face or None on failure.\n"
448 "   :rtype: (:class:`bmesh.types.BMFace`, :class:`bmesh.types.BMLoop`) pair\n"
449 );
450 static PyObject *bpy_bm_utils_face_split(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
451 {
452         static const char *kwlist[] = {"face", "vert_a", "vert_b",
453                                        "coords", "use_exist", "example", NULL};
454
455         BPy_BMFace *py_face;
456         BPy_BMVert *py_vert_a;
457         BPy_BMVert *py_vert_b;
458
459         /* optional */
460         PyObject *py_coords = NULL;
461         bool edge_exists = true;
462         BPy_BMEdge *py_edge_example = NULL;
463
464         float *coords;
465         int ncoords = 0;
466
467         BMesh *bm;
468         BMFace *f_new = NULL;
469         BMLoop *l_new = NULL;
470         BMLoop *l_a, *l_b;
471
472         if (!PyArg_ParseTupleAndKeywords(
473                 args, kw,
474                 "O!O!O!|OO&O!:face_split", (char **)kwlist,
475                 &BPy_BMFace_Type, &py_face,
476                 &BPy_BMVert_Type, &py_vert_a,
477                 &BPy_BMVert_Type, &py_vert_b,
478                 &py_coords,
479                 PyC_ParseBool, &edge_exists,
480                 &BPy_BMEdge_Type, &py_edge_example))
481         {
482                 return NULL;
483         }
484
485         BPY_BM_CHECK_OBJ(py_face);
486         BPY_BM_CHECK_OBJ(py_vert_a);
487         BPY_BM_CHECK_OBJ(py_vert_b);
488
489         if (py_edge_example) {
490                 BPY_BM_CHECK_OBJ(py_edge_example);
491         }
492
493         /* this doubles for checking that the verts are in the same mesh */
494         if ((l_a = BM_face_vert_share_loop(py_face->f, py_vert_a->v)) &&
495             (l_b = BM_face_vert_share_loop(py_face->f, py_vert_b->v)))
496         {
497                 /* pass */
498         }
499         else {
500                 PyErr_SetString(PyExc_ValueError,
501                                 "face_split(...): one of the verts passed is not found in the face");
502                 return NULL;
503         }
504
505         if (py_vert_a->v == py_vert_b->v) {
506                 PyErr_SetString(PyExc_ValueError,
507                                 "face_split(...): vert arguments must differ");
508                 return NULL;
509         }
510
511         if (py_coords) {
512                 ncoords = mathutils_array_parse_alloc_v(&coords, 3, py_coords, "face_split(...): ");
513                 if (ncoords == -1) {
514                         return NULL;
515                 }
516         }
517         else {
518                 if (BM_loop_is_adjacent(l_a, l_b)) {
519                         PyErr_SetString(PyExc_ValueError,
520                                         "face_split(...): verts are adjacent in the face");
521                         return NULL;
522                 }
523         }
524
525         /* --- main function body --- */
526         bm = py_face->bm;
527
528         if (ncoords) {
529                 f_new = BM_face_split_n(bm, py_face->f,
530                                         l_a, l_b,
531                                         (float (*)[3])coords, ncoords,
532                                         &l_new, py_edge_example ? py_edge_example->e : NULL);
533                 PyMem_Free(coords);
534         }
535         else {
536                 f_new = BM_face_split(bm, py_face->f,
537                                       l_a, l_b,
538                                       &l_new, py_edge_example ? py_edge_example->e : NULL, edge_exists);
539         }
540
541         if (f_new && l_new) {
542                 PyObject *ret = PyTuple_New(2);
543                 PyTuple_SET_ITEMS(ret,
544                         BPy_BMFace_CreatePyObject(bm, f_new),
545                         BPy_BMLoop_CreatePyObject(bm, l_new));
546                 return ret;
547         }
548         else {
549                 PyErr_SetString(PyExc_ValueError,
550                                 "face_split(...): couldn't split the face, internal error");
551                 return NULL;
552         }
553 }
554
555
556 PyDoc_STRVAR(bpy_bm_utils_face_split_edgenet_doc,
557 ".. method:: face_split_edgenet(face, edgenet)\n"
558 "\n"
559 "   Splits a face into any number of regions defined by an edgenet.\n"
560 "\n"
561 "   :arg face: The face to split.\n"
562 "   :type face: :class:`bmesh.types.BMFace`\n"
563 "   :arg face: The face to split.\n"
564 "   :type face: :class:`bmesh.types.BMFace`\n"
565 "   :arg edgenet: Sequence of edges.\n"
566 "   :type edgenet: :class:`bmesh.types.BMEdge`\n"
567 "   :return: The newly created faces.\n"
568 "   :rtype: tuple of (:class:`bmesh.types.BMFace`)\n"
569 "\n"
570 "   .. note::\n"
571 "\n"
572 "      Regions defined by edges need to connect to the face, otherwise they're ignored as loose edges.\n"
573 );
574 static PyObject *bpy_bm_utils_face_split_edgenet(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
575 {
576         static const char *kwlist[] = {"face", "edgenet", NULL};
577
578         BPy_BMFace *py_face;
579         PyObject *edge_seq;
580
581         BMEdge **edge_array;
582         Py_ssize_t edge_array_len;
583
584         BMesh *bm;
585
586         BMFace **face_arr;
587         int face_arr_len;
588         bool ok;
589
590
591         if (!PyArg_ParseTupleAndKeywords(args, kw, "O!O:face_split_edgenet", (char **)kwlist,
592                                          &BPy_BMFace_Type, &py_face,
593                                          &edge_seq))
594         {
595                 return NULL;
596         }
597
598         BPY_BM_CHECK_OBJ(py_face);
599
600         bm = py_face->bm;
601
602         edge_array = BPy_BMElem_PySeq_As_Array(&bm, edge_seq, 1, PY_SSIZE_T_MAX,
603                                                &edge_array_len, BM_EDGE,
604                                                true, true, "face_split_edgenet(...)");
605
606         if (edge_array == NULL) {
607                 return NULL;
608         }
609
610         /* --- main function body --- */
611
612         ok = BM_face_split_edgenet(bm, py_face->f, edge_array, edge_array_len,
613                                    &face_arr, &face_arr_len);
614
615         PyMem_FREE(edge_array);
616
617         if (ok) {
618                 PyObject *ret = BPy_BMFace_Array_As_Tuple(bm, face_arr, face_arr_len);
619                 if (face_arr) {
620                         MEM_freeN(face_arr);
621                 }
622                 return ret;
623         }
624         else {
625                 PyErr_SetString(PyExc_ValueError,
626                                 "face_split_edgenet(...): couldn't split the face, internal error");
627                 return NULL;
628         }
629 }
630
631
632 PyDoc_STRVAR(bpy_bm_utils_face_join_doc,
633 ".. method:: face_join(faces, remove=True)\n"
634 "\n"
635 "   Joins a sequence of faces.\n"
636 "\n"
637 "   :arg faces: Sequence of faces.\n"
638 "   :type faces: :class:`bmesh.types.BMFace`\n"
639 "   :arg remove: Remove the edges and vertices between the faces.\n"
640 "   :type remove: boolean\n"
641 "   :return: The newly created face or None on failure.\n"
642 "   :rtype: :class:`bmesh.types.BMFace`\n"
643 );
644 static PyObject *bpy_bm_utils_face_join(PyObject *UNUSED(self), PyObject *args)
645 {
646         BMesh *bm = NULL;
647         PyObject *py_face_array;
648         BMFace **face_array;
649         Py_ssize_t face_seq_len = 0;
650         BMFace *f_new;
651         bool do_remove = true;
652
653         if (!PyArg_ParseTuple(
654                 args, "O|O&:face_join",
655                 &py_face_array,
656                 PyC_ParseBool, &do_remove))
657         {
658                 return NULL;
659         }
660
661         face_array = BPy_BMElem_PySeq_As_Array(&bm, py_face_array, 2, PY_SSIZE_T_MAX,
662                                                &face_seq_len, BM_FACE,
663                                                true, true, "face_join(...)");
664
665         if (face_array == NULL) {
666                 return NULL; /* error will be set */
667         }
668
669         /* Go ahead and join the face!
670          * --------------------------- */
671         f_new = BM_faces_join(bm, face_array, (int)face_seq_len, do_remove);
672
673         PyMem_FREE(face_array);
674
675         if (f_new) {
676                 return BPy_BMFace_CreatePyObject(bm, f_new);
677         }
678         else {
679                 Py_RETURN_NONE;
680         }
681 }
682
683
684 PyDoc_STRVAR(bpy_bm_utils_face_vert_separate_doc,
685 ".. method:: face_vert_separate(face, vert)\n"
686 "\n"
687 "   Rip a vertex in a face away and add a new vertex.\n"
688 "\n"
689 "   :arg face: The face to separate.\n"
690 "   :type face: :class:`bmesh.types.BMFace`\n"
691 "   :arg vert: A vertex in the face to separate.\n"
692 "   :type vert: :class:`bmesh.types.BMVert`\n"
693 "   :return vert: The newly created vertex or None on failure.\n"
694 "   :rtype vert: :class:`bmesh.types.BMVert`\n"
695 "\n"
696 "   .. note::\n"
697 "\n"
698 "      This is the same as loop_separate, and has only been added for convenience.\n"
699 );
700 static PyObject *bpy_bm_utils_face_vert_separate(PyObject *UNUSED(self), PyObject *args)
701 {
702         BPy_BMFace *py_face;
703         BPy_BMVert *py_vert;
704
705         BMesh *bm;
706         BMLoop *l;
707         BMVert *v_old, *v_new;
708
709         if (!PyArg_ParseTuple(args, "O!O!:face_vert_separate",
710                               &BPy_BMFace_Type, &py_face,
711                               &BPy_BMVert_Type, &py_vert))
712         {
713                 return NULL;
714         }
715
716         bm = py_face->bm;
717
718         BPY_BM_CHECK_OBJ(py_face);
719         BPY_BM_CHECK_SOURCE_OBJ(bm, "face_vert_separate()", py_vert);
720
721         l = BM_face_vert_share_loop(py_face->f, py_vert->v);
722
723         if (l == NULL) {
724                 PyErr_SetString(PyExc_ValueError,
725                                 "vertex not found in face");
726                 return NULL;
727         }
728
729         v_old = l->v;
730         v_new = BM_face_loop_separate(bm, l);
731
732         if (v_new != v_old) {
733                 return BPy_BMVert_CreatePyObject(bm, v_new);
734         }
735         else {
736                 Py_RETURN_NONE;
737         }
738 }
739
740
741 PyDoc_STRVAR(bpy_bm_utils_face_flip_doc,
742 ".. method:: face_flip(faces)\n"
743 "\n"
744 "   Flip the faces direction.\n"
745 "\n"
746 "   :arg face: Face to flip.\n"
747 "   :type face: :class:`bmesh.types.BMFace`\n"
748 );
749 static PyObject *bpy_bm_utils_face_flip(PyObject *UNUSED(self), BPy_BMFace *value)
750 {
751         if (!BPy_BMFace_Check(value)) {
752                 PyErr_Format(PyExc_TypeError,
753                              "face_flip(face): BMFace expected, not '%.200s'",
754                              Py_TYPE(value)->tp_name);
755                 return NULL;
756         }
757
758         BPY_BM_CHECK_OBJ(value);
759
760         BM_face_normal_flip(value->bm, value->f);
761
762         Py_RETURN_NONE;
763 }
764
765
766
767 PyDoc_STRVAR(bpy_bm_utils_loop_separate_doc,
768 ".. method:: loop_separate(loop)\n"
769 "\n"
770 "   Rip a vertex in a face away and add a new vertex.\n"
771 "\n"
772 "   :arg loop: The loop to separate.\n"
773 "   :type loop: :class:`bmesh.types.BMLoop`\n"
774 "   :return vert: The newly created vertex or None on failure.\n"
775 "   :rtype vert: :class:`bmesh.types.BMVert`\n"
776 );
777 static PyObject *bpy_bm_utils_loop_separate(PyObject *UNUSED(self), BPy_BMLoop *value)
778 {
779         BMesh *bm;
780         BMLoop *l;
781         BMVert *v_old, *v_new;
782
783         if (!BPy_BMLoop_Check(value)) {
784                 PyErr_Format(PyExc_TypeError,
785                              "loop_separate(loop): BMLoop expected, not '%.200s'",
786                              Py_TYPE(value)->tp_name);
787                 return NULL;
788         }
789
790         BPY_BM_CHECK_OBJ(value);
791
792         bm = value->bm;
793         l = value->l;
794
795         v_old = l->v;
796         v_new = BM_face_loop_separate(bm, l);
797
798         if (v_new != v_old) {
799                 return BPy_BMVert_CreatePyObject(bm, v_new);
800         }
801         else {
802                 Py_RETURN_NONE;
803         }
804 }
805
806
807 static struct PyMethodDef BPy_BM_utils_methods[] = {
808         {"vert_collapse_edge",  (PyCFunction)bpy_bm_utils_vert_collapse_edge,  METH_VARARGS, bpy_bm_utils_vert_collapse_edge_doc},
809         {"vert_collapse_faces", (PyCFunction)bpy_bm_utils_vert_collapse_faces, METH_VARARGS, bpy_bm_utils_vert_collapse_faces_doc},
810         {"vert_dissolve",       (PyCFunction)bpy_bm_utils_vert_dissolve,       METH_VARARGS, bpy_bm_utils_vert_dissolve_doc}, /* could use METH_O */
811         {"vert_splice",         (PyCFunction)bpy_bm_utils_vert_splice,         METH_VARARGS, bpy_bm_utils_vert_splice_doc},
812         {"vert_separate",       (PyCFunction)bpy_bm_utils_vert_separate,       METH_VARARGS, bpy_bm_utils_vert_separate_doc},
813         {"edge_split",          (PyCFunction)bpy_bm_utils_edge_split,          METH_VARARGS, bpy_bm_utils_edge_split_doc},
814         {"edge_rotate",         (PyCFunction)bpy_bm_utils_edge_rotate,         METH_VARARGS, bpy_bm_utils_edge_rotate_doc},
815         {"face_split",          (PyCFunction)bpy_bm_utils_face_split,          METH_VARARGS | METH_KEYWORDS, bpy_bm_utils_face_split_doc},
816         {"face_split_edgenet",  (PyCFunction)bpy_bm_utils_face_split_edgenet,  METH_VARARGS | METH_KEYWORDS, bpy_bm_utils_face_split_edgenet_doc},
817         {"face_join",           (PyCFunction)bpy_bm_utils_face_join,           METH_VARARGS, bpy_bm_utils_face_join_doc},
818         {"face_vert_separate",  (PyCFunction)bpy_bm_utils_face_vert_separate,  METH_VARARGS, bpy_bm_utils_face_vert_separate_doc},
819         {"face_flip",           (PyCFunction)bpy_bm_utils_face_flip,           METH_O,       bpy_bm_utils_face_flip_doc},
820         {"loop_separate",       (PyCFunction)bpy_bm_utils_loop_separate,       METH_O,       bpy_bm_utils_loop_separate_doc},
821         {NULL, NULL, 0, NULL}
822 };
823
824
825 PyDoc_STRVAR(BPy_BM_utils_doc,
826 "This module provides access to blenders bmesh data structures."
827 );
828 static struct PyModuleDef BPy_BM_utils_module_def = {
829         PyModuleDef_HEAD_INIT,
830         "bmesh.utils",  /* m_name */
831         BPy_BM_utils_doc,  /* m_doc */
832         0,  /* m_size */
833         BPy_BM_utils_methods,  /* m_methods */
834         NULL,  /* m_reload */
835         NULL,  /* m_traverse */
836         NULL,  /* m_clear */
837         NULL,  /* m_free */
838 };
839
840
841 PyObject *BPyInit_bmesh_utils(void)
842 {
843         PyObject *submodule;
844
845         submodule = PyModule_Create(&BPy_BM_utils_module_def);
846
847         return submodule;
848 }