[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [44805] trunk/blender/source/blender: bmesh python api additions:

Campbell Barton ideasman42 at gmail.com
Sun Mar 11 06:58:33 CET 2012


Revision: 44805
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=44805
Author:   campbellbarton
Date:     2012-03-11 05:58:22 +0000 (Sun, 11 Mar 2012)
Log Message:
-----------
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()

Modified Paths:
--------------
    trunk/blender/source/blender/bmesh/intern/bmesh_mesh.c
    trunk/blender/source/blender/bmesh/intern/bmesh_queries.c
    trunk/blender/source/blender/bmesh/intern/bmesh_queries.h
    trunk/blender/source/blender/python/bmesh/bmesh_py_api.c
    trunk/blender/source/blender/python/bmesh/bmesh_py_types.c
    trunk/blender/source/blender/python/bmesh/bmesh_py_types.h

Modified: trunk/blender/source/blender/bmesh/intern/bmesh_mesh.c
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_mesh.c	2012-03-11 04:07:22 UTC (rev 44804)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_mesh.c	2012-03-11 05:58:22 UTC (rev 44805)
@@ -154,13 +154,6 @@
 
 	BLI_freelistN(&bm->selected);
 
-	if (bm->py_handle) {
-		extern void bpy_bm_generic_invalidate(void *self);
-
-		bpy_bm_generic_invalidate(bm->py_handle);
-		bm->py_handle = NULL;
-	}
-
 	BMO_error_clear(bm);
 }
 
@@ -195,6 +188,16 @@
 void BM_mesh_free(BMesh *bm)
 {
 	BM_mesh_data_free(bm);
+
+	if (bm->py_handle) {
+		/* keep this out of 'BM_mesh_data_free' because we wan't python
+		 * to be able to clear the mesh and maintain access. */
+		extern void bpy_bm_generic_invalidate(void *self);
+
+		bpy_bm_generic_invalidate(bm->py_handle);
+		bm->py_handle = NULL;
+	}
+
 	MEM_freeN(bm);
 }
 

Modified: trunk/blender/source/blender/bmesh/intern/bmesh_queries.c
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_queries.c	2012-03-11 04:07:22 UTC (rev 44804)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_queries.c	2012-03-11 05:58:22 UTC (rev 44805)
@@ -617,6 +617,65 @@
 }
 
 /**
+ * \brief BM_loop_face_normal
+ *
+ * Calculate the normal at this loop corner or fallback to the face normal on straignt lines.
+ *
+ * \param bm The BMesh
+ * \param l The loop to calculate the normal at
+ * \param r_normal Resulting normal
+ */
+void BM_loop_face_normal(BMesh *UNUSED(bm), BMLoop *l, float r_normal[3])
+{
+	if (normal_tri_v3(r_normal,
+	                  l->prev->v->co,
+	                  l->v->co,
+	                  l->next->v->co) != 0.0f)
+	{
+		return;
+	}
+	else {
+		copy_v3_v3(r_normal, l->f->no);
+	}
+}
+
+/**
+ * \brief BM_loop_face_tangent
+ *
+ * Calculate the tangent at this loop corner or fallback to the face normal on straignt lines.
+ * This vector always points inward into the face.
+ *
+ * \param bm The BMesh
+ * \param l The loop to calculate the tangent at
+ * \param r_tangent Resulting tangent
+ */
+void BM_loop_face_tangent(BMesh *UNUSED(bm), BMLoop *l, float r_tangent[3])
+{
+	float v_prev[3];
+	float v_next[3];
+
+	sub_v3_v3v3(v_prev, l->prev->v->co, l->v->co);
+	sub_v3_v3v3(v_next, l->v->co, l->next->v->co);
+
+	normalize_v3(v_prev);
+	normalize_v3(v_next);
+
+	if (compare_v3v3(v_prev, v_next, FLT_EPSILON) == FALSE) {
+		float dir[3];
+		float nor[3]; /* for this purpose doesnt need to be normalized */
+		add_v3_v3v3(dir, v_prev, v_next);
+		cross_v3_v3v3(nor, v_prev, v_next);
+		cross_v3_v3v3(r_tangent, dir, nor);
+	}
+	else {
+		/* prev/next are the same - compare with face normal since we dont have one */
+		cross_v3_v3v3(r_tangent, v_next, l->f->no);
+	}
+
+	normalize_v3(r_tangent);
+}
+
+/**
  * \brief BMESH EDGE/FACE ANGLE
  *
  *  Calculates the angle between two faces.

Modified: trunk/blender/source/blender/bmesh/intern/bmesh_queries.h
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_queries.h	2012-03-11 04:07:22 UTC (rev 44804)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_queries.h	2012-03-11 05:58:22 UTC (rev 44805)
@@ -54,6 +54,8 @@
 int     BM_edge_is_boundary(BMEdge *e);
 
 float   BM_loop_face_angle(BMesh *bm, BMLoop *l);
+void    BM_loop_face_normal(BMesh *bm, BMLoop *l, float r_normal[3]);
+void    BM_loop_face_tangent(BMesh *bm, BMLoop *l, float r_tangent[3]);
 
 float   BM_edge_face_angle(BMesh *bm, BMEdge *e);
 float   BM_vert_edge_angle(BMesh *bm, BMVert *v);

Modified: trunk/blender/source/blender/python/bmesh/bmesh_py_api.c
===================================================================
--- trunk/blender/source/blender/python/bmesh/bmesh_py_api.c	2012-03-11 04:07:22 UTC (rev 44804)
+++ trunk/blender/source/blender/python/bmesh/bmesh_py_api.c	2012-03-11 05:58:22 UTC (rev 44805)
@@ -57,14 +57,11 @@
 
 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 @@
 );
 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 @@
 
 	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[] = {

Modified: trunk/blender/source/blender/python/bmesh/bmesh_py_types.c
===================================================================
--- trunk/blender/source/blender/python/bmesh/bmesh_py_types.c	2012-03-11 04:07:22 UTC (rev 44804)
+++ trunk/blender/source/blender/python/bmesh/bmesh_py_types.c	2012-03-11 05:58:22 UTC (rev 44805)
@@ -36,6 +36,7 @@
 
 #include "BKE_depsgraph.h"
 #include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
 
 #include "bmesh.h"
 
@@ -252,7 +253,16 @@
 	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 @@
     {(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 @@
 /* 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 @@
 	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 @@
 	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 @@
 /* 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,22 +1404,55 @@
 }
 
 
-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"

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list