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