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