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

Campbell Barton ideasman42 at gmail.com
Thu Feb 23 18:15:01 CET 2012


Revision: 44382
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=44382
Author:   campbellbarton
Date:     2012-02-23 17:14:53 +0000 (Thu, 23 Feb 2012)
Log Message:
-----------
bmesh py api
bmesh.utils.face_join(faces)

added a utility function for converting a list of python BMesh elements into a C array.
use for this face_join as well as BMesh.faces.new()

Modified Paths:
--------------
    trunk/blender/source/blender/python/bmesh/bmesh_py_types.c
    trunk/blender/source/blender/python/bmesh/bmesh_py_types.h
    trunk/blender/source/blender/python/bmesh/bmesh_py_utils.c

Modified: trunk/blender/source/blender/python/bmesh/bmesh_py_types.c
===================================================================
--- trunk/blender/source/blender/python/bmesh/bmesh_py_types.c	2012-02-23 16:12:36 UTC (rev 44381)
+++ trunk/blender/source/blender/python/bmesh/bmesh_py_types.c	2012-02-23 17:14:53 UTC (rev 44382)
@@ -913,69 +913,24 @@
 	}
 	else {
 		BMesh *bm = self->bm;
-		PyObject *vert_seq_fast;
 		Py_ssize_t vert_seq_len;
 		Py_ssize_t i, i_prev;
 
-		void *alloc;
-		BMVert **vert_array;
-		BMEdge **edge_array;
+		BMVert **vert_array = NULL;
+		BMEdge **edge_array = NULL;
 
-		BPy_BMVert *item;
 		PyObject *ret = NULL;
-		int ok;
 
-		BMFace *f;
+		BMFace *f_new;
 
 		if (py_face_example) {
 			BPY_BM_CHECK_OBJ(py_face_example);
 		}
 
-		if (!(vert_seq_fast=PySequence_Fast(vert_seq, "faces.new(...)"))) {
-			return NULL;
-		}
+		vert_array = bpy_bm_generic_py_seq_as_array(&bm, vert_seq, 3, PY_SSIZE_T_MAX,
+		                                            &vert_seq_len, &BPy_BMVert_Type,
+		                                            TRUE, TRUE, "faces.new(...)");
 
-		vert_seq_len = PySequence_Fast_GET_SIZE(vert_seq_fast);
-
-		alloc = PyMem_MALLOC(vert_seq_len * sizeof(BMVert **) + vert_seq_len * sizeof(BMEdge **));
-
-		vert_array = (BMVert **) alloc;
-		edge_array = (BMEdge **) &(((BMVert **)alloc)[vert_seq_len]);
-
-		/* --- */
-		for (i = 0; i < vert_seq_len; i++) {
-			item = (BPy_BMVert *)PySequence_Fast_GET_ITEM(vert_seq_fast, i);
-
-			if (!BPy_BMVert_Check(item)) {
-				PyErr_Format(PyExc_TypeError,
-				             "faces.new(verts): expected BMVert sequence, not '%.200s'",
-				             Py_TYPE(item)->tp_name);
-			}
-			else if (item->bm != bm) {
-				PyErr_Format(PyExc_TypeError,
-				             "faces.new(verts): %d vertex is from another mesh", i);
-			}
-
-			vert_array[i] = item->v;
-
-			BM_elem_flag_enable(item->v, BM_ELEM_TAG);
-		}
-
-		/* check for double verts! */
-		ok = TRUE;
-		for (i = 0; i < vert_seq_len; i++) {
-			if (UNLIKELY(BM_elem_flag_test(vert_array[i], BM_ELEM_TAG) == FALSE)) {
-				ok = FALSE;
-			}
-			BM_elem_flag_disable(item->v, BM_ELEM_TAG);
-		}
-
-		if (ok == FALSE) {
-			PyErr_SetString(PyExc_ValueError,
-			                "faces.new(verts): found the same vertex used multiple times");
-			goto cleanup;
-		}
-
 		/* check if the face exists */
 		if (BM_face_exists(bm, vert_array, vert_seq_len, NULL)) {
 			PyErr_SetString(PyExc_ValueError,
@@ -983,34 +938,34 @@
 			goto cleanup;
 		}
 
-
 		/* Go ahead and make the face!
 		 * --------------------------- */
 
+		edge_array = (BMEdge **)PyMem_MALLOC(vert_seq_len * sizeof(BMEdge **));
+
 		/* ensure edges */
-		ok = TRUE;
 		for (i = 0, i_prev = vert_seq_len - 1; i < vert_seq_len; (i_prev=i++)) {
 			edge_array[i] = BM_edge_create(bm, vert_array[i], vert_array[i_prev], NULL, TRUE);
 		}
 
-		f = BM_face_create(bm, vert_array, edge_array, vert_seq_len, FALSE);
+		f_new = BM_face_create(bm, vert_array, edge_array, vert_seq_len, FALSE);
 
-		if (f == NULL) {
+		if (f_new == NULL) {
 			PyErr_SetString(PyExc_ValueError,
 			                "faces.new(verts): couldn't create the new face, internal error");
 			goto cleanup;
 		}
 
 		if (py_face_example) {
-			BM_elem_attrs_copy(py_face_example->bm, bm, py_face_example->f, f);
+			BM_elem_attrs_copy(py_face_example->bm, bm, py_face_example->f, f_new);
 		}
 
-		ret = BPy_BMFace_CreatePyObject(bm, f);
+		ret = BPy_BMFace_CreatePyObject(bm, f_new);
 
 		/* pass through */
 cleanup:
-		Py_DECREF(vert_seq_fast);
-		PyMem_FREE(alloc);
+		if (vert_array) PyMem_FREE(vert_array);
+		if (edge_array) PyMem_FREE(edge_array);
 		return ret;
 	}
 }
@@ -1805,3 +1760,107 @@
 {
 	self->bm = NULL;
 }
+
+/* generic python seq as BMVert/Edge/Face array,
+ * return value must be freed with PyMem_FREE(...);
+ *
+ * The 'bm_r' value is assigned when empty, and used when set.
+ */
+void *bpy_bm_generic_py_seq_as_array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
+                                     PyTypeObject *type,
+                                     const char do_unique_check, const char do_bm_check,
+                                     const char *error_prefix)
+{
+	BMesh *bm = (r_bm && *r_bm) ? *r_bm : NULL;
+	PyObject *seq_fast;
+	*r_size = 0;
+
+	if (!(seq_fast=PySequence_Fast(seq, error_prefix))) {
+		return NULL;
+	}
+	else {
+		Py_ssize_t seq_len;
+		Py_ssize_t i;
+
+		BPy_BMElem *item;
+		BMHeader **alloc;
+
+		seq_len = PySequence_Fast_GET_SIZE(seq_fast);
+
+		if (seq_len < min || seq_len > max) {
+			PyErr_Format(PyExc_TypeError,
+			             "%s: sequence incorrect size, expected [%d - %d], given %d",
+			             error_prefix, min, max, seq_len);
+			return NULL;
+		}
+
+
+		/* from now on, use goto */
+		alloc = PyMem_MALLOC(seq_len * sizeof(BPy_BMElem **));
+
+		for (i = 0; i < seq_len; i++) {
+			item = (BPy_BMElem *)PySequence_Fast_GET_ITEM(seq_fast, i);
+
+			if (Py_TYPE(item) != type) {
+				PyErr_Format(PyExc_TypeError,
+				             "%s: expected '%.200', not '%.200s'",
+				             error_prefix, type->tp_name, Py_TYPE(item)->tp_name);
+				goto err_cleanup;
+			}
+			else if (item->bm == NULL) {
+				PyErr_Format(PyExc_TypeError,
+				             "%s: %d %s has been removed",
+				             error_prefix, i, type->tp_name);
+				goto err_cleanup;
+			}
+			/* trick so we can ensure all items have the same mesh,
+			 * and allows us to pass the 'bm' as NULL. */
+			else if (do_bm_check && (bm  && bm != item->bm)) {
+				PyErr_Format(PyExc_TypeError,
+				             "%s: %d %s is from another mesh",
+				             error_prefix, i, type->tp_name);
+				goto err_cleanup;
+			}
+
+			if (bm == NULL) {
+				bm = item->bm;
+			}
+
+			alloc[i] = item->ele;
+
+			if (do_unique_check) {
+				BM_elem_flag_enable(item->ele, BM_ELEM_TAG);
+			}
+		}
+
+		if (do_unique_check) {
+			/* check for double verts! */
+			int ok = TRUE;
+			for (i = 0; i < seq_len; i++) {
+				if (UNLIKELY(BM_elem_flag_test(alloc[i], BM_ELEM_TAG) == FALSE)) {
+					ok = FALSE;
+				}
+
+				/* ensure we dont leave this enabled */
+				BM_elem_flag_disable(alloc[i], BM_ELEM_TAG);
+			}
+
+			if (ok == FALSE) {
+				PyErr_Format(PyExc_ValueError,
+				             "%s: found the same %s used multiple times",
+				             error_prefix, type->tp_name);
+				goto err_cleanup;
+			}
+		}
+
+		Py_DECREF(seq_fast);
+		*r_size = seq_len;
+		if (r_bm) *r_bm = bm;
+		return alloc;
+
+err_cleanup:
+		Py_DECREF(seq_fast);
+		PyMem_FREE(alloc);
+		return NULL;
+	}
+}

