Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2012-03-11 09:58:22 +0400
committerCampbell Barton <ideasman42@gmail.com>2012-03-11 09:58:22 +0400
commit7fa7e4ba1faf7a122f99a683c04935e01725061c (patch)
tree7d55eacad074fd83c744de19cae006a7d9f86eac /source/blender/python
parent050439fd9dcf3b7e79bae1fd409364cb1220e598 (diff)
bmesh python api additions:
- BMesh.is_wrapped - BMesh.copy() - BMesh.clear() - BMesh.free() - BMesh.from_object(obj, apply_modifiers=True) - BMEdge.calc_length() - BMLoop.calc_normal() - BMLoop.calc_tangent()
Diffstat (limited to 'source/blender/python')
-rw-r--r--source/blender/python/bmesh/bmesh_py_api.c10
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c212
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.h9
3 files changed, 205 insertions, 26 deletions
diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c
index 51c4acda45e..1601034542b 100644
--- a/source/blender/python/bmesh/bmesh_py_api.c
+++ b/source/blender/python/bmesh/bmesh_py_api.c
@@ -57,14 +57,11 @@ PyDoc_STRVAR(bpy_bm_new_doc,
static PyObject *bpy_bm_new(PyObject *UNUSED(self))
{
- BPy_BMesh *py_bmesh;
BMesh *bm;
bm = BM_mesh_create(NULL, &bm_mesh_allocsize_default);
- py_bmesh = (BPy_BMesh *)BPy_BMesh_CreatePyObject(bm);
- py_bmesh->py_owns = TRUE;
- return (PyObject *)py_bmesh;
+ return BPy_BMesh_CreatePyObject(bm, BPY_BMFLAG_NOP);
}
PyDoc_STRVAR(bpy_bm_from_edit_mesh_doc,
@@ -77,7 +74,6 @@ PyDoc_STRVAR(bpy_bm_from_edit_mesh_doc,
);
static PyObject *bpy_bm_from_edit_mesh(PyObject *UNUSED(self), PyObject *value)
{
- BPy_BMesh *py_bmesh;
BMesh *bm;
Mesh *me = PyC_RNA_AsPointer(value, "Mesh");
@@ -93,9 +89,7 @@ static PyObject *bpy_bm_from_edit_mesh(PyObject *UNUSED(self), PyObject *value)
bm = me->edit_btmesh->bm;
- py_bmesh = (BPy_BMesh *)BPy_BMesh_CreatePyObject(bm);
- py_bmesh->py_owns = FALSE;
- return (PyObject *)py_bmesh;
+ return BPy_BMesh_CreatePyObject(bm, BPY_BMFLAG_IS_WRAPPED);
}
static struct PyMethodDef BPy_BM_methods[] = {
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index 075e4889515..53f32292cc3 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -36,6 +36,7 @@
#include "BKE_depsgraph.h"
#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
#include "bmesh.h"
@@ -252,6 +253,15 @@ static PyObject *bpy_bm_is_valid_get(BPy_BMGeneric *self)
return PyBool_FromLong(BPY_BM_IS_VALID(self));
}
+PyDoc_STRVAR(bpy_bmesh_is_wrapped_doc,
+"True when this mesh is owned by blender (typically the editmode BMesh).\n\n:type: boolean"
+);
+static PyObject *bpy_bmesh_is_wrapped_get(BPy_BMesh *self)
+{
+ BPY_BM_CHECK_OBJ(self);
+
+ return PyBool_FromLong(self->flag & BPY_BMFLAG_IS_WRAPPED);
+}
PyDoc_STRVAR(bpy_bmesh_select_mode_doc,
"The selection mode, values can be {'VERT', 'EDGE', 'FACE'}, can't be assigned an empty set.\n\n:type: set"
@@ -484,7 +494,8 @@ static PyGetSetDef bpy_bmesh_getseters[] = {
{(char *)"select_history", (getter)bpy_bmesh_select_history_get, (setter)bpy_bmesh_select_history_set, (char *)bpy_bmesh_select_history_doc, NULL},
/* readonly checks */
- {(char *)"is_valid", (getter)bpy_bm_is_valid_get, (setter)NULL, (char *)bpy_bm_is_valid_doc, NULL},
+ {(char *)"is_wrapped", (getter)bpy_bmesh_is_wrapped_get, (setter)NULL, (char *)bpy_bmesh_is_wrapped_doc, NULL}, /* as with mathutils */
+ {(char *)"is_valid", (getter)bpy_bm_is_valid_get, (setter)NULL, (char *)bpy_bm_is_valid_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -590,6 +601,76 @@ static PyGetSetDef bpy_bmloop_getseters[] = {
/* Mesh
* ---- */
+PyDoc_STRVAR(bpy_bmesh_copy_doc,
+".. method:: copy()\n"
+"\n"
+" :return: A copy of this BMesh.\n"
+" :rtype: :class:`BMesh`\n"
+);
+static PyObject *bpy_bmesh_copy(BPy_BMesh *self)
+{
+ BMesh *bm;
+ BMesh *bm_copy;
+
+ BPY_BM_CHECK_OBJ(self);
+
+ bm = self->bm;
+
+ bm_copy = BM_mesh_copy(bm);
+
+ if (bm_copy) {
+ return BPy_BMesh_CreatePyObject(bm_copy, BPY_BMFLAG_NOP);
+ }
+ else {
+ PyErr_SetString(PyExc_SystemError, "Unable to copy BMesh, internal error");
+ return NULL;
+ }
+}
+
+PyDoc_STRVAR(bpy_bmesh_clear_doc,
+".. method:: clear()\n"
+"\n"
+" Clear all mesh data.\n"
+);
+static PyObject *bpy_bmesh_clear(BPy_BMesh *self)
+{
+ BMesh *bm;
+
+ BPY_BM_CHECK_OBJ(self);
+
+ bm = self->bm;
+
+ BM_mesh_clear(bm);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpy_bmesh_free_doc,
+".. method:: free()\n"
+"\n"
+" Explicitly free the BMesh data from memory, causing exceptions on further access.\n"
+"\n"
+" .. note::\n"
+"\n"
+" The BMesh is freed automatically, typically when the script finishes executing.\n"
+" However in some cases its hard to predict when this will be and its useful to\n"
+" explicitly free the data.\n"
+);
+static PyObject *bpy_bmesh_free(BPy_BMesh *self)
+{
+ if (self->bm) {
+ BMesh *bm = self->bm;
+
+ if ((self->flag & BPY_BMFLAG_IS_WRAPPED) == 0) {
+ BM_mesh_free(bm);
+ }
+
+ bpy_bm_generic_invalidate((BPy_BMGeneric *)self);
+ }
+
+ Py_RETURN_NONE;
+}
+
PyDoc_STRVAR(bpy_bmesh_to_mesh_doc,
".. method:: to_mesh(mesh)\n"
"\n"
@@ -630,6 +711,49 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
Py_RETURN_NONE;
}
+/* note: rna_Object_to_mesh() also has apply_modifiers arg that works the same way */
+PyDoc_STRVAR(bpy_bmesh_from_object_doc,
+".. method:: from_object(mesh, apply_modifiers=True)\n"
+"\n"
+" Initialize this bmesh from existing object datablock.\n"
+"\n"
+" :arg object: The object data to load.\n"
+" :type object: :class:`Object`\n"
+" :arg apply_modifiers: Use the final display mesh rather then the deformed cage.\n"
+" :type apply_modifiers: boolean\n"
+);
+static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args)
+{
+ PyObject *py_object;
+ Object *ob;
+ BMesh *bm;
+ int apply_modifiers = TRUE;
+ DerivedMesh *dm;
+
+ BPY_BM_CHECK_OBJ(self);
+
+ if (!PyArg_ParseTuple(args, "O|i:from_object", &py_object, &apply_modifiers) ||
+ !(ob = PyC_RNA_AsPointer(py_object, "Object")))
+ {
+ return NULL;
+ }
+
+ dm = apply_modifiers ? ob->derivedFinal : ob->derivedDeform;
+
+ if (dm == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "from_object(...): Object '%s' has no usable mesh data", ob->id.name + 2);
+ return NULL;
+ }
+
+ bm = self->bm;
+
+ DM_to_bmesh_ex(dm, bm);
+
+ Py_RETURN_NONE;
+}
+
+
PyDoc_STRVAR(bpy_bmesh_from_mesh_doc,
".. method:: from_mesh(mesh, use_shape_key=False, shape_key_index=0)\n"
"\n"
@@ -651,7 +775,7 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *
int use_shape_key = FALSE;
int shape_key_index = 0;
- if (!PyArg_ParseTupleAndKeywords(args, kw, "O|ii:to_mesh", (char **)kwlist,
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "O|ii:from_mesh", (char **)kwlist,
&py_mesh, &use_shape_key, &shape_key_index) ||
!(me = PyC_RNA_AsPointer(py_mesh, "Mesh")))
{
@@ -1001,12 +1125,22 @@ static PyObject *bpy_bmvert_normal_update(BPy_BMVert *self)
/* Edge
* ---- */
+PyDoc_STRVAR(bpy_bmedge_calc_length_doc,
+".. method:: calc_length()\n"
+"\n"
+" :return: The length between both verts.\n"
+" :rtype: float\n"
+);
+static PyObject *bpy_bmedge_calc_length(BPy_BMEdge *self)
+{
+ BPY_BM_CHECK_OBJ(self);
+ return PyFloat_FromDouble(len_v3v3(self->e->v1->co, self->e->v2->co));
+}
+
PyDoc_STRVAR(bpy_bmedge_calc_face_angle_doc,
".. method:: calc_face_angle()\n"
"\n"
-" Return the angle between 2 connected faces.\n"
-"\n"
-" :return: The angle between both faces in radians.\n"
+" :return: The angle between 2 connected faces in radians.\n"
" :rtype: float\n"
);
static PyObject *bpy_bmedge_calc_face_angle(BPy_BMEdge *self)
@@ -1270,21 +1404,54 @@ static PyObject *bpy_bmloop_copy_from_face_interp(BPy_BMLoop *self, PyObject *ar
}
-PyDoc_STRVAR(bpy_bmloop_calc_face_angle_doc,
-".. method:: calc_face_angle()\n"
+PyDoc_STRVAR(bpy_bmloop_calc_angle_doc,
+".. method:: calc_angle()\n"
"\n"
-" Return angle at this loops corner of the face.\n"
+" Return the angle at this loops corner of the face.\n"
" This is calculated so sharper corners give lower angles.\n"
"\n"
" :return: The angle in radians.\n"
" :rtype: float\n"
);
-static PyObject *bpy_bmloop_calc_face_angle(BPy_BMLoop *self)
+static PyObject *bpy_bmloop_calc_angle(BPy_BMLoop *self)
{
BPY_BM_CHECK_OBJ(self);
return PyFloat_FromDouble(BM_loop_face_angle(self->bm, self->l));
}
+PyDoc_STRVAR(bpy_bmloop_calc_normal_doc,
+".. method:: calc_normal()\n"
+"\n"
+" Return normal at this loops corner of the face.\n"
+" Falls back to the face normal for straignt lines.\n"
+"\n"
+" :return: a normalized vector.\n"
+" :rtype: :class:`mathutils.Vector`\n"
+);
+static PyObject *bpy_bmloop_calc_normal(BPy_BMLoop *self)
+{
+ float vec[3];
+ BPY_BM_CHECK_OBJ(self);
+ BM_loop_face_normal(self->bm, self->l, vec);
+ return Vector_CreatePyObject(vec, 3, Py_NEW, NULL);
+}
+
+PyDoc_STRVAR(bpy_bmloop_calc_tangent_doc,
+".. method:: calc_tangent()\n"
+"\n"
+" Return the tangent at this loops corner of the face (pointing inward into the face).\n"
+" Falls back to the face normal for straignt lines.\n"
+"\n"
+" :return: a normalized vector.\n"
+" :rtype: :class:`mathutils.Vector`\n"
+);
+static PyObject *bpy_bmloop_calc_tangent(BPy_BMLoop *self)
+{
+ float vec[3];
+ BPY_BM_CHECK_OBJ(self);
+ BM_loop_face_tangent(self->bm, self->l, vec);
+ return Vector_CreatePyObject(vec, 3, Py_NEW, NULL);
+}
/* Vert Seq
* -------- */
@@ -1796,9 +1963,17 @@ static PyObject *bpy_bmelemseq_index_update(BPy_BMElemSeq *self)
static struct PyMethodDef bpy_bmesh_methods[] = {
- {"from_mesh", (PyCFunction)bpy_bmesh_from_mesh, METH_VARARGS | METH_KEYWORDS, bpy_bmesh_from_mesh_doc},
- {"to_mesh", (PyCFunction)bpy_bmesh_to_mesh, METH_VARARGS, bpy_bmesh_to_mesh_doc},
+ /* utility */
+ {"copy", (PyCFunction)bpy_bmesh_copy, METH_NOARGS, bpy_bmesh_copy_doc},
+ {"clear", (PyCFunction)bpy_bmesh_clear, METH_NOARGS, bpy_bmesh_clear_doc},
+ {"free", (PyCFunction)bpy_bmesh_free, METH_NOARGS, bpy_bmesh_free_doc},
+
+ /* conversion */
+ {"from_object", (PyCFunction)bpy_bmesh_from_object, METH_VARARGS | METH_KEYWORDS, bpy_bmesh_from_object_doc},
+ {"from_mesh", (PyCFunction)bpy_bmesh_from_mesh, METH_VARARGS | METH_KEYWORDS, bpy_bmesh_from_mesh_doc},
+ {"to_mesh", (PyCFunction)bpy_bmesh_to_mesh, METH_VARARGS, bpy_bmesh_to_mesh_doc},
+ /* meshdata */
{"select_flush_mode", (PyCFunction)bpy_bmesh_select_flush_mode, METH_NOARGS, bpy_bmesh_select_flush_mode_doc},
{"select_flush", (PyCFunction)bpy_bmesh_select_flush, METH_O, bpy_bmesh_select_flush_doc},
{"normal_update", (PyCFunction)bpy_bmesh_normal_update, METH_VARARGS, bpy_bmesh_normal_update_doc},
@@ -1827,6 +2002,7 @@ static struct PyMethodDef bpy_bmedge_methods[] = {
{"other_vert", (PyCFunction)bpy_bmedge_other_vert, METH_O, bpy_bmedge_other_vert_doc},
+ {"calc_length", (PyCFunction)bpy_bmedge_calc_length, METH_NOARGS, bpy_bmedge_calc_length_doc},
{"calc_face_angle", (PyCFunction)bpy_bmedge_calc_face_angle, METH_NOARGS, bpy_bmedge_calc_face_angle_doc},
{"normal_update", (PyCFunction)bpy_bmedge_normal_update, METH_NOARGS, bpy_bmedge_normal_update_doc},
@@ -1856,7 +2032,9 @@ static struct PyMethodDef bpy_bmloop_methods[] = {
{"copy_from", (PyCFunction)bpy_bm_elem_copy_from, METH_O, bpy_bm_elem_copy_from_doc},
{"copy_from_face_interp", (PyCFunction)bpy_bmloop_copy_from_face_interp, METH_O, bpy_bmloop_copy_from_face_interp_doc},
- {"calc_angle", (PyCFunction)bpy_bmloop_calc_face_angle, METH_NOARGS, bpy_bmloop_calc_face_angle_doc},
+ {"calc_angle", (PyCFunction)bpy_bmloop_calc_angle, METH_NOARGS, bpy_bmloop_calc_angle_doc},
+ {"calc_normal", (PyCFunction)bpy_bmloop_calc_normal, METH_NOARGS, bpy_bmloop_calc_normal_doc},
+ {"calc_tangent", (PyCFunction)bpy_bmloop_calc_tangent, METH_NOARGS, bpy_bmloop_calc_tangent_doc},
{NULL, NULL, 0, NULL}
};
@@ -2143,10 +2321,10 @@ static void bpy_bmesh_dealloc(BPy_BMesh *self)
BM_data_layer_free(bm, &bm->ldata, CD_BM_ELEM_PYPTR);
bm->py_handle = NULL;
- }
- if (self->py_owns) {
- BM_mesh_free(bm);
+ if ((self->flag & BPY_BMFLAG_IS_WRAPPED) == 0) {
+ BM_mesh_free(bm);
+ }
}
PyObject_DEL(self);
@@ -2476,7 +2654,7 @@ PyObject *BPyInit_bmesh_types(void)
/* Utility Functions
* ***************** */
-PyObject *BPy_BMesh_CreatePyObject(BMesh *bm)
+PyObject *BPy_BMesh_CreatePyObject(BMesh *bm, int flag)
{
BPy_BMesh *self;
@@ -2487,6 +2665,8 @@ PyObject *BPy_BMesh_CreatePyObject(BMesh *bm)
else {
self = PyObject_New(BPy_BMesh, &BPy_BMesh_Type);
self->bm = bm;
+ self->flag = flag;
+
bm->py_handle = self; /* point back */
BM_data_layer_add(bm, &bm->vdata, CD_BM_ELEM_PYPTR);
diff --git a/source/blender/python/bmesh/bmesh_py_types.h b/source/blender/python/bmesh/bmesh_py_types.h
index 88569c5eeaf..b5b96002ccc 100644
--- a/source/blender/python/bmesh/bmesh_py_types.h
+++ b/source/blender/python/bmesh/bmesh_py_types.h
@@ -62,7 +62,7 @@ typedef struct BPy_BMElem {
typedef struct BPy_BMesh {
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
- char py_owns; /* when set, free along with the PyObject */
+ int flag;
} BPy_BMesh;
/* element types */
@@ -120,7 +120,12 @@ void BPy_BM_init_types(void);
PyObject *BPyInit_bmesh_types(void);
-PyObject *BPy_BMesh_CreatePyObject(BMesh *bm);
+enum {
+ BPY_BMFLAG_NOP = 0, /* do nothing */
+ BPY_BMFLAG_IS_WRAPPED = 1 /* the mesh is owned by editmode */
+};
+
+PyObject *BPy_BMesh_CreatePyObject(BMesh *bm, int flag);
PyObject *BPy_BMVert_CreatePyObject(BMesh *bm, BMVert *v);
PyObject *BPy_BMEdge_CreatePyObject(BMesh *bm, BMEdge *e);
PyObject *BPy_BMFace_CreatePyObject(BMesh *bm, BMFace *f);