Commit: e9e37ddeb62595c62dc2fddfd02a4cdc7d96d53c
Author: Lukas Tönne
Date:   Tue Jul 14 17:27:01 2015 +0200
Branches: mathutils_bvhtree
https://developer.blender.org/rBe9e37ddeb62595c62dc2fddfd02a4cdc7d96d53c

Another alternative BVH Tree representation for totally custom user
geometry.

The new constructor method allows creating a BVHTree from a list of
vertices and triangles directly, without a separate mesh representation.

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

M       source/blender/blenkernel/BKE_bvhutils.h
M       source/blender/blenkernel/intern/bvhutils.c
M       source/blender/python/mathutils/mathutils_bvhtree.c
M       source/blender/python/mathutils/mathutils_bvhtree.h

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

diff --git a/source/blender/blenkernel/BKE_bvhutils.h 
b/source/blender/blenkernel/BKE_bvhutils.h
index a360511..8109f46 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -101,6 +101,7 @@ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data);
  * Math functions used by callbacks
  */
 float bvhtree_ray_tri_intersection(const BVHTreeRay *ray, const float m_dist, 
const float v0[3], const float v1[3], const float v2[3]);
+float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray, float radius, 
const float m_dist, const float v0[3], const float v1[3], const float v2[3]);
 float nearest_point_in_tri_surface_squared(const float v0[3], const float 
v1[3], const float v2[3], const float p[3], int *v, int *e, float nearest[3]);
 
 /*
diff --git a/source/blender/blenkernel/intern/bvhutils.c 
b/source/blender/blenkernel/intern/bvhutils.c
index 1a4a4bd..2213869 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -60,7 +60,7 @@ float bvhtree_ray_tri_intersection(const BVHTreeRay *ray, 
const float UNUSED(m_d
        return FLT_MAX;
 }
 
-static float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, 
const float m_dist, const float v0[3], const float v1[3], const float v2[3])
+float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray, float radius, 
const float m_dist, const float v0[3], const float v1[3], const float v2[3])
 {
        
        float idist;
@@ -163,7 +163,7 @@ static void mesh_faces_spherecast(void *userdata, int 
index, const BVHTreeRay *r
                if (data->sphere_radius == 0.0f)
                        dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, 
t1, t2);
                else
-                       dist = sphereray_tri_intersection(ray, 
data->sphere_radius, hit->dist, t0, t1, t2);
+                       dist = bvhtree_sphereray_tri_intersection(ray, 
data->sphere_radius, hit->dist, t0, t1, t2);
 
                if (dist >= 0 && dist < hit->dist) {
                        hit->index = index;
@@ -200,7 +200,7 @@ static void editmesh_faces_spherecast(void *userdata, int 
index, const BVHTreeRa
                if (data->sphere_radius == 0.0f)
                        dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, 
t1, t2);
                else
-                       dist = sphereray_tri_intersection(ray, 
data->sphere_radius, hit->dist, t0, t1, t2);
+                       dist = bvhtree_sphereray_tri_intersection(ray, 
data->sphere_radius, hit->dist, t0, t1, t2);
 
                if (dist >= 0 && dist < hit->dist) {
                        hit->index = index;
diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c 
b/source/blender/python/mathutils/mathutils_bvhtree.c
index 7d4d4ef..310ec41 100644
--- a/source/blender/python/mathutils/mathutils_bvhtree.c
+++ b/source/blender/python/mathutils/mathutils_bvhtree.c
@@ -73,6 +73,26 @@ typedef struct {
        int bmtotlooptris;
 } PyBVHTree_BMesh;
 
+typedef struct BVHVertex {
+       float co[3];
+} BVHVertex;
+
+typedef struct BVHTriangle {
+       int v1, v2, v3;
+} BVHTriangle;
+
+typedef struct PyBVHTree_Custom {
+       PyBVHTree base;
+       /* geometry data */
+       struct BVHTree *tree;
+       
+       struct BVHVertex *vert;
+       struct BVHTriangle *tri;
+       int totvert, tottri;
+       
+       float epsilon;
+} PyBVHTree_Custom;
+
 /* -------------------------------------------------------------------- */
 /* Utility helper functions */
 
@@ -691,6 +711,360 @@ PyTypeObject PyBVHTreeBMesh_Type = {
 };
 
 /* -------------------------------------------------------------------- */
