Blender V4.5
bmesh_py_types.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
8
9#include "BLI_math_geom.h"
10#include "BLI_math_matrix.h"
11#include "BLI_math_vector.h"
12#include "BLI_sort.h"
13#include "BLI_string_utils.hh"
14
15#include "DNA_material_types.h"
16#include "DNA_mesh_types.h"
17#include "DNA_object_types.h"
18
19#include "BKE_customdata.hh"
20#include "BKE_global.hh"
21#include "BKE_lib_id.hh"
22#include "BKE_mesh.h"
23#include "BKE_mesh_runtime.hh"
24#include "BKE_mesh_types.hh"
25#include "BKE_object.hh"
26
27#include "DEG_depsgraph.hh"
29
30#include "bmesh.hh"
31
32#include <Python.h>
33
34#include "../generic/python_compat.hh" /* IWYU pragma: keep. */
35
37
40
41#include "bmesh_py_types.hh" /* own include */
45
47
48/* Common Flags
49 * ************ */
50
51/* scene does not use BM_* flags. */
53 {1, "VERT"},
54 {2, "EDGE"},
55 {4, "FACE"},
56 {0, nullptr},
57};
58
60 {BM_VERT, "VERT"},
61 {BM_EDGE, "EDGE"},
62 {BM_FACE, "FACE"},
63 {0, nullptr},
64};
65
67 {BM_VERT, "VERT"},
68 {BM_LOOP, "EDGE"},
69 {BM_FACE, "FACE"},
70 {BM_LOOP, "LOOP"},
71 {0, nullptr},
72};
73
74#define BPY_BM_HFLAG_ALL_STR "('SELECT', 'HIDE', 'SEAM', 'SMOOTH', 'TAG')"
75
77 {BM_ELEM_SELECT, "SELECT"},
78 {BM_ELEM_HIDDEN, "HIDE"},
79 {BM_ELEM_SEAM, "SEAM"},
80 {BM_ELEM_SMOOTH, "SMOOTH"},
81 {BM_ELEM_TAG, "TAG"},
82 {0, nullptr},
83};
84
85/* py-type definitions
86 * ******************* */
87
88/* getseters
89 * ========= */
90
91/* bmesh elems
92 * ----------- */
93
95 /* Wrap. */
96 bpy_bm_elem_select_doc,
97 "Selected state of this element.\n"
98 "\n"
99 ":type: bool");
101 /* Wrap. */
102 bpy_bm_elem_hide_doc,
103 "Hidden state of this element.\n"
104 "\n"
105 ":type: bool");
107 /* Wrap. */
108 bpy_bm_elem_tag_doc,
109 "Generic attribute scripts can use for own logic\n"
110 "\n"
111 ":type: bool");
113 /* Wrap. */
114 bpy_bm_elem_smooth_doc,
115 "Smooth state of this element.\n"
116 "\n"
117 ":type: bool");
119 /* Wrap. */
120 bpy_bm_elem_seam_doc,
121 "Seam for UV unwrapping.\n"
122 "\n"
123 ":type: bool");
124
125static PyObject *bpy_bm_elem_hflag_get(BPy_BMElem *self, void *flag)
126{
127 const char hflag = char(POINTER_AS_INT(flag));
128
130
131 return PyBool_FromLong(BM_elem_flag_test(self->ele, hflag));
132}
133
134static int bpy_bm_elem_hflag_set(BPy_BMElem *self, PyObject *value, void *flag)
135{
136 const char hflag = char(POINTER_AS_INT(flag));
137 int param;
138
140
141 if ((param = PyC_Long_AsBool(value)) == -1) {
142 return -1;
143 }
144
145 if (hflag == BM_ELEM_SELECT) {
146 BM_elem_select_set(self->bm, self->ele, param);
147 }
148 else {
149 BM_elem_flag_set(self->ele, hflag, param);
150 }
151 return 0;
152}
153
155 /* Wrap. */
156 bpy_bm_elem_index_doc,
157 "Index of this element.\n"
158 "\n"
159 ":type: int\n"
160 "\n"
161 ".. note::\n"
162 "\n"
163 " This value is not necessarily valid, while editing the mesh it can become *dirty*.\n"
164 "\n"
165 " It's also possible to assign any number to this attribute for a scripts internal logic.\n"
166 "\n"
167 " To ensure the value is up to date - see :class:`BMElemSeq.index_update`.\n");
168static PyObject *bpy_bm_elem_index_get(BPy_BMElem *self, void * /*flag*/)
169{
171
172 return PyLong_FromLong(BM_elem_index_get(self->ele));
173}
174
175static int bpy_bm_elem_index_set(BPy_BMElem *self, PyObject *value, void * /*flag*/)
176{
177 int param;
178
180
181 if (((param = PyC_Long_AsI32(value)) == -1) && PyErr_Occurred()) {
182 /* error is set */
183 return -1;
184 }
185
186 BM_elem_index_set(self->ele, param); /* set_dirty! */
187
188 /* when setting the index assume its set invalid */
189 self->bm->elem_index_dirty |= self->ele->head.htype;
190
191 return 0;
192}
193
194/* type specific get/sets
195 * ---------------------- */
196
197/* Mesh
198 * ^^^^ */
199
200/* doc-strings for all uses of this function */
201
203 /* Wrap. */
204 bpy_bmvertseq_doc,
205 "This meshes vert sequence (read-only).\n"
206 "\n"
207 ":type: :class:`BMVertSeq`");
208static PyObject *bpy_bmvertseq_get(BPy_BMesh *self, void * /*closure*/)
209{
212}
213
215 /* Wrap. */
216 bpy_bmedgeseq_doc,
217 "This meshes edge sequence (read-only).\n"
218 "\n"
219 ":type: :class:`BMEdgeSeq`");
220static PyObject *bpy_bmedgeseq_get(BPy_BMesh *self, void * /*closure*/)
221{
224}
225
227 /* Wrap. */
228 bpy_bmfaceseq_doc,
229 "This meshes face sequence (read-only).\n"
230 "\n"
231 ":type: :class:`BMFaceSeq`");
232static PyObject *bpy_bmfaceseq_get(BPy_BMesh *self, void * /*closure*/)
233{
236}
237
239 /* Wrap. */
240 bpy_bmloopseq_doc,
241 "This meshes loops (read-only).\n"
242 "\n"
243 ":type: :class:`BMLoopSeq`\n"
244 "\n"
245 ".. note::\n"
246 "\n"
247 " Loops must be accessed via faces, this is only exposed for layer access.\n");
248static PyObject *bpy_bmloopseq_get(BPy_BMesh *self, void * /*closure*/)
249{
252}
253
254/* vert */
255PyDoc_STRVAR(bpy_bmvert_link_edges_doc,
256 "Edges connected to this vertex (read-only).\n"
257 "\n"
258 ":type: :class:`BMElemSeq` of :class:`BMEdge`");
259PyDoc_STRVAR(bpy_bmvert_link_faces_doc,
260 "Faces connected to this vertex (read-only).\n"
261 "\n"
262 ":type: :class:`BMElemSeq` of :class:`BMFace`");
263PyDoc_STRVAR(bpy_bmvert_link_loops_doc,
264 "Loops that use this vertex (read-only).\n"
265 "\n"
266 ":type: :class:`BMElemSeq` of :class:`BMLoop`");
267/* edge */
269 /* Wrap. */
270 bpy_bmedge_verts_doc,
271 "Verts this edge uses (always 2), (read-only).\n"
272 "\n"
273 ":type: :class:`BMElemSeq` of "
274 ":class:`BMVert`");
275PyDoc_STRVAR(bpy_bmedge_link_faces_doc,
276 "Faces connected to this edge, (read-only).\n"
277 "\n"
278 ":type: :class:`BMElemSeq` of :class:`BMFace`");
279PyDoc_STRVAR(bpy_bmedge_link_loops_doc,
280 "Loops connected to this edge, (read-only).\n"
281 "\n"
282 ":type: :class:`BMElemSeq` of :class:`BMLoop`");
283/* face */
285 /* Wrap. */
286 bpy_bmface_verts_doc,
287 "Verts of this face, (read-only).\n"
288 "\n"
289 ":type: :class:`BMElemSeq` of :class:`BMVert`");
291 /* Wrap. */
292 bpy_bmface_edges_doc,
293 "Edges of this face, (read-only).\n"
294 "\n"
295 ":type: :class:`BMElemSeq` of :class:`BMEdge`");
297 /* Wrap. */
298 bpy_bmface_loops_doc,
299 "Loops of this face, (read-only).\n"
300 "\n"
301 ":type: :class:`BMElemSeq` of :class:`BMLoop`");
302/* loop */
303PyDoc_STRVAR(bpy_bmloops_link_loops_doc,
304 "Loops connected to this loop, (read-only).\n"
305 "\n"
306 ":type: :class:`BMElemSeq` of :class:`BMLoop`");
307
313
315 /* Wrap. */
316 bpy_bm_is_valid_doc,
317 "True when this element is valid (hasn't been removed).\n"
318 "\n"
319 ":type: bool");
320static PyObject *bpy_bm_is_valid_get(BPy_BMGeneric *self, void * /*closure*/)
321{
322 return PyBool_FromLong(BPY_BM_IS_VALID(self));
323}
324
325PyDoc_STRVAR(bpy_bmesh_is_wrapped_doc,
326 "True when this mesh is owned by blender (typically the editmode BMesh).\n"
327 "\n"
328 ":type: bool");
329static PyObject *bpy_bmesh_is_wrapped_get(BPy_BMesh *self, void * /*closure*/)
330{
332
333 return PyBool_FromLong(self->flag & BPY_BMFLAG_IS_WRAPPED);
334}
335
337 /* Wrap. */
338 bpy_bmesh_select_mode_doc,
339 "The selection mode, values can be {'VERT', 'EDGE', 'FACE'}, can't be assigned an empty set.\n"
340 "\n"
341 ":type: set");
342static PyObject *bpy_bmesh_select_mode_get(BPy_BMesh *self, void * /*closure*/)
343{
345
347}
348
349static int bpy_bmesh_select_mode_set(BPy_BMesh *self, PyObject *value, void * /*closure*/)
350{
351 int flag = 0;
353
354 if (PyC_FlagSet_ToBitfield(bpy_bm_scene_vert_edge_face_flags, value, &flag, "bm.select_mode") ==
355 -1)
356 {
357 return -1;
358 }
359 if (flag == 0) {
360 PyErr_SetString(PyExc_TypeError, "bm.select_mode: can't assign an empty value");
361 return -1;
362 }
363
364 self->bm->selectmode = flag;
365 return 0;
366}
367
369 /* Wrap. */
370 bpy_bmesh_select_history_doc,
371 "Sequence of selected items (the last is displayed as active).\n"
372 "\n"
373 ":type: "
374 ":class:`BMEditSelSeq`");
375static PyObject *bpy_bmesh_select_history_get(BPy_BMesh *self, void * /*closure*/)
376{
378
380}
381
382static int bpy_bmesh_select_history_set(BPy_BMesh *self, PyObject *value, void * /*closure*/)
383{
385
386 return BPy_BMEditSel_Assign(self, value);
387}
388
389/* Vert
390 * ^^^^ */
391
393 /* Wrap. */
394 bpy_bmvert_co_doc,
395 "The coordinates for this vertex as a 3D, wrapped vector.\n"
396 "\n"
397 ":type: "
398 ":class:`mathutils.Vector`");
399static PyObject *bpy_bmvert_co_get(BPy_BMVert *self, void * /*closure*/)
400{
402 return Vector_CreatePyObject_wrap(self->v->co, 3, nullptr);
403}
404
405static int bpy_bmvert_co_set(BPy_BMVert *self, PyObject *value, void * /*closure*/)
406{
408
409 if (mathutils_array_parse(self->v->co, 3, 3, value, "BMVert.co") != -1) {
410 return 0;
411 }
412
413 return -1;
414}
415
416PyDoc_STRVAR(bpy_bmvert_normal_doc,
417 "The normal for this vertex as a 3D, wrapped vector.\n"
418 "\n"
419 ":type: :class:`mathutils.Vector`");
420static PyObject *bpy_bmvert_normal_get(BPy_BMVert *self, void * /*closure*/)
421{
423 return Vector_CreatePyObject_wrap(self->v->no, 3, nullptr);
424}
425
426static int bpy_bmvert_normal_set(BPy_BMVert *self, PyObject *value, void * /*closure*/)
427{
429
430 if (mathutils_array_parse(self->v->no, 3, 3, value, "BMVert.normal") != -1) {
431 return 0;
432 }
433
434 return -1;
435}
436
438 /* Wrap. */
439 bpy_bmvert_is_manifold_doc,
440 "True when this vertex is manifold (read-only).\n"
441 "\n"
442 ":type: bool");
443static PyObject *bpy_bmvert_is_manifold_get(BPy_BMVert *self, void * /*closure*/)
444{
446 return PyBool_FromLong(BM_vert_is_manifold(self->v));
447}
448
450 /* Wrap. */
451 bpy_bmvert_is_wire_doc,
452 "True when this vertex is not connected to any faces (read-only).\n"
453 "\n"
454 ":type: bool");
455static PyObject *bpy_bmvert_is_wire_get(BPy_BMVert *self, void * /*closure*/)
456{
458 return PyBool_FromLong(BM_vert_is_wire(self->v));
459}
460
461PyDoc_STRVAR(bpy_bmvert_is_boundary_doc,
462 "True when this vertex is connected to boundary edges (read-only).\n"
463 "\n"
464 ":type: bool");
465static PyObject *bpy_bmvert_is_boundary_get(BPy_BMVert *self, void * /*closure*/)
466{
468 return PyBool_FromLong(BM_vert_is_boundary(self->v));
469}
470
471/* Edge
472 * ^^^^ */
473
475 /* Wrap. */
476 bpy_bmedge_is_manifold_doc,
477 "True when this edge is manifold (read-only).\n"
478 "\n"
479 ":type: bool");
480static PyObject *bpy_bmedge_is_manifold_get(BPy_BMEdge *self, void * /*closure*/)
481{
483 return PyBool_FromLong(BM_edge_is_manifold(self->e));
484}
485
487 /* Wrap. */
488 bpy_bmedge_is_contiguous_doc,
489 "True when this edge is manifold, between two faces with the same winding "
490 "(read-only).\n"
491 "\n"
492 ":type: bool");
493static PyObject *bpy_bmedge_is_contiguous_get(BPy_BMEdge *self, void * /*closure*/)
494{
496 return PyBool_FromLong(BM_edge_is_contiguous(self->e));
497}
498
500 /* Wrap. */
501 bpy_bmedge_is_convex_doc,
502 "True when this edge joins two convex faces, depends on a valid face normal (read-only).\n"
503 "\n"
504 ":type: bool");
505static PyObject *bpy_bmedge_is_convex_get(BPy_BMEdge *self, void * /*closure*/)
506{
508 return PyBool_FromLong(BM_edge_is_convex(self->e));
509}
510
512 /* Wrap. */
513 bpy_bmedge_is_wire_doc,
514 "True when this edge is not connected to any faces (read-only).\n"
515 "\n"
516 ":type: bool");
517static PyObject *bpy_bmedge_is_wire_get(BPy_BMEdge *self, void * /*closure*/)
518{
520 return PyBool_FromLong(BM_edge_is_wire(self->e));
521}
522
524 /* Wrap. */
525 bpy_bmedge_is_boundary_doc,
526 "True when this edge is at the boundary of a face (read-only).\n"
527 "\n"
528 ":type: bool");
529static PyObject *bpy_bmedge_is_boundary_get(BPy_BMEdge *self, void * /*closure*/)
530{
532 return PyBool_FromLong(BM_edge_is_boundary(self->e));
533}
534
535/* Face
536 * ^^^^ */
537
538PyDoc_STRVAR(bpy_bmface_normal_doc,
539 "The normal for this face as a 3D, wrapped vector.\n"
540 "\n"
541 ":type: :class:`mathutils.Vector`");
542static PyObject *bpy_bmface_normal_get(BPy_BMFace *self, void * /*closure*/)
543{
545 return Vector_CreatePyObject_wrap(self->f->no, 3, nullptr);
546}
547
548static int bpy_bmface_normal_set(BPy_BMFace *self, PyObject *value, void * /*closure*/)
549{
551
552 if (mathutils_array_parse(self->f->no, 3, 3, value, "BMFace.normal") != -1) {
553 return 0;
554 }
555
556 return -1;
557}
558
560 /* Wrap. */
561 bpy_bmface_material_index_doc,
562 "The face's material index.\n"
563 "\n"
564 ":type: int");
565static PyObject *bpy_bmface_material_index_get(BPy_BMFace *self, void * /*closure*/)
566{
568 return PyLong_FromLong(self->f->mat_nr);
569}
570
571static int bpy_bmface_material_index_set(BPy_BMFace *self, PyObject *value, void * /*closure*/)
572{
573 int param;
574
576
577 if (((param = PyC_Long_AsI32(value)) == -1) && PyErr_Occurred()) {
578 /* error is set */
579 return -1;
580 }
581
582 if ((param < 0) || (param > MAXMAT)) {
583 /* normally we clamp but in this case raise an error */
584 PyErr_SetString(PyExc_ValueError, "material index outside of usable range (0 - 32766)");
585 return -1;
586 }
587
588 self->f->mat_nr = short(param);
589 return 0;
590}
591
592/* Loop
593 * ^^^^ */
594
596 /* Wrap. */
597 bpy_bmloop_vert_doc,
598 "The loop's vertex (read-only).\n"
599 "\n"
600 ":type: :class:`BMVert`");
601static PyObject *bpy_bmloop_vert_get(BPy_BMLoop *self, void * /*closure*/)
602{
604 return BPy_BMVert_CreatePyObject(self->bm, self->l->v);
605}
606
607PyDoc_STRVAR(bpy_bmloop_edge_doc,
608 "The loop's edge (between this loop and the next), (read-only).\n"
609 "\n"
610 ":type: :class:`BMEdge`");
611static PyObject *bpy_bmloop_edge_get(BPy_BMLoop *self, void * /*closure*/)
612{
614 return BPy_BMEdge_CreatePyObject(self->bm, self->l->e);
615}
616
618 /* Wrap. */
619 bpy_bmloop_face_doc,
620 "The face this loop makes (read-only).\n"
621 "\n"
622 ":type: :class:`BMFace`");
623static PyObject *bpy_bmloop_face_get(BPy_BMLoop *self, void * /*closure*/)
624{
626 return BPy_BMFace_CreatePyObject(self->bm, self->l->f);
627}
628
630 /* Wrap. */
631 bpy_bmloop_link_loop_next_doc,
632 "The next face corner (read-only).\n"
633 "\n"
634 ":type: :class:`BMLoop`");
635static PyObject *bpy_bmloop_link_loop_next_get(BPy_BMLoop *self, void * /*closure*/)
636{
638 return BPy_BMLoop_CreatePyObject(self->bm, self->l->next);
639}
640
642 /* Wrap. */
643 bpy_bmloop_link_loop_prev_doc,
644 "The previous face corner (read-only).\n"
645 "\n"
646 ":type: :class:`BMLoop`");
647static PyObject *bpy_bmloop_link_loop_prev_get(BPy_BMLoop *self, void * /*closure*/)
648{
650 return BPy_BMLoop_CreatePyObject(self->bm, self->l->prev);
651}
652
654 /* Wrap. */
655 bpy_bmloop_link_loop_radial_next_doc,
656 "The next loop around the edge (read-only).\n"
657 "\n"
658 ":type: :class:`BMLoop`");
659static PyObject *bpy_bmloop_link_loop_radial_next_get(BPy_BMLoop *self, void * /*closure*/)
660{
662 return BPy_BMLoop_CreatePyObject(self->bm, self->l->radial_next);
663}
664
666 /* Wrap. */
667 bpy_bmloop_link_loop_radial_prev_doc,
668 "The previous loop around the edge (read-only).\n"
669 "\n"
670 ":type: :class:`BMLoop`");
671static PyObject *bpy_bmloop_link_loop_radial_prev_get(BPy_BMLoop *self, void * /*closure*/)
672{
674 return BPy_BMLoop_CreatePyObject(self->bm, self->l->radial_prev);
675}
676
678 /* Wrap. */
679 bpy_bmloop_is_convex_doc,
680 "True when this loop is at the convex corner of a face, depends on a valid face "
681 "normal (read-only).\n"
682 "\n"
683 ":type: bool");
684static PyObject *bpy_bmloop_is_convex_get(BPy_BMLoop *self, void * /*closure*/)
685{
687 return PyBool_FromLong(BM_loop_is_convex(self->l));
688}
689
690/* ElemSeq
691 * ^^^^^^^ */
692
693/* NOTE: use for bmvert/edge/face/loop seq's use these, not bmelemseq directly. */
695 /* Wrap. */
696 bpy_bmelemseq_layers_vert_doc,
697 "custom-data layers (read-only).\n"
698 "\n"
699 ":type: :class:`BMLayerAccessVert`");
701 /* Wrap. */
702 bpy_bmelemseq_layers_edge_doc,
703 "custom-data layers (read-only).\n"
704 "\n"
705 ":type: :class:`BMLayerAccessEdge`");
707 /* Wrap. */
708 bpy_bmelemseq_layers_face_doc,
709 "custom-data layers (read-only).\n"
710 "\n"
711 ":type: :class:`BMLayerAccessFace`");
713 /* Wrap. */
714 bpy_bmelemseq_layers_loop_doc,
715 "custom-data layers (read-only).\n"
716 "\n"
717 ":type: :class:`BMLayerAccessLoop`");
718static PyObject *bpy_bmelemseq_layers_get(BPy_BMElemSeq *self, void *htype)
719{
721
723}
724
725/* FaceSeq
726 * ^^^^^^^ */
727
729 /* Wrap. */
730 bpy_bmfaceseq_active_doc,
731 "active face.\n"
732 "\n"
733 ":type: :class:`BMFace` or None");
734static PyObject *bpy_bmfaceseq_active_get(BPy_BMElemSeq *self, void * /*closure*/)
735{
736 BMesh *bm = self->bm;
738
739 if (bm->act_face) {
740 return BPy_BMElem_CreatePyObject(bm, (BMHeader *)bm->act_face);
741 }
742
743 Py_RETURN_NONE;
744}
745
746static int bpy_bmfaceseq_active_set(BPy_BMElem *self, PyObject *value, void * /*closure*/)
747{
748 BMesh *bm = self->bm;
749 if (value == Py_None) {
750 bm->act_face = nullptr;
751 return 0;
752 }
753 if (BPy_BMFace_Check(value)) {
754 BPY_BM_CHECK_SOURCE_INT(bm, "faces.active = f", value);
755
756 bm->act_face = ((BPy_BMFace *)value)->f;
757 return 0;
758 }
759
760 PyErr_Format(PyExc_TypeError,
761 "faces.active = f: expected BMFace or None, not %.200s",
762 Py_TYPE(value)->tp_name);
763 return -1;
764}
765
766static PyGetSetDef bpy_bmesh_getseters[] = {
767 {"verts", (getter)bpy_bmvertseq_get, (setter) nullptr, bpy_bmvertseq_doc, nullptr},
768 {"edges", (getter)bpy_bmedgeseq_get, (setter) nullptr, bpy_bmedgeseq_doc, nullptr},
769 {"faces", (getter)bpy_bmfaceseq_get, (setter) nullptr, bpy_bmfaceseq_doc, nullptr},
770 {"loops", (getter)bpy_bmloopseq_get, (setter) nullptr, bpy_bmloopseq_doc, nullptr},
771 {"select_mode",
774 bpy_bmesh_select_mode_doc,
775 nullptr},
776
777 {"select_history",
780 bpy_bmesh_select_history_doc,
781 nullptr},
782
783 /* readonly checks */
784 {"is_wrapped",
786 (setter) nullptr,
787 bpy_bmesh_is_wrapped_doc,
788 nullptr}, /* as with mathutils */
789 {"is_valid", (getter)bpy_bm_is_valid_get, (setter) nullptr, bpy_bm_is_valid_doc, nullptr},
790
791 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
792};
793
794static PyGetSetDef bpy_bmvert_getseters[] = {
795 /* generic */
796 {"select",
797 (getter)bpy_bm_elem_hflag_get,
798 (setter)bpy_bm_elem_hflag_set,
799 bpy_bm_elem_select_doc,
800 (void *)BM_ELEM_SELECT},
801 {"hide",
802 (getter)bpy_bm_elem_hflag_get,
803 (setter)bpy_bm_elem_hflag_set,
804 bpy_bm_elem_hide_doc,
805 (void *)BM_ELEM_HIDDEN},
806 {"tag",
807 (getter)bpy_bm_elem_hflag_get,
808 (setter)bpy_bm_elem_hflag_set,
809 bpy_bm_elem_tag_doc,
810 (void *)BM_ELEM_TAG},
811 {"index",
812 (getter)bpy_bm_elem_index_get,
813 (setter)bpy_bm_elem_index_set,
814 bpy_bm_elem_index_doc,
815 nullptr},
816
817 {"co", (getter)bpy_bmvert_co_get, (setter)bpy_bmvert_co_set, bpy_bmvert_co_doc, nullptr},
818 {"normal",
819 (getter)bpy_bmvert_normal_get,
820 (setter)bpy_bmvert_normal_set,
821 bpy_bmvert_normal_doc,
822 nullptr},
823
824 /* connectivity data */
825 {"link_edges",
827 (setter) nullptr,
828 bpy_bmvert_link_edges_doc,
829 (void *)BM_EDGES_OF_VERT},
830 {"link_faces",
832 (setter) nullptr,
833 bpy_bmvert_link_faces_doc,
834 (void *)BM_FACES_OF_VERT},
835 {"link_loops",
837 (setter) nullptr,
838 bpy_bmvert_link_loops_doc,
839 (void *)BM_LOOPS_OF_VERT},
840
841 /* readonly checks */
842 {"is_manifold",
844 (setter) nullptr,
845 bpy_bmvert_is_manifold_doc,
846 nullptr},
847 {"is_wire", (getter)bpy_bmvert_is_wire_get, (setter) nullptr, bpy_bmvert_is_wire_doc, nullptr},
848 {"is_boundary",
850 (setter) nullptr,
851 bpy_bmvert_is_boundary_doc,
852 nullptr},
853 {"is_valid", (getter)bpy_bm_is_valid_get, (setter) nullptr, bpy_bm_is_valid_doc, nullptr},
854
855 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
856};
857
858static PyGetSetDef bpy_bmedge_getseters[] = {
859 /* generic */
860 {"select",
861 (getter)bpy_bm_elem_hflag_get,
862 (setter)bpy_bm_elem_hflag_set,
863 bpy_bm_elem_select_doc,
864 (void *)BM_ELEM_SELECT},
865 {"hide",
866 (getter)bpy_bm_elem_hflag_get,
867 (setter)bpy_bm_elem_hflag_set,
868 bpy_bm_elem_hide_doc,
869 (void *)BM_ELEM_HIDDEN},
870 {"tag",
871 (getter)bpy_bm_elem_hflag_get,
872 (setter)bpy_bm_elem_hflag_set,
873 bpy_bm_elem_tag_doc,
874 (void *)BM_ELEM_TAG},
875 {"index",
876 (getter)bpy_bm_elem_index_get,
877 (setter)bpy_bm_elem_index_set,
878 bpy_bm_elem_index_doc,
879 nullptr},
880
881 {"smooth",
882 (getter)bpy_bm_elem_hflag_get,
883 (setter)bpy_bm_elem_hflag_set,
884 bpy_bm_elem_smooth_doc,
885 (void *)BM_ELEM_SMOOTH},
886 {"seam",
887 (getter)bpy_bm_elem_hflag_get,
888 (setter)bpy_bm_elem_hflag_set,
889 bpy_bm_elem_seam_doc,
890 (void *)BM_ELEM_SEAM},
891
892 /* connectivity data */
893 {"verts",
895 (setter) nullptr,
896 bpy_bmedge_verts_doc,
897 (void *)BM_VERTS_OF_EDGE},
898
899 {"link_faces",
901 (setter) nullptr,
902 bpy_bmedge_link_faces_doc,
903 (void *)BM_FACES_OF_EDGE},
904 {"link_loops",
906 (setter) nullptr,
907 bpy_bmedge_link_loops_doc,
908 (void *)BM_LOOPS_OF_EDGE},
909
910 /* readonly checks */
911 {"is_manifold",
913 (setter) nullptr,
914 bpy_bmedge_is_manifold_doc,
915 nullptr},
916 {"is_contiguous",
918 (setter) nullptr,
919 bpy_bmedge_is_contiguous_doc,
920 nullptr},
921 {"is_convex",
923 (setter) nullptr,
924 bpy_bmedge_is_convex_doc,
925 nullptr},
926 {"is_wire", (getter)bpy_bmedge_is_wire_get, (setter) nullptr, bpy_bmedge_is_wire_doc, nullptr},
927 {"is_boundary",
929 (setter) nullptr,
930 bpy_bmedge_is_boundary_doc,
931 nullptr},
932 {"is_valid", (getter)bpy_bm_is_valid_get, (setter) nullptr, bpy_bm_is_valid_doc, nullptr},
933
934 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
935};
936
937static PyGetSetDef bpy_bmface_getseters[] = {
938 /* generic */
939 {"select",
940 (getter)bpy_bm_elem_hflag_get,
941 (setter)bpy_bm_elem_hflag_set,
942 bpy_bm_elem_select_doc,
943 (void *)BM_ELEM_SELECT},
944 {"hide",
945 (getter)bpy_bm_elem_hflag_get,
946 (setter)bpy_bm_elem_hflag_set,
947 bpy_bm_elem_hide_doc,
948 (void *)BM_ELEM_HIDDEN},
949 {"tag",
950 (getter)bpy_bm_elem_hflag_get,
951 (setter)bpy_bm_elem_hflag_set,
952 bpy_bm_elem_tag_doc,
953 (void *)BM_ELEM_TAG},
954 {"index",
955 (getter)bpy_bm_elem_index_get,
956 (setter)bpy_bm_elem_index_set,
957 bpy_bm_elem_index_doc,
958 nullptr},
959
960 {"smooth",
961 (getter)bpy_bm_elem_hflag_get,
962 (setter)bpy_bm_elem_hflag_set,
963 bpy_bm_elem_smooth_doc,
964 (void *)BM_ELEM_SMOOTH},
965
966 {"normal",
967 (getter)bpy_bmface_normal_get,
968 (setter)bpy_bmface_normal_set,
969 bpy_bmface_normal_doc,
970 nullptr},
971
972 {"material_index",
975 bpy_bmface_material_index_doc,
976 nullptr},
977
978 /* connectivity data */
979 {"verts",
981 (setter) nullptr,
982 bpy_bmface_verts_doc,
983 (void *)BM_VERTS_OF_FACE},
984 {"edges",
986 (setter) nullptr,
987 bpy_bmface_edges_doc,
988 (void *)BM_EDGES_OF_FACE},
989 {"loops",
991 (setter) nullptr,
992 bpy_bmface_loops_doc,
993 (void *)BM_LOOPS_OF_FACE},
994
995 /* readonly checks */
996 {"is_valid", (getter)bpy_bm_is_valid_get, (setter) nullptr, bpy_bm_is_valid_doc, nullptr},
997
998 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
999};
1000
1001static PyGetSetDef bpy_bmloop_getseters[] = {
1002/* generic */
1003/* flags are available but not used for loops. */
1004#if 0
1005 {"select",
1006 (getter)bpy_bm_elem_hflag_get,
1007 (setter)bpy_bm_elem_hflag_set,
1008 bpy_bm_elem_select_doc,
1009 (void *)BM_ELEM_SELECT},
1010 {"hide",
1011 (getter)bpy_bm_elem_hflag_get,
1012 (setter)bpy_bm_elem_hflag_set,
1013 bpy_bm_elem_hide_doc,
1014 (void *)BM_ELEM_HIDDEN},
1015#endif
1016 {"tag",
1017 (getter)bpy_bm_elem_hflag_get,
1018 (setter)bpy_bm_elem_hflag_set,
1019 bpy_bm_elem_tag_doc,
1020 (void *)BM_ELEM_TAG},
1021 {"index",
1022 (getter)bpy_bm_elem_index_get,
1023 (setter)bpy_bm_elem_index_set,
1024 bpy_bm_elem_index_doc,
1025 nullptr},
1026
1027 {"vert", (getter)bpy_bmloop_vert_get, (setter) nullptr, bpy_bmloop_vert_doc, nullptr},
1028 {"edge", (getter)bpy_bmloop_edge_get, (setter) nullptr, bpy_bmloop_edge_doc, nullptr},
1029 {"face", (getter)bpy_bmloop_face_get, (setter) nullptr, bpy_bmloop_face_doc, nullptr},
1030
1031 /* connectivity data */
1032 {"link_loops",
1033 (getter)bpy_bmelemseq_elem_get,
1034 (setter) nullptr,
1035 bpy_bmloops_link_loops_doc,
1036 (void *)BM_LOOPS_OF_LOOP},
1037 {"link_loop_next",
1039 (setter) nullptr,
1040 bpy_bmloop_link_loop_next_doc,
1041 nullptr},
1042 {"link_loop_prev",
1044 (setter) nullptr,
1045 bpy_bmloop_link_loop_prev_doc,
1046 nullptr},
1047 {"link_loop_radial_next",
1049 (setter) nullptr,
1050 bpy_bmloop_link_loop_radial_next_doc,
1051 nullptr},
1052 {"link_loop_radial_prev",
1054 (setter) nullptr,
1055 bpy_bmloop_link_loop_radial_prev_doc,
1056 nullptr},
1057
1058 /* readonly checks */
1059 {"is_convex",
1061 (setter) nullptr,
1062 bpy_bmloop_is_convex_doc,
1063 nullptr},
1064 {"is_valid", (getter)bpy_bm_is_valid_get, (setter) nullptr, bpy_bm_is_valid_doc, nullptr},
1065
1066 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
1067};
1068
1069static PyGetSetDef bpy_bmvertseq_getseters[] = {
1070 {"layers",
1072 (setter) nullptr,
1073 bpy_bmelemseq_layers_vert_doc,
1074 (void *)BM_VERT},
1075 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
1076};
1077static PyGetSetDef bpy_bmedgeseq_getseters[] = {
1078 {"layers",
1080 (setter) nullptr,
1081 bpy_bmelemseq_layers_edge_doc,
1082 (void *)BM_EDGE},
1083 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
1084};
1085static PyGetSetDef bpy_bmfaceseq_getseters[] = {
1086 {"layers",
1088 (setter) nullptr,
1089 bpy_bmelemseq_layers_face_doc,
1090 (void *)BM_FACE},
1091 /* face only */
1092 {"active",
1095 bpy_bmfaceseq_active_doc,
1096 nullptr},
1097 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
1098};
1099static PyGetSetDef bpy_bmloopseq_getseters[] = {
1100 {"layers",
1102 (setter) nullptr,
1103 bpy_bmelemseq_layers_loop_doc,
1104 (void *)BM_LOOP},
1105 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
1106};
1107
1108/* Methods
1109 * ======= */
1110
1111/* Mesh
1112 * ---- */
1113
1115 /* Wrap. */
1116 bpy_bmesh_copy_doc,
1117 ".. method:: copy()\n"
1118 "\n"
1119 " :return: A copy of this BMesh.\n"
1120 " :rtype: :class:`BMesh`\n");
1122{
1123 BMesh *bm;
1124 BMesh *bm_copy;
1125
1127
1128 bm = self->bm;
1129
1130 bm_copy = BM_mesh_copy(bm);
1131
1132 if (bm_copy) {
1134 }
1135
1136 PyErr_SetString(PyExc_SystemError, "Unable to copy BMesh, internal error");
1137 return nullptr;
1138}
1139
1141 /* Wrap. */
1142 bpy_bmesh_clear_doc,
1143 ".. method:: clear()\n"
1144 "\n"
1145 " Clear all mesh data.\n");
1147{
1148 BMesh *bm;
1149
1151
1152 bm = self->bm;
1153
1155
1156 Py_RETURN_NONE;
1157}
1158
1160 /* Wrap. */
1161 bpy_bmesh_free_doc,
1162 ".. method:: free()\n"
1163 "\n"
1164 " Explicitly free the BMesh data from memory, causing exceptions on further access.\n"
1165 "\n"
1166 " .. note::\n"
1167 "\n"
1168 " The BMesh is freed automatically, typically when the script finishes executing.\n"
1169 " However in some cases its hard to predict when this will be and its useful to\n"
1170 " explicitly free the data.\n");
1172{
1173 if (self->bm) {
1174 BMesh *bm = self->bm;
1175
1177
1178 if (self->flag & BPY_BMFLAG_IS_WRAPPED) {
1179 /* Ensure further access doesn't return this invalid object, see: #105715. */
1180 bm->py_handle = nullptr;
1181 }
1182 else {
1184 }
1185
1187 }
1188
1189 Py_RETURN_NONE;
1190}
1191
1193 /* Wrap. */
1194 bpy_bmesh_to_mesh_doc,
1195 ".. method:: to_mesh(mesh)\n"
1196 "\n"
1197 " Writes this BMesh data into an existing Mesh datablock.\n"
1198 "\n"
1199 " :arg mesh: The mesh data to write into.\n"
1200 " :type mesh: :class:`Mesh`\n");
1201static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
1202{
1203 PyObject *py_mesh;
1204 Mesh *mesh;
1205 BMesh *bm;
1206
1208
1209 if (!PyArg_ParseTuple(args, "O:to_mesh", &py_mesh) ||
1210 !(mesh = static_cast<Mesh *>(PyC_RNA_AsPointer(py_mesh, "Mesh"))))
1211 {
1212 return nullptr;
1213 }
1214
1215 /* we could allow this but its almost certainly _not_ what script authors want */
1216 if (mesh->runtime->edit_mesh) {
1217 PyErr_Format(PyExc_ValueError, "to_mesh(): Mesh '%s' is in editmode", mesh->id.name + 2);
1218 return nullptr;
1219 }
1220
1221 bm = self->bm;
1222
1223 Main *bmain = nullptr;
1225 params.update_shapekey_indices = true;
1226 if (mesh->id.tag & ID_TAG_NO_MAIN) {
1227 /* Mesh might be coming from a self-contained source like object.to_mesh(). No need to remap
1228 * anything in this case. */
1229 }
1230 else {
1232 bmain = G_MAIN; /* XXX UGLY! */
1233 params.calc_object_remap = true;
1234 }
1235
1236 BM_mesh_bm_to_me(bmain, bm, mesh, &params);
1237
1238 /* We could have the user do this but if they forget blender can easy crash
1239 * since the references arrays for the objects evaluated meshes are now invalid. */
1241
1242 Py_RETURN_NONE;
1243}
1244
1246 /* Wrap. */
1247 bpy_bmesh_from_object_doc,
1248 ".. method:: from_object(object, depsgraph, cage=False, face_normals=True, "
1249 "vertex_normals=True)\n"
1250 "\n"
1251 " Initialize this bmesh from existing object data-block (only meshes are currently "
1252 "supported).\n"
1253 "\n"
1254 " :arg object: The object data to load.\n"
1255 " :type object: :class:`Object`\n"
1256 " :type depsgraph: :class:`Depsgraph`\n"
1257 " :arg cage: Get the mesh as a deformed cage.\n"
1258 " :type cage: bool\n"
1259 " :arg face_normals: Calculate face normals.\n"
1260 " :type face_normals: bool\n"
1261 " :arg vertex_normals: Calculate vertex normals.\n"
1262 " :type vertex_normals: bool\n");
1263static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw)
1264{
1265 static const char *kwlist[] = {
1266 "object", "depsgraph", "cage", "face_normals", "vertex_normals", nullptr};
1267 PyObject *py_object;
1268 PyObject *py_depsgraph;
1269 Object *ob, *ob_eval;
1270 Depsgraph *depsgraph;
1271 Scene *scene_eval;
1272 const Mesh *mesh_eval;
1273 BMesh *bm;
1274 bool use_cage = false;
1275 bool use_fnorm = true;
1276 bool use_vert_normal = true;
1277 const CustomData_MeshMasks data_masks = CD_MASK_BMESH;
1278
1280
1281 if (!PyArg_ParseTupleAndKeywords(args,
1282 kw,
1283 "OO|$O&O&O&:from_object",
1284 (char **)kwlist,
1285 &py_object,
1286 &py_depsgraph,
1288 &use_cage,
1290 &use_fnorm,
1292 &use_vert_normal) ||
1293 !(ob = static_cast<Object *>(PyC_RNA_AsPointer(py_object, "Object"))) ||
1294 !(depsgraph = static_cast<Depsgraph *>(PyC_RNA_AsPointer(py_depsgraph, "Depsgraph"))))
1295 {
1296 return nullptr;
1297 }
1298
1299 if (ob->type != OB_MESH) {
1300 PyErr_SetString(PyExc_ValueError,
1301 "from_object(...): currently only mesh objects are supported");
1302 return nullptr;
1303 }
1304
1305 const bool use_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
1306 scene_eval = DEG_get_evaluated_scene(depsgraph);
1307 ob_eval = DEG_get_evaluated(depsgraph, ob);
1308 bool need_free = false;
1309
1310 /* Write the display mesh into the dummy mesh */
1311 if (use_render) {
1312 if (use_cage) {
1313 PyErr_SetString(PyExc_ValueError,
1314 "from_object(...): cage arg is unsupported when dependency graph "
1315 "evaluation mode is RENDER");
1316 return nullptr;
1317 }
1318
1319 mesh_eval = BKE_mesh_new_from_object(depsgraph, ob_eval, true, false, true);
1320 need_free = true;
1321 }
1322 else {
1323 if (use_cage) {
1324 mesh_eval = blender::bke::mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &data_masks);
1325 }
1326 else {
1327 mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
1328 }
1329 }
1330
1331 if (mesh_eval == nullptr) {
1332 PyErr_Format(PyExc_ValueError,
1333 "from_object(...): Object '%s' has no usable mesh data",
1334 ob->id.name + 2);
1335 return nullptr;
1336 }
1337
1338 bm = self->bm;
1339
1341 params.calc_face_normal = use_fnorm;
1342 params.calc_vert_normal = use_vert_normal;
1343 BM_mesh_bm_from_me(bm, mesh_eval, &params);
1344
1345 if (need_free) {
1346 BKE_id_free(nullptr, (Mesh *)mesh_eval);
1347 }
1348
1349 Py_RETURN_NONE;
1350}
1351
1353 /* Wrap. */
1354 bpy_bmesh_from_mesh_doc,
1355 ".. method:: from_mesh(mesh, face_normals=True, vertex_normals=True, use_shape_key=False, "
1356 "shape_key_index=0)\n"
1357 "\n"
1358 " Initialize this bmesh from existing mesh datablock.\n"
1359 "\n"
1360 " :arg mesh: The mesh data to load.\n"
1361 " :type mesh: :class:`Mesh`\n"
1362 " :type face_normals: bool\n"
1363 " :type vertex_normals: bool\n"
1364 " :arg use_shape_key: Use the locations from a shape key.\n"
1365 " :type use_shape_key: bool\n"
1366 " :arg shape_key_index: The shape key index to use.\n"
1367 " :type shape_key_index: int\n"
1368 "\n"
1369 " .. note::\n"
1370 "\n"
1371 " Multiple calls can be used to join multiple meshes.\n"
1372 "\n"
1373 " Custom-data layers are only copied from ``mesh`` on initialization.\n"
1374 " Further calls will copy custom-data to matching layers, layers missing on the target "
1375 "mesh won't be added.\n");
1376static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw)
1377{
1378 static const char *kwlist[] = {
1379 "mesh", "face_normals", "vertex_normals", "use_shape_key", "shape_key_index", nullptr};
1380 BMesh *bm;
1381 PyObject *py_mesh;
1382 Mesh *mesh;
1383 bool use_fnorm = true;
1384 bool use_vert_normal = true;
1385 bool use_shape_key = false;
1386 int shape_key_index = 0;
1387
1389
1390 if (!PyArg_ParseTupleAndKeywords(args,
1391 kw,
1392 "O|$O&O&O&i:from_mesh",
1393 (char **)kwlist,
1394 &py_mesh,
1396 &use_fnorm,
1398 &use_vert_normal,
1400 &use_shape_key,
1401 &shape_key_index) ||
1402 !(mesh = static_cast<Mesh *>(PyC_RNA_AsPointer(py_mesh, "Mesh"))))
1403 {
1404 return nullptr;
1405 }
1406
1407 bm = self->bm;
1408
1410 params.calc_face_normal = use_fnorm;
1411 params.calc_vert_normal = use_vert_normal;
1412 params.use_shapekey = use_shape_key;
1413 params.active_shapekey = shape_key_index + 1;
1414 BM_mesh_bm_from_me(bm, mesh, &params);
1415
1416 Py_RETURN_NONE;
1417}
1418
1420 /* Wrap. */
1421 bpy_bmesh_select_flush_mode_doc,
1422 ".. method:: select_flush_mode()\n"
1423 "\n"
1424 " flush selection based on the current mode current :class:`BMesh.select_mode`.\n");
1426{
1428
1430
1431 Py_RETURN_NONE;
1432}
1433
1435 /* Wrap. */
1436 bpy_bmesh_select_flush_doc,
1437 ".. method:: select_flush(select)\n"
1438 "\n"
1439 " Flush selection, independent of the current selection mode.\n"
1440 "\n"
1441 " :arg select: flush selection or de-selected elements.\n"
1442 " :type select: bool\n");
1443static PyObject *bpy_bmesh_select_flush(BPy_BMesh *self, PyObject *value)
1444{
1445 int param;
1446
1448
1449 if ((param = PyC_Long_AsBool(value)) == -1) {
1450 return nullptr;
1451 }
1452
1453 if (param) {
1455 }
1456 else {
1458 }
1459
1460 Py_RETURN_NONE;
1461}
1462
1464 /* Wrap. */
1465 bpy_bmesh_normal_update_doc,
1466 ".. method:: normal_update()\n"
1467 "\n"
1468 " Update normals of mesh faces and verts.\n"
1469 "\n"
1470 " .. note::\n"
1471 "\n"
1472 " The normal of any vertex where :attr:`is_wire` is True will be a zero vector.\n");
1473
1475{
1477
1479
1480 Py_RETURN_NONE;
1481}
1482
1484 /* Wrap. */
1485 bpy_bmesh_transform_doc,
1486 ".. method:: transform(matrix, filter=None)\n"
1487 "\n"
1488 " Transform the mesh (optionally filtering flagged data only).\n"
1489 "\n"
1490 " :arg matrix: 4x4x transform matrix.\n"
1491 " :type matrix: :class:`mathutils.Matrix`\n"
1492 " :arg filter: set of values in " BPY_BM_HFLAG_ALL_STR
1493 ".\n"
1494 " :type filter: set[str]\n");
1495static PyObject *bpy_bmesh_transform(BPy_BMElem *self, PyObject *args, PyObject *kw)
1496{
1497 static const char *kwlist[] = {"matrix", "filter", nullptr};
1498
1499 MatrixObject *mat;
1500 PyObject *filter = nullptr;
1501 int filter_flags = 0;
1502
1504
1505 if (!PyArg_ParseTupleAndKeywords(
1506 args, kw, "O!|$O!:transform", (char **)kwlist, &matrix_Type, &mat, &PySet_Type, &filter))
1507 {
1508 return nullptr;
1509 }
1510
1511 BMVert *eve;
1512 BMIter iter;
1513 void *mat_ptr;
1514
1515 if (BaseMath_ReadCallback(mat) == -1) {
1516 return nullptr;
1517 }
1518 if (mat->col_num != 4 || mat->row_num != 4) {
1519 PyErr_SetString(PyExc_ValueError, "expected a 4x4 matrix");
1520 return nullptr;
1521 }
1522
1523 if (filter != nullptr &&
1524 PyC_FlagSet_ToBitfield(bpy_bm_hflag_all_flags, filter, &filter_flags, "bm.transform") == -1)
1525 {
1526 return nullptr;
1527 }
1528
1529 mat_ptr = mat->matrix;
1530
1531 if (!filter_flags) {
1532 BM_ITER_MESH (eve, &iter, self->bm, BM_VERTS_OF_MESH) {
1533 mul_m4_v3((float(*)[4])mat_ptr, eve->co);
1534 }
1535 }
1536 else {
1537 const char filter_flags_ch = char(filter_flags);
1538 BM_ITER_MESH (eve, &iter, self->bm, BM_VERTS_OF_MESH) {
1539 if (BM_elem_flag_test(eve, filter_flags_ch)) {
1540 mul_m4_v3((float(*)[4])mat_ptr, eve->co);
1541 }
1542 }
1543 }
1544
1545 Py_RETURN_NONE;
1546}
1547
1549 /* Wrap. */
1550 bpy_bmesh_calc_volume_doc,
1551 ".. method:: calc_volume(signed=False)\n"
1552 "\n"
1553 " Calculate mesh volume based on face normals.\n"
1554 "\n"
1555 " :arg signed: when signed is true, negative values may be returned.\n"
1556 " :type signed: bool\n"
1557 " :return: The volume of the mesh.\n"
1558 " :rtype: float\n");
1559static PyObject *bpy_bmesh_calc_volume(BPy_BMElem *self, PyObject *args, PyObject *kw)
1560{
1561 static const char *kwlist[] = {"signed", nullptr};
1562 PyObject *is_signed = Py_False;
1563
1565
1566 if (!PyArg_ParseTupleAndKeywords(
1567 args, kw, "|$O!:calc_volume", (char **)kwlist, &PyBool_Type, &is_signed))
1568 {
1569 return nullptr;
1570 }
1571
1572 return PyFloat_FromDouble(BM_mesh_calc_volume(self->bm, is_signed != Py_False));
1573}
1574
1576 /* Wrap. */
1577 bpy_bmesh_calc_loop_triangles_doc,
1578 ".. method:: calc_loop_triangles()\n"
1579 "\n"
1580 " Calculate triangle tessellation from quads/ngons.\n"
1581 "\n"
1582 " :return: The triangulated faces.\n"
1583 " :rtype: list[tuple[:class:`BMLoop`, :class:`BMLoop`, :class:`BMLoop`]]\n");
1585{
1586 BMesh *bm;
1587
1588 int corner_tris_tot;
1589
1590 PyObject *ret;
1591 int i;
1592
1594
1595 bm = self->bm;
1596
1597 corner_tris_tot = poly_to_tri_count(bm->totface, bm->totloop);
1598 blender::Array<std::array<BMLoop *, 3>> corner_tris(corner_tris_tot);
1599 BM_mesh_calc_tessellation(bm, corner_tris);
1600
1601 ret = PyList_New(corner_tris_tot);
1602 for (i = 0; i < corner_tris_tot; i++) {
1603 PyList_SET_ITEM(ret, i, BPy_BMLoop_Array_As_Tuple(bm, corner_tris[i].data(), 3));
1604 }
1605
1606 return ret;
1607}
1608
1609/* Elem
1610 * ---- */
1611
1613 /* Wrap. */
1614 bpy_bm_elem_select_set_doc,
1615 ".. method:: select_set(select)\n"
1616 "\n"
1617 " Set the selection.\n"
1618 " This is different from the *select* attribute because it updates the selection "
1619 "state of associated geometry.\n"
1620 "\n"
1621 " :arg select: Select or de-select.\n"
1622 " :type select: bool\n"
1623 "\n"
1624 " .. note::\n"
1625 "\n"
1626 " Currently this only flushes down, so selecting a face will select all its "
1627 "vertices but de-selecting a vertex "
1628 " won't de-select all the faces that use it, before finishing with a mesh "
1629 "typically flushing is still needed.\n");
1630static PyObject *bpy_bm_elem_select_set(BPy_BMElem *self, PyObject *value)
1631{
1632 int param;
1633
1635
1636 if ((param = PyC_Long_AsBool(value)) == -1) {
1637 return nullptr;
1638 }
1639
1640 BM_elem_select_set(self->bm, self->ele, param);
1641
1642 Py_RETURN_NONE;
1643}
1644
1646 /* Wrap. */
1647 bpy_bm_elem_hide_set_doc,
1648 ".. method:: hide_set(hide)\n"
1649 "\n"
1650 " Set the hide state.\n"
1651 " This is different from the *hide* attribute because it updates the selection and "
1652 "hide state of associated geometry.\n"
1653 "\n"
1654 " :arg hide: Hidden or visible.\n"
1655 " :type hide: bool\n");
1656static PyObject *bpy_bm_elem_hide_set(BPy_BMElem *self, PyObject *value)
1657{
1658 int param;
1659
1661
1662 if ((param = PyC_Long_AsBool(value)) == -1) {
1663 return nullptr;
1664 }
1665
1666 BM_elem_hide_set(self->bm, self->ele, param);
1667
1668 Py_RETURN_NONE;
1669}
1670
1672 /* Wrap. */
1673 bpy_bm_elem_copy_from_doc,
1674 ".. method:: copy_from(other)\n"
1675 "\n"
1676 " Copy values from another element of matching type.\n");
1678{
1680
1681 if (Py_TYPE(self) != Py_TYPE(value)) {
1682 PyErr_Format(PyExc_TypeError,
1683 "expected element of type '%.200s' not '%.200s'",
1684 Py_TYPE(self)->tp_name,
1685 Py_TYPE(value)->tp_name);
1686 return nullptr;
1687 }
1688
1689 if (value->ele != self->ele) {
1690 switch (self->ele->head.htype) {
1691 case BM_VERT: {
1693 value->bm->vdata, self->bm->vdata, CD_MASK_BM_ELEM_PYPTR);
1695 cd_vert_map,
1696 reinterpret_cast<const BMVert *>(value->ele),
1697 reinterpret_cast<BMVert *>(self->ele));
1698 break;
1699 }
1700 case BM_EDGE: {
1702 value->bm->edata, self->bm->edata, CD_MASK_BM_ELEM_PYPTR);
1704 cd_edge_map,
1705 reinterpret_cast<const BMEdge *>(value->ele),
1706 reinterpret_cast<BMEdge *>(self->ele));
1707 break;
1708 }
1709 case BM_FACE: {
1711 value->bm->pdata, self->bm->pdata, CD_MASK_BM_ELEM_PYPTR);
1713 cd_face_map,
1714 reinterpret_cast<const BMFace *>(value->ele),
1715 reinterpret_cast<BMFace *>(self->ele));
1716 break;
1717 }
1718 case BM_LOOP: {
1720 value->bm->ldata, self->bm->ldata, CD_MASK_BM_ELEM_PYPTR);
1722 cd_loop_map,
1723 reinterpret_cast<const BMLoop *>(value->ele),
1724 reinterpret_cast<BMLoop *>(self->ele));
1725 break;
1726 }
1727 }
1728 }
1729
1730 Py_RETURN_NONE;
1731}
1732
1733/* Vert
1734 * ---- */
1735
1737 /* Wrap. */
1738 bpy_bmvert_copy_from_vert_interp_doc,
1739 ".. method:: copy_from_vert_interp(vert_pair, fac)\n"
1740 "\n"
1741 " Interpolate the customdata from a vert between 2 other verts.\n"
1742 "\n"
1743 " :arg vert_pair: The verts between which to interpolate data from.\n"
1744 " :type vert_pair: Sequence[:class:`BMVert`]\n"
1745 " :type fac: float\n");
1746static PyObject *bpy_bmvert_copy_from_vert_interp(BPy_BMVert *self, PyObject *args)
1747{
1748 PyObject *vert_seq;
1749 float fac;
1750
1752
1753 if (!PyArg_ParseTuple(args, "Of:BMVert.copy_from_vert_interp", &vert_seq, &fac)) {
1754 return nullptr;
1755 }
1756
1757 BMesh *bm = self->bm;
1758 BMVert **vert_array = nullptr;
1759 Py_ssize_t vert_seq_len; /* always 2 */
1760
1761 vert_array = static_cast<BMVert **>(
1763 vert_seq,
1764 2,
1765 2,
1766 &vert_seq_len,
1767 BM_VERT,
1768 true,
1769 true,
1770 "BMVert.copy_from_vert_interp(...)"));
1771
1772 if (vert_array == nullptr) {
1773 return nullptr;
1774 }
1775
1776 BM_data_interp_from_verts(bm, vert_array[0], vert_array[1], self->v, clamp_f(fac, 0.0f, 1.0f));
1777
1778 PyMem_FREE(vert_array);
1779 Py_RETURN_NONE;
1780}
1781
1783 /* Wrap. */
1784 bpy_bmvert_copy_from_face_interp_doc,
1785 ".. method:: copy_from_face_interp(face)\n"
1786 "\n"
1787 " Interpolate the customdata from a face onto this loop (the loops vert should "
1788 "overlap the face).\n"
1789 "\n"
1790 " :arg face: The face to interpolate data from.\n"
1791 " :type face: :class:`BMFace`\n");
1792static PyObject *bpy_bmvert_copy_from_face_interp(BPy_BMVert *self, PyObject *args)
1793{
1794 BPy_BMFace *py_face = nullptr;
1795
1797
1798 if (!PyArg_ParseTuple(args, "O!:BMVert.copy_from_face_interp", &BPy_BMFace_Type, &py_face)) {
1799 return nullptr;
1800 }
1801
1802 BMesh *bm = self->bm;
1803
1804 BPY_BM_CHECK_SOURCE_OBJ(bm, "copy_from_face_interp()", py_face);
1805
1806 BM_vert_interp_from_face(bm, self->v, py_face->f);
1807
1808 Py_RETURN_NONE;
1809}
1810
1812 /* Wrap. */
1813 bpy_bmvert_calc_edge_angle_doc,
1814 ".. method:: calc_edge_angle(fallback=None)\n"
1815 "\n"
1816 " Return the angle between this vert's two connected edges.\n"
1817 "\n"
1818 " :arg fallback: return this when the vert doesn't have 2 edges\n"
1819 " (instead of raising a :exc:`ValueError`).\n"
1820 " :type fallback: Any\n"
1821 " :return: Angle between edges in radians.\n"
1822 " :rtype: float\n");
1823static PyObject *bpy_bmvert_calc_edge_angle(BPy_BMVert *self, PyObject *args)
1824{
1825 const float angle_invalid = -1.0f;
1826 float angle;
1827 PyObject *fallback = nullptr;
1828
1830
1831 if (!PyArg_ParseTuple(args, "|O:calc_edge_angle", &fallback)) {
1832 return nullptr;
1833 }
1834
1835 angle = BM_vert_calc_edge_angle_ex(self->v, angle_invalid);
1836
1837 if (angle == angle_invalid) {
1838 /* avoid exception */
1839 if (fallback) {
1840 Py_INCREF(fallback);
1841 return fallback;
1842 }
1843
1844 PyErr_SetString(PyExc_ValueError,
1845 "BMVert.calc_edge_angle(): "
1846 "vert must connect to exactly 2 edges");
1847 return nullptr;
1848 }
1849
1850 return PyFloat_FromDouble(angle);
1851}
1852
1854 /* Wrap. */
1855 bpy_bmvert_calc_shell_factor_doc,
1856 ".. method:: calc_shell_factor()\n"
1857 "\n"
1858 " Return a multiplier calculated based on the sharpness of the vertex.\n"
1859 " Where a flat surface gives 1.0, and higher values sharper edges.\n"
1860 " This is used to maintain shell thickness when offsetting verts along their normals.\n"
1861 "\n"
1862 " :return: offset multiplier\n"
1863 " :rtype: float\n");
1865{
1867 return PyFloat_FromDouble(BM_vert_calc_shell_factor(self->v));
1868}
1869
1871 /* Wrap. */
1872 bpy_bmvert_normal_update_doc,
1873 ".. method:: normal_update()\n"
1874 "\n"
1875 " Update vertex normal.\n"
1876 " This does not update the normals of adjoining faces.\n"
1877 "\n"
1878 " .. note::\n"
1879 "\n"
1880 " The vertex normal will be a zero vector if vertex :attr:`is_wire` is True.\n");
1882{
1884
1886
1887 Py_RETURN_NONE;
1888}
1889
1890/* Edge
1891 * ---- */
1892
1894 /* Wrap. */
1895 bpy_bmedge_calc_length_doc,
1896 ".. method:: calc_length()\n"
1897 "\n"
1898 " :return: The length between both verts.\n"
1899 " :rtype: float\n");
1901{
1903 return PyFloat_FromDouble(len_v3v3(self->e->v1->co, self->e->v2->co));
1904}
1905
1907 /* Wrap. */
1908 bpy_bmedge_calc_face_angle_doc,
1909 ".. method:: calc_face_angle(fallback=None)\n"
1910 "\n"
1911 " :arg fallback: return this when the edge doesn't have 2 faces\n"
1912 " (instead of raising a :exc:`ValueError`).\n"
1913 " :type fallback: Any\n"
1914 " :return: The angle between 2 connected faces in radians.\n"
1915 " :rtype: float\n");
1916static PyObject *bpy_bmedge_calc_face_angle(BPy_BMEdge *self, PyObject *args)
1917{
1918 const float angle_invalid = -1.0f;
1919 float angle;
1920 PyObject *fallback = nullptr;
1921
1923
1924 if (!PyArg_ParseTuple(args, "|O:calc_face_angle", &fallback)) {
1925 return nullptr;
1926 }
1927
1928 angle = BM_edge_calc_face_angle_ex(self->e, angle_invalid);
1929
1930 if (angle == angle_invalid) {
1931 /* avoid exception */
1932 if (fallback) {
1933 Py_INCREF(fallback);
1934 return fallback;
1935 }
1936
1937 PyErr_SetString(PyExc_ValueError,
1938 "BMEdge.calc_face_angle(): "
1939 "edge doesn't use 2 faces");
1940 return nullptr;
1941 }
1942
1943 return PyFloat_FromDouble(angle);
1944}
1945
1947 /* Wrap. */
1948 bpy_bmedge_calc_face_angle_signed_doc,
1949 ".. method:: calc_face_angle_signed(fallback=None)\n"
1950 "\n"
1951 " :arg fallback: return this when the edge doesn't have 2 faces\n"
1952 " (instead of raising a :exc:`ValueError`).\n"
1953 " :type fallback: Any\n"
1954 " :return: The angle between 2 connected faces in radians (negative for concave join).\n"
1955 " :rtype: float\n");
1956static PyObject *bpy_bmedge_calc_face_angle_signed(BPy_BMEdge *self, PyObject *args)
1957{
1958 const float angle_invalid = -FLT_MAX;
1959 float angle;
1960 PyObject *fallback = nullptr;
1961
1963
1964 if (!PyArg_ParseTuple(args, "|O:calc_face_angle_signed", &fallback)) {
1965 return nullptr;
1966 }
1967
1968 angle = BM_edge_calc_face_angle_signed_ex(self->e, angle_invalid);
1969
1970 if (angle == angle_invalid) {
1971 /* avoid exception */
1972 if (fallback) {
1973 Py_INCREF(fallback);
1974 return fallback;
1975 }
1976
1977 PyErr_SetString(PyExc_ValueError,
1978 "BMEdge.calc_face_angle_signed(): "
1979 "edge doesn't use 2 faces");
1980 return nullptr;
1981 }
1982
1983 return PyFloat_FromDouble(angle);
1984}
1985
1987 /* Wrap. */
1988 bpy_bmedge_calc_tangent_doc,
1989 ".. method:: calc_tangent(loop)\n"
1990 "\n"
1991 " Return the tangent at this edge relative to a face (pointing inward into the face).\n"
1992 " This uses the face normal for calculation.\n"
1993 "\n"
1994 " :arg loop: The loop used for tangent calculation.\n"
1995 " :type loop: :class:`BMLoop`\n"
1996 " :return: a normalized vector.\n"
1997 " :rtype: :class:`mathutils.Vector`\n");
1998static PyObject *bpy_bmedge_calc_tangent(BPy_BMEdge *self, PyObject *args)
1999{
2000 BPy_BMLoop *py_loop;
2002
2003 if (!PyArg_ParseTuple(args, "O!:BMEdge.calc_face_tangent", &BPy_BMLoop_Type, &py_loop)) {
2004 return nullptr;
2005 }
2006
2007 float vec[3];
2008 BPY_BM_CHECK_OBJ(py_loop);
2009 /* no need to check if they are from the same mesh or even connected */
2010 BM_edge_calc_face_tangent(self->e, py_loop->l, vec);
2011 return Vector_CreatePyObject(vec, 3, nullptr);
2012}
2013
2015 /* Wrap. */
2016 bpy_bmedge_other_vert_doc,
2017 ".. method:: other_vert(vert)\n"
2018 "\n"
2019 " Return the other vertex on this edge or None if the vertex is not used by this edge.\n"
2020 "\n"
2021 " :arg vert: a vert in this edge.\n"
2022 " :type vert: :class:`BMVert`\n"
2023 " :return: The edges other vert.\n"
2024 " :rtype: :class:`BMVert` | None\n");
2026{
2027 BMVert *other;
2029
2030 if (!BPy_BMVert_Check(value)) {
2031 PyErr_Format(PyExc_TypeError,
2032 "BMEdge.other_vert(vert): BMVert expected, not '%.200s'",
2033 Py_TYPE(value)->tp_name);
2034 return nullptr;
2035 }
2036
2037 BPY_BM_CHECK_SOURCE_OBJ(self->bm, "BMEdge.other_vert(vert)", value);
2038
2039 other = BM_edge_other_vert(self->e, value->v);
2040
2041 if (other) {
2042 return BPy_BMVert_CreatePyObject(self->bm, other);
2043 }
2044
2045 /* could raise an exception here */
2046 Py_RETURN_NONE;
2047}
2048
2050 /* Wrap. */
2051 bpy_bmedge_normal_update_doc,
2052 ".. method:: normal_update()\n"
2053 "\n"
2054 " Update normals of all connected faces and the edge verts.\n"
2055 "\n"
2056 " .. note::\n"
2057 "\n"
2058 " The normal of edge vertex will be a zero vector if vertex :attr:`is_wire` is True.\n");
2060{
2062
2064
2065 Py_RETURN_NONE;
2066}
2067
2068/* Face
2069 * ---- */
2070
2072 /* Wrap. */
2073 bpy_bmface_copy_from_face_interp_doc,
2074 ".. method:: copy_from_face_interp(face, vert=True)\n"
2075 "\n"
2076 " Interpolate the customdata from another face onto this one (faces should overlap).\n"
2077 "\n"
2078 " :arg face: The face to interpolate data from.\n"
2079 " :type face: :class:`BMFace`\n"
2080 " :arg vert: When True, also copy vertex data.\n"
2081 " :type vert: bool\n");
2082static PyObject *bpy_bmface_copy_from_face_interp(BPy_BMFace *self, PyObject *args)
2083{
2084 BPy_BMFace *py_face = nullptr;
2085 bool do_vertex = true;
2086
2088
2089 if (!PyArg_ParseTuple(args,
2090 "O!|O&:BMFace.copy_from_face_interp",
2092 &py_face,
2094 &do_vertex))
2095 {
2096 return nullptr;
2097 }
2098
2099 BMesh *bm = self->bm;
2100
2101 BPY_BM_CHECK_SOURCE_OBJ(bm, "BMFace.copy_from_face_interp(face)", py_face);
2102
2103 BM_face_interp_from_face(bm, self->f, py_face->f, do_vertex);
2104
2105 Py_RETURN_NONE;
2106}
2107
2109 /* Wrap. */
2110 bpy_bmface_copy_doc,
2111 ".. method:: copy(verts=True, edges=True)\n"
2112 "\n"
2113 " Make a copy of this face.\n"
2114 "\n"
2115 " :arg verts: When set, the faces verts will be duplicated too.\n"
2116 " :type verts: bool\n"
2117 " :arg edges: When set, the faces edges will be duplicated too.\n"
2118 " :type edges: bool\n"
2119 " :return: The newly created face.\n"
2120 " :rtype: :class:`BMFace`\n");
2121static PyObject *bpy_bmface_copy(BPy_BMFace *self, PyObject *args, PyObject *kw)
2122{
2123 static const char *kwlist[] = {"verts", "edges", nullptr};
2124
2125 BMesh *bm = self->bm;
2126 bool do_verts = true;
2127 bool do_edges = true;
2128
2129 BMFace *f_cpy;
2131
2132 if (!PyArg_ParseTupleAndKeywords(args,
2133 kw,
2134 "|$O&O&:BMFace.copy",
2135 (char **)kwlist,
2137 &do_verts,
2139 &do_edges))
2140 {
2141 return nullptr;
2142 }
2143
2144 f_cpy = BM_face_copy(bm, self->f, do_verts, do_edges);
2145
2146 if (f_cpy) {
2147 return BPy_BMFace_CreatePyObject(bm, f_cpy);
2148 }
2149
2150 PyErr_SetString(PyExc_ValueError, "BMFace.copy(): couldn't create the new face, internal error");
2151 return nullptr;
2152}
2153
2155 /* Wrap. */
2156 bpy_bmface_calc_area_doc,
2157 ".. method:: calc_area()\n"
2158 "\n"
2159 " Return the area of the face.\n"
2160 "\n"
2161 " :return: Return the area of the face.\n"
2162 " :rtype: float\n");
2164{
2166 return PyFloat_FromDouble(BM_face_calc_area(self->f));
2167}
2168
2170 /* Wrap. */
2171 bpy_bmface_calc_perimeter_doc,
2172 ".. method:: calc_perimeter()\n"
2173 "\n"
2174 " Return the perimeter of the face.\n"
2175 "\n"
2176 " :return: Return the perimeter of the face.\n"
2177 " :rtype: float\n");
2179{
2181 return PyFloat_FromDouble(BM_face_calc_perimeter(self->f));
2182}
2183
2185 /* Wrap. */
2186 bpy_bmface_calc_tangent_edge_doc,
2187 ".. method:: calc_tangent_edge()\n"
2188 "\n"
2189 " Return face tangent based on longest edge.\n"
2190 "\n"
2191 " :return: a normalized vector.\n"
2192 " :rtype: :class:`mathutils.Vector`\n");
2194{
2195 float tangent[3];
2196
2199 return Vector_CreatePyObject(tangent, 3, nullptr);
2200}
2201
2203 /* Wrap. */
2204 bpy_bmface_calc_tangent_edge_pair_doc,
2205 ".. method:: calc_tangent_edge_pair()\n"
2206 "\n"
2207 " Return face tangent based on the two longest disconnected edges.\n"
2208 "\n"
2209 " - Tris: Use the edge pair with the most similar lengths.\n"
2210 " - Quads: Use the longest edge pair.\n"
2211 " - NGons: Use the two longest disconnected edges.\n"
2212 "\n"
2213 " :return: a normalized vector.\n"
2214 " :rtype: :class:`mathutils.Vector`\n");
2216{
2217 float tangent[3];
2218
2221 return Vector_CreatePyObject(tangent, 3, nullptr);
2222}
2223
2225 /* Wrap. */
2226 bpy_bmface_calc_tangent_edge_diagonal_doc,
2227 ".. method:: calc_tangent_edge_diagonal()\n"
2228 "\n"
2229 " Return face tangent based on the edge farthest from any vertex.\n"
2230 "\n"
2231 " :return: a normalized vector.\n"
2232 " :rtype: :class:`mathutils.Vector`\n");
2234{
2235 float tangent[3];
2236
2239 return Vector_CreatePyObject(tangent, 3, nullptr);
2240}
2241
2243 /* Wrap. */
2244 bpy_bmface_calc_tangent_vert_diagonal_doc,
2245 ".. method:: calc_tangent_vert_diagonal()\n"
2246 "\n"
2247 " Return face tangent based on the two most distant vertices.\n"
2248 "\n"
2249 " :return: a normalized vector.\n"
2250 " :rtype: :class:`mathutils.Vector`\n");
2252{
2253 float tangent[3];
2254
2257 return Vector_CreatePyObject(tangent, 3, nullptr);
2258}
2259
2261 /* Wrap. */
2262 bpy_bmface_calc_center_median_doc,
2263 ".. method:: calc_center_median()\n"
2264 "\n"
2265 " Return median center of the face.\n"
2266 "\n"
2267 " :return: a 3D vector.\n"
2268 " :rtype: :class:`mathutils.Vector`\n");
2270{
2271 float cent[3];
2272
2275 return Vector_CreatePyObject(cent, 3, nullptr);
2276}
2277
2279 /* Wrap. */
2280 bpy_bmface_calc_center_median_weighted_doc,
2281 ".. method:: calc_center_median_weighted()\n"
2282 "\n"
2283 " Return median center of the face weighted by edge lengths.\n"
2284 "\n"
2285 " :return: a 3D vector.\n"
2286 " :rtype: :class:`mathutils.Vector`\n");
2288{
2289 float cent[3];
2290
2293 return Vector_CreatePyObject(cent, 3, nullptr);
2294}
2295
2297 /* Wrap. */
2298 bpy_bmface_calc_center_bounds_doc,
2299 ".. method:: calc_center_bounds()\n"
2300 "\n"
2301 " Return bounds center of the face.\n"
2302 "\n"
2303 " :return: a 3D vector.\n"
2304 " :rtype: :class:`mathutils.Vector`\n");
2306{
2307 float cent[3];
2308
2311 return Vector_CreatePyObject(cent, 3, nullptr);
2312}
2313
2315 /* Wrap. */
2316 bpy_bmface_normal_update_doc,
2317 ".. method:: normal_update()\n"
2318 "\n"
2319 " Update face normal based on the positions of the face verts.\n"
2320 " This does not update the normals of face verts.\n");
2322{
2324
2326
2327 Py_RETURN_NONE;
2328}
2329
2331 /* Wrap. */
2332 bpy_bmface_normal_flip_doc,
2333 ".. method:: normal_flip()\n"
2334 "\n"
2335 " Reverses winding of a face, which flips its normal.\n");
2337{
2339
2340 BM_face_normal_flip(self->bm, self->f);
2341
2342 Py_RETURN_NONE;
2343}
2344
2345/* Loop
2346 * ---- */
2347
2349 /* Wrap. */
2350 bpy_bmloop_copy_from_face_interp_doc,
2351 ".. method:: copy_from_face_interp(face, vert=True, multires=True)\n"
2352 "\n"
2353 " Interpolate the customdata from a face onto this loop (the loops vert should "
2354 "overlap the face).\n"
2355 "\n"
2356 " :arg face: The face to interpolate data from.\n"
2357 " :type face: :class:`BMFace`\n"
2358 " :arg vert: When enabled, interpolate the loops vertex data (optional).\n"
2359 " :type vert: bool\n"
2360 " :arg multires: When enabled, interpolate the loops multires data (optional).\n"
2361 " :type multires: bool\n");
2362static PyObject *bpy_bmloop_copy_from_face_interp(BPy_BMLoop *self, PyObject *args)
2363{
2364 BPy_BMFace *py_face = nullptr;
2365 bool do_vertex = true;
2366 bool do_multires = true;
2367
2369
2370 if (!PyArg_ParseTuple(args,
2371 "O!|O&O&:BMLoop.copy_from_face_interp",
2373 &py_face,
2375 &do_vertex,
2377 &do_multires))
2378 {
2379 return nullptr;
2380 }
2381
2382 BMesh *bm = self->bm;
2383
2384 BPY_BM_CHECK_SOURCE_OBJ(bm, "BMLoop.copy_from_face_interp(face)", py_face);
2385
2386 BM_loop_interp_from_face(bm, self->l, py_face->f, do_vertex, do_multires);
2387
2388 Py_RETURN_NONE;
2389}
2390
2392 /* Wrap. */
2393 bpy_bmloop_calc_angle_doc,
2394 ".. method:: calc_angle()\n"
2395 "\n"
2396 " Return the angle at this loops corner of the face.\n"
2397 " This is calculated so sharper corners give lower angles.\n"
2398 "\n"
2399 " :return: The angle in radians.\n"
2400 " :rtype: float\n");
2402{
2404 return PyFloat_FromDouble(BM_loop_calc_face_angle(self->l));
2405}
2406
2408 /* Wrap. */
2409 bpy_bmloop_calc_normal_doc,
2410 ".. method:: calc_normal()\n"
2411 "\n"
2412 " Return normal at this loops corner of the face.\n"
2413 " Falls back to the face normal for straight lines.\n"
2414 "\n"
2415 " :return: a normalized vector.\n"
2416 " :rtype: :class:`mathutils.Vector`\n");
2418{
2419 float vec[3];
2422 return Vector_CreatePyObject(vec, 3, nullptr);
2423}
2424
2426 /* Wrap. */
2427 bpy_bmloop_calc_tangent_doc,
2428 ".. method:: calc_tangent()\n"
2429 "\n"
2430 " Return the tangent at this loops corner of the face (pointing inward into the face).\n"
2431 " Falls back to the face normal for straight lines.\n"
2432 "\n"
2433 " :return: a normalized vector.\n"
2434 " :rtype: :class:`mathutils.Vector`\n");
2436{
2437 float vec[3];
2440 return Vector_CreatePyObject(vec, 3, nullptr);
2441}
2442
2443/* Vert Seq
2444 * -------- */
2446 /* Wrap. */
2447 bpy_bmvertseq_new_doc,
2448 ".. method:: new(co=(0.0, 0.0, 0.0), example=None)\n"
2449 "\n"
2450 " Create a new vertex.\n"
2451 "\n"
2452 " :arg co: The initial location of the vertex (optional argument).\n"
2453 " :type co: float triplet\n"
2454 " :arg example: Existing vert to initialize settings.\n"
2455 " :type example: :class:`BMVert`\n"
2456 " :return: The newly created vertex.\n"
2457 " :rtype: :class:`BMVert`\n");
2458static PyObject *bpy_bmvertseq_new(BPy_BMElemSeq *self, PyObject *args)
2459{
2460 PyObject *py_co = nullptr;
2461 BPy_BMVert *py_vert_example = nullptr; /* optional */
2462
2464
2465 if (!PyArg_ParseTuple(args, "|OO!:verts.new", &py_co, &BPy_BMVert_Type, &py_vert_example)) {
2466 return nullptr;
2467 }
2468
2469 BMesh *bm = self->bm;
2470 BMVert *v;
2471 float co[3] = {0.0f, 0.0f, 0.0f};
2472
2473 if (py_vert_example) {
2474 BPY_BM_CHECK_OBJ(py_vert_example);
2475 }
2476
2477 if (py_co && mathutils_array_parse(co, 3, 3, py_co, "verts.new(co)") == -1) {
2478 return nullptr;
2479 }
2480
2481 v = BM_vert_create(bm, co, nullptr, BM_CREATE_NOP);
2482
2483 if (v == nullptr) {
2484 PyErr_SetString(PyExc_ValueError,
2485 "faces.new(verts): couldn't create the new face, internal error");
2486 return nullptr;
2487 }
2488
2489 if (py_vert_example) {
2490 if (py_vert_example->bm == bm) {
2491 BM_elem_attrs_copy(bm, py_vert_example->v, v);
2492 }
2493 else {
2495 py_vert_example->bm->vdata, bm->vdata);
2496 BM_elem_attrs_copy(bm, cd_vert_map, py_vert_example->v, v);
2497 }
2498 }
2499
2501}
2502
2503/* Edge Seq
2504 * -------- */
2506 /* Wrap. */
2507 bpy_bmedgeseq_new_doc,
2508 ".. method:: new(verts, example=None)\n"
2509 "\n"
2510 " Create a new edge from a given pair of verts.\n"
2511 "\n"
2512 " :arg verts: Vertex pair.\n"
2513 " :type verts: Sequence[:class:`BMVert`]\n"
2514 " :arg example: Existing edge to initialize settings (optional argument).\n"
2515 " :type example: :class:`BMEdge`\n"
2516 " :return: The newly created edge.\n"
2517 " :rtype: :class:`BMEdge`\n");
2518static PyObject *bpy_bmedgeseq_new(BPy_BMElemSeq *self, PyObject *args)
2519{
2520 PyObject *vert_seq;
2521 BPy_BMEdge *py_edge_example = nullptr; /* optional */
2522
2524
2525 if (!PyArg_ParseTuple(args, "O|O!:edges.new", &vert_seq, &BPy_BMEdge_Type, &py_edge_example)) {
2526 return nullptr;
2527 }
2528
2529 BMesh *bm = self->bm;
2530 BMEdge *e;
2531 BMVert **vert_array = nullptr;
2532 Py_ssize_t vert_seq_len; /* always 2 */
2533 PyObject *ret = nullptr;
2534
2535 if (py_edge_example) {
2536 BPY_BM_CHECK_OBJ(py_edge_example);
2537 }
2538
2539 vert_array = static_cast<BMVert **>(BPy_BMElem_PySeq_As_Array(
2540 &bm, vert_seq, 2, 2, &vert_seq_len, BM_VERT, true, true, "edges.new(...)"));
2541
2542 if (vert_array == nullptr) {
2543 return nullptr;
2544 }
2545
2546 if (BM_edge_exists(vert_array[0], vert_array[1])) {
2547 PyErr_SetString(PyExc_ValueError, "edges.new(): this edge exists");
2548 goto cleanup;
2549 }
2550
2551 e = BM_edge_create(bm, vert_array[0], vert_array[1], nullptr, BM_CREATE_NOP);
2552
2553 if (e == nullptr) {
2554 PyErr_SetString(PyExc_ValueError,
2555 "faces.new(verts): couldn't create the new face, internal error");
2556 goto cleanup;
2557 }
2558
2559 if (py_edge_example) {
2560 if (py_edge_example->bm == bm) {
2561 BM_elem_attrs_copy(bm, py_edge_example->e, e);
2562 }
2563 else {
2565 py_edge_example->bm->edata, bm->edata);
2566 BM_elem_attrs_copy(bm, cd_edge_map, py_edge_example->e, e);
2567 }
2568 }
2569
2571
2572cleanup:
2573 if (vert_array) {
2574 PyMem_FREE(vert_array);
2575 }
2576 return ret;
2577}
2578
2579/* Face Seq
2580 * -------- */
2582 /* Wrap. */
2583 bpy_bmfaceseq_new_doc,
2584 ".. method:: new(verts, example=None)\n"
2585 "\n"
2586 " Create a new face from a given set of verts.\n"
2587 "\n"
2588 " :arg verts: Sequence of 3 or more verts.\n"
2589 " :type verts: Sequence[:class:`BMVert`]\n"
2590 " :arg example: Existing face to initialize settings (optional argument).\n"
2591 " :type example: :class:`BMFace`\n"
2592 " :return: The newly created face.\n"
2593 " :rtype: :class:`BMFace`\n");
2594static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args)
2595{
2596 PyObject *vert_seq;
2597 BPy_BMFace *py_face_example = nullptr; /* optional */
2598
2600
2601 if (!PyArg_ParseTuple(args, "O|O!:faces.new", &vert_seq, &BPy_BMFace_Type, &py_face_example)) {
2602 return nullptr;
2603 }
2604
2605 BMesh *bm = self->bm;
2606 Py_ssize_t vert_seq_len;
2607
2608 BMVert **vert_array = nullptr;
2609
2610 PyObject *ret = nullptr;
2611
2612 BMFace *f_new;
2613
2614 if (py_face_example) {
2615 BPY_BM_CHECK_OBJ(py_face_example);
2616 }
2617
2618 vert_array = static_cast<BMVert **>(BPy_BMElem_PySeq_As_Array(
2619 &bm, vert_seq, 3, PY_SSIZE_T_MAX, &vert_seq_len, BM_VERT, true, true, "faces.new(...)"));
2620
2621 if (vert_array == nullptr) {
2622 return nullptr;
2623 }
2624
2625 /* check if the face exists */
2626 if (BM_face_exists(vert_array, vert_seq_len) != nullptr) {
2627 PyErr_SetString(PyExc_ValueError, "faces.new(verts): face already exists");
2628 goto cleanup;
2629 }
2630
2631 /* Go ahead and make the face!
2632 * --------------------------- */
2633
2634 f_new = BM_face_create_verts(bm,
2635 vert_array,
2636 vert_seq_len,
2637 py_face_example ? py_face_example->f : nullptr,
2639 true);
2640
2641 if (UNLIKELY(f_new == nullptr)) {
2642 PyErr_SetString(PyExc_ValueError,
2643 "faces.new(verts): couldn't create the new face, internal error");
2644 goto cleanup;
2645 }
2646
2648
2649/* pass through */
2650cleanup:
2651 if (vert_array) {
2652 PyMem_FREE(vert_array);
2653 }
2654 return ret;
2655}
2656
2657/* Elem Seq
2658 * -------- */
2659
2661 /* Wrap. */
2662 bpy_bmvertseq_remove_doc,
2663 ".. method:: remove(vert)\n"
2664 "\n"
2665 " Remove a vert.\n"
2666 "\n"
2667 " :type vert: :class:`BMVert`\n");
2669{
2671
2672 if (!BPy_BMVert_Check(value)) {
2673 return nullptr;
2674 }
2675
2676 BMesh *bm = self->bm;
2677
2678 BPY_BM_CHECK_SOURCE_OBJ(bm, "verts.remove(vert)", value);
2679
2680 BM_vert_kill(bm, value->v);
2682
2683 Py_RETURN_NONE;
2684}
2685
2687 /* Wrap. */
2688 bpy_bmedgeseq_remove_doc,
2689 ".. method:: remove(edge)\n"
2690 "\n"
2691 " Remove an edge.\n"
2692 "\n"
2693 " :type edge: :class:`BMEdge`\n");
2695{
2697
2698 if (!BPy_BMEdge_Check(value)) {
2699 return nullptr;
2700 }
2701
2702 BMesh *bm = self->bm;
2703
2704 BPY_BM_CHECK_SOURCE_OBJ(bm, "edges.remove(edges)", value);
2705
2706 BM_edge_kill(bm, value->e);
2708
2709 Py_RETURN_NONE;
2710}
2711
2713 /* Wrap. */
2714 bpy_bmfaceseq_remove_doc,
2715 ".. method:: remove(face)\n"
2716 "\n"
2717 " Remove a face.\n"
2718 "\n"
2719 " :type face: :class:`BMFace`\n");
2721{
2723
2724 if (!BPy_BMFace_Check(value)) {
2725 return nullptr;
2726 }
2727
2728 BMesh *bm = self->bm;
2729
2730 BPY_BM_CHECK_SOURCE_OBJ(bm, "faces.remove(face)", value);
2731
2732 BM_face_kill(bm, value->f);
2734
2735 Py_RETURN_NONE;
2736}
2737
2739 /* Wrap. */
2740 bpy_bmedgeseq_get__method_doc,
2741 ".. method:: get(verts, fallback=None)\n"
2742 "\n"
2743 " Return an edge which uses the **verts** passed.\n"
2744 "\n"
2745 " :arg verts: Sequence of verts.\n"
2746 " :type verts: Sequence[:class:`BMVert`]\n"
2747 " :arg fallback: Return this value if nothing is found.\n"
2748 " :return: The edge found or None\n"
2749 " :rtype: :class:`BMEdge`\n");
2750static PyObject *bpy_bmedgeseq_get__method(BPy_BMElemSeq *self, PyObject *args)
2751{
2752 PyObject *vert_seq;
2753 PyObject *fallback = Py_None; /* optional */
2754
2756
2757 if (!PyArg_ParseTuple(args, "O|O:edges.get", &vert_seq, &fallback)) {
2758 return nullptr;
2759 }
2760
2761 BMesh *bm = self->bm;
2762 BMEdge *e;
2763 BMVert **vert_array = nullptr;
2764 Py_ssize_t vert_seq_len; /* always 2 */
2765 PyObject *ret = nullptr;
2766
2767 vert_array = static_cast<BMVert **>(BPy_BMElem_PySeq_As_Array(
2768 &bm, vert_seq, 2, 2, &vert_seq_len, BM_VERT, true, true, "edges.get(...)"));
2769
2770 if (vert_array == nullptr) {
2771 return nullptr;
2772 }
2773
2774 if ((e = BM_edge_exists(vert_array[0], vert_array[1]))) {
2776 }
2777 else {
2778 ret = fallback;
2779 Py_INCREF(ret);
2780 }
2781
2782 PyMem_FREE(vert_array);
2783 return ret;
2784}
2785
2787 /* Wrap. */
2788 bpy_bmfaceseq_get__method_doc,
2789 ".. method:: get(verts, fallback=None)\n"
2790 "\n"
2791 " Return a face which uses the **verts** passed.\n"
2792 "\n"
2793 " :arg verts: Sequence of verts.\n"
2794 " :type verts: Sequence[:class:`BMVert`]\n"
2795 " :arg fallback: Return this value if nothing is found.\n"
2796 " :return: The face found or None\n"
2797 " :rtype: :class:`BMFace`\n");
2798static PyObject *bpy_bmfaceseq_get__method(BPy_BMElemSeq *self, PyObject *args)
2799{
2800 PyObject *vert_seq;
2801 PyObject *fallback = Py_None; /* optional */
2802
2804
2805 if (!PyArg_ParseTuple(args, "O|O:faces.get", &vert_seq, &fallback)) {
2806 return nullptr;
2807 }
2808
2809 BMesh *bm = self->bm;
2810 BMFace *f = nullptr;
2811 BMVert **vert_array = nullptr;
2812 Py_ssize_t vert_seq_len;
2813 PyObject *ret = nullptr;
2814
2815 vert_array = static_cast<BMVert **>(BPy_BMElem_PySeq_As_Array(
2816 &bm, vert_seq, 1, PY_SSIZE_T_MAX, &vert_seq_len, BM_VERT, true, true, "faces.get(...)"));
2817
2818 if (vert_array == nullptr) {
2819 return nullptr;
2820 }
2821
2822 f = BM_face_exists(vert_array, vert_seq_len);
2823 if (f != nullptr) {
2825 }
2826 else {
2827 ret = fallback;
2828 Py_INCREF(ret);
2829 }
2830
2831 PyMem_FREE(vert_array);
2832 return ret;
2833}
2834
2836 /* Wrap. */
2837 bpy_bmelemseq_index_update_doc,
2838 ".. method:: index_update()\n"
2839 "\n"
2840 " Initialize the index values of this sequence.\n"
2841 "\n"
2842 " This is the equivalent of looping over all elements and assigning the index values.\n"
2843 "\n"
2844 " .. code-block:: python\n"
2845 "\n"
2846 " for index, ele in enumerate(sequence):\n"
2847 " ele.index = index\n"
2848 "\n"
2849 " .. note::\n"
2850 "\n"
2851 " Running this on sequences besides :class:`BMesh.verts`, :class:`BMesh.edges`, "
2852 ":class:`BMesh.faces`\n"
2853 " works but won't result in each element having a valid index, instead its order in the "
2854 "sequence will be set.\n");
2856{
2857 BMesh *bm = self->bm;
2858
2860
2861 switch ((BMIterType)self->itype) {
2862 case BM_VERTS_OF_MESH:
2864 break;
2865 case BM_EDGES_OF_MESH:
2867 break;
2868 case BM_FACES_OF_MESH:
2870 break;
2871 default: {
2872 BMIter iter;
2873 BMElem *ele;
2874 int index = 0;
2875 const char htype = bm_iter_itype_htype_map[self->itype];
2876
2877 BM_ITER_BPY_BM_SEQ (ele, &iter, self) {
2878 BM_elem_index_set(ele, index); /* set_dirty! */
2879 index++;
2880 }
2881
2882 /* since this isn't the normal vert/edge/face loops,
2883 * we're setting dirty values here. so tag as dirty. */
2884 bm->elem_index_dirty |= htype;
2885
2886 break;
2887 }
2888 }
2889
2890 Py_RETURN_NONE;
2891}
2892
2894 /* Wrap. */
2895 bpy_bmelemseq_ensure_lookup_table_doc,
2896 ".. method:: ensure_lookup_table()\n"
2897 "\n"
2898 " Ensure internal data needed for int subscription is initialized with "
2899 "verts/edges/faces, eg ``bm.verts[index]``.\n"
2900 "\n"
2901 " This needs to be called again after adding/removing data in this sequence.");
2903{
2905
2907
2908 Py_RETURN_NONE;
2909}
2910
2912 /* Wrap. */
2913 bpy_bmelemseq_sort_doc,
2914 ".. method:: sort(key=None, reverse=False)\n"
2915 "\n"
2916 " Sort the elements of this sequence, using an optional custom sort key.\n"
2917 " Indices of elements are not changed, :class:`BMElemSeq.index_update` can be used for "
2918 "that.\n"
2919 "\n"
2920 " :arg key: The key that sets the ordering of the elements.\n"
2921 " :type key: Callable[[:class:`BMVert` | :class:`BMEdge` | :class:`BMFace`], int] | None\n"
2922 " :arg reverse: Reverse the order of the elements\n"
2923 " :type reverse: bool\n"
2924 "\n"
2925 " .. note::\n"
2926 "\n"
2927 " When the 'key' argument is not provided, the elements are reordered following their "
2928 "current index value.\n"
2929 " In particular this can be used by setting indices manually before calling this "
2930 "method.\n"
2931 "\n"
2932 " .. warning::\n"
2933 "\n"
2934 " Existing references to the N'th element, will continue to point the data at that "
2935 "index.\n");
2936
2937/* Use a static variable here because there is the need to sort some array
2938 * doing comparisons on elements of another array, qsort_r would have been
2939 * wonderful to use here, but unfortunately it is not standard and it's not
2940 * portable across different platforms.
2941 *
2942 * If a portable alternative to qsort_r becomes available, remove this static
2943 * var hack!
2944 *
2945 * NOTE: the functions below assumes the keys array has been allocated and it
2946 * has enough elements to complete the task.
2947 */
2948
2949static int bpy_bmelemseq_sort_cmp_by_keys_ascending(const void *index1_v,
2950 const void *index2_v,
2951 void *keys_v)
2952{
2953 const double *keys = static_cast<const double *>(keys_v);
2954 const int *index1 = (int *)index1_v;
2955 const int *index2 = (int *)index2_v;
2956
2957 if (keys[*index1] < keys[*index2]) {
2958 return -1;
2959 }
2960 if (keys[*index1] > keys[*index2]) {
2961 return 1;
2962 }
2963
2964 return 0;
2965}
2966
2967static int bpy_bmelemseq_sort_cmp_by_keys_descending(const void *index1_v,
2968 const void *index2_v,
2969 void *keys_v)
2970{
2971 return -bpy_bmelemseq_sort_cmp_by_keys_ascending(index1_v, index2_v, keys_v);
2972}
2973
2974static PyObject *bpy_bmelemseq_sort(BPy_BMElemSeq *self, PyObject *args, PyObject *kw)
2975{
2976 static const char *kwlist[] = {"key", "reverse", nullptr};
2977 PyObject *keyfunc = nullptr; /* optional */
2978 bool do_reverse = false; /* optional */
2979
2980 const char htype = bm_iter_itype_htype_map[self->itype];
2981 int n_elem;
2982
2983 BMIter iter;
2984 BMElem *ele;
2985
2986 double *keys;
2987 int *elem_idx;
2988 uint *elem_map_idx;
2989 int (*elem_idx_compare_by_keys)(const void *, const void *, void *);
2990
2991 uint *vert_idx = nullptr;
2992 uint *edge_idx = nullptr;
2993 uint *face_idx = nullptr;
2994 int i;
2995
2996 BMesh *bm = self->bm;
2997
2999
3000 if (args != nullptr) {
3001 if (!PyArg_ParseTupleAndKeywords(args,
3002 kw,
3003 "|$OO&:BMElemSeq.sort",
3004 (char **)kwlist,
3005 &keyfunc,
3007 &do_reverse))
3008 {
3009 return nullptr;
3010 }
3011 if (keyfunc == Py_None) {
3012 keyfunc = nullptr;
3013 }
3014 }
3015
3016 if (keyfunc != nullptr && !PyCallable_Check(keyfunc)) {
3017 PyErr_SetString(PyExc_TypeError, "the 'key' argument is not a callable object");
3018 return nullptr;
3019 }
3020
3021 n_elem = BM_mesh_elem_count(bm, htype);
3022 if (n_elem <= 1) {
3023 /* 0 or 1 elements: sorted already */
3024 Py_RETURN_NONE;
3025 }
3026
3027 keys = static_cast<double *>(PyMem_MALLOC(sizeof(*keys) * n_elem));
3028 if (keys == nullptr) {
3029 PyErr_NoMemory();
3030 return nullptr;
3031 }
3032
3033 i = 0;
3034 BM_ITER_BPY_BM_SEQ (ele, &iter, self) {
3035 if (keyfunc != nullptr) {
3036 PyObject *py_elem;
3037 PyObject *index;
3038
3039 py_elem = BPy_BMElem_CreatePyObject(self->bm, (BMHeader *)ele);
3040 index = PyObject_CallFunctionObjArgs(keyfunc, py_elem, nullptr);
3041 Py_DECREF(py_elem);
3042 if (index == nullptr) {
3043 /* No need to set the exception here,
3044 * PyObject_CallFunctionObjArgs() does that */
3045 PyMem_FREE(keys);
3046 return nullptr;
3047 }
3048
3049 if ((keys[i] = PyFloat_AsDouble(index)) == -1 && PyErr_Occurred()) {
3050 PyErr_SetString(PyExc_ValueError,
3051 "the value returned by the 'key' function is not a number");
3052 Py_DECREF(index);
3053 PyMem_FREE(keys);
3054 return nullptr;
3055 }
3056
3057 Py_DECREF(index);
3058 }
3059 else {
3060 /* If the 'key' function is not provided we sort
3061 * according to the current index values */
3062 keys[i] = ele->head.index;
3063 }
3064
3065 i++;
3066 }
3067
3068 elem_idx = static_cast<int *>(PyMem_MALLOC(sizeof(*elem_idx) * n_elem));
3069 if (elem_idx == nullptr) {
3070 PyErr_NoMemory();
3071 PyMem_FREE(keys);
3072 return nullptr;
3073 }
3074
3075 /* Initialize the element index array */
3076 range_vn_i(elem_idx, n_elem, 0);
3077
3078 /* Sort the index array according to the order of the 'keys' array */
3079 if (do_reverse) {
3080 elem_idx_compare_by_keys = bpy_bmelemseq_sort_cmp_by_keys_descending;
3081 }
3082 else {
3083 elem_idx_compare_by_keys = bpy_bmelemseq_sort_cmp_by_keys_ascending;
3084 }
3085
3086 BLI_qsort_r(elem_idx, n_elem, sizeof(*elem_idx), elem_idx_compare_by_keys, keys);
3087
3088 elem_map_idx = static_cast<uint *>(PyMem_MALLOC(sizeof(*elem_map_idx) * n_elem));
3089 if (elem_map_idx == nullptr) {
3090 PyErr_NoMemory();
3091 PyMem_FREE(elem_idx);
3092 PyMem_FREE(keys);
3093 return nullptr;
3094 }
3095
3096 /* Initialize the map array
3097 *
3098 * We need to know the index such that if used as the new_index in
3099 * BM_mesh_remap() will give the order of the sorted keys like in
3100 * elem_idx */
3101 for (i = 0; i < n_elem; i++) {
3102 elem_map_idx[elem_idx[i]] = i;
3103 }
3104
3105 switch ((BMIterType)self->itype) {
3106 case BM_VERTS_OF_MESH:
3107 vert_idx = elem_map_idx;
3108 break;
3109 case BM_EDGES_OF_MESH:
3110 edge_idx = elem_map_idx;
3111 break;
3112 case BM_FACES_OF_MESH:
3113 face_idx = elem_map_idx;
3114 break;
3115 default:
3116 PyErr_Format(PyExc_TypeError, "element type %d not supported", self->itype);
3117 PyMem_FREE(elem_map_idx);
3118 PyMem_FREE(elem_idx);
3119 PyMem_FREE(keys);
3120 return nullptr;
3121 }
3122
3123 BM_mesh_remap(bm, vert_idx, edge_idx, face_idx);
3124
3125 PyMem_FREE(elem_map_idx);
3126 PyMem_FREE(elem_idx);
3127 PyMem_FREE(keys);
3128
3129 Py_RETURN_NONE;
3130}
3131
3132#ifdef __GNUC__
3133# ifdef __clang__
3134# pragma clang diagnostic push
3135# pragma clang diagnostic ignored "-Wcast-function-type"
3136# else
3137# pragma GCC diagnostic push
3138# pragma GCC diagnostic ignored "-Wcast-function-type"
3139# endif
3140#endif
3141
3142static PyMethodDef bpy_bmesh_methods[] = {
3143 /* utility */
3144 {"copy", (PyCFunction)bpy_bmesh_copy, METH_NOARGS, bpy_bmesh_copy_doc},
3145 {"clear", (PyCFunction)bpy_bmesh_clear, METH_NOARGS, bpy_bmesh_clear_doc},
3146 {"free", (PyCFunction)bpy_bmesh_free, METH_NOARGS, bpy_bmesh_free_doc},
3147
3148 /* conversion */
3149 {"from_object",
3150 (PyCFunction)bpy_bmesh_from_object,
3151 METH_VARARGS | METH_KEYWORDS,
3152 bpy_bmesh_from_object_doc},
3153 {"from_mesh",
3154 (PyCFunction)bpy_bmesh_from_mesh,
3155 METH_VARARGS | METH_KEYWORDS,
3156 bpy_bmesh_from_mesh_doc},
3157 {"to_mesh", (PyCFunction)bpy_bmesh_to_mesh, METH_VARARGS, bpy_bmesh_to_mesh_doc},
3158
3159 /* meshdata */
3160 {"select_flush_mode",
3161 (PyCFunction)bpy_bmesh_select_flush_mode,
3162 METH_NOARGS,
3163 bpy_bmesh_select_flush_mode_doc},
3164 {"select_flush", (PyCFunction)bpy_bmesh_select_flush, METH_O, bpy_bmesh_select_flush_doc},
3165 {"normal_update",
3166 (PyCFunction)bpy_bmesh_normal_update,
3167 METH_NOARGS,
3168 bpy_bmesh_normal_update_doc},
3169 {"transform",
3170 (PyCFunction)bpy_bmesh_transform,
3171 METH_VARARGS | METH_KEYWORDS,
3172 bpy_bmesh_transform_doc},
3173
3174 /* calculations */
3175 {"calc_volume",
3176 (PyCFunction)bpy_bmesh_calc_volume,
3177 METH_VARARGS | METH_KEYWORDS,
3178 bpy_bmesh_calc_volume_doc},
3179 {"calc_loop_triangles",
3180 (PyCFunction)bpy_bmesh_calc_loop_triangles,
3181 METH_NOARGS,
3182 bpy_bmesh_calc_loop_triangles_doc},
3183 {nullptr, nullptr, 0, nullptr},
3184};
3185
3186static PyMethodDef bpy_bmvert_methods[] = {
3187 {"select_set", (PyCFunction)bpy_bm_elem_select_set, METH_O, bpy_bm_elem_select_set_doc},
3188 {"hide_set", (PyCFunction)bpy_bm_elem_hide_set, METH_O, bpy_bm_elem_hide_set_doc},
3189 {"copy_from", (PyCFunction)bpy_bm_elem_copy_from, METH_O, bpy_bm_elem_copy_from_doc},
3190 {"copy_from_face_interp",
3192 METH_VARARGS,
3193 bpy_bmvert_copy_from_face_interp_doc},
3194 {"copy_from_vert_interp",
3196 METH_VARARGS,
3197 bpy_bmvert_copy_from_vert_interp_doc},
3198
3199 {"calc_edge_angle",
3200 (PyCFunction)bpy_bmvert_calc_edge_angle,
3201 METH_VARARGS,
3202 bpy_bmvert_calc_edge_angle_doc},
3203 {"calc_shell_factor",
3204 (PyCFunction)bpy_bmvert_calc_shell_factor,
3205 METH_NOARGS,
3206 bpy_bmvert_calc_shell_factor_doc},
3207
3208 {"normal_update",
3209 (PyCFunction)bpy_bmvert_normal_update,
3210 METH_NOARGS,
3211 bpy_bmvert_normal_update_doc},
3212
3213 {nullptr, nullptr, 0, nullptr},
3214};
3215
3216static PyMethodDef bpy_bmedge_methods[] = {
3217 {"select_set", (PyCFunction)bpy_bm_elem_select_set, METH_O, bpy_bm_elem_select_set_doc},
3218 {"hide_set", (PyCFunction)bpy_bm_elem_hide_set, METH_O, bpy_bm_elem_hide_set_doc},
3219 {"copy_from", (PyCFunction)bpy_bm_elem_copy_from, METH_O, bpy_bm_elem_copy_from_doc},
3220
3221 {"other_vert", (PyCFunction)bpy_bmedge_other_vert, METH_O, bpy_bmedge_other_vert_doc},
3222
3223 {"calc_length", (PyCFunction)bpy_bmedge_calc_length, METH_NOARGS, bpy_bmedge_calc_length_doc},
3224 {"calc_face_angle",
3225 (PyCFunction)bpy_bmedge_calc_face_angle,
3226 METH_VARARGS,
3227 bpy_bmedge_calc_face_angle_doc},
3228 {"calc_face_angle_signed",
3230 METH_VARARGS,
3231 bpy_bmedge_calc_face_angle_signed_doc},
3232 {"calc_tangent",
3233 (PyCFunction)bpy_bmedge_calc_tangent,
3234 METH_VARARGS,
3235 bpy_bmedge_calc_tangent_doc},
3236
3237 {"normal_update",
3238 (PyCFunction)bpy_bmedge_normal_update,
3239 METH_NOARGS,
3240 bpy_bmedge_normal_update_doc},
3241
3242 {nullptr, nullptr, 0, nullptr},
3243};
3244
3245static PyMethodDef bpy_bmface_methods[] = {
3246 {"select_set", (PyCFunction)bpy_bm_elem_select_set, METH_O, bpy_bm_elem_select_set_doc},
3247 {"hide_set", (PyCFunction)bpy_bm_elem_hide_set, METH_O, bpy_bm_elem_hide_set_doc},
3248
3249 {"copy_from", (PyCFunction)bpy_bm_elem_copy_from, METH_O, bpy_bm_elem_copy_from_doc},
3250 {"copy_from_face_interp",
3252 METH_VARARGS,
3253 bpy_bmface_copy_from_face_interp_doc},
3254
3255 {"copy", (PyCFunction)bpy_bmface_copy, METH_VARARGS | METH_KEYWORDS, bpy_bmface_copy_doc},
3256
3257 {"calc_area", (PyCFunction)bpy_bmface_calc_area, METH_NOARGS, bpy_bmface_calc_area_doc},
3258 {"calc_perimeter",
3259 (PyCFunction)bpy_bmface_calc_perimeter,
3260 METH_NOARGS,
3261 bpy_bmface_calc_perimeter_doc},
3262 {"calc_tangent_edge",
3263 (PyCFunction)bpy_bmface_calc_tangent_edge,
3264 METH_NOARGS,
3265 bpy_bmface_calc_tangent_edge_doc},
3266 {"calc_tangent_edge_pair",
3268 METH_NOARGS,
3269 bpy_bmface_calc_tangent_edge_pair_doc},
3270 {"calc_tangent_edge_diagonal",
3272 METH_NOARGS,
3273 bpy_bmface_calc_tangent_edge_diagonal_doc},
3274 {"calc_tangent_vert_diagonal",
3276 METH_NOARGS,
3277 bpy_bmface_calc_tangent_vert_diagonal_doc},
3278 {"calc_center_median",
3279 (PyCFunction)bpy_bmface_calc_center_mean,
3280 METH_NOARGS,
3281 bpy_bmface_calc_center_median_doc},
3282 {"calc_center_median_weighted",
3284 METH_NOARGS,
3285 bpy_bmface_calc_center_median_weighted_doc},
3286 {"calc_center_bounds",
3287 (PyCFunction)bpy_bmface_calc_center_bounds,
3288 METH_NOARGS,
3289 bpy_bmface_calc_center_bounds_doc},
3290
3291 {"normal_update",
3292 (PyCFunction)bpy_bmface_normal_update,
3293 METH_NOARGS,
3294 bpy_bmface_normal_update_doc},
3295 {"normal_flip", (PyCFunction)bpy_bmface_normal_flip, METH_NOARGS, bpy_bmface_normal_flip_doc},
3296
3297 {nullptr, nullptr, 0, nullptr},
3298};
3299
3300static PyMethodDef bpy_bmloop_methods[] = {
3301 {"copy_from", (PyCFunction)bpy_bm_elem_copy_from, METH_O, bpy_bm_elem_copy_from_doc},
3302 {"copy_from_face_interp",
3304 METH_VARARGS,
3305 bpy_bmloop_copy_from_face_interp_doc},
3306
3307 {"calc_angle", (PyCFunction)bpy_bmloop_calc_angle, METH_NOARGS, bpy_bmloop_calc_angle_doc},
3308 {"calc_normal", (PyCFunction)bpy_bmloop_calc_normal, METH_NOARGS, bpy_bmloop_calc_normal_doc},
3309 {"calc_tangent",
3310 (PyCFunction)bpy_bmloop_calc_tangent,
3311 METH_NOARGS,
3312 bpy_bmloop_calc_tangent_doc},
3313 {nullptr, nullptr, 0, nullptr},
3314};
3315
3316static PyMethodDef bpy_bmelemseq_methods[] = {
3317 /* odd function, initializes index values */
3318 {"index_update",
3319 (PyCFunction)bpy_bmelemseq_index_update,
3320 METH_NOARGS,
3321 bpy_bmelemseq_index_update_doc},
3322 {nullptr, nullptr, 0, nullptr},
3323};
3324
3325static PyMethodDef bpy_bmvertseq_methods[] = {
3326 {"new", (PyCFunction)bpy_bmvertseq_new, METH_VARARGS, bpy_bmvertseq_new_doc},
3327 {"remove", (PyCFunction)bpy_bmvertseq_remove, METH_O, bpy_bmvertseq_remove_doc},
3328
3329 /* odd function, initializes index values */
3330 {"index_update",
3331 (PyCFunction)bpy_bmelemseq_index_update,
3332 METH_NOARGS,
3333 bpy_bmelemseq_index_update_doc},
3334 {"ensure_lookup_table",
3336 METH_NOARGS,
3337 bpy_bmelemseq_ensure_lookup_table_doc},
3338 {"sort",
3339 (PyCFunction)bpy_bmelemseq_sort,
3340 METH_VARARGS | METH_KEYWORDS,
3341 bpy_bmelemseq_sort_doc},
3342 {nullptr, nullptr, 0, nullptr},
3343};
3344
3345static PyMethodDef bpy_bmedgeseq_methods[] = {
3346 {"new", (PyCFunction)bpy_bmedgeseq_new, METH_VARARGS, bpy_bmedgeseq_new_doc},
3347 {"remove", (PyCFunction)bpy_bmedgeseq_remove, METH_O, bpy_bmedgeseq_remove_doc},
3348 /* 'bpy_bmelemseq_get' for different purpose */
3349 {"get", (PyCFunction)bpy_bmedgeseq_get__method, METH_VARARGS, bpy_bmedgeseq_get__method_doc},
3350
3351 /* odd function, initializes index values */
3352 {"index_update",
3353 (PyCFunction)bpy_bmelemseq_index_update,
3354 METH_NOARGS,
3355 bpy_bmelemseq_index_update_doc},
3356 {"ensure_lookup_table",
3358 METH_NOARGS,
3359 bpy_bmelemseq_ensure_lookup_table_doc},
3360 {"sort",
3361 (PyCFunction)bpy_bmelemseq_sort,
3362 METH_VARARGS | METH_KEYWORDS,
3363 bpy_bmelemseq_sort_doc},
3364 {nullptr, nullptr, 0, nullptr},
3365};
3366
3367static PyMethodDef bpy_bmfaceseq_methods[] = {
3368 {"new", (PyCFunction)bpy_bmfaceseq_new, METH_VARARGS, bpy_bmfaceseq_new_doc},
3369 {"remove", (PyCFunction)bpy_bmfaceseq_remove, METH_O, bpy_bmfaceseq_remove_doc},
3370 /* 'bpy_bmelemseq_get' for different purpose */
3371 {"get", (PyCFunction)bpy_bmfaceseq_get__method, METH_VARARGS, bpy_bmfaceseq_get__method_doc},
3372
3373 /* odd function, initializes index values */
3374 {"index_update",
3375 (PyCFunction)bpy_bmelemseq_index_update,
3376 METH_NOARGS,
3377 bpy_bmelemseq_index_update_doc},
3378 {"ensure_lookup_table",
3380 METH_NOARGS,
3381 bpy_bmelemseq_ensure_lookup_table_doc},
3382 {"sort",
3383 (PyCFunction)bpy_bmelemseq_sort,
3384 METH_VARARGS | METH_KEYWORDS,
3385 bpy_bmelemseq_sort_doc},
3386 {nullptr, nullptr, 0, nullptr},
3387};
3388
3389static PyMethodDef bpy_bmloopseq_methods[] = {
3390 /* odd function, initializes index values */
3391 /* no: index_update() function since we can't iterate over loops */
3392 /* no: sort() function since we can't iterate over loops */
3393 {nullptr, nullptr, 0, nullptr},
3394};
3395
3396#ifdef __GNUC__
3397# ifdef __clang__
3398# pragma clang diagnostic pop
3399# else
3400# pragma GCC diagnostic pop
3401# endif
3402#endif
3403
3404/* Sequences
3405 * ========= */
3406
3407/* BMElemSeq / Iter
3408 * ---------------- */
3409
3410static PyTypeObject *bpy_bm_itype_as_pytype(const char itype)
3411{
3412 /* should cover all types */
3413 switch ((BMIterType)itype) {
3414 case BM_VERTS_OF_MESH:
3415 case BM_VERTS_OF_FACE:
3416 case BM_VERTS_OF_EDGE:
3417 return &BPy_BMVert_Type;
3418
3419 case BM_EDGES_OF_MESH:
3420 case BM_EDGES_OF_FACE:
3421 case BM_EDGES_OF_VERT:
3422 return &BPy_BMEdge_Type;
3423
3424 case BM_FACES_OF_MESH:
3425 case BM_FACES_OF_EDGE:
3426 case BM_FACES_OF_VERT:
3427 return &BPy_BMFace_Type;
3428
3429 // case BM_ALL_LOOPS_OF_FACE:
3430 case BM_LOOPS_OF_FACE:
3431 case BM_LOOPS_OF_EDGE:
3432 case BM_LOOPS_OF_VERT:
3433 case BM_LOOPS_OF_LOOP:
3434 return &BPy_BMLoop_Type;
3435 }
3436
3437 return nullptr;
3438}
3439
3441{
3443
3444 /* first check if the size is known */
3445 switch ((BMIterType)self->itype) {
3446 /* main-types */
3447 case BM_VERTS_OF_MESH:
3448 return self->bm->totvert;
3449 case BM_EDGES_OF_MESH:
3450 return self->bm->totedge;
3451 case BM_FACES_OF_MESH:
3452 return self->bm->totface;
3453
3454 /* sub-types */
3455 case BM_VERTS_OF_FACE:
3456 case BM_EDGES_OF_FACE:
3457 case BM_LOOPS_OF_FACE:
3458 BPY_BM_CHECK_INT(self->py_ele);
3459 return ((BMFace *)self->py_ele->ele)->len;
3460
3461 case BM_VERTS_OF_EDGE:
3462 return 2;
3463
3464 default:
3465 /* quiet compiler */
3466 break;
3467 }
3468
3469 /* loop over all items, avoid this if we can */
3470 {
3471 BMIter iter;
3472 BMHeader *ele;
3473 Py_ssize_t tot = 0;
3474
3475 BM_ITER_BPY_BM_SEQ (ele, &iter, self) {
3476 tot++;
3477 }
3478 return tot;
3479 }
3480}
3481
3482static PyObject *bpy_bmelemseq_subscript_int(BPy_BMElemSeq *self, Py_ssize_t keynum)
3483{
3485
3486 if (keynum < 0) {
3487 /* only get length on negative value, may loop entire seq */
3488 keynum += bpy_bmelemseq_length(self);
3489 }
3490 if (keynum >= 0) {
3491 if (self->itype <= BM_FACES_OF_MESH) {
3492 if ((self->bm->elem_table_dirty & bm_iter_itype_htype_map[self->itype]) == 0) {
3493 BMHeader *ele = nullptr;
3494 switch (self->itype) {
3495 case BM_VERTS_OF_MESH:
3496 if (keynum < self->bm->totvert) {
3497 ele = (BMHeader *)self->bm->vtable[keynum];
3498 }
3499 break;
3500 case BM_EDGES_OF_MESH:
3501 if (keynum < self->bm->totedge) {
3502 ele = (BMHeader *)self->bm->etable[keynum];
3503 }
3504 break;
3505 case BM_FACES_OF_MESH:
3506 if (keynum < self->bm->totface) {
3507 ele = (BMHeader *)self->bm->ftable[keynum];
3508 }
3509 break;
3510 }
3511 if (ele) {
3512 return BPy_BMElem_CreatePyObject(self->bm, ele);
3513 }
3514 /* fall through to index error below */
3515 }
3516 else {
3517 PyErr_SetString(PyExc_IndexError,
3518 "BMElemSeq[index]: outdated internal index table, "
3519 "run ensure_lookup_table() first");
3520 return nullptr;
3521 }
3522 }
3523 else {
3524 BMHeader *ele = static_cast<BMHeader *>(BM_iter_at_index(
3525 self->bm, self->itype, self->py_ele ? self->py_ele->ele : nullptr, keynum));
3526 if (ele) {
3527 return BPy_BMElem_CreatePyObject(self->bm, ele);
3528 }
3529 }
3530 }
3531
3532 PyErr_Format(PyExc_IndexError, "BMElemSeq[index]: index %d out of range", keynum);
3533 return nullptr;
3534}
3535
3537 Py_ssize_t start,
3538 Py_ssize_t stop)
3539{
3540 BMIter iter;
3541 int count = 0;
3542 bool ok;
3543
3544 PyObject *list;
3545 BMHeader *ele;
3546
3548
3549 list = PyList_New(0);
3550
3551 ok = BM_iter_init(&iter, self->bm, self->itype, self->py_ele ? self->py_ele->ele : nullptr);
3552
3553 BLI_assert(ok == true);
3554
3555 if (UNLIKELY(ok == false)) {
3556 return list;
3557 }
3558
3559 /* first loop up-until the start */
3560 for (ok = true; ok; ok = (BM_iter_step(&iter) != nullptr)) {
3561 if (count == start) {
3562 break;
3563 }
3564 count++;
3565 }
3566
3567 /* add items until stop */
3568 while ((ele = static_cast<BMHeader *>(BM_iter_step(&iter)))) {
3569 PyList_APPEND(list, BPy_BMElem_CreatePyObject(self->bm, ele));
3570
3571 count++;
3572 if (count == stop) {
3573 break;
3574 }
3575 }
3576
3577 return list;
3578}
3579
3580static PyObject *bpy_bmelemseq_subscript(BPy_BMElemSeq *self, PyObject *key)
3581{
3582 /* don't need error check here */
3583 if (PyIndex_Check(key)) {
3584 const Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
3585 if (i == -1 && PyErr_Occurred()) {
3586 return nullptr;
3587 }
3589 }
3590 if (PySlice_Check(key)) {
3591 PySliceObject *key_slice = (PySliceObject *)key;
3592 Py_ssize_t step = 1;
3593
3594 if (key_slice->step != Py_None && !_PyEval_SliceIndex(key, &step)) {
3595 return nullptr;
3596 }
3597 if (step != 1) {
3598 PyErr_SetString(PyExc_TypeError, "BMElemSeq[slice]: slice steps not supported");
3599 return nullptr;
3600 }
3601 if (key_slice->start == Py_None && key_slice->stop == Py_None) {
3602 return bpy_bmelemseq_subscript_slice(self, 0, PY_SSIZE_T_MAX);
3603 }
3604
3605 Py_ssize_t start = 0, stop = PY_SSIZE_T_MAX;
3606
3607 /* avoid PySlice_GetIndicesEx because it needs to know the length ahead of time. */
3608 if (key_slice->start != Py_None && !_PyEval_SliceIndex(key_slice->start, &start)) {
3609 return nullptr;
3610 }
3611 if (key_slice->stop != Py_None && !_PyEval_SliceIndex(key_slice->stop, &stop)) {
3612 return nullptr;
3613 }
3614
3615 if (start < 0 || stop < 0) {
3616 /* only get the length for negative values */
3617 const Py_ssize_t len = bpy_bmelemseq_length(self);
3618 if (start < 0) {
3619 start += len;
3620 CLAMP_MIN(start, 0);
3621 }
3622 if (stop < 0) {
3623 stop += len;
3624 CLAMP_MIN(stop, 0);
3625 }
3626 }
3627
3628 if (stop - start <= 0) {
3629 return PyList_New(0);
3630 }
3631
3632 return bpy_bmelemseq_subscript_slice(self, start, stop);
3633 }
3634
3635 PyErr_SetString(PyExc_AttributeError, "BMElemSeq[key]: invalid key, key must be an int");
3636 return nullptr;
3637}
3638
3639static int bpy_bmelemseq_contains(BPy_BMElemSeq *self, PyObject *value)
3640{
3642
3643 if (Py_TYPE(value) == bpy_bm_itype_as_pytype(self->itype)) {
3644 BPy_BMElem *value_bm_ele = (BPy_BMElem *)value;
3645 if (value_bm_ele->bm == self->bm) {
3646 BMElem *ele, *ele_test = value_bm_ele->ele;
3647 BMIter iter;
3648 BM_ITER_BPY_BM_SEQ (ele, &iter, self) {
3649 if (ele == ele_test) {
3650 return 1;
3651 }
3652 }
3653 }
3654 }
3655
3656 return 0;
3657}
3658
3659/* BMElem (customdata)
3660 * ------------------- */
3661
3663{
3665
3666 return BPy_BMLayerItem_GetItem(self, key);
3667}
3668
3669static int bpy_bmelem_ass_subscript(BPy_BMElem *self, BPy_BMLayerItem *key, PyObject *value)
3670{
3672
3673 return BPy_BMLayerItem_SetItem(self, key, value);
3674}
3675
3676static PySequenceMethods bpy_bmelemseq_as_sequence = {
3677 /*sq_length*/ (lenfunc)bpy_bmelemseq_length,
3678 /*sq_concat*/ nullptr,
3679 /*sq_repeat*/ nullptr,
3680 /* Only set this so `PySequence_Check()` returns True. */
3681 /*sq_item*/ (ssizeargfunc)bpy_bmelemseq_subscript_int,
3682 /*was_sq_slice*/ nullptr,
3683 /*sq_ass_item*/ nullptr,
3684 /*was_sq_ass_slice*/ nullptr,
3685 /*sq_contains*/ (objobjproc)bpy_bmelemseq_contains,
3686 /*sq_inplace_concat*/ nullptr,
3687 /*sq_inplace_repeat*/ nullptr,
3688};
3689
3690static PyMappingMethods bpy_bmelemseq_as_mapping = {
3691 /*mp_length*/ (lenfunc)bpy_bmelemseq_length,
3692 /*mp_subscript*/ (binaryfunc)bpy_bmelemseq_subscript,
3693 /*mp_ass_subscript*/ (objobjargproc) nullptr,
3694};
3695
3696/* for customdata access */
3697static PyMappingMethods bpy_bm_elem_as_mapping = {
3698 /*mp_length*/ (lenfunc) nullptr, /* Keep this empty, messes up `if elem: ...` test. */
3699 /*mp_subscript*/ (binaryfunc)bpy_bmelem_subscript,
3700 /*mp_ass_subscript*/ (objobjargproc)bpy_bmelem_ass_subscript,
3701};
3702
3703/* Iterator
3704 * -------- */
3705
3707{
3708 BPy_BMIter *py_iter;
3709
3711 py_iter = (BPy_BMIter *)BPy_BMIter_CreatePyObject(self->bm);
3713 &(py_iter->iter), self->bm, self->itype, self->py_ele ? self->py_ele->ele : nullptr);
3714 return (PyObject *)py_iter;
3715}
3716
3718{
3719 BMHeader *ele = static_cast<BMHeader *>(BM_iter_step(&self->iter));
3720 if (ele == nullptr) {
3721 PyErr_SetNone(PyExc_StopIteration);
3722 return nullptr;
3723 }
3724
3725 return BPy_BMElem_CreatePyObject(self->bm, ele);
3726}
3727
3728/* Deallocate Functions
3729 * ==================== */
3730
3732{
3733 BMesh *bm = self->bm;
3734
3735 /* The mesh has not been freed by #BMesh. */
3736 if (bm) {
3738
3741 }
3744 }
3747 }
3750 }
3751
3752 bm->py_handle = nullptr;
3753
3754 if ((self->flag & BPY_BMFLAG_IS_WRAPPED) == 0) {
3756 }
3757 }
3758
3759 PyObject_DEL(self);
3760}
3761
3763{
3764 BMesh *bm = self->bm;
3765 if (bm) {
3766 void **ptr = static_cast<void **>(
3767 CustomData_bmesh_get(&bm->vdata, self->ele->head.data, CD_BM_ELEM_PYPTR));
3768 if (ptr) {
3769 *ptr = nullptr;
3770 }
3771 }
3772 PyObject_DEL(self);
3773}
3774
3776{
3777 BMesh *bm = self->bm;
3778 if (bm) {
3779 void **ptr = static_cast<void **>(
3780 CustomData_bmesh_get(&bm->edata, self->ele->head.data, CD_BM_ELEM_PYPTR));
3781 if (ptr) {
3782 *ptr = nullptr;
3783 }
3784 }
3785 PyObject_DEL(self);
3786}
3787
3789{
3790 BMesh *bm = self->bm;
3791 if (bm) {
3792 void **ptr = static_cast<void **>(
3793 CustomData_bmesh_get(&bm->pdata, self->ele->head.data, CD_BM_ELEM_PYPTR));
3794 if (ptr) {
3795 *ptr = nullptr;
3796 }
3797 }
3798 PyObject_DEL(self);
3799}
3800
3802{
3803 BMesh *bm = self->bm;
3804 if (bm) {
3805 void **ptr = static_cast<void **>(
3806 CustomData_bmesh_get(&bm->ldata, self->ele->head.data, CD_BM_ELEM_PYPTR));
3807 if (ptr) {
3808 *ptr = nullptr;
3809 }
3810 }
3811 PyObject_DEL(self);
3812}
3813
3815{
3816 Py_XDECREF(self->py_ele);
3817
3818 PyObject_DEL(self);
3819}
3820
3821/* not sure where this should go */
3822static Py_hash_t bpy_bm_elem_hash(PyObject *self)
3823{
3824 return Py_HashPointer(((BPy_BMElem *)self)->ele);
3825}
3826
3827static Py_hash_t bpy_bm_hash(PyObject *self)
3828{
3829 return Py_HashPointer(((BPy_BMesh *)self)->bm);
3830}
3831
3832/* Type Doc-strings
3833 * ================ */
3834
3836 /* Wrap. */
3837 bpy_bmesh_doc,
3838 "The BMesh data structure\n");
3840 /* Wrap. */
3841 bpy_bmvert_doc,
3842 "The BMesh vertex type\n");
3844 /* Wrap. */
3845 bpy_bmedge_doc,
3846 "The BMesh edge connecting 2 verts\n");
3848 /* Wrap. */
3849 bpy_bmface_doc,
3850 "The BMesh face with 3 or more sides\n");
3852 /* Wrap. */
3853 bpy_bmloop_doc,
3854 "This is normally accessed from :class:`BMFace.loops` where each face loop "
3855 "represents a corner of the face.\n");
3857 /* Wrap. */
3858 bpy_bmelemseq_doc,
3859 "General sequence type used for accessing any sequence of\n"
3860 ":class:`BMVert`, :class:`BMEdge`, :class:`BMFace`, :class:`BMLoop`.\n"
3861 "\n"
3862 "When accessed via :class:`BMesh.verts`, :class:`BMesh.edges`, :class:`BMesh.faces`\n"
3863 "there are also functions to create/remove items.\n");
3865 /* Wrap. */
3866 bpy_bmiter_doc,
3867 "Internal BMesh type for looping over verts/faces/edges,\n"
3868 "used for iterating over :class:`BMElemSeq` types.\n");
3869
3871{
3872 BMesh *bm = self->bm;
3873
3874 if (bm) {
3875 return PyUnicode_FromFormat("<BMesh(%p), totvert=%d, totedge=%d, totface=%d, totloop=%d>",
3876 bm,
3877 bm->totvert,
3878 bm->totedge,
3879 bm->totface,
3880 bm->totloop);
3881 }
3882
3883 return PyUnicode_FromFormat("<BMesh dead at %p>", self);
3884}
3885
3887{
3888 BMesh *bm = self->bm;
3889
3890 if (bm) {
3891 BMVert *v = self->v;
3892 return PyUnicode_FromFormat("<BMVert(%p), index=%d>", v, BM_elem_index_get(v));
3893 }
3894
3895 return PyUnicode_FromFormat("<BMVert dead at %p>", self);
3896}
3897
3899{
3900 BMesh *bm = self->bm;
3901
3902 if (bm) {
3903 BMEdge *e = self->e;
3904 return PyUnicode_FromFormat("<BMEdge(%p), index=%d, verts=(%p/%d, %p/%d)>",
3905 e,
3907 e->v1,
3908 BM_elem_index_get(e->v1),
3909 e->v2,
3910 BM_elem_index_get(e->v2));
3911 }
3912
3913 return PyUnicode_FromFormat("<BMEdge dead at %p>", self);
3914}
3915
3917{
3918 BMesh *bm = self->bm;
3919
3920 if (bm) {
3921 BMFace *f = self->f;
3922 return PyUnicode_FromFormat(
3923 "<BMFace(%p), index=%d, totverts=%d>", f, BM_elem_index_get(f), f->len);
3924 }
3925
3926 return PyUnicode_FromFormat("<BMFace dead at %p>", self);
3927}
3928
3930{
3931 BMesh *bm = self->bm;
3932
3933 if (bm) {
3934 BMLoop *l = self->l;
3935 return PyUnicode_FromFormat("<BMLoop(%p), index=%d, vert=%p/%d, edge=%p/%d, face=%p/%d>",
3936 l,
3938 l->v,
3939 BM_elem_index_get(l->v),
3940 l->e,
3941 BM_elem_index_get(l->e),
3942 l->f,
3943 BM_elem_index_get(l->f));
3944 }
3945
3946 return PyUnicode_FromFormat("<BMLoop dead at %p>", self);
3947}
3948
3949/* Types
3950 * ===== */
3951
3952PyTypeObject BPy_BMesh_Type;
3953PyTypeObject BPy_BMVert_Type;
3954PyTypeObject BPy_BMEdge_Type;
3955PyTypeObject BPy_BMFace_Type;
3956PyTypeObject BPy_BMLoop_Type;
3962PyTypeObject BPy_BMIter_Type;
3963
3965{
3966 BPy_BMesh_Type.tp_basicsize = sizeof(BPy_BMesh);
3967 BPy_BMVert_Type.tp_basicsize = sizeof(BPy_BMVert);
3968 BPy_BMEdge_Type.tp_basicsize = sizeof(BPy_BMEdge);
3969 BPy_BMFace_Type.tp_basicsize = sizeof(BPy_BMFace);
3970 BPy_BMLoop_Type.tp_basicsize = sizeof(BPy_BMLoop);
3971 BPy_BMElemSeq_Type.tp_basicsize = sizeof(BPy_BMElemSeq);
3972 BPy_BMVertSeq_Type.tp_basicsize = sizeof(BPy_BMElemSeq);
3973 BPy_BMEdgeSeq_Type.tp_basicsize = sizeof(BPy_BMElemSeq);
3974 BPy_BMFaceSeq_Type.tp_basicsize = sizeof(BPy_BMElemSeq);
3975 BPy_BMLoopSeq_Type.tp_basicsize = sizeof(BPy_BMElemSeq);
3976 BPy_BMIter_Type.tp_basicsize = sizeof(BPy_BMIter);
3977
3978 BPy_BMesh_Type.tp_name = "BMesh";
3979 BPy_BMVert_Type.tp_name = "BMVert";
3980 BPy_BMEdge_Type.tp_name = "BMEdge";
3981 BPy_BMFace_Type.tp_name = "BMFace";
3982 BPy_BMLoop_Type.tp_name = "BMLoop";
3983 BPy_BMElemSeq_Type.tp_name = "BMElemSeq";
3984 BPy_BMVertSeq_Type.tp_name = "BMVertSeq";
3985 BPy_BMEdgeSeq_Type.tp_name = "BMEdgeSeq";
3986 BPy_BMFaceSeq_Type.tp_name = "BMFaceSeq";
3987 BPy_BMLoopSeq_Type.tp_name = "BMLoopSeq";
3988 BPy_BMIter_Type.tp_name = "BMIter";
3989
3990 BPy_BMesh_Type.tp_doc = bpy_bmesh_doc;
3991 BPy_BMVert_Type.tp_doc = bpy_bmvert_doc;
3992 BPy_BMEdge_Type.tp_doc = bpy_bmedge_doc;
3993 BPy_BMFace_Type.tp_doc = bpy_bmface_doc;
3994 BPy_BMLoop_Type.tp_doc = bpy_bmloop_doc;
3995 BPy_BMElemSeq_Type.tp_doc = bpy_bmelemseq_doc;
3996 BPy_BMVertSeq_Type.tp_doc = nullptr;
3997 BPy_BMEdgeSeq_Type.tp_doc = nullptr;
3998 BPy_BMFaceSeq_Type.tp_doc = nullptr;
3999 BPy_BMLoopSeq_Type.tp_doc = nullptr;
4000 BPy_BMIter_Type.tp_doc = bpy_bmiter_doc;
4001
4002 BPy_BMesh_Type.tp_repr = (reprfunc)bpy_bmesh_repr;
4003 BPy_BMVert_Type.tp_repr = (reprfunc)bpy_bmvert_repr;
4004 BPy_BMEdge_Type.tp_repr = (reprfunc)bpy_bmedge_repr;
4005 BPy_BMFace_Type.tp_repr = (reprfunc)bpy_bmface_repr;
4006 BPy_BMLoop_Type.tp_repr = (reprfunc)bpy_bmloop_repr;
4007 BPy_BMElemSeq_Type.tp_repr = nullptr;
4008 BPy_BMVertSeq_Type.tp_repr = nullptr;
4009 BPy_BMEdgeSeq_Type.tp_repr = nullptr;
4010 BPy_BMFaceSeq_Type.tp_repr = nullptr;
4011 BPy_BMLoopSeq_Type.tp_repr = nullptr;
4012 BPy_BMIter_Type.tp_repr = nullptr;
4013
4019 BPy_BMElemSeq_Type.tp_getset = nullptr;
4024 BPy_BMIter_Type.tp_getset = nullptr;
4025
4026 BPy_BMesh_Type.tp_methods = bpy_bmesh_methods;
4036 BPy_BMIter_Type.tp_methods = nullptr;
4037
4038 /* #BPy_BMElem_Check() uses #bpy_bm_elem_hash() to check types.
4039 * if this changes update the macro. */
4040 BPy_BMesh_Type.tp_hash = bpy_bm_hash;
4045 BPy_BMElemSeq_Type.tp_hash = nullptr;
4046 BPy_BMVertSeq_Type.tp_hash = nullptr;
4047 BPy_BMEdgeSeq_Type.tp_hash = nullptr;
4048 BPy_BMFaceSeq_Type.tp_hash = nullptr;
4049 BPy_BMLoopSeq_Type.tp_hash = nullptr;
4050 BPy_BMIter_Type.tp_hash = nullptr;
4051
4056 BPy_BMLoopSeq_Type.tp_as_sequence =
4057 nullptr; /* this is not a seq really, only for layer access */
4058
4063 BPy_BMLoopSeq_Type.tp_as_mapping = nullptr; /* this is not a seq really, only for layer access */
4064
4065 /* layer access */
4066 BPy_BMVert_Type.tp_as_mapping = &bpy_bm_elem_as_mapping;
4067 BPy_BMEdge_Type.tp_as_mapping = &bpy_bm_elem_as_mapping;
4068 BPy_BMFace_Type.tp_as_mapping = &bpy_bm_elem_as_mapping;
4069 BPy_BMLoop_Type.tp_as_mapping = &bpy_bm_elem_as_mapping;
4070
4071 BPy_BMElemSeq_Type.tp_iter = (getiterfunc)bpy_bmelemseq_iter;
4072 BPy_BMVertSeq_Type.tp_iter = (getiterfunc)bpy_bmelemseq_iter;
4073 BPy_BMEdgeSeq_Type.tp_iter = (getiterfunc)bpy_bmelemseq_iter;
4074 BPy_BMFaceSeq_Type.tp_iter = (getiterfunc)bpy_bmelemseq_iter;
4075 BPy_BMLoopSeq_Type.tp_iter = nullptr; /* no mapping */
4076
4077 /* Only 1 iterator so far. */
4078 BPy_BMIter_Type.tp_iternext = (iternextfunc)bpy_bmiter_next;
4079 BPy_BMIter_Type.tp_iter = PyObject_SelfIter;
4080
4081 BPy_BMesh_Type.tp_dealloc = (destructor)bpy_bmesh_dealloc;
4082 BPy_BMVert_Type.tp_dealloc = (destructor)bpy_bmvert_dealloc;
4083 BPy_BMEdge_Type.tp_dealloc = (destructor)bpy_bmedge_dealloc;
4084 BPy_BMFace_Type.tp_dealloc = (destructor)bpy_bmface_dealloc;
4085 BPy_BMLoop_Type.tp_dealloc = (destructor)bpy_bmloop_dealloc;
4086 BPy_BMElemSeq_Type.tp_dealloc = (destructor)bpy_bmelemseq_dealloc;
4087 BPy_BMVertSeq_Type.tp_dealloc = (destructor)bpy_bmelemseq_dealloc;
4088 BPy_BMEdgeSeq_Type.tp_dealloc = (destructor)bpy_bmelemseq_dealloc;
4089 BPy_BMFaceSeq_Type.tp_dealloc = (destructor)bpy_bmelemseq_dealloc;
4090 BPy_BMLoopSeq_Type.tp_dealloc = (destructor)bpy_bmelemseq_dealloc;
4091 BPy_BMIter_Type.tp_dealloc = nullptr;
4092
4093 BPy_BMesh_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4094 BPy_BMVert_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4095 BPy_BMEdge_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4096 BPy_BMFace_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4097 BPy_BMLoop_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4098 BPy_BMElemSeq_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4099 BPy_BMVertSeq_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4100 BPy_BMEdgeSeq_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4101 BPy_BMFaceSeq_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4102 BPy_BMLoopSeq_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4103 BPy_BMIter_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4104
4105 PyType_Ready(&BPy_BMesh_Type);
4106 PyType_Ready(&BPy_BMVert_Type);
4107 PyType_Ready(&BPy_BMEdge_Type);
4108 PyType_Ready(&BPy_BMFace_Type);
4109 PyType_Ready(&BPy_BMLoop_Type);
4110 PyType_Ready(&BPy_BMElemSeq_Type);
4111 PyType_Ready(&BPy_BMVertSeq_Type);
4112 PyType_Ready(&BPy_BMEdgeSeq_Type);
4113 PyType_Ready(&BPy_BMFaceSeq_Type);
4114 PyType_Ready(&BPy_BMLoopSeq_Type);
4115 PyType_Ready(&BPy_BMIter_Type);
4116}
4117
4118/* bmesh.types submodule
4119 * ********************* */
4120
4121static PyModuleDef BPy_BM_types_module_def = {
4122 /*m_base*/ PyModuleDef_HEAD_INIT,
4123 /*m_name*/ "bmesh.types",
4124 /*m_doc*/ nullptr,
4125 /*m_size*/ 0,
4126 /*m_methods*/ nullptr,
4127 /*m_slots*/ nullptr,
4128 /*m_traverse*/ nullptr,
4129 /*m_clear*/ nullptr,
4130 /*m_free*/ nullptr,
4131};
4132
4134{
4135 PyObject *submodule;
4136
4137 submodule = PyModule_Create(&BPy_BM_types_module_def);
4138
4139 /* `bmesh_py_types.cc` */
4140 PyModule_AddType(submodule, &BPy_BMesh_Type);
4141 PyModule_AddType(submodule, &BPy_BMVert_Type);
4142 PyModule_AddType(submodule, &BPy_BMEdge_Type);
4143 PyModule_AddType(submodule, &BPy_BMFace_Type);
4144 PyModule_AddType(submodule, &BPy_BMLoop_Type);
4145 PyModule_AddType(submodule, &BPy_BMElemSeq_Type);
4146 PyModule_AddType(submodule, &BPy_BMVertSeq_Type);
4147 PyModule_AddType(submodule, &BPy_BMEdgeSeq_Type);
4148 PyModule_AddType(submodule, &BPy_BMFaceSeq_Type);
4149 PyModule_AddType(submodule, &BPy_BMLoopSeq_Type);
4150 PyModule_AddType(submodule, &BPy_BMIter_Type);
4151 /* `bmesh_py_types_select.cc` */
4152 PyModule_AddType(submodule, &BPy_BMEditSelSeq_Type);
4153 PyModule_AddType(submodule, &BPy_BMEditSelIter_Type);
4154 /* `bmesh_py_types_customdata.cc` */
4155 PyModule_AddType(submodule, &BPy_BMLayerAccessVert_Type);
4156 PyModule_AddType(submodule, &BPy_BMLayerAccessEdge_Type);
4157 PyModule_AddType(submodule, &BPy_BMLayerAccessFace_Type);
4158 PyModule_AddType(submodule, &BPy_BMLayerAccessLoop_Type);
4159 PyModule_AddType(submodule, &BPy_BMLayerCollection_Type);
4160 PyModule_AddType(submodule, &BPy_BMLayerItem_Type);
4161 /* `bmesh_py_types_meshdata.cc` */
4162 PyModule_AddType(submodule, &BPy_BMLoopUV_Type);
4163 PyModule_AddType(submodule, &BPy_BMDeformVert_Type);
4164
4165 return submodule;
4166}
4167
4168/* Utility Functions
4169 * ***************** */
4170
4172{
4173 BPy_BMesh *self;
4174
4175 if (bm->py_handle) {
4176 self = static_cast<BPy_BMesh *>(bm->py_handle);
4177 Py_INCREF(self);
4178 }
4179 else {
4180 self = PyObject_New(BPy_BMesh, &BPy_BMesh_Type);
4181 self->bm = bm;
4182 self->flag = flag;
4183
4184 bm->py_handle = self; /* point back */
4185
4186/* avoid allocating layers when we don't have to */
4187#if 0
4192#endif
4193 }
4194
4195 return (PyObject *)self;
4196}
4197
4199{
4201
4202 void **ptr = static_cast<void **>(
4203 CustomData_bmesh_get(&bm->vdata, v->head.data, CD_BM_ELEM_PYPTR));
4204
4205 /* bmesh may free layers, ensure we have one to store ourself */
4206 if (UNLIKELY(ptr == nullptr)) {
4208 ptr = static_cast<void **>(CustomData_bmesh_get(&bm->vdata, v->head.data, CD_BM_ELEM_PYPTR));
4209 }
4210
4211 if (*ptr != nullptr) {
4212 self = static_cast<BPy_BMVert *>(*ptr);
4213 Py_INCREF(self);
4214 }
4215 else {
4216 self = PyObject_New(BPy_BMVert, &BPy_BMVert_Type);
4217 BLI_assert(v != nullptr);
4218 self->bm = bm;
4219 self->v = v;
4220 *ptr = self;
4221 }
4222 return (PyObject *)self;
4223}
4224
4226{
4228
4229 void **ptr = static_cast<void **>(
4230 CustomData_bmesh_get(&bm->edata, e->head.data, CD_BM_ELEM_PYPTR));
4231
4232 /* bmesh may free layers, ensure we have one to store ourself */
4233 if (UNLIKELY(ptr == nullptr)) {
4235 ptr = static_cast<void **>(CustomData_bmesh_get(&bm->edata, e->head.data, CD_BM_ELEM_PYPTR));
4236 }
4237
4238 if (*ptr != nullptr) {
4239 self = static_cast<BPy_BMEdge *>(*ptr);
4240 Py_INCREF(self);
4241 }
4242 else {
4243 self = PyObject_New(BPy_BMEdge, &BPy_BMEdge_Type);
4244 BLI_assert(e != nullptr);
4245 self->bm = bm;
4246 self->e = e;
4247 *ptr = self;
4248 }
4249 return (PyObject *)self;
4250}
4251
4253{
4255
4256 void **ptr = static_cast<void **>(
4258
4259 /* bmesh may free layers, ensure we have one to store ourself */
4260 if (UNLIKELY(ptr == nullptr)) {
4262 ptr = static_cast<void **>(CustomData_bmesh_get(&bm->pdata, f->head.data, CD_BM_ELEM_PYPTR));
4263 }
4264
4265 if (*ptr != nullptr) {
4266 self = static_cast<BPy_BMFace *>(*ptr);
4267 Py_INCREF(self);
4268 }
4269 else {
4270 self = PyObject_New(BPy_BMFace, &BPy_BMFace_Type);
4271 BLI_assert(f != nullptr);
4272 self->bm = bm;
4273 self->f = f;
4274 *ptr = self;
4275 }
4276 return (PyObject *)self;
4277}
4278
4280{
4282
4283 void **ptr = static_cast<void **>(
4284 CustomData_bmesh_get(&bm->ldata, l->head.data, CD_BM_ELEM_PYPTR));
4285
4286 /* bmesh may free layers, ensure we have one to store ourself */
4287 if (UNLIKELY(ptr == nullptr)) {
4289 ptr = static_cast<void **>(CustomData_bmesh_get(&bm->ldata, l->head.data, CD_BM_ELEM_PYPTR));
4290 }
4291
4292 if (*ptr != nullptr) {
4293 self = static_cast<BPy_BMLoop *>(*ptr);
4294 Py_INCREF(self);
4295 }
4296 else {
4297 self = PyObject_New(BPy_BMLoop, &BPy_BMLoop_Type);
4298 BLI_assert(l != nullptr);
4299 self->bm = bm;
4300 self->l = l;
4301 *ptr = self;
4302 }
4303 return (PyObject *)self;
4304}
4305
4306PyObject *BPy_BMElemSeq_CreatePyObject(BMesh *bm, BPy_BMElem *py_ele, const char itype)
4307{
4309 self->bm = bm;
4310 self->py_ele = py_ele; /* can be nullptr */
4311 self->itype = itype;
4312 Py_XINCREF(py_ele);
4313 return (PyObject *)self;
4314}
4315
4317{
4319 self->bm = bm;
4320 self->py_ele = nullptr; /* unused */
4321 self->itype = BM_VERTS_OF_MESH;
4322 return (PyObject *)self;
4323}
4324
4326{
4328 self->bm = bm;
4329 self->py_ele = nullptr; /* unused */
4330 self->itype = BM_EDGES_OF_MESH;
4331 return (PyObject *)self;
4332}
4333
4335{
4337 self->bm = bm;
4338 self->py_ele = nullptr; /* unused */
4339 self->itype = BM_FACES_OF_MESH;
4340 return (PyObject *)self;
4341}
4342
4344{
4346 self->bm = bm;
4347 self->py_ele = nullptr; /* unused */
4348 self->itype = 0; /* should never be passed to the iterator function */
4349 return (PyObject *)self;
4350}
4351
4353{
4354 BPy_BMIter *self = PyObject_New(BPy_BMIter, &BPy_BMIter_Type);
4355 self->bm = bm;
4356 /* caller must initialize 'iter' member */
4357 return (PyObject *)self;
4358}
4359
4361{
4362 switch (ele->htype) {
4363 case BM_VERT:
4364 return BPy_BMVert_CreatePyObject(bm, (BMVert *)ele);
4365 case BM_EDGE:
4366 return BPy_BMEdge_CreatePyObject(bm, (BMEdge *)ele);
4367 case BM_FACE:
4368 return BPy_BMFace_CreatePyObject(bm, (BMFace *)ele);
4369 case BM_LOOP:
4370 return BPy_BMLoop_CreatePyObject(bm, (BMLoop *)ele);
4371 default:
4373 PyErr_SetString(PyExc_SystemError, "internal error");
4374 return nullptr;
4375 }
4376}
4377
4379{
4380 if (LIKELY(self->bm)) {
4381
4382/* far too slow to enable by default but handy
4383 * to uncomment for debugging tricky errors,
4384 * note that this will throw error on entering a
4385 * function where the actual error will be caused by
4386 * the previous action. */
4387#if 0
4388 if (BM_mesh_validate(self->bm) == false) {
4389 PyErr_Format(
4390 PyExc_ReferenceError, "BMesh used by %.200s has become invalid", Py_TYPE(self)->tp_name);
4391 return -1;
4392 }
4393#endif
4394
4395 return 0;
4396 }
4397
4398 PyErr_Format(
4399 PyExc_ReferenceError, "BMesh data of type %.200s has been removed", Py_TYPE(self)->tp_name);
4400 return -1;
4401}
4402
4404 const char *error_prefix,
4405 void **args,
4406 uint args_tot)
4407{
4408 int ret = 0;
4409
4410 while (args_tot--) {
4411 BPy_BMGeneric *py_bm_elem = static_cast<BPy_BMGeneric *>(args[args_tot]);
4412 if (py_bm_elem) {
4413
4414 BLI_assert(BPy_BMesh_Check(py_bm_elem) || BPy_BMElem_Check(py_bm_elem));
4415
4416 ret = bpy_bm_generic_valid_check(py_bm_elem);
4417 if (UNLIKELY(ret == -1)) {
4418 break;
4419 }
4420
4421 if (UNLIKELY(py_bm_elem->bm != bm_source)) {
4422 /* could give more info here */
4423 PyErr_Format(PyExc_ValueError,
4424 "%.200s: BMesh data of type %.200s is from another mesh",
4425 error_prefix,
4426 Py_TYPE(py_bm_elem)->tp_name);
4427 ret = -1;
4428 break;
4429 }
4430 }
4431 }
4432
4433 return ret;
4434}
4435
4437{
4438 self->bm = nullptr;
4439}
4440
4442 PyObject *seq_fast,
4443 Py_ssize_t min,
4444 Py_ssize_t max,
4445 Py_ssize_t *r_size,
4446 const char htype,
4447 const bool do_unique_check,
4448 const bool do_bm_check,
4449 const char *error_prefix)
4450{
4451 BMesh *bm = (r_bm && *r_bm) ? *r_bm : nullptr;
4452 PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast);
4453 const Py_ssize_t seq_len = PySequence_Fast_GET_SIZE(seq_fast);
4454 Py_ssize_t i, i_last_dirty = PY_SSIZE_T_MAX;
4455
4456 BPy_BMElem *item;
4457 BMElem **alloc;
4458
4459 *r_size = 0;
4460
4461 if (seq_len < min || seq_len > max) {
4462 PyErr_Format(PyExc_TypeError,
4463 "%s: sequence incorrect size, expected [%d - %d], given %d",
4464 error_prefix,
4465 min,
4466 max,
4467 seq_len);
4468 return nullptr;
4469 }
4470
4471 /* from now on, use goto */
4472 alloc = static_cast<BMElem **>(PyMem_MALLOC(seq_len * sizeof(BPy_BMElem **)));
4473
4474 for (i = 0; i < seq_len; i++) {
4475 item = (BPy_BMElem *)seq_fast_items[i];
4476
4477 if (!BPy_BMElem_CheckHType(Py_TYPE(item), htype)) {
4478 PyErr_Format(PyExc_TypeError,
4479 "%s: expected %.200s, not '%.200s'",
4480 error_prefix,
4482 Py_TYPE(item)->tp_name);
4483 goto err_cleanup;
4484 }
4485 else if (!BPY_BM_IS_VALID(item)) {
4486 PyErr_Format(
4487 PyExc_TypeError, "%s: %d %s has been removed", error_prefix, i, Py_TYPE(item)->tp_name);
4488 goto err_cleanup;
4489 }
4490 /* trick so we can ensure all items have the same mesh,
4491 * and allows us to pass the 'bm' as nullptr. */
4492 else if (do_bm_check && (bm && bm != item->bm)) {
4493 PyErr_Format(PyExc_ValueError,
4494 "%s: %d %s is from another mesh",
4495 error_prefix,
4496 i,
4498 goto err_cleanup;
4499 }
4500
4501 if (bm == nullptr) {
4502 bm = item->bm;
4503 }
4504
4505 alloc[i] = item->ele;
4506
4507 if (do_unique_check) {
4509 i_last_dirty = i;
4510 }
4511 }
4512
4513 if (do_unique_check) {
4514 /* check for double verts! */
4515 bool ok = true;
4516 for (i = 0; i < seq_len; i++) {
4517 if (UNLIKELY(BM_elem_flag_test(alloc[i], BM_ELEM_INTERNAL_TAG) == false)) {
4518 ok = false;
4519 }
4520
4521 /* ensure we don't leave this enabled */
4523 }
4524
4525 if (ok == false) {
4526 /* Cleared above. */
4527 i_last_dirty = PY_SSIZE_T_MAX;
4528 PyErr_Format(PyExc_ValueError,
4529 "%s: found the same %.200s used multiple times",
4530 error_prefix,
4532 goto err_cleanup;
4533 }
4534 }
4535
4536 *r_size = seq_len;
4537 if (r_bm) {
4538 *r_bm = bm;
4539 }
4540 return alloc;
4541
4542err_cleanup:
4543 if (do_unique_check && (i_last_dirty != PY_SSIZE_T_MAX)) {
4544 for (i = 0; i <= i_last_dirty; i++) {
4546 }
4547 }
4548 PyMem_FREE(alloc);
4549 return nullptr;
4550}
4551
4553 PyObject *seq,
4554 Py_ssize_t min,
4555 Py_ssize_t max,
4556 Py_ssize_t *r_size,
4557 const char htype,
4558 const bool do_unique_check,
4559 const bool do_bm_check,
4560 const char *error_prefix)
4561{
4562 PyObject *seq_fast;
4563 PyObject *ret;
4564
4565 if (!(seq_fast = PySequence_Fast(seq, error_prefix))) {
4566 return nullptr;
4567 }
4568
4569 ret = static_cast<PyObject *>(BPy_BMElem_PySeq_As_Array_FAST(
4570 r_bm, seq_fast, min, max, r_size, htype, do_unique_check, do_bm_check, error_prefix));
4571
4572 Py_DECREF(seq_fast);
4573 return ret;
4574}
4575
4576PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len)
4577{
4578 Py_ssize_t i;
4579 PyObject *ret = PyTuple_New(elem_len);
4580 for (i = 0; i < elem_len; i++) {
4581 PyTuple_SET_ITEM(ret, i, BPy_BMElem_CreatePyObject(bm, elem[i]));
4582 }
4583 return ret;
4584}
4585PyObject *BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_len)
4586{
4587 Py_ssize_t i;
4588 PyObject *ret = PyTuple_New(elem_len);
4589 for (i = 0; i < elem_len; i++) {
4590 PyTuple_SET_ITEM(ret, i, BPy_BMVert_CreatePyObject(bm, elem[i]));
4591 }
4592 return ret;
4593}
4594PyObject *BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_len)
4595{
4596 Py_ssize_t i;
4597 PyObject *ret = PyTuple_New(elem_len);
4598 for (i = 0; i < elem_len; i++) {
4599 PyTuple_SET_ITEM(ret, i, BPy_BMEdge_CreatePyObject(bm, elem[i]));
4600 }
4601
4602 return ret;
4603}
4604PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_len)
4605{
4606 Py_ssize_t i;
4607 PyObject *ret = PyTuple_New(elem_len);
4608 for (i = 0; i < elem_len; i++) {
4609 PyTuple_SET_ITEM(ret, i, BPy_BMFace_CreatePyObject(bm, elem[i]));
4610 }
4611
4612 return ret;
4613}
4614PyObject *BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop *const *elem, Py_ssize_t elem_len)
4615{
4616 Py_ssize_t i;
4617 PyObject *ret = PyTuple_New(elem_len);
4618 for (i = 0; i < elem_len; i++) {
4619 PyTuple_SET_ITEM(ret, i, BPy_BMLoop_CreatePyObject(bm, elem[i]));
4620 }
4621
4622 return ret;
4623}
4624
4625int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype)
4626{
4627 return (((htype & BM_VERT) && (type == &BPy_BMVert_Type)) ||
4628 ((htype & BM_EDGE) && (type == &BPy_BMEdge_Type)) ||
4629 ((htype & BM_FACE) && (type == &BPy_BMFace_Type)) ||
4630 ((htype & BM_LOOP) && (type == &BPy_BMLoop_Type)));
4631}
4632
4633char *BPy_BMElem_StringFromHType_ex(const char htype, char ret[32])
4634{
4635 /* Zero to ensure string is always null terminated. */
4636 const char *ret_array[4];
4637 int i = 0;
4638 if (htype & BM_VERT) {
4639 ret_array[i++] = BPy_BMVert_Type.tp_name;
4640 }
4641 if (htype & BM_EDGE) {
4642 ret_array[i++] = BPy_BMEdge_Type.tp_name;
4643 }
4644 if (htype & BM_FACE) {
4645 ret_array[i++] = BPy_BMFace_Type.tp_name;
4646 }
4647 if (htype & BM_LOOP) {
4648 ret_array[i++] = BPy_BMLoop_Type.tp_name;
4649 }
4650 ret[0] = '(';
4651 int ret_ofs = BLI_string_join_array_by_sep_char(ret + 1, 30, '/', ret_array, i) + 1;
4652 ret[ret_ofs] = ')';
4653 ret[ret_ofs + 1] = '\0';
4654 return ret;
4655}
4656char *BPy_BMElem_StringFromHType(const char htype)
4657{
4658 /* Zero to ensure string is always null terminated. */
4659 static char ret[32];
4660 return BPy_BMElem_StringFromHType_ex(htype, ret);
4661}
4662
4663/* -------------------------------------------------------------------- */
4664/* keep at bottom */
4665
4666/* This function is called on free, it should stay quite fast */
4668{
4669 if (self->flag & BPY_BMFLAG_IS_WRAPPED) {
4670 /* Currently NOP - this works without warnings now. */
4671 }
4672}
CustomData interface, see also DNA_customdata_types.h.
BMCustomDataCopyMap CustomData_bmesh_copy_map_calc(const CustomData &src, const CustomData &dst, eCustomDataMask mask_exclude=0)
void * CustomData_bmesh_get(const CustomData *data, void *block, eCustomDataType type)
const CustomData_MeshMasks CD_MASK_BMESH
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
#define G_MAIN
void BKE_id_free(Main *bmain, void *idv)
bool BKE_id_is_in_global_main(ID *id)
Definition lib_id.cc:2480
Mesh * BKE_mesh_new_from_object(Depsgraph *depsgraph, Object *object, bool preserve_all_data_layers, bool preserve_origindex, bool ensure_subdivision)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE float clamp_f(float value, float min, float max)
MINLINE int poly_to_tri_count(int poly_count, int corner_count)
void mul_m4_v3(const float M[4][4], float r[3])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void range_vn_i(int *array_tar, int size, int start)
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
Definition sort.cc:77
size_t BLI_string_join_array_by_sep_char(char *result, size_t result_maxncpy, char sep, const char *strings[], uint strings_num) ATTR_NONNULL()
unsigned int uint
#define POINTER_AS_INT(i)
#define UNLIKELY(x)
#define CLAMP_MIN(a, b)
#define LIKELY(x)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ DAG_EVAL_RENDER
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_GEOMETRY_ALL_MODES
Definition DNA_ID.h:1089
@ ID_TAG_NO_MAIN
Definition DNA_ID.h:886
@ CD_BM_ELEM_PYPTR
#define MAXMAT
Object is a sort of wrapper for general info.
@ OB_MESH
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
bool stop
Definition WM_types.hh:1016
@ BM_LOOP
@ BM_ELEM_HIDDEN
@ BM_ELEM_SEAM
@ BM_ELEM_SELECT
@ BM_ELEM_SMOOTH
@ BM_ELEM_INTERNAL_TAG
@ BM_ELEM_TAG
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMVert *src, BMVert *dst)
BMesh * BM_mesh_copy(BMesh *bm_old)
void BM_vert_kill(BMesh *bm, BMVert *v)
void BM_face_kill(BMesh *bm, BMFace *f)
BMFace * BM_face_create_verts(BMesh *bm, BMVert **vert_arr, const int len, const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
BMFace * BM_face_copy(BMesh *bm_dst, const BMCustomDataCopyMap &cd_face_map, const BMCustomDataCopyMap &cd_loop_map, BMFace *f, const bool copy_verts, const bool copy_edges)
void BM_edge_kill(BMesh *bm, BMEdge *e)
BMVert * BM_vert_create(BMesh *bm, const float co[3], const BMVert *v_example, const eBMCreateFlag create_flag)
Main function for creating a new vertex.
Definition bmesh_core.cc:41
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
@ BM_CREATE_NOP
Definition bmesh_core.hh:28
#define BM_elem_index_get(ele)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_flag_set(ele, hflag, val)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
void BM_data_layer_free(BMesh *bm, CustomData *data, int type)
void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src)
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, const bool do_vertex)
void BM_loop_interp_from_face(BMesh *bm, BMLoop *l_dst, const BMFace *f_src, const bool do_vertex, const bool do_multires)
void BM_data_interp_from_verts(BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac)
Data, Interpolate From Verts.
void * BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
const char bm_iter_itype_htype_map[BM_ITYPE_MAX]
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_iter_init(iter, bm, itype, data)
BMIterType
BMesh Iterators.
@ BM_LOOPS_OF_LOOP
@ BM_FACES_OF_EDGE
@ BM_FACES_OF_VERT
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_EDGE
@ BM_VERTS_OF_FACE
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_EDGE
@ BM_EDGES_OF_VERT
@ BM_EDGES_OF_FACE
@ BM_LOOPS_OF_FACE
BMesh const char void * data
BMesh * bm
BMesh const char itype
void BM_mesh_select_mode_flush(BMesh *bm)
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
void BM_mesh_select_flush(BMesh *bm)
void BM_mesh_deselect_flush(BMesh *bm)
#define BM_elem_hide_set(bm, ele, hide)
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx)
void BM_mesh_clear(BMesh *bm)
BMesh Clear Mesh.
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
int BM_mesh_elem_count(BMesh *bm, const char htype)
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *mesh, const BMeshFromMeshParams *params)
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *mesh, const BMeshToMeshParams *params)
void BM_mesh_normals_update(BMesh *bm)
void BM_mesh_calc_tessellation(BMesh *bm, MutableSpan< std::array< BMLoop *, 3 > > looptris)
bool BM_mesh_validate(BMesh *bm)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void BM_face_calc_tangent_from_vert_diagonal(const BMFace *f, float r_tangent[3])
void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
void BM_vert_normal_update(BMVert *v)
void BM_face_calc_tangent_from_edge_pair(const BMFace *f, float r_tangent[3])
void BM_face_normal_update(BMFace *f)
void BM_face_normal_flip(BMesh *bm, BMFace *f)
float BM_face_calc_area(const BMFace *f)
void BM_face_calc_tangent_from_edge(const BMFace *f, float r_tangent[3])
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
void BM_face_calc_tangent_from_edge_diagonal(const BMFace *f, float r_tangent[3])
void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3])
float BM_face_calc_perimeter(const BMFace *f)
void BM_edge_normals_update(BMEdge *e)
static Py_hash_t bpy_bm_hash(PyObject *self)
PyObject * BPy_BMEdgeSeq_CreatePyObject(BMesh *bm)
static PyObject * bpy_bmedge_calc_face_angle_signed(BPy_BMEdge *self, PyObject *args)
static void bpy_bmvert_dealloc(BPy_BMElem *self)
PyObject * BPy_BMFace_CreatePyObject(BMesh *bm, BMFace *f)
static PyObject * bpy_bmvert_normal_update(BPy_BMVert *self)
static PyObject * bpy_bmloop_vert_get(BPy_BMLoop *self, void *)
static Py_hash_t bpy_bm_elem_hash(PyObject *self)
static PyObject * bpy_bmloop_link_loop_prev_get(BPy_BMLoop *self, void *)
PyC_FlagSet bpy_bm_htype_all_flags[]
static PyMappingMethods bpy_bmelemseq_as_mapping
static PyObject * bpy_bmesh_normal_update(BPy_BMesh *self)
static PyObject * bpy_bmesh_select_flush_mode(BPy_BMesh *self)
static PyObject * bpy_bmface_calc_center_bounds(BPy_BMFace *self)
PyObject * BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_len)
static int bpy_bmvert_co_set(BPy_BMVert *self, PyObject *value, void *)
static PyObject * bpy_bmface_normal_update(BPy_BMFace *self)
static PyObject * bpy_bmvertseq_get(BPy_BMesh *self, void *)
static PyObject * bpy_bmesh_clear(BPy_BMesh *self)
static PyObject * bpy_bmesh_select_history_get(BPy_BMesh *self, void *)
static PyObject * bpy_bmesh_calc_loop_triangles(BPy_BMElem *self)
PyObject * BPy_BMLoopSeq_CreatePyObject(BMesh *bm)
static PyObject * bpy_bmvert_calc_edge_angle(BPy_BMVert *self, PyObject *args)
PyObject * BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len)
PyObject * BPy_BMFaceSeq_CreatePyObject(BMesh *bm)
static PyObject * bpy_bmloop_link_loop_radial_next_get(BPy_BMLoop *self, void *)
static PyObject * bpy_bmloop_calc_tangent(BPy_BMLoop *self)
static PyObject * bpy_bmelemseq_iter(BPy_BMElemSeq *self)
static PyGetSetDef bpy_bmvertseq_getseters[]
PyObject * BPy_BMElem_CreatePyObject(BMesh *bm, BMHeader *ele)
static PyObject * bpy_bmface_calc_tangent_vert_diagonal(BPy_BMFace *self)
static PyGetSetDef bpy_bmloopseq_getseters[]
static PyObject * bpy_bmloop_calc_normal(BPy_BMLoop *self)
PyObject * BPy_BMesh_CreatePyObject(BMesh *bm, int flag)
PyObject * BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_len)
static PyObject * bpy_bmedge_is_contiguous_get(BPy_BMEdge *self, void *)
static PyObject * bpy_bmvert_is_boundary_get(BPy_BMVert *self, void *)
PyTypeObject BPy_BMesh_Type
PyObject * BPy_BMElemSeq_CreatePyObject(BMesh *bm, BPy_BMElem *py_ele, const char itype)
static PyObject * bpy_bmelemseq_subscript(BPy_BMElemSeq *self, PyObject *key)
static int bpy_bm_elem_index_set(BPy_BMElem *self, PyObject *value, void *)
static PyModuleDef BPy_BM_types_module_def
static PyObject * bpy_bmloop_is_convex_get(BPy_BMLoop *self, void *)
PyC_FlagSet bpy_bm_htype_vert_edge_face_flags[]
PyObject * BPy_BMVert_CreatePyObject(BMesh *bm, BMVert *v)
PyObject * BPy_BMLoop_CreatePyObject(BMesh *bm, BMLoop *l)
static PyMethodDef bpy_bmedgeseq_methods[]
static PyObject * bpy_bmvert_calc_shell_factor(BPy_BMVert *self)
static PyObject * bpy_bmesh_calc_volume(BPy_BMElem *self, PyObject *args, PyObject *kw)
static PyObject * bpy_bmface_normal_get(BPy_BMFace *self, void *)
static PyObject * bpy_bmloop_edge_get(BPy_BMLoop *self, void *)
PyObject * BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop *const *elem, Py_ssize_t elem_len)
static PyMappingMethods bpy_bm_elem_as_mapping
static PyObject * bpy_bmloop_calc_angle(BPy_BMLoop *self)
static PyObject * bpy_bm_elem_hide_set(BPy_BMElem *self, PyObject *value)
char * BPy_BMElem_StringFromHType(const char htype)
static int bpy_bmelem_ass_subscript(BPy_BMElem *self, BPy_BMLayerItem *key, PyObject *value)
static PyObject * bpy_bmvertseq_remove(BPy_BMElemSeq *self, BPy_BMVert *value)
static PyObject * bpy_bmloop_link_loop_next_get(BPy_BMLoop *self, void *)
static PyObject * bpy_bmloop_link_loop_radial_prev_get(BPy_BMLoop *self, void *)
static PyObject * bpy_bmedge_calc_face_angle(BPy_BMEdge *self, PyObject *args)
static PyObject * bpy_bmelemseq_elem_get(BPy_BMElem *self, void *itype)
static void bm_dealloc_editmode_warn(BPy_BMesh *self)
static PyObject * bpy_bmedge_is_wire_get(BPy_BMEdge *self, void *)
PyTypeObject BPy_BMVertSeq_Type
PyTypeObject BPy_BMLoopSeq_Type
static PyObject * bpy_bmface_repr(BPy_BMFace *self)
static void bpy_bmedge_dealloc(BPy_BMElem *self)
static int bpy_bmvert_normal_set(BPy_BMVert *self, PyObject *value, void *)
static PyObject * bpy_bmesh_repr(BPy_BMesh *self)
static PyGetSetDef bpy_bmvert_getseters[]
PyObject * BPy_BMVertSeq_CreatePyObject(BMesh *bm)
static PyObject * bpy_bmedge_normal_update(BPy_BMEdge *self)
static PyObject * bpy_bmedge_repr(BPy_BMEdge *self)
static PyMethodDef bpy_bmedge_methods[]
static void bpy_bmloop_dealloc(BPy_BMElem *self)
static Py_ssize_t bpy_bmelemseq_length(BPy_BMElemSeq *self)
char * BPy_BMElem_StringFromHType_ex(const char htype, char ret[32])
static PyObject * bpy_bmvert_is_wire_get(BPy_BMVert *self, void *)
static PyGetSetDef bpy_bmesh_getseters[]
void bpy_bm_generic_invalidate(BPy_BMGeneric *self)
PyObject * BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_len)
void BPy_BM_init_types()
static PyMethodDef bpy_bmvert_methods[]
static PyObject * bpy_bmedgeseq_remove(BPy_BMElemSeq *self, BPy_BMEdge *value)
static int bpy_bmface_normal_set(BPy_BMFace *self, PyObject *value, void *)
static PyObject * bpy_bmloop_face_get(BPy_BMLoop *self, void *)
static PyObject * bpy_bmesh_copy(BPy_BMesh *self)
static PyObject * bpy_bmedge_calc_tangent(BPy_BMEdge *self, PyObject *args)
static PyObject * bpy_bm_elem_hflag_get(BPy_BMElem *self, void *flag)
PyTypeObject BPy_BMEdgeSeq_Type
static PyObject * bpy_bmvert_is_manifold_get(BPy_BMVert *self, void *)
static PyObject * bpy_bmedge_is_convex_get(BPy_BMEdge *self, void *)
static PyObject * bpy_bmedgeseq_get__method(BPy_BMElemSeq *self, PyObject *args)
static PyObject * bpy_bmface_calc_tangent_edge_diagonal(BPy_BMFace *self)
static PyObject * bpy_bmesh_select_flush(BPy_BMesh *self, PyObject *value)
PyTypeObject BPy_BMEdge_Type
static PyObject * bpy_bmedge_calc_length(BPy_BMEdge *self)
static PyMethodDef bpy_bmelemseq_methods[]
static PyObject * bpy_bmedgeseq_get(BPy_BMesh *self, void *)
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)
static PyObject * bpy_bmvertseq_new(BPy_BMElemSeq *self, PyObject *args)
static PyObject * bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
static PyObject * bpy_bmface_calc_tangent_edge_pair(BPy_BMFace *self)
static PyTypeObject * bpy_bm_itype_as_pytype(const char itype)
static PyObject * bpy_bmface_normal_flip(BPy_BMFace *self)
static PyObject * bpy_bmedge_is_manifold_get(BPy_BMEdge *self, void *)
static PyGetSetDef bpy_bmfaceseq_getseters[]
static PyObject * bpy_bmfaceseq_remove(BPy_BMElemSeq *self, BPy_BMFace *value)
static PyObject * bpy_bmloop_repr(BPy_BMLoop *self)
static PyGetSetDef bpy_bmedge_getseters[]
static int bpy_bmfaceseq_active_set(BPy_BMElem *self, PyObject *value, void *)
static PyObject * bpy_bmelemseq_index_update(BPy_BMElemSeq *self)
static PyObject * bpy_bm_is_valid_get(BPy_BMGeneric *self, void *)
static int bpy_bmelemseq_sort_cmp_by_keys_descending(const void *index1_v, const void *index2_v, void *keys_v)
static PyObject * bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw)
static PyObject * bpy_bmesh_transform(BPy_BMElem *self, PyObject *args, PyObject *kw)
int bpy_bm_generic_valid_check_source(BMesh *bm_source, const char *error_prefix, void **args, uint args_tot)
static PyObject * bpy_bmvert_co_get(BPy_BMVert *self, void *)
static PyObject * bpy_bmesh_select_mode_get(BPy_BMesh *self, void *)
static PyObject * bpy_bmedgeseq_new(BPy_BMElemSeq *self, PyObject *args)
static PyMethodDef bpy_bmfaceseq_methods[]
static PyObject * bpy_bmfaceseq_get__method(BPy_BMElemSeq *self, PyObject *args)
static PyMethodDef bpy_bmloopseq_methods[]
static PyObject * bpy_bmedge_is_boundary_get(BPy_BMEdge *self, void *)
static PyObject * bpy_bmface_copy(BPy_BMFace *self, PyObject *args, PyObject *kw)
static PyGetSetDef bpy_bmedgeseq_getseters[]
static PyObject * bpy_bmelemseq_subscript_slice(BPy_BMElemSeq *self, Py_ssize_t start, Py_ssize_t stop)
static void bpy_bmelemseq_dealloc(BPy_BMElemSeq *self)
int bpy_bm_generic_valid_check(BPy_BMGeneric *self)
static PyObject * bpy_bmelemseq_subscript_int(BPy_BMElemSeq *self, Py_ssize_t keynum)
static PyObject * bpy_bmface_calc_perimeter(BPy_BMFace *self)
void * BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm, PyObject *seq_fast, 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)
static void bpy_bmface_dealloc(BPy_BMElem *self)
PyTypeObject BPy_BMFaceSeq_Type
PyTypeObject BPy_BMVert_Type
PyTypeObject BPy_BMIter_Type
static int bpy_bmface_material_index_set(BPy_BMFace *self, PyObject *value, void *)
static PyObject * bpy_bmvert_copy_from_vert_interp(BPy_BMVert *self, PyObject *args)
static int bpy_bmesh_select_history_set(BPy_BMesh *self, PyObject *value, void *)
static PyMethodDef bpy_bmface_methods[]
static PyMethodDef bpy_bmloop_methods[]
static PyObject * bpy_bmface_calc_center_mean(BPy_BMFace *self)
static PyObject * bpy_bm_elem_index_get(BPy_BMElem *self, void *)
PyDoc_STRVAR(bpy_bm_elem_select_doc, "Selected state of this element.\n" "\n" ":type: bool")
static PyObject * bpy_bmface_calc_tangent_edge(BPy_BMFace *self)
#define BPY_BM_HFLAG_ALL_STR
static PyObject * bpy_bmelemseq_sort(BPy_BMElemSeq *self, PyObject *args, PyObject *kw)
PyTypeObject BPy_BMElemSeq_Type
static PyMethodDef bpy_bmesh_methods[]
static PyObject * bpy_bmfaceseq_active_get(BPy_BMElemSeq *self, void *)
static PyObject * bpy_bmloopseq_get(BPy_BMesh *self, void *)
static PyObject * bpy_bmvert_normal_get(BPy_BMVert *self, void *)
static PyObject * bpy_bmelemseq_ensure_lookup_table(BPy_BMElemSeq *self)
static PyGetSetDef bpy_bmface_getseters[]
static PyObject * bpy_bmfaceseq_get(BPy_BMesh *self, void *)
static PyObject * bpy_bmiter_next(BPy_BMIter *self)
static PyObject * bpy_bmesh_free(BPy_BMesh *self)
PyTypeObject BPy_BMFace_Type
static PyObject * bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw)
static int bpy_bmesh_select_mode_set(BPy_BMesh *self, PyObject *value, void *)
static int bpy_bmelemseq_sort_cmp_by_keys_ascending(const void *index1_v, const void *index2_v, void *keys_v)
static PyObject * bpy_bmface_calc_center_median_weighted(BPy_BMFace *self)
static void bpy_bmesh_dealloc(BPy_BMesh *self)
static PyGetSetDef bpy_bmloop_getseters[]
static PyObject * bpy_bmface_calc_area(BPy_BMFace *self)
PyTypeObject BPy_BMLoop_Type
PyObject * BPy_BMIter_CreatePyObject(BMesh *bm)
static int bpy_bmelemseq_contains(BPy_BMElemSeq *self, PyObject *value)
static PyObject * bpy_bmloop_copy_from_face_interp(BPy_BMLoop *self, PyObject *args)
PyC_FlagSet bpy_bm_hflag_all_flags[]
static PyMethodDef bpy_bmvertseq_methods[]
static PyObject * bpy_bmvert_copy_from_face_interp(BPy_BMVert *self, PyObject *args)
PyC_FlagSet bpy_bm_scene_vert_edge_face_flags[]
int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype)
static PyObject * bpy_bm_elem_select_set(BPy_BMElem *self, PyObject *value)
static PySequenceMethods bpy_bmelemseq_as_sequence
static PyObject * bpy_bmelem_subscript(BPy_BMElem *self, BPy_BMLayerItem *key)
static PyObject * bpy_bmelemseq_layers_get(BPy_BMElemSeq *self, void *htype)
static PyObject * bpy_bmface_material_index_get(BPy_BMFace *self, void *)
static PyObject * bpy_bmedge_other_vert(BPy_BMEdge *self, BPy_BMVert *value)
PyObject * BPyInit_bmesh_types()
PyObject * BPy_BMEdge_CreatePyObject(BMesh *bm, BMEdge *e)
static PyObject * bpy_bmface_copy_from_face_interp(BPy_BMFace *self, PyObject *args)
static PyObject * bpy_bmesh_is_wrapped_get(BPy_BMesh *self, void *)
static int bpy_bm_elem_hflag_set(BPy_BMElem *self, PyObject *value, void *flag)
static PyObject * bpy_bm_elem_copy_from(BPy_BMElem *self, BPy_BMElem *value)
static PyObject * bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args)
static PyObject * bpy_bmvert_repr(BPy_BMVert *self)
#define BPy_BMFace_Check(v)
#define BPY_BM_CHECK_OBJ(obj)
@ BPY_BMFLAG_IS_WRAPPED
@ BPY_BMFLAG_NOP
#define BPY_BM_CHECK_SOURCE_INT(bm, errmsg,...)
#define BPy_BMVert_Check(v)
#define BPy_BMElem_Check(v)
#define BPy_BMesh_Check(v)
#define BPy_BMEdge_Check(v)
#define BPY_BM_CHECK_SOURCE_OBJ(bm, errmsg,...)
#define BPY_BM_IS_VALID(obj)
#define BM_ITER_BPY_BM_SEQ(ele, iter, bpy_bmelemseq)
#define BPY_BM_CHECK_INT(obj)
PyTypeObject BPy_BMLayerCollection_Type
PyObject * BPy_BMLayerAccess_CreatePyObject(BMesh *bm, const char htype)
PyTypeObject BPy_BMLayerItem_Type
PyTypeObject BPy_BMLayerAccessLoop_Type
PyTypeObject BPy_BMLayerAccessVert_Type
int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObject *py_value)
PyTypeObject BPy_BMLayerAccessFace_Type
PyTypeObject BPy_BMLayerAccessEdge_Type
PyObject * BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
BMElem.__getitem__() / setitem().
PyTypeObject BPy_BMDeformVert_Type
PyTypeObject BPy_BMLoopUV_Type
int BPy_BMEditSel_Assign(BPy_BMesh *self, PyObject *value)
PyTypeObject BPy_BMEditSelSeq_Type
PyTypeObject BPy_BMEditSelIter_Type
PyObject * BPy_BMEditSel_CreatePyObject(BMesh *bm)
bool BM_vert_is_wire(const BMVert *v)
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
BM_loop_calc_face_tangent.
BMFace * BM_face_exists(BMVert *const *varr, int len)
bool BM_vert_is_manifold(const BMVert *v)
float BM_vert_calc_shell_factor(const BMVert *v)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback)
BMESH VERT/EDGE ANGLE.
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback)
BMESH EDGE/FACE ANGLE.
bool BM_loop_is_convex(const BMLoop *l)
double BM_mesh_calc_volume(BMesh *bm, bool is_signed)
float BM_loop_calc_face_angle(const BMLoop *l)
float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback)
BMESH EDGE/FACE ANGLE.
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
BMESH EDGE/FACE TANGENT.
float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
BM_loop_calc_face_normal.
bool BM_vert_is_boundary(const BMVert *v)
bool BM_edge_is_convex(const BMEdge *e)
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
PyObject * self
BPy_StructRNA * depsgraph
#define filter
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
#define CD_MASK_BM_ELEM_PYPTR
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
int count
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
Definition mathutils.cc:96
#define BaseMath_ReadCallback(_self)
Definition mathutils.hh:126
PyTypeObject matrix_Type
PyObject * Vector_CreatePyObject(const float *vec, const int vec_num, PyTypeObject *base_type)
PyObject * Vector_CreatePyObject_wrap(float *vec, const int vec_num, PyTypeObject *base_type)
Mesh * mesh_get_eval_deform(Depsgraph *depsgraph, const Scene *scene, Object *ob, const CustomData_MeshMasks *dataMask)
void * PyC_RNA_AsPointer(PyObject *value, const char *type_name)
int PyC_Long_AsBool(PyObject *value)
int PyC_FlagSet_ToBitfield(const PyC_FlagSet *items, PyObject *value, int *r_value, const char *error_prefix)
int PyC_ParseBool(PyObject *o, void *p)
PyObject * PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag)
header-only compatibility defines.
#define Py_HashPointer
header-only utilities
return ret
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
BMHeader head
BMHeader head
void * data
float co[3]
CustomData vdata
CustomData edata
CustomData pdata
CustomData ldata
PyObject_VAR_HEAD BMesh * bm
PyObject_VAR_HEAD BMesh * bm
PyObject_VAR_HEAD BMesh * bm
PyObject_VAR_HEAD BMesh * bm
int tag
Definition DNA_ID.h:424
char name[66]
Definition DNA_ID.h:415
MeshRuntimeHandle * runtime
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
uint len
PointerRNA * ptr
Definition wm_files.cc:4226
uint8_t flag
Definition wm_window.cc:139