31 bpy_bm_utils_vert_collapse_edge_doc,
32 ".. method:: vert_collapse_edge(vert, edge)\n"
34 " Collapse a vertex into an edge.\n"
36 " :arg vert: The vert that will be collapsed.\n"
37 " :type vert: :class:`bmesh.types.BMVert`\n"
38 " :arg edge: The edge to collapse into.\n"
39 " :type edge: :class:`bmesh.types.BMEdge`\n"
40 " :return: The resulting edge from the collapse operation.\n"
41 " :rtype: :class:`bmesh.types.BMEdge`\n");
50 if (!PyArg_ParseTuple(
60 if (!(py_edge->
e->
v1 == py_vert->
v || py_edge->
e->
v2 == py_vert->
v)) {
61 PyErr_SetString(PyExc_ValueError,
62 "vert_collapse_edge(vert, edge): the vertex is not found in the edge");
67 PyErr_SetString(PyExc_ValueError,
68 "vert_collapse_edge(vert, edge): vert has more than 2 connected edges");
80 PyErr_SetString(PyExc_ValueError,
81 "vert_collapse_edge(vert, edge): no new edge created, internal error");
87 bpy_bm_utils_vert_collapse_faces_doc,
88 ".. method:: vert_collapse_faces(vert, edge, fac, join_faces)\n"
90 " Collapses a vertex that has only two manifold edges onto a vertex it shares an "
93 " :arg vert: The vert that will be collapsed.\n"
94 " :type vert: :class:`bmesh.types.BMVert`\n"
95 " :arg edge: The edge to collapse into.\n"
96 " :type edge: :class:`bmesh.types.BMEdge`\n"
97 " :arg fac: The factor to use when merging customdata [0 - 1].\n"
99 " :arg join_faces: When true the faces around the vertex will be joined otherwise "
100 "collapse the vertex by merging the 2 edges this vertex connects to into one.\n"
101 " :type join_faces: bool\n"
102 " :return: The resulting edge from the collapse operation.\n"
103 " :rtype: :class:`bmesh.types.BMEdge`\n");
115 if (!PyArg_ParseTuple(args,
116 "O!O!fi:vert_collapse_faces",
131 if (!(py_edge->
e->
v1 == py_vert->
v || py_edge->
e->
v2 == py_vert->
v)) {
132 PyErr_SetString(PyExc_ValueError,
133 "vert_collapse_faces(vert, edge): the vertex is not found in the edge");
138 PyErr_SetString(PyExc_ValueError,
139 "vert_collapse_faces(vert, edge): vert has more than 2 connected edges");
146 bm, py_edge->
e, py_vert->
v,
clamp_f(fac, 0.0f, 1.0f),
true, do_join_faces,
true,
true);
152 PyErr_SetString(PyExc_ValueError,
153 "vert_collapse_faces(vert, edge): no new edge created, internal error");
159 bpy_bm_utils_vert_dissolve_doc,
160 ".. method:: vert_dissolve(vert)\n"
162 " Dissolve this vertex (will be removed).\n"
164 " :arg vert: The vert to be dissolved.\n"
165 " :type vert: :class:`bmesh.types.BMVert`\n"
166 " :return: True when the vertex dissolve is successful.\n"
174 if (!PyArg_ParseTuple(args,
"O!:vert_dissolve", &
BPy_BMVert_Type, &py_vert)) {
187 bpy_bm_utils_vert_splice_doc,
188 ".. method:: vert_splice(vert, vert_target)\n"
190 " Splice vert into vert_target.\n"
192 " :arg vert: The vertex to be removed.\n"
193 " :type vert: :class:`bmesh.types.BMVert`\n"
194 " :arg vert_target: The vertex to use.\n"
195 " :type vert_target: :class:`bmesh.types.BMVert`\n"
197 " .. note:: The verts mustn't share an edge or face.\n");
200 const char *error_prefix =
"vert_splice(...)";
208 if (!PyArg_ParseTuple(
220 if (py_vert->
v == py_vert_target->
v) {
221 PyErr_Format(PyExc_ValueError,
"%s: vert arguments match", error_prefix);
226 PyErr_Format(PyExc_ValueError,
"%s: verts cannot share an edge", error_prefix);
231 PyErr_Format(PyExc_ValueError,
"%s: verts cannot share a face", error_prefix);
245 bpy_bm_utils_vert_separate_doc,
246 ".. method:: vert_separate(vert, edges)\n"
248 " Separate this vertex at every edge.\n"
250 " :arg vert: The vert to be separated.\n"
251 " :type vert: :class:`bmesh.types.BMVert`\n"
252 " :arg edges: The edges to separated.\n"
253 " :type edges: :class:`bmesh.types.BMEdge`\n"
254 " :return: The newly separated verts (including the vertex passed).\n"
255 " :rtype: tuple[:class:`bmesh.types.BMVert`, ...]\n");
258 const char *error_prefix =
"vert_separate(...)";
268 if (!PyArg_ParseTuple(args,
"O!O:vert_separate", &
BPy_BMVert_Type, &py_vert, &edge_seq)) {
277 Py_ssize_t edge_array_num;
279 &
bm, edge_seq, 0, PY_SSIZE_T_MAX, &edge_array_num,
true,
true, error_prefix);
281 if (edge_array ==
nullptr) {
290 PyMem_FREE(edge_array);
297 bpy_bm_utils_edge_split_doc,
298 ".. method:: edge_split(edge, vert, fac)\n"
300 " Split an edge, return the newly created data.\n"
302 " :arg edge: The edge to split.\n"
303 " :type edge: :class:`bmesh.types.BMEdge`\n"
304 " :arg vert: One of the verts on the edge, defines the split direction.\n"
305 " :type vert: :class:`bmesh.types.BMVert`\n"
306 " :arg fac: The point on the edge where the new vert will be created [0 - 1].\n"
307 " :type fac: float\n"
308 " :return: The newly created (edge, vert) pair.\n"
309 " :rtype: tuple[:class:`bmesh.types.BMEdge`, :class:`bmesh.types.BMVert`]\n");
320 if (!PyArg_ParseTuple(
330 if (!(py_edge->
e->
v1 == py_vert->
v || py_edge->
e->
v2 == py_vert->
v)) {
331 PyErr_SetString(PyExc_ValueError,
332 "edge_split(edge, vert): the vertex is not found in the edge");
340 if (v_new && e_new) {
341 PyObject *
ret = PyTuple_New(2);
347 PyErr_SetString(PyExc_ValueError,
348 "edge_split(edge, vert): couldn't split the edge, internal error");
354 bpy_bm_utils_edge_rotate_doc,
355 ".. method:: edge_rotate(edge, ccw=False)\n"
357 " Rotate the edge and return the newly created edge.\n"
358 " If rotating the edge fails, None will be returned.\n"
360 " :arg edge: The edge to rotate.\n"
361 " :type edge: :class:`bmesh.types.BMEdge`\n"
362 " :arg ccw: When True the edge will be rotated counter clockwise.\n"
364 " :return: The newly rotated edge.\n"
365 " :rtype: :class:`bmesh.types.BMEdge`\n");
374 if (!PyArg_ParseTuple(
395 bpy_bm_utils_face_split_doc,
396 ".. method:: face_split(face, vert_a, vert_b, *, coords=(), use_exist=True, example=None)\n"
398 " Face split with optional intermediate points.\n"
400 " :arg face: The face to cut.\n"
401 " :type face: :class:`bmesh.types.BMFace`\n"
402 " :arg vert_a: First vertex to cut in the face (face must contain the vert).\n"
403 " :type vert_a: :class:`bmesh.types.BMVert`\n"
404 " :arg vert_b: Second vertex to cut in the face (face must contain the vert).\n"
405 " :type vert_b: :class:`bmesh.types.BMVert`\n"
406 " :arg coords: Optional sequence of 3D points in between *vert_a* and *vert_b*.\n"
407 " :type coords: Sequence[Sequence[float]]\n"
408 " :arg use_exist: .Use an existing edge if it exists (Only used when *coords* argument is "
409 "empty or omitted)\n"
410 " :type use_exist: bool\n"
411 " :arg example: Newly created edge will copy settings from this one.\n"
412 " :type example: :class:`bmesh.types.BMEdge`\n"
413 " :return: The newly created face or None on failure.\n"
414 " :rtype: tuple[:class:`bmesh.types.BMFace`, :class:`bmesh.types.BMLoop`]\n");
417 static const char *kwlist[] = {
418 "face",
"vert_a",
"vert_b",
"coords",
"use_exist",
"example",
nullptr};
425 PyObject *py_coords =
nullptr;
426 bool edge_exists =
true;
437 if (!PyArg_ParseTupleAndKeywords(args,
439 "O!O!O!|$OO&O!:face_split",
460 if (py_edge_example) {
471 PyErr_SetString(PyExc_ValueError,
472 "face_split(...): one of the verts passed is not found in the face");
476 if (py_vert_a->
v == py_vert_b->
v) {
477 PyErr_SetString(PyExc_ValueError,
"face_split(...): vert arguments must differ");
489 PyErr_SetString(PyExc_ValueError,
"face_split(...): verts are adjacent in the face");
502 (
float (*)[3])coords,
505 py_edge_example ? py_edge_example->
e :
nullptr);
514 py_edge_example ? py_edge_example->
e :
nullptr,
518 if (f_new && l_new) {
519 PyObject *
ret = PyTuple_New(2);
525 PyErr_SetString(PyExc_ValueError,
"face_split(...): couldn't split the face, internal error");
531 bpy_bm_utils_face_split_edgenet_doc,
532 ".. method:: face_split_edgenet(face, edgenet)\n"
534 " Splits a face into any number of regions defined by an edgenet.\n"
536 " :arg face: The face to split.\n"
537 " :type face: :class:`bmesh.types.BMFace`\n"
538 " :arg face: The face to split.\n"
539 " :type face: :class:`bmesh.types.BMFace`\n"
540 " :arg edgenet: Sequence of edges.\n"
541 " :type edgenet: Sequence[:class:`bmesh.types.BMEdge`]\n"
542 " :return: The newly created faces.\n"
543 " :rtype: tuple[:class:`bmesh.types.BMFace`, ...]\n"
547 " Regions defined by edges need to connect to the face, otherwise they're "
548 "ignored as loose edges.\n");
551 const char *error_prefix =
"face_split_edgenet(...)";
552 static const char *kwlist[] = {
"face",
"edgenet",
nullptr};
561 if (!PyArg_ParseTupleAndKeywords(args,
563 "O!O:face_split_edgenet",
576 Py_ssize_t edge_array_num;
578 &
bm, edge_seq, 1, PY_SSIZE_T_MAX, &edge_array_num,
true,
true, error_prefix);
580 if (edge_array ==
nullptr) {
588 PyMem_FREE(edge_array);
595 PyErr_SetString(PyExc_ValueError,
596 "face_split_edgenet(...): couldn't split the face, internal error");
602 bpy_bm_utils_face_join_doc,
603 ".. method:: face_join(faces, remove=True)\n"
605 " Joins a sequence of faces.\n"
607 " :arg faces: Sequence of faces.\n"
608 " :type faces: :class:`bmesh.types.BMFace`\n"
609 " :arg remove: Remove the edges and vertices between the faces.\n"
610 " :type remove: bool\n"
611 " :return: The newly created face or None on failure.\n"
612 " :rtype: :class:`bmesh.types.BMFace`\n");
615 const char *error_prefix =
"face_join(...)";
617 PyObject *py_face_array;
619 bool do_remove =
true;
621 if (!PyArg_ParseTuple(args,
"O|O&:face_join", &py_face_array,
PyC_ParseBool, &do_remove)) {
625 Py_ssize_t face_seq_len = 0;
627 &
bm, py_face_array, 2, PY_SSIZE_T_MAX, &face_seq_len,
true,
true, error_prefix);
628 if (face_array ==
nullptr) {
635 f_new =
BM_faces_join(
bm, face_array,
int(face_seq_len), do_remove, &f_double);
638 "Doubled face detected at " AT ". Resulting mesh may be corrupt.");
640 PyMem_FREE(face_array);
651 bpy_bm_utils_face_vert_separate_doc,
652 ".. method:: face_vert_separate(face, vert)\n"
654 " Rip a vertex in a face away and add a new vertex.\n"
656 " :arg face: The face to separate.\n"
657 " :type face: :class:`bmesh.types.BMFace`\n"
658 " :arg vert: A vertex in the face to separate.\n"
659 " :type vert: :class:`bmesh.types.BMVert`\n"
660 " :return vert: The newly created vertex or None on failure.\n"
661 " :rtype vert: :class:`bmesh.types.BMVert`\n"
665 " This is the same as loop_separate, and has only been added for convenience.\n");
668 const char *error_prefix =
"face_vert_separate()";
676 if (!PyArg_ParseTuple(
690 PyErr_Format(PyExc_ValueError,
"%s: vertex not found in face", error_prefix);
697 if (v_new != v_old) {
706 bpy_bm_utils_face_flip_doc,
707 ".. method:: face_flip(faces)\n"
709 " Flip the faces direction.\n"
711 " :arg face: Face to flip.\n"
712 " :type face: :class:`bmesh.types.BMFace`\n");
716 PyErr_Format(PyExc_TypeError,
717 "face_flip(face): BMFace expected, not '%.200s'",
718 Py_TYPE(value)->tp_name);
731 bpy_bm_utils_loop_separate_doc,
732 ".. method:: loop_separate(loop)\n"
734 " Rip a vertex in a face away and add a new vertex.\n"
736 " :arg loop: The loop to separate.\n"
737 " :type loop: :class:`bmesh.types.BMLoop`\n"
738 " :return vert: The newly created vertex or None on failure.\n"
739 " :rtype vert: :class:`bmesh.types.BMVert`\n");
747 PyErr_Format(PyExc_TypeError,
748 "loop_separate(loop): BMLoop expected, not '%.200s'",
749 Py_TYPE(value)->tp_name);
761 if (v_new != v_old) {
770 bpy_bm_utils_uv_select_check_doc,
771 ".. method:: uv_select_check(bm, /, *, sync=True, flush=False, contiguous=False)\n"
773 " Split an edge, return the newly created data.\n"
775 " :arg sync: Check the data is properly synchronized between UV's and the underlying mesh. "
776 "Failure to synchronize with the mesh selection may cause tools not to behave properly.\n"
777 " :type sync: bool\n"
778 " :arg flush: Check the selection has been properly flushed between elements "
779 "(based on the current :class:`BMesh.select_mode`).\n"
780 " :type flush: bool\n"
781 " :arg contiguous: Check connected UV's and edges have a matching selection state.\n"
782 " :type contiguous: bool\n"
783 " :return: An error dictionary or None when there are no errors found.\n"
784 " :rtype: dict[str, int] | None\n");
787 const char *error_prefix =
"uv_select_check(...)";
789 bool check_sync =
true;
790 bool check_contiguous =
false;
791 bool check_flush =
false;
793 static const char *_keywords[] = {
800 static _PyArg_Parser _parser = {
811 if (!_PyArg_ParseTupleAndKeywordsFast(args,
835 const int cd_loop_uv_offset = check_contiguous ?
838 if (check_contiguous) {
839 if (cd_loop_uv_offset == -1) {
840 PyErr_SetString(PyExc_ValueError,
"contiguous=True for a mesh without UV coordinates");
847 bm, cd_loop_uv_offset, check_sync, check_flush, check_contiguous, &info);
852 PyObject *
result = PyDict_New();
854#define DICT_ADD_INT_MEMBER(info_struct, member) \
855 PyDict_SetItemString(result, STRINGIFY(member), PyLong_FromLong(info_struct.member))
878 if (check_contiguous) {
884 if (check_flush && check_contiguous) {
891#undef DICT_ADD_INT_MEMBER
898# pragma clang diagnostic push
899# pragma clang diagnostic ignored "-Wcast-function-type"
901# pragma GCC diagnostic push
902# pragma GCC diagnostic ignored "-Wcast-function-type"
907 {
"vert_collapse_edge",
910 bpy_bm_utils_vert_collapse_edge_doc},
911 {
"vert_collapse_faces",
914 bpy_bm_utils_vert_collapse_faces_doc},
918 bpy_bm_utils_vert_dissolve_doc},
922 bpy_bm_utils_vert_splice_doc},
926 bpy_bm_utils_vert_separate_doc},
930 bpy_bm_utils_edge_split_doc},
934 bpy_bm_utils_edge_rotate_doc},
937 METH_VARARGS | METH_KEYWORDS,
938 bpy_bm_utils_face_split_doc},
939 {
"face_split_edgenet",
941 METH_VARARGS | METH_KEYWORDS,
942 bpy_bm_utils_face_split_edgenet_doc},
944 {
"face_vert_separate",
947 bpy_bm_utils_face_vert_separate_doc},
952 bpy_bm_utils_loop_separate_doc},
955 METH_VARARGS | METH_KEYWORDS,
956 bpy_bm_utils_uv_select_check_doc},
957 {
nullptr,
nullptr, 0,
nullptr},
962# pragma clang diagnostic pop
964# pragma GCC diagnostic pop
971 "This module provides access to blenders bmesh data structures.");
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
#define BLI_assert_msg(a, msg)
MINLINE float clamp_f(float value, float min, float max)
#define UNUSED_VARS_NDEBUG(...)
Read Guarded memory(de)allocation.
void BM_vert_separate(BMesh *bm, BMVert *v, BMEdge **e_in, int e_in_len, const bool copy_select, BMVert ***r_vout, int *r_vout_len)
BMFace * BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del, BMFace **r_double)
Join Connected Faces.
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
Splice Vert.
BMFace * BM_face_split_n(BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, float cos[][3], int n, BMLoop **r_l, BMEdge *example)
Face Split with intermediate points.
BMVert * BM_face_loop_separate(BMesh *bm, BMLoop *l_sep)
Rip a single face from a vertex fan.
BMEdge * BM_vert_collapse_faces(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac, const bool do_del, const bool join_faces, const bool kill_degenerate_faces, const bool kill_duplicate_faces)
Vert Collapse Faces.
bool BM_vert_dissolve(BMesh *bm, BMVert *v)
Dissolve Vert.
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
BMEdge * BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces, const bool kill_duplicate_faces)
Vert Collapse Faces.
BMEdge * BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag)
Rotate Edge.
BMFace * BM_face_split(BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, BMLoop **r_l, BMEdge *example, const bool no_double)
Face Split.
void BM_face_normal_flip(BMesh *bm, BMFace *f)
bool BM_face_split_edgenet(BMesh *bm, BMFace *f, BMEdge **edge_net, const int edge_net_len, blender::Vector< BMFace * > *r_face_arr)
PyObject * BPy_BMFace_CreatePyObject(BMesh *bm, BMFace *f)
PyObject * BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_num)
PyTypeObject BPy_BMesh_Type
PyObject * BPy_BMVert_CreatePyObject(BMesh *bm, BMVert *v)
PyObject * BPy_BMLoop_CreatePyObject(BMesh *bm, BMLoop *l)
PyObject * BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_num)
PyTypeObject BPy_BMEdge_Type
BMEdge ** BPy_BMEdge_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_seq_num, bool do_unique_check, bool do_bm_check, const char *error_prefix)
PyTypeObject BPy_BMVert_Type
int bpy_bm_check_uv_select_sync_valid(BMesh *bm, const char *error_prefix)
PyTypeObject BPy_BMFace_Type
PyObject * BPy_BMEdge_CreatePyObject(BMesh *bm, BMEdge *e)
BMFace ** BPy_BMFace_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_seq_num, bool do_unique_check, bool do_bm_check, const char *error_prefix)
#define BPy_BMFace_Check(v)
#define BPY_BM_CHECK_OBJ(obj)
#define BPy_BMLoop_Check(v)
#define BPY_BM_CHECK_SOURCE_OBJ(bm, errmsg,...)
PyObject * BPyInit_bmesh_utils()
static PyObject * bpy_bm_utils_vert_splice(PyObject *, PyObject *args)
static PyModuleDef BPy_BM_utils_module_def
static PyObject * bpy_bm_utils_vert_collapse_faces(PyObject *, PyObject *args)
PyDoc_STRVAR(bpy_bm_utils_vert_collapse_edge_doc, ".. method:: vert_collapse_edge(vert, edge)\n" "\n" " Collapse a vertex into an edge.\n" "\n" " :arg vert: The vert that will be collapsed.\n" " :type vert: :class:`bmesh.types.BMVert`\n" " :arg edge: The edge to collapse into.\n" " :type edge: :class:`bmesh.types.BMEdge`\n" " :return: The resulting edge from the collapse operation.\n" " :rtype: :class:`bmesh.types.BMEdge`\n")
static PyObject * bpy_bm_utils_face_split(PyObject *, PyObject *args, PyObject *kw)
static PyObject * bpy_bm_utils_face_join(PyObject *, PyObject *args)
static PyObject * bpy_bm_utils_vert_collapse_edge(PyObject *, PyObject *args)
static PyObject * bpy_bm_utils_vert_dissolve(PyObject *, PyObject *args)
static PyObject * bpy_bm_utils_vert_separate(PyObject *, PyObject *args)
static PyObject * bpy_bm_utils_loop_separate(PyObject *, BPy_BMLoop *value)
static PyObject * bpy_bm_utils_uv_select_check(PyObject *, PyObject *args, PyObject *kwds)
static PyObject * bpy_bm_utils_face_flip(PyObject *, BPy_BMFace *value)
static PyObject * bpy_bm_utils_edge_split(PyObject *, PyObject *args)
static PyObject * bpy_bm_utils_face_split_edgenet(PyObject *, PyObject *args, PyObject *kw)
static PyObject * bpy_bm_utils_edge_rotate(PyObject *, PyObject *args)
static PyMethodDef BPy_BM_utils_methods[]
static PyObject * bpy_bm_utils_face_vert_separate(PyObject *, PyObject *args)
#define DICT_ADD_INT_MEMBER(info_struct, member)
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
BMLoop * BM_face_vert_share_loop(BMFace *f, BMVert *v)
Return the Loop Shared by Face and Vertex.
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define BM_vert_edge_count_is_over(v, n)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
bool BM_mesh_uvselect_is_valid(BMesh *bm, const int cd_loop_uv_offset, const bool check_sync, const bool check_flush, const bool check_contiguous, UVSelectValidateInfo *info_p)
void MEM_freeN(void *vmemh)
int mathutils_array_parse_alloc_v(float **array, int array_dim, PyObject *value, const char *error_prefix)
int PyC_ParseBool(PyObject *o, void *p)
header-only compatibility defines.
#define PY_ARG_PARSER_HEAD_COMPAT()
#define PyTuple_SET_ITEMS(op_arg,...)
PyObject_VAR_HEAD BMesh * bm
PyObject_VAR_HEAD BMesh * bm
PyObject_VAR_HEAD BMesh * bm
PyObject_VAR_HEAD BMesh * bm
PyObject_VAR_HEAD BMesh * bm
UVSelectValidateInfo_Flush flush
UVSelectValidateInfo_FlushAndContiguous flush_contiguous
UVSelectValidateInfo_Sync sync
UVSelectValidateInfo_Contiguous contiguous