[Bf-blender-cvs] [067f0d4] mathutils_bvhtree: Splitting the BVHTree python type into two distinct subclasses for DerivedMesh and BMesh support.

Lukas Tönne noreply at git.blender.org
Sat Jan 3 11:09:23 CET 2015


Commit: 067f0d48e3e0c8883a03cccd020093701c629a2c
Author: Lukas Tönne
Date:   Sun Dec 28 15:26:16 2014 +0100
Branches: mathutils_bvhtree
https://developer.blender.org/rB067f0d48e3e0c8883a03cccd020093701c629a2c

Splitting the BVHTree python type into two distinct subclasses for
DerivedMesh and BMesh support.

This avoids messy code due to mixed data in the same py type. And makes
it clear at any point what kind of data the BVHTree instance represents.

Both types are based on the common BVHTree type, which currently does
not have any functionality of its own. Eventually it could implement
common BVH functions (find-nearest and ray casting) as well as return
read-only info about the size and type of BVH data.

Note: While the BVH functions already use callbacks for providing a
common interface in C, using this for python types would be redundant.
It also still requires specialized data for some details of testing
elements.

===================================================================

M	source/blender/python/mathutils/mathutils_bvhtree.c
M	source/blender/python/mathutils/mathutils_bvhtree.h

===================================================================

diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c
index 3fbb220..73ce4ff 100644
--- a/source/blender/python/mathutils/mathutils_bvhtree.c
+++ b/source/blender/python/mathutils/mathutils_bvhtree.c
@@ -54,14 +54,22 @@
 
 typedef struct {
 	PyObject_HEAD
+} PyBVHTree;
+
+typedef struct {
+	PyBVHTree base;
 	/* Object DerivedMesh data */
 	Object *ob;
 	BVHTreeFromMesh meshdata;
+} PyDerivedMeshBVHTree;
+
+typedef struct {
+	PyBVHTree base;
 	/* BMesh data */
 	BMBVHTree *bmdata;
 	BMLoop *(*bmlooptris)[3];
 	int bmtotlooptris;
-} PyBVHTree;
+} PyBMeshBVHTree;
 
 /* -------------------------------------------------------------------- */
 /* Utility helper functions */