Modified: trunk/blender/source/blender/python/bmesh/bmesh_py_types.h
===================================================================
--- trunk/blender/source/blender/python/bmesh/bmesh_py_types.h	2012-02-23 16:12:36 UTC (rev 44381)
+++ trunk/blender/source/blender/python/bmesh/bmesh_py_types.h	2012-02-23 17:14:53 UTC (rev 44382)
@@ -132,6 +132,11 @@
 int  bpy_bm_generic_valid_check(BPy_BMGeneric *self);
 void bpy_bm_generic_invalidate(BPy_BMGeneric *self);
 
+void *bpy_bm_generic_py_seq_as_array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
+                                     PyTypeObject *type,
+                                     const char do_unique_check, const char do_bm_check,
+                                     const char *error_prefix);
+
 #define BPY_BM_CHECK_OBJ(obj) if (bpy_bm_generic_valid_check((BPy_BMGeneric *)obj) == -1) { return NULL; } (void)NULL
 #define BPY_BM_CHECK_INT(obj) if (bpy_bm_generic_valid_check((BPy_BMGeneric *)obj) == -1) { return -1; }   (void)NULL
 

Modified: trunk/blender/source/blender/python/bmesh/bmesh_py_utils.c
===================================================================
--- trunk/blender/source/blender/python/bmesh/bmesh_py_utils.c	2012-02-23 16:12:36 UTC (rev 44381)
+++ trunk/blender/source/blender/python/bmesh/bmesh_py_utils.c	2012-02-23 17:14:53 UTC (rev 44382)
@@ -378,7 +378,43 @@
 	}
 }
 