+/* BVHTreeCustom */
+
+static BVHTree *bvhtree_from_triangles_create_tree(float epsilon, int 
tree_type, int axis,
+                                                   BVHVertex *vert, 
BVHTriangle *tri, int numtris)
+{
+       BVHTree *tree = NULL;
+       int i;
+       
+       if (numtris == 0 || !vert || !tri)
+               return NULL;
+       
+       /* Create a bvh-tree of the given target */
+       tree = BLI_bvhtree_new(numtris, epsilon, (char)tree_type, (char)axis);
+       if (tree) {
+               for (i = 0; i < numtris; i++) {
+                       float co[3][3];
+                       
+                       copy_v3_v3(co[0], vert[tri[i].v1].co);
+                       copy_v3_v3(co[1], vert[tri[i].v2].co);
+                       copy_v3_v3(co[2], vert[tri[i].v3].co);
+                       
+                       BLI_bvhtree_insert(tree, i, co[0], 3);
+               }
+               
+               BLI_bvhtree_balance(tree);
+       }
+       
+       return tree;
+}
+
+static int PyBVHTreeCustom__tp_init(PyBVHTree_Custom *self, PyObject *args, 
PyObject *kwargs)
+{
+       const char *keywords[] = {"vertices", "triangles", NULL};
+       
+       PyObject *py_verts, *py_tris;
+       int numverts, numtris;
+       BVHVertex *verts, *vp;
+       BVHTriangle *tris, *tp;
+       int i;
+       bool valid = true;
+       
+       if (PyBVHTree_Type.tp_init((PyObject *)self, args, kwargs) < 0)
+               return -1;
+       
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char 
*)"OO:BVHTreeCustom", (char **)keywords,
+                                        &py_verts, &py_tris))
+       {
+               return -1;
+       }
+       
+       if (!PySequence_Check(py_verts)) {
+               PyErr_SetString(PyExc_TypeError,
+                               "expected a sequence of vectors");
+               return -1;
+       }
+       
+       if (!PySequence_Check(py_tris)) {
+               PyErr_SetString(PyExc_TypeError,
+                               "expected a sequence of lists of integers");
+               return -1;
+       }
+       
+       if (valid) {
+               numverts = (int)PySequence_Size(py_verts);
+               vp = verts = MEM_mallocN(sizeof(BVHVertex) * (size_t)numverts, 
"BPy BVHTree vertices");
+               for (i = 0; i < numverts; i++, vp++) {
+                       PyObject *py_vert = PySequence_GetItem(py_verts, i);
+                       
+                       if (mathutils_array_parse(vp->co, 3, 3, py_vert, 
"BVHTree vertex: ") == -1) {
+                               valid = false;
+                               break;
+                       }
+               }
+       }
+       
+       if (valid) {
+               numtris = (int)PySequence_Size(py_tris);
+               /* now construct loop list */
+               tp = tris = MEM_mallocN(sizeof(BVHTriangle) * (size_t)numtris, 
"BPy BVHTree triangles");
+               for (i = 0; i < numtris; i++) {
+                       PyObject *py_triverts = PySequence_GetItem(py_tris, i);
+                       int tottri = (int)PySequence_Size(py_triverts);
+                       
+                       if (tottri != 3) {
+                               Py_XDECREF(py_triverts); /* may be null so use 
Py_XDECREF*/
+                               PyErr_SetString(PyExc_TypeError,
+                                               "One or more of the triangles 
does not have 3 indices");
+                               valid = false;
+                               break;
+                       }
+                       
+                       tp->v1 = 
(int)PyLong_AsLong(PySequence_GetItem(py_triverts, 0));
+                       tp->v2 = 
(int)PyLong_AsLong(PySequence_GetItem(py_triverts, 1));
+                       tp->v3 = 
(int)PyLong_AsLong(PySequence_GetItem(py_triverts, 2));
+               }
+       }
+       
+       if (valid) {
+               self->vert = verts;
+               self->totvert = numverts;
+               self->tri = tris;
+               self->tottri = numtris;
+               
+               /* XXX make configurable? */
+               self->epsilon = 0.0f;
+               
+               self->tree = bvhtree_from_triangles_create_tree(self->epsilon, 
4, 6, self->vert, self->tri, self->tottri);
+               
+               return 0;
+       }
+       else {
+               if (verts)
+                       MEM_freeN(verts);
+               if (tris)
+                       MEM_freeN(tris);
+               
+               return -1;
+       }
+}
+
+static void PyBVHTreeCustom__tp_dealloc(PyBVHTree_Custom *self)
+{
+       if (self->tree)
+               BLI_bvhtree_free(self->tree);
+       
+       if (self->vert)
+               MEM_freeN(self->vert);
+       if (self->tri)
+               MEM_freeN(self->tri);
+       
+       Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static void bvhtree_custom_raycast_cb(void *userdata, int index, const 
BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+       PyBVHTree_Custom *self = (PyBVHTree_Custom *)userdata;
+       const BVHVertex *verts = self->vert;
+       const BVHTriangle *tris = self->tri;
+
+       const float *t0, *t1, *t2;
+       t0 = verts[ tris[index].v1 ].co;
+       t1 = verts[ tris[index].v2 ].co;
+       t2 = verts[ tris[index].v3 ].co;
+
+       {
+               float dist;
+               if (self->epsilon == 0.0f)
+                       dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, 
t1, t2);
+               else
+                       dist = bvhtree_sphereray_tri_intersection(ray, 
self->epsilon, hit->dist, t0, t1, t2);
+
+               if (dist >= 0 && dist < hit->dist) {
+                       hit->index = index;
+                       hit->dist = dist;
+                       madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, 
dist);
+
+                       normal_tri_v3(hit->no, t0, t1, t2);
+               }
+       }
+}
+
+PyDoc_STRVAR(py_BVHTreeCustom_ray_cast_doc,
+".. method:: ray_cast(ray_start, ray_end)\n"
+"\n"
+"   Cast a ray onto the mesh.\n"
+"\n"
+"   :arg ray_point: Start location of the ray in object space.\n"
+"   :type ray_point: :class:`Vector`\n"
+"   :arg ray_direction: Direction of the ray in object space.\n"
+"   :type ray_direction: :class:`Vector`\n"
+"   :arg ray_maxdist: Maximum distance of intersection.\n"
+"   :type ray_maxdist: :float\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_BVHTreeCustom_ray_cast(PyBVHTree_Custom *self, PyObject 
*args)
+{
+       const char *error_prefix = "ray_cast";
+       
+       PyObject *py_point, *py_direction;
+       float ray_point[3], ray_direction[3];
+       float ray_maxdist = FLT_MAX;
+       
+       if (!PyArg_ParseTuple(args, (char *)"OO|f:ray_cast", &py_point, 
&py_direction, &ray_maxdist))
+       {
+               return NULL;
+       }
+       
+       if (mathutils_array_parse(ray_point, 2, 3, py_point, error_prefix) == 
-1 ||
+           mathutils_array_parse(ray_direction, 2, 3, py_direction, 
error_prefix) == -1)
+       {
+               return NULL;
+       }
+       
+       normalize_v3(ray_direction);
+       
+       /* may fail if the mesh has no faces, in that case the ray-cast misses 
*/
+       if (self->tree) {
+               BVHTreeRayHit hit;
+               hit.dist = ray_maxdist;
+               hit.index = -1;
+               
+               if (BLI_bvhtree_ray_cast(self->tree, ray_point, ray_direction, 
0.0f, &hit,
+                                        bvhtree_custom_raycast_cb, self) != -1)
+               {
+                       if (hit.dist <= ray_maxdist) {
+                               return bvhtree_ray_hit_to_py(hit.co, hit.no, 
hit.index, hit.dist);
+                       }
+               }
+       }
+       
+       return bvhtree_ray_hit_to_py(NULL, NULL, -1, 0.0f);
+}
+
+/* Callback to bvh tree nearest point. The tree must have been built using 
bvhtree_from_mesh_faces.
+ * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the 
tree. */
+static void bvhtree_custom_nearest_point_cb(void *userdata, int index, const 
float co[3], BVHTreeNearest *nearest)
+{
+       PyBVHTree_Custom *self = (PyBVHTree_Custom *)userdata;
+       const BVHVertex *verts = self->vert;
+       const BVHTriangle *tris = self->tri;
+
+       const float *t0, *t1, *t2, *t3;
+       t0 = verts[ tris->v1 ].co;
+       t1 = verts[ tris->v2 ].co;
+       t2 = verts[ tris->v3 ].co;
+
+       {
+               float nearest_tmp[3], dist_sq;
+
+               closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
+               dist_sq = len_squared_v3v3(co, nearest_tmp);
+
+               if (dist_sq < nearest->dist_sq) {
+                       nearest->index = index;
+                       nearest->dist_sq = dist_sq;
+                       copy_v3_v3(nearest->co, nearest_tmp);
+                       normal_tri_v3(near

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to