@@ -131,176 +139,320 @@ static PyObject *bvhtree_nearest_to_py(const float co[3], const float no[3], int
 /* -------------------------------------------------------------------- */
 /* BVHTree */
 
-/* generic cleanup function for resetting everything */
-static void free_BVHTree(PyBVHTree *self)
-{
-	BVHTreeFromMesh *meshdata = &self->meshdata;
-	
-	self->ob = NULL;
-	free_bvhtree_from_mesh(meshdata);
-	
-	if (self->bmlooptris) {
-		MEM_freeN(self->bmlooptris);
-		self->bmlooptris = NULL;
-		self->bmtotlooptris = 0;
-	}
-	if (self->bmdata) {
-		BKE_bmbvh_free(self->bmdata);
-		self->bmdata = NULL;
-	}
-}
-
 static int PyBVHTree__tp_init(PyBVHTree *self, PyObject *args, PyObject *kwargs)
 {
-	self->ob = NULL;
-	memset(&self->meshdata, 0, sizeof(BVHTreeFromMesh));
-	self->bmdata = NULL;
-	
 	return 0;
 }
 
 static void PyBVHTree__tp_dealloc(PyBVHTree *self)
 {
-	free_BVHTree(self);
-	
 	Py_TYPE(self)->tp_free((PyObject *)self);
 }
 
-PyDoc_STRVAR(py_BVHTree_from_object_verts_doc,
-".. method:: from_object_verts(object)\n"
-"\n"
-"   Construct the BVHTree from object vertices.\n"
-"\n"
-"   :arg object: Object used for constructing the BVH tree.\n"
-"   :type object: :class:`Object`\n"
+static PyMethodDef PyBVHTree_methods[] = {
+	{NULL, NULL, 0, NULL}
+};
+
+PyDoc_STRVAR(py_BVHTree_doc,
+"BVH tree based on :class:`Mesh` data.\n"
 );
-static PyObject *py_BVHTree_from_object_verts(PyBVHTree *self, PyObject *args, PyObject *kwargs)
+PyTypeObject PyBVHTree_Type = {
+	PyVarObject_HEAD_INIT(NULL, 0)
+	"BVHTree",                                   /* tp_name */
+	sizeof(PyBVHTree),                           /* tp_basicsize */
+	0,                                           /* tp_itemsize */
+	/* methods */
+	(destructor)PyBVHTree__tp_dealloc,           /* tp_dealloc */
+	NULL,                                        /* tp_print */
+	NULL,                                        /* tp_getattr */
+	NULL,                                        /* tp_setattr */
+	NULL,                                        /* tp_compare */
+	NULL,                                        /* tp_repr */
+	NULL,                                        /* tp_as_number */
+	NULL,                                        /* tp_as_sequence */
+	NULL,                                        /* tp_as_mapping */
+	NULL,                                        /* tp_hash */
+	NULL,                                        /* tp_call */
+	NULL,                                        /* tp_str */
+	NULL,                                        /* tp_getattro */
+	NULL,                                        /* tp_setattro */
+	NULL,                                        /* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT,                          /* tp_flags */
+	py_BVHTree_doc,                              /* Documentation string */
+	NULL,                                        /* tp_traverse */
+	NULL,                                        /* tp_clear */
+	NULL,                                        /* tp_richcompare */
+	0,                                           /* tp_weaklistoffset */
+	NULL,                                        /* tp_iter */
+	NULL,                                        /* tp_iternext */
+	(struct PyMethodDef *)PyBVHTree_methods,     /* tp_methods */
+	NULL,                                        /* tp_members */
+	NULL,                                        /* tp_getset */
+	NULL,                                        /* tp_base */
+	NULL,                                        /* tp_dict */
+	NULL,                                        /* tp_descr_get */
+	NULL,                                        /* tp_descr_set */
+	0,                                           /* tp_dictoffset */
+	(initproc)PyBVHTree__tp_init,                /* tp_init */
+	(allocfunc)PyType_GenericAlloc,              /* tp_alloc */
+	(newfunc)PyType_GenericNew,                  /* tp_new */
+	(freefunc)0,                                 /* tp_free */
+	NULL,                                        /* tp_is_gc */
+	NULL,                                        /* tp_bases */
+	NULL,                                        /* tp_mro */
+	NULL,                                        /* tp_cache */
+	NULL,                                        /* tp_subclasses */
+	NULL,                                        /* tp_weaklist */
+	(destructor) NULL                            /* tp_del */
+};
+
+/* -------------------------------------------------------------------- */
+/* DerivedMeshBVHTree */
+
+static int PyDerivedMeshBVHTree__tp_init(PyDerivedMeshBVHTree *self, PyObject *args, PyObject *kwargs)
 {
 	BVHTreeFromMesh *meshdata = &self->meshdata;
-	const char *keywords[] = {"object", NULL};
+	const char *keywords[] = {"object", "type", NULL};
 	
 	PyObject *py_ob;
 	Object *ob;
+	const char *type = "FACES";
 	
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *)"O:from_object_verts", (char **)keywords,
-	                                 &py_ob))
+	if (PyBVHTree_Type.tp_init((PyObject *)self, args, kwargs) < 0)
+		return -1;
+	
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *)"O|s:DerivedMeshBVHTree", (char **)keywords,
+	                                 &py_ob, &type))
 	{
-		return NULL;
+		return -1;
 	}
 	
 	ob = PyC_RNA_AsPointer(py_ob, "Object");
 	if (!ob) {
-		return NULL;
+		return -1;
 	}
 	
 	if (ob->derivedFinal == NULL) {
 		PyErr_Format(PyExc_ValueError, "Object '%.200s' has no mesh data to be used for BVH tree", ob->id.name + 2);
-		return NULL;
+		return -1;
 	}
 	
-	/* free existing data */
-	free_BVHTree(self);
-	
 	self->ob = ob;
 	
-	bvhtree_from_mesh_verts(meshdata, ob->derivedFinal, 0.0f, 4, 6);
+	if (STREQ(type, "FACES")) {
+		bvhtree_from_mesh_faces(meshdata, ob->derivedFinal, 0.0f, 4, 6);
+	}
+	else if (STREQ(type, "VERTS")) {
+		bvhtree_from_mesh_verts(meshdata, ob->derivedFinal, 0.0f, 4, 6);
+	}
+	else if (STREQ(type, "EDGES")) {
+		bvhtree_from_mesh_edges(meshdata, ob->derivedFinal, 0.0f, 4, 6);
+	}
+	else {
+		PyErr_Format(PyExc_ValueError, "'type' must be 'FACES', 'VERTS' or 'EDGES', not '%.200s'", type);
+		return -1;
+	}
 	