+PyDoc_STRVAR(bpy_bm_utils_face_join_doc,
+".. method:: face_join(faces)\n"
+"\n"
+"   Joins a sequence of faces.\n"
+"\n"
+"   :arg faces: Sequence of faces .\n"
+"   :type faces: :class:`bmesh.tupes.BMFace`\n"
+"   :return: The newly created face or None on failier.\n"
+"   :rtype: :class:`bmesh.tupes.BMFace`\n"
+);
+static PyObject *bpy_bm_utils_face_join(PyObject *UNUSED(self), PyObject *value)
+{
+	BMesh *bm = NULL;
+	BMFace **face_array;
+	Py_ssize_t face_seq_len = 0;
+	BMFace *f_new;
 
+	face_array = bpy_bm_generic_py_seq_as_array(&bm, value, 2, PY_SSIZE_T_MAX,
+												&face_seq_len, &BPy_BMFace_Type,
+												TRUE, TRUE, "face_join(...)");
+
+	if (face_array == NULL) {
+		return NULL; /* error will be set */
+	}
+
+	/* Go ahead and join the face!
+	 * --------------------------- */
+	f_new = BM_faces_join(bm, face_array, (int)face_seq_len);
+
+	if (f_new) {
+		return BPy_BMFace_CreatePyObject(bm, f_new);
+	}
+	else {
+		Py_RETURN_NONE;
+	}
+}
+
 static struct PyMethodDef BPy_BM_utils_methods[] = {
     {"vert_collapse_edge",  (PyCFunction)bpy_bm_utils_vert_collapse_edge,  METH_VARARGS, bpy_bm_utils_vert_collapse_edge_doc},
     {"vert_collapse_faces", (PyCFunction)bpy_bm_utils_vert_collapse_faces, METH_VARARGS, bpy_bm_utils_vert_collapse_faces_doc},
@@ -386,6 +422,7 @@
     {"edge_split",          (PyCFunction)bpy_bm_utils_edge_split,          METH_VARARGS, bpy_bm_utils_edge_split_doc},
     {"edge_rotate",         (PyCFunction)bpy_bm_utils_edge_rotate,         METH_VARARGS, bpy_bm_utils_edge_rotate_doc},
     {"face_split",          (PyCFunction)bpy_bm_utils_face_split,          METH_VARARGS, bpy_bm_utils_face_split_doc},
+    {"face_join",           (PyCFunction)bpy_bm_utils_face_join,           METH_O,       bpy_bm_utils_face_join_doc},
     {NULL, NULL, 0, NULL}
 };
 




More information about the Bf-blender-cvs mailing list