3fc4b7003fbb4ca6c795e005138b5a4dcf516540
[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_api.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 "bmesh.h"
36
37 #include "bmesh_py_types.h"
38
39 #include "BLI_utildefines.h"
40
41 #include "bmesh_py_utils.h" /* own include */
42
43
44 PyDoc_STRVAR(bpy_bm_utils_vert_collapse_edge_doc,
45 ".. method:: vert_collapse_edge(vert, edge)\n"
46 "\n"
47 "   Collapse a vertex into an edge.\n"
48 "\n"
49 "   :arg vert: The vert that will be collapsed.\n"
50 "   :type vert: :class:`BMVert`\n"
51 "   :arg edge: The edge to collapse into.\n"
52 "   :type edge: :class:`BMEdge`\n"
53 "   :return: The resulting edge from the collapse operation.\n"
54 "   :rtype: :class:`BMEdge`\n"
55 );
56 static PyObject *bpy_bm_utils_vert_collapse_edge(PyObject *UNUSED(self), PyObject *args)
57 {
58         BPy_BMEdge *py_edge;
59         BPy_BMVert *py_vert;
60
61         BMesh *bm;
62         BMEdge *e_new = NULL;
63
64         if (!PyArg_ParseTuple(args, "O!O!:vert_collapse_edge",
65                               &BPy_BMVert_Type, &py_vert,
66                               &BPy_BMEdge_Type, &py_edge))
67         {
68                 return NULL;
69         }
70
71         BPY_BM_CHECK_OBJ(py_edge);
72         BPY_BM_CHECK_OBJ(py_vert);
73
74         /* this doubles for checking that the verts are in the same mesh */
75         if (!(py_edge->e->v1 == py_vert->v ||
76               py_edge->e->v2 == py_vert->v))
77         {
78                 PyErr_SetString(PyExc_ValueError,
79                                 "vert_collapse_edge(vert, edge): the vertex is not found in the edge");
80                 return NULL;
81         }
82
83         if (BM_vert_edge_count(py_vert->v) > 2) {
84                 PyErr_SetString(PyExc_ValueError,
85                                 "vert_collapse_edge(vert, edge): vert has more then 2 connected edges");
86                 return NULL;
87         }
88
89         bm = py_edge->bm;
90
91         e_new = BM_vert_collapse_edge(bm, py_edge->e, py_vert->v, TRUE);
92
93         if (e_new) {
94                 return BPy_BMEdge_CreatePyObject(bm, e_new);
95         }
96         else {
97                 PyErr_SetString(PyExc_ValueError,
98                                 "vert_collapse_edge(vert, edge): no new edge created, internal error");
99                 return NULL;
100         }
101 }
102
103
104 PyDoc_STRVAR(bpy_bm_utils_vert_collapse_faces_doc,
105 ".. method:: vert_collapse_faces(vert, edge, fac, join_faces)\n"
106 "\n"
107 "   Split an edge, return the newly created data.\n"
108 "\n"
109 "   :arg vert: The vert that will be collapsed.\n"
110 "   :type vert: :class:`BMVert`\n"
111 "   :arg edge: The edge to collapse into.\n"
112 "   :type edge: :class:`BMEdge`\n"
113 "   :arg fac: The factor to use when merging customdata [0 - 1].\n"
114 "   :type fac: float\n"
115 "   :return: The resulting edge from the collapse operation.\n"
116 "   :rtype: :class:`BMEdge`\n"
117 );
118 static PyObject *bpy_bm_utils_vert_collapse_faces(PyObject *UNUSED(self), PyObject *args)
119 {
120         BPy_BMEdge *py_edge;
121         BPy_BMVert *py_vert;
122
123         float fac;
124         int do_join_faces;
125
126         BMesh *bm;
127         BMEdge *e_new = NULL;
128
129         if (!PyArg_ParseTuple(args, "O!O!fi:vert_collapse_faces",
130                               &BPy_BMVert_Type, &py_vert,
131                               &BPy_BMEdge_Type, &py_edge,
132                               &fac, &do_join_faces))
133         {
134                 return NULL;
135         }
136
137         BPY_BM_CHECK_OBJ(py_edge);
138         BPY_BM_CHECK_OBJ(py_vert);
139
140         /* this doubles for checking that the verts are in the same mesh */
141         if (!(py_edge->e->v1 == py_vert->v ||
142               py_edge->e->v2 == py_vert->v))
143         {
144                 PyErr_SetString(PyExc_ValueError,
145                                 "vert_collapse_faces(vert, edge): the vertex is not found in the edge");
146                 return NULL;
147         }
148
149         if (BM_vert_edge_count(py_vert->v) > 2) {
150                 PyErr_SetString(PyExc_ValueError,
151                                 "vert_collapse_faces(vert, edge): vert has more then 2 connected edges");
152                 return NULL;
153         }
154
155         bm = py_edge->bm;
156
157         e_new = BM_vert_collapse_faces(bm, py_edge->e, py_vert->v, CLAMPIS(fac, 0.0f, 1.0f), do_join_faces, TRUE);
158
159         if (e_new) {
160                 return BPy_BMEdge_CreatePyObject(bm, e_new);
161         }
162         else {
163                 PyErr_SetString(PyExc_ValueError,
164                                 "vert_collapse_edge(vert, edge): no new edge created, internal error");
165                 return NULL;
166         }
167 }
168
169
170 PyDoc_STRVAR(bpy_bm_utils_vert_dissolve_doc,
171 ".. method:: vert_dissolve(vert)\n"
172 "\n"
173 "   Dissolve this vertex (will be removed).\n"
174 "\n"
175 "   :arg vert: The vert to be dissolved.\n"
176 "   :type vert: :class:`BMVert`\n"
177 "   :return: True when the vertex dissolve is successful.\n"
178 "   :rtype: boolean\n"
179 );
180 static PyObject *bpy_bm_utils_vert_dissolve(PyObject *UNUSED(self), PyObject *args)
181 {
182         BPy_BMVert *py_vert;
183
184         BMesh *bm;
185
186         if (!PyArg_ParseTuple(args, "O!:vert_dissolve",
187                               &BPy_BMVert_Type, &py_vert))
188         {
189                 return NULL;
190         }
191
192         BPY_BM_CHECK_OBJ(py_vert);
193
194         bm = py_vert->bm;
195
196         return PyBool_FromLong((BM_vert_dissolve(bm, py_vert->v)));
197 }
198
199
200 PyDoc_STRVAR(bpy_bm_utils_edge_split_doc,
201 ".. method:: edge_split(edge, vert, fac)\n"
202 "\n"
203 "   Split an edge, return the newly created data.\n"
204 "\n"
205 "   :arg edge: The edge to split.\n"
206 "   :type edge: :class:`BMEdge`\n"
207 "   :arg vert: One of the verts on the edge, defines the split direction.\n"
208 "   :type vert: :class:`BMVert`\n"
209 "   :arg fac: The point on the edge where the new vert will be created [0 - 1].\n"
210 "   :type fac: float\n"
211 "   :return: The newly created (edge, vert) pair.\n"
212 "   :rtype: tuple\n"
213 );
214 static PyObject *bpy_bm_utils_edge_split(PyObject *UNUSED(self), PyObject *args)
215 {
216         BPy_BMEdge *py_edge;
217         BPy_BMVert *py_vert;
218         float fac;
219
220         BMesh *bm;
221         BMVert *v_new = NULL;
222         BMEdge *e_new = NULL;
223
224         if (!PyArg_ParseTuple(args, "O!O!f:edge_split",
225                               &BPy_BMEdge_Type, &py_edge,
226                               &BPy_BMVert_Type, &py_vert,
227                               &fac))
228         {
229                 return NULL;
230         }
231
232         BPY_BM_CHECK_OBJ(py_edge);
233         BPY_BM_CHECK_OBJ(py_vert);
234
235         /* this doubles for checking that the verts are in the same mesh */
236         if (!(py_edge->e->v1 == py_vert->v ||
237               py_edge->e->v2 == py_vert->v))
238         {
239                 PyErr_SetString(PyExc_ValueError,
240                                 "edge_split(edge, vert): the vertex is not found in the edge");
241                 return NULL;
242         }
243
244         bm = py_edge->bm;
245
246         v_new = BM_edge_split(bm, py_edge->e, py_vert->v, &e_new, CLAMPIS(fac, 0.0f, 1.0f));
247
248         if (v_new && e_new) {
249                 PyObject *ret = PyTuple_New(2);
250                 PyTuple_SET_ITEM(ret, 0, BPy_BMEdge_CreatePyObject(bm, e_new));
251                 PyTuple_SET_ITEM(ret, 1, BPy_BMVert_CreatePyObject(bm, v_new));
252                 return ret;
253         }
254         else {
255                 PyErr_SetString(PyExc_ValueError,
256                                 "edge_split(edge, vert): couldn't split the edge, internal error");
257                 return NULL;
258         }
259 }
260
261
262 PyDoc_STRVAR(bpy_bm_utils_edge_rotate_doc,
263 ".. method:: edge_rotate(edge, ccw=False)\n"
264 "\n"
265 "   Rotate the edge and return the newly created edge.\n"
266 "   If rotating the edge fails, None will be returned.\n"
267 "\n"
268 "   :arg edge: The edge to rotate.\n"
269 "   :type edge: :class:`BMEdge`\n"
270 "   :arg ccw: When True the edge will be rotated counter clockwise.\n"
271 "   :type ccw: boolean\n"
272 "   :return: The newly rotated edge.\n"
273 "   :rtype: :class:`BMEdge`\n"
274 );
275 static PyObject *bpy_bm_utils_edge_rotate(PyObject *UNUSED(self), PyObject *args)
276 {
277         BPy_BMEdge *py_edge;
278         int do_ccw = FALSE;
279
280         BMesh *bm;
281         BMEdge *e_new = NULL;
282
283         if (!PyArg_ParseTuple(args, "O!|i:edge_rotate",
284                               &BPy_BMEdge_Type, &py_edge,
285                               &do_ccw))
286         {
287                 return NULL;
288         }
289
290         BPY_BM_CHECK_OBJ(py_edge);
291
292         bm = py_edge->bm;
293
294         e_new = BM_edge_rotate(bm, py_edge->e, do_ccw, 0); /* BMESH_TODO - expose to API */
295
296         if (e_new) {
297                 return BPy_BMEdge_CreatePyObject(bm, e_new);
298         }
299         else {
300                 Py_RETURN_NONE;
301         }
302 }
303
304
305 PyDoc_STRVAR(bpy_bm_utils_face_split_doc,
306 ".. method:: face_split(face, vert, vert_a, vert_b, edge_example)\n"
307 "\n"
308 "   Split an edge, return the newly created data.\n"
309 "\n"
310 "   :arg face: The face to cut.\n"
311 "   :type face: :class:`BMFace`\n"
312 "   :arg vert_a: First vertex to cut in the face (face must contain the vert).\n"
313 "   :type vert_a: :class:`BMVert`\n"
314 "   :arg vert_b: Second vertex to cut in the face (face must contain the vert).\n"
315 "   :type vert_b: :class:`BMVert`\n"
316 "   :arg edge_example: Optional edge argument, newly created edge will copy settings from this one.\n"
317 "   :type edge_example: :class:`BMEdge`\n"
318 );
319 static PyObject *bpy_bm_utils_face_split(PyObject *UNUSED(self), PyObject *args)
320 {
321         BPy_BMFace *py_face;
322         BPy_BMVert *py_vert_a;
323         BPy_BMVert *py_vert_b;
324         BPy_BMEdge *py_edge_example = NULL; /* optional */
325
326         BMesh *bm;
327         BMFace *f_new = NULL;
328         BMLoop *l_new = NULL;
329
330         if (!PyArg_ParseTuple(args, "O!O!O!|O!:face_split",
331                               &BPy_BMFace_Type, &py_face,
332                               &BPy_BMVert_Type, &py_vert_a,
333                               &BPy_BMVert_Type, &py_vert_b,
334                               &BPy_BMEdge_Type, &py_edge_example))
335         {
336                 return NULL;
337         }
338
339         BPY_BM_CHECK_OBJ(py_face);
340         BPY_BM_CHECK_OBJ(py_vert_a);
341         BPY_BM_CHECK_OBJ(py_vert_b);
342
343         if (py_edge_example) {
344                 BPY_BM_CHECK_OBJ(py_edge_example);
345         }
346
347         /* this doubles for checking that the verts are in the same mesh */
348         if (BM_vert_in_face(py_face->f, py_vert_a->v) == FALSE ||
349             BM_vert_in_face(py_face->f, py_vert_b->v) == FALSE)
350         {
351                 PyErr_SetString(PyExc_ValueError,
352                                 "face_split(...): one of the verts passed is not found in the face");
353                 return NULL;
354         }
355
356         if (py_vert_a->v == py_vert_b->v) {
357                 PyErr_SetString(PyExc_ValueError,
358                                 "face_split(...): vert arguments must differ");
359                 return NULL;
360         }
361
362         bm = py_face->bm;
363
364         f_new = BM_face_split(bm, py_face->f,
365                               py_vert_a->v, py_vert_b->v,
366                               &l_new, py_edge_example ? py_edge_example->e : NULL, FALSE); /* BMESH_TODO, make arg */
367
368         if (f_new && l_new) {
369                 PyObject *ret = PyTuple_New(2);
370                 PyTuple_SET_ITEM(ret, 0, BPy_BMFace_CreatePyObject(bm, f_new));
371                 PyTuple_SET_ITEM(ret, 1, BPy_BMLoop_CreatePyObject(bm, l_new));
372                 return ret;
373         }
374         else {
375                 PyErr_SetString(PyExc_ValueError,
376                                 "face_split(...): couldn't split the face, internal error");
377                 return NULL;
378         }
379 }
380
381
382 PyDoc_STRVAR(bpy_bm_utils_face_join_doc,
383 ".. method:: face_join(faces)\n"
384 "\n"
385 "   Joins a sequence of faces.\n"
386 "\n"
387 "   :arg faces: Sequence of faces.\n"
388 "   :type faces: :class:`BMFace`\n"
389 "   :return: The newly created face or None on failure.\n"
390 "   :rtype: :class:`BMFace`\n"
391 );
392 static PyObject *bpy_bm_utils_face_join(PyObject *UNUSED(self), PyObject *value)
393 {
394         BMesh *bm = NULL;
395         BMFace **face_array;
396         Py_ssize_t face_seq_len = 0;
397         BMFace *f_new;
398
399         face_array = BPy_BMElem_PySeq_As_Array(&bm, value, 2, PY_SSIZE_T_MAX,
400                                                &face_seq_len, &BPy_BMFace_Type,
401                                                TRUE, TRUE, "face_join(...)");
402
403         if (face_array == NULL) {
404                 return NULL; /* error will be set */
405         }
406
407         /* Go ahead and join the face!
408          * --------------------------- */
409         f_new = BM_faces_join(bm, face_array, (int)face_seq_len);
410
411         if (f_new) {
412                 return BPy_BMFace_CreatePyObject(bm, f_new);
413         }
414         else {
415                 Py_RETURN_NONE;
416         }
417 }
418
419
420 PyDoc_STRVAR(bpy_bm_utils_face_flip_doc,
421 ".. method:: face_flip(faces)\n"
422 "\n"
423 "   Flip the faces direction.\n"
424 "\n"
425 "   :arg face: Face to flip.\n"
426 "   :type face: :class:`BMFace`\n"
427 );
428 static PyObject *bpy_bm_utils_face_flip(PyObject *UNUSED(self), BPy_BMFace *value)
429 {
430         if (!BPy_BMFace_Check(value)) {
431                 PyErr_Format(PyExc_TypeError,
432                              "face_flip(face): BMFace expected, not '%.200s'",
433                              Py_TYPE(value)->tp_name);
434                 return NULL;
435         }
436
437         BPY_BM_CHECK_OBJ(value);
438
439         BM_face_normal_flip(value->bm, value->f);
440
441         Py_RETURN_NONE;
442 }
443
444
445 static struct PyMethodDef BPy_BM_utils_methods[] = {
446     {"vert_collapse_edge",  (PyCFunction)bpy_bm_utils_vert_collapse_edge,  METH_VARARGS, bpy_bm_utils_vert_collapse_edge_doc},
447     {"vert_collapse_faces", (PyCFunction)bpy_bm_utils_vert_collapse_faces, METH_VARARGS, bpy_bm_utils_vert_collapse_faces_doc},
448     {"vert_dissolve",       (PyCFunction)bpy_bm_utils_vert_dissolve,       METH_VARARGS, bpy_bm_utils_vert_dissolve_doc},
449     {"edge_split",          (PyCFunction)bpy_bm_utils_edge_split,          METH_VARARGS, bpy_bm_utils_edge_split_doc},
450     {"edge_rotate",         (PyCFunction)bpy_bm_utils_edge_rotate,         METH_VARARGS, bpy_bm_utils_edge_rotate_doc},
451     {"face_split",          (PyCFunction)bpy_bm_utils_face_split,          METH_VARARGS, bpy_bm_utils_face_split_doc},
452     {"face_join",           (PyCFunction)bpy_bm_utils_face_join,           METH_O,       bpy_bm_utils_face_join_doc},
453     {"face_flip",           (PyCFunction)bpy_bm_utils_face_flip,           METH_O,       bpy_bm_utils_face_flip_doc},
454     {NULL, NULL, 0, NULL}
455 };
456
457
458 PyDoc_STRVAR(BPy_BM_doc,
459 "This module provides access to blenders bmesh data structures."
460 );
461 static struct PyModuleDef BPy_BM_types_module_def = {
462     PyModuleDef_HEAD_INIT,
463     "bmesh.utils",  /* m_name */
464     BPy_BM_doc,  /* m_doc */
465     0,  /* m_size */
466     BPy_BM_utils_methods,  /* m_methods */
467     NULL,  /* m_reload */
468     NULL,  /* m_traverse */
469     NULL,  /* m_clear */
470     NULL,  /* m_free */
471 };
472
473
474 PyObject *BPyInit_bmesh_utils(void)
475 {
476         PyObject *submodule;
477
478         submodule = PyModule_Create(&BPy_BM_types_module_def);
479
480         return submodule;
481 }