-	Py_RETURN_NONE;
+	return 0;
 }
 
-PyDoc_STRVAR(py_BVHTree_from_object_faces_doc,
-".. method:: from_object_faces(object)\n"
+static void PyDerivedMeshBVHTree__tp_dealloc(PyDerivedMeshBVHTree *self)
+{
+	BVHTreeFromMesh *meshdata = &self->meshdata;
+	
+	self->ob = NULL;
+	free_bvhtree_from_mesh(meshdata);
+	
+	Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+PyDoc_STRVAR(py_DerivedMeshBVHTree_ray_cast_doc,
+".. method:: ray_cast(ray_start, ray_end, use_poly_index=True)\n"
 "\n"
-"   Construct the BVHTree from object faces.\n"
+"   Cast a ray onto the mesh.\n"
 "\n"
-"   :arg object: Object used for constructing the BVH tree.\n"
-"   :type object: :class:`Object`\n"
+"   :arg ray_start: Start location of the ray in object space.\n"
+"   :type ray_start: :class:`Vector`\n"
+"   :arg ray_end: End location of the ray in object space.\n"
+"   :type ray_end: :class:`Vector`\n"
+"   :arg use_poly_index: Return poly index instead of tessface index.\n"
+"   :type use_poly_index: :boolean\n"
+"   :return: Returns a tuple (:class:`Vector` location, :class:`Vector` normal, int index, float distance), index==-1 if no hit was found.\n"
+"   :rtype: :class:`tuple`\n"
 );
-static PyObject *py_BVHTree_from_object_faces(PyBVHTree *self, PyObject *args, PyObject *kwargs)
+static PyObject *py_DerivedMeshBVHTree_ray_cast(PyDerivedMeshBVHTree *self, PyObject *args, PyObject *kwargs)
 {
+	static const float ZERO[3] = {0.0f, 0.0f, 0.0f};
+	
 	BVHTreeFromMesh *meshdata = &self->meshdata;
-	const char *keywords[] = {"object", NULL};
+	Object *ob = self->ob;
+	const char *keywords[] = {"ray_start", "ray_end", "use_poly_index", NULL};
 	
-	PyObject *py_ob;
-	Object *ob;
+	PyObject *py_ray_start, *py_ray_end;
+	float ray_start[3], ray_end[3];
+	int use_poly_index = true;
+	float ray_nor[3], ray_len;
 	
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *)"O:from_object_faces", (char **)keywords,
-	                                 &py_ob))
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *)"O!O!|i:ray_cast", (char **)keywords,
+	                                 &vector_Type, &py_ray_start,
+	                                 &vector_Type, &py_ray_end,
+	                                 &use_poly_index))
 	{
 		return NULL;
 	}
 	
-	ob = PyC_RNA_AsPointer(py_ob, "Object");
-	if (!ob) {
+	if (!parse_vector(py_ray_start, ray_start))
 		return NULL;
-	}
-	
-	if (ob->derivedFinal == NULL) {
-		PyErr_Format(PyExc_ValueError, "Object '%.200s' has no mesh data to be used for BVH tree", ob->id.name + 2);
+	if (!parse_vector(py_ray_end, ray_end))
 		return NULL;
-	}
 	
-	/* free existing data */
-	free_BVHTree(self);
+	/* can only look up poly index for object mesh data */
+	if (!self->ob)
+		use_poly_index = false;
 	
-	self->ob = ob;
+	sub_v3_v3v3(ray_nor, ray_end, ray_start);
+	ray_len = normalize_v3(ray_nor);
 	
-	bvhtree_from_mesh_faces(meshdata, ob->derivedFinal, 0.0f, 4, 6);
+	/* may fail if the mesh has no faces, in that case the ray-cast misses */
+	if (meshdata->tree && meshdata->raycast_callback && ob->derivedFinal)
+	{
+		BVHTreeRayHit hit;
+		hit.dist = ray_len;
+		hit.index = -1;
+		
+		if (BLI_bvhtree_ray_cast(meshdata->tree, ray_start, ray_nor, 0.0f, &hit,
+		                         meshdata->raycast_callback, meshdata) != -1)
+		{
+			if (hit.dist <= ray_len) {
+				int ret_index = use_poly_index ? dm_tessface_to_poly_index_safe(o

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list