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