In this post I will demonstrate how to use VTK to perform ray-casting, i.e., intersecting lines/rays with surface meshes, and retrieving the coordinates of those intersection points. This will include loading such meshes from STL files, performing the intersections, as well as visualizing the mesh, lines, and points in VTK. In addition, I will present my very own pycaster
package which cleanly wraps the VTK parts and allows for cleaner code and added functionality.
Introduction
Background
Today I’ll be talking about ray-casting which, to quote Wikipedia, is “the use of ray-surface intersection tests to solve a variety of problems in computer graphics and computational geometry”.
A pivotal difference between ray-casting and ‘ray-tracing’ is that the former only ‘casts’ a single ray, tests for its intersection with objects, and stops there. Ray-tracing on the other hand, is more physically accurate as it treats the rays with physics laws on reflection, refraction, attenuation, etc to ‘trace’, i.e., follow, that ray and its derivative rays.
However, I should make clear that ray-casting is the natural precursor to ray-tracing as it tells us what part of which object the ray intersects with and provides all necessary information to cast subsequent rays.
Summary
Today I’ll show how to use Python and VTK to perform ray-casting on surface meshes loaded from STL files and the vtkOBBTree
class.
I will first demonstrate the approach on a very simple model of a hollow sphere which was designed in Rhino3D and exported to STL. Upon establishing the approach, I will talk about my very own pycaster
package which I wrote to wrap the VTK part of the code, simplify the whole process, and provide some additional functionality. Subsequently, I will repeat the ray-casting process with pycaster
on the model of the human skull we extracted and saved as an STL file in the previous post.
Helper-functions
As I keep writing new posts I will try my darndest to build upon previously presented snippets in the interest of code-reuse, consistency, and brevity. I will be utilizing those snippets in the form of ‘helper-functions’, briefly documenting their function and referencing past posts where they were presented in more detail.
The following helper-functions will be used:
vtk_show(renderer, width=400, height=300)
: This function allows me to pass avtkRenderer
object and get an IPython Notebook compatible image output of that render with given dimensions. This code was presented in this past post about VTK integration with an IPython Notebook.addPoint(renderer, p, radius=1.0, color=[0.0, 0.0, 0.0])
: This function allows me to pass the aforementionedvtkRenderer
object, which ‘holds’ the entire scene, and to add a ‘point’ to that scene (prior to its being rendered usingvtk_show
). Upon inspecting the code you will see that we’re in fact rendering a sphere with its center coordinates stored within alist
ortuple
under thep
parameter. The sphere’sradius
defaults to1.0
, while we can also control itscolor
which defaults to the RGB value for black. This code was presented in this past post about VTK integration with an IPython Notebook, where I showed how to render a red sphere.addLine(renderer, p1, p2, color=[0.0, 0.0, 1.0])
: This function is very similar toaddPoint
but instead adds a line withp1
andp2
coordinates using thevtkLineSource
class. Its code is truly similar toaddPoint
so just take a look at this post’s IPython Notebook and this past post to understand the mechanics.loadSTL(filenameSTL)
: This function uses thevtkSTLReader
class to load the contents of an.stl
file underfilenameSTL
and return avtkPolyData
object containing the mesh. While I’ve demonstrated how to write an STL file in the previous post, I haven’t exactly presented this function so here’s its code:
def loadSTL(filenameSTL):
readerSTL = vtk.vtkSTLReader()
readerSTL.SetFileName(filenameSTL)
# 'update' the reader i.e. read the .stl file
readerSTL.Update()
polydata = readerSTL.GetOutput()
# If there are no points in 'vtkPolyData' something went wrong
if polydata.GetNumberOfPoints() == 0:
raise ValueError(
"No point data could be loaded from '" + filenameSTL)
return None
return polydata
Similarly to how one writes an STL file (shown in this previous post), we simply create a new vtkSTLReader
object, pass the filename of the .stl
file through the SetFileName
method, and call Update
to read in that file.
The mesh is then stored internally in a vtkPolyData
object, a pointer to which we retrieve through GetOutput
and store under polydata
which we eventually return. A point of interest in the above code lies in the usage of the GetNumberOfPoints
method of the vtkPolyData
class through which we check if the vtkSTLReader
object managed to read in anything. As I’ve said time and time again, VTK is not big on throwing exceptions or giving warnings. Thus, one should always check that the operation was indeed successful.
Ray-Casting with Python & VTK
In this example I will show the pure Python+VTK code so you can understand the entire process, while the simpler pycaster
version will follow . You can find the corresponding notebook here, while the STL model of the hollow-sphere can be download here.
Loading and rendering the mesh
Initially we load and render the mesh-surface of the hollow sphere using the loadSTL
and vtk_show
helper-functions presented prior:
mesh = loadSTL("sphereHollow.stl")
mapper = vtk.vtkPolyDataMapper()
mapper.SetInput(mesh)
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetOpacity(0.25)
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
renderer.SetBackground(1.0, 1.0, 1.0)
vtk_show(renderer)
If you’re still having trouble getting this code then do read the past post about VTK integration with an IPython Notebook. The only novelty here is the GetProperty
method of the vtkActor
class. This method returns a pointer to this actor’s vtkProperty
object which we can then use to set a whole bunch of visual properties such as the color, visibility of edges, lighting, shading, etc. In this case, we use it to set this actor’s ‘opacity’ through the SetOpacity
method to 25%
so we can see ‘inside’ the surface. Lastly, I want to emphasize that the vtkRenderer
is stored under the renderer
variable to which we’ll keep adding actors as we proceed while mesh
holds a pointer to the vtkPolyData
loaded from the STL file. The above code yields the below figure.
Preparing and rendering the ray
This hollow sphere model is centered around (0,0,0)
, exhibits an outer radius of 25 mm
, and an inner radius of 20 mm
, resulting in a shell thickness of 5 mm
. Therefore, for the purposes of this example, we set the source and target points of the ray to 50 mm
on each side of the the x
axis as such:
pSource = [-50.0, 0.0, 0.0]
pTarget = [50.0, 0.0, 0.0]
Note that there’s nothing special about the above ‘points’. They’re simply two
list
objects with threefloat
coordinates each.
To make the whole thing more visual we use the addPoint
, and addLine
helper-functions to add two actors representing the ray’s points and an actor representing the line/ray to the renderer
:
addPoint(renderer, pSource, color=[1.0, 0.0, 0.0])
addPoint(renderer, pTarget, color=[0.0, 1.0, 0.0])
addLine(renderer, pSource, pTarget)
vtk_show(renderer)
As you can see the ‘source’ point will be rendered as red, while the ‘target’ is green. After adding the three actors, we simply use vtk_show
again and get the following figure.
Testing for intersection
Now here comes the fun part! At this point we have the surface-mesh under the mesh
variable and we’ve configured the ray, defined by the coordinates in pSource
and pTarget
, we want to test for intersection with. The heart of this approach, however, lies in the usage of vtkOBBTree
which generates a oriented bounding-box ‘tree’ for the given geometry (the mesh in our case).
Firstly we need to prepare the OBB tree as follows:
obbTree = vtk.vtkOBBTree()
obbTree.SetDataSet(mesh)
obbTree.BuildLocator()
That’s it! We now have a world-class intersection tester at our disposal. We create a new vtkOBBTree
under obbTree
, set our mesh
as its dataset through SetDataSet
, and call BuildLocator
which will create the OBB tree, and allow for super-fast intersection testing :).
Before we proceed I want you to check the docs for the vtkOBBTree
. The method we’ll be using is IntersectWithLine
which as you can see sports 4 overloaded versions. The signature of the one we’ll be using is the following:
int vtkOBBTree::IntersectWithLine(const double a0[3], const double a1[3], vtkPoints * points, vtkIdList * cellIds)
which provides the following docstring: “Take the passed line segment and intersect it with the data set. This method assumes that the data set is a vtkPolyData that describes a closed surface, and the intersection points that are returned in ‘points’ alternate between entrance points and exit points. The return value of the function is 0 if no intersections were found, –1 if point ‘a0’ lies inside the closed surface, or +1 if point ‘a0’ lies outside the closed surface. Either ‘points’ or ‘cellIds’ can be set to NULL if you don’t want to receive that information.”
As in the case of ray-casting we don’t care about the cells with which the ray will intersect but do want information on the intersection points, we call the aforementioned method as such:
pointsVTKintersection = vtk.vtkPoints()
code = obbTree.IntersectWithLine(pSource, pTarget, pointsVTKintersection, None)
As you can see we create a new vtkPoints
object, as required by the IntersectWithLine
signature, which we call pointsVTKintersection
. We then pass the pSource
and pTarget
coordinates of the ray along with pointsVTKintersection
where the intersection points will be stored. Lastly, we’re using None
for cellIds
which will be interpreted as NULL
as we don’t want that information.
Notice the
code
variable which stores the return value ofIntersectWithLine
? As you saw in this method’s docstring, a particular ‘code’ is returned depending on the result of the intersection test. It’d be a very good idea to always ‘check’ that value and ensure that intersection points were indeed found.
Extracting the intersection point coordinates
At this point we have acquired the intersection points which are stored under pointsVTKintersection
, an object of vtkPoints
type. However, we still need to ‘convert’ those vtkPoints
to something that can be manipulated in Python. This next part of the code is important:
pointsVTKIntersectionData = pointsVTKintersection.GetData()
noPointsVTKIntersection = pointsVTKIntersectionData.GetNumberOfTuples()
pointsIntersection = []
for idx in range(noPointsVTKIntersection):
_tup = pointsVTKIntersectionData.GetTuple3(idx)
pointsIntersection.append(_tup)
As you can see, we first need to ‘extract’ the actual vtkDataArray
from pointsVTKintersection
using the GetData
method, which we then assign to pointsVTKIntersectionData
(lengthy name, I know). We then get the number of intersection points found through pointsVTKIntersectionData.GetNumberOfTuples()
as every point will be stored as a 3-value tuple of the 3D coordinates. We create an empty list
under pointsIntersection
which will store all those tuples. Subsequently, we loop through those tuples stored in pointsVTKIntersectionData
, acquiring each of them through the GetTuple3
method, appending each tuple in the pointsIntersection
list. A simple print
shows us those coordinates:
[(-24.91461181640625, 0.0, 0.0),
(-19.914684295654297, 0.0, 0.0),
(19.914684295654297, 0.0, 0.0),
(24.91461181640625, 0.0, 0.0)]
Finally, using the addPoint
and vtk_show
helper functions we loop through these points and render them (in blue) as such:
for p in pointsIntersection:
addPoint(renderer, p, color=[0.0, 0.0, 1.0])
vtk_show(renderer)
yielding the figure below.
Ray-Casting with pycaster
The pycaster
package
Background
I wrote pycaster
in order to wrap and simplify the VTK functionality you saw above. The pycaster
package is currently being hosted on PyPI under this link, while the repo can be found on BitBucket under this link. If you’re interested, I suggest you take a look at the BitBucket repo link first for instructions.
The pycaster
package really only has a single module, also called pycaster
, and contains a single class called rayCaster
with methods that are simply wrapping the VTK code you saw above. Actually, the VTK code you saw above was pretty much copied from pycaster
.
Installation
If you want to jump straight in then installing pycaster
is as easy as:
pip install pycaster
As expected pycaster
depends on VTK which, if not already installed, might be a hassle to install through pip
. If you run into trouble with the installation the I suggest you read my first post on Anaconda, follow the instructions to create a nice environment, e.g., py27
, and install pycaster
as such:
source activate py27 # use 'activate py27' on Windows
conda install vtk
conda install nose
pip install pycaster --no-deps
In this example I will show how to use pycaster
to repeat the above process but this time I’ll be doing so on the STL model of the human skull we extracted in the previous post about surface-extraction. You can find the corresponding notebook here, while the STL model of the skull can be download here. I’ve also repeated the hollow-sphere example we saw above with pycaster
which you can find in this notebook.
The VTK rendering parts of the code we saw before are still the same so I won’t be repeating them here. Please check the notebook for this example.
Loading and rendering the mesh
The loadSTL
helper-function we used before to… well load the STL, was actually copied from a static method residing under the rayCaster
class with which we initialize a new rayCaster
object. Let’s see how it’s done:
from pycaster import pycaster
caster = pycaster.rayCaster.fromSTL("bones.stl", scale=1)
As you can see we initially import
the pycaster
module from
the pycaster
package. Subsequently, we use the fromSTL
static-method of the rayCaster
class to immediately load the STL file, ensure that it was loaded correctly, and then create a new rayCaster
object under the caster
variable. Note that we can also set a scale
for that mesh which is particularly useful when we want to ‘convert’ the mesh units, e.g., from mm
to m
etc. If scale
is set to anything but the default 1.0
the rayCaster
method scaleMesh
is called during initialization, scales the mesh, and replaces it internally.
If you already have a
vtkPolyData
mesh loaded/created in some other way, you can create arayCaster
object through the default constructor as such:caster = pycaster.rayCaster(mesh)
wheremesh
is avtkPolyData
object. If you then want to ‘scale’ that mesh as was done above, you can use thescaleMesh
method and do so as such:caster.scaleMesh(scale)
.
Using the same VTK code to render the mesh
, which now resides under caster.mesh
, we get the next figure.
You might notice that the skull rendered above displays a much cleaner surface than what we extracted in the ‘Surface Extraction: Creating a mesh from pixel-data using Python and VTK’ post. Well, to be honest I cheated a tad and edited the model through Rhino3D and Geomagic Studio. I did so to place the model around the cartesian origin point, thus eliminating the need to reposition the scene camera, to get rid of all those disjoint meshes, and to clean spikes and holes.
Preparing and rendering the ray
The ‘preparation’ of the ray is exactly the same as in the case of the pure-VTK code. We simply create two list
objects with the coordinates which in this case are:
pSource = [100.0, 100.0, 0.0]
pTarget = [0.0, 0.0, 0.0]
We then use the same VTK code as before to render that ray (prior to the actual intersection) resulting in the following figure.
Testing for intersection and extracting the intersection point coordinates
Now here comes why I bothered writing pycaster
. As you saw in the VTK example before, at this point we would need to create and initialize the vtkOBBTree
, create empty vtkPoints
objects, test for intersection, and then convert the coordinates to tuple
objects. However, with pycaster
the whole process is much simpler.
Using the pSource
and pTarget
coordinates we set before, we test for intersection and retrieve the point coordinates using the castRay
method of the rayCaster
class as such:
pointsIntersection = caster.castRay(pSource, pTarget)
which returns a list
of tuple
under pointsIntersection
. As you can see we saved ourselves a bunch of code and got a clean pythonic object which we can easily print
and get:
[(62.1171, 62.1171, 0.0000), (56.1171, 56.1171, 0.0000)]
Note that the
castRay
method will return an emptylist
if no intersection points were found and give aninfo
message through thelogging
package.
Using the same VTK rendering approach to display the intersection points as last time we get the following figure.
The calcDistanceInSolid
method
I should mention another method within the rayCaster
class which IMHO is very useful. The method is called calcDistanceInSolid
and its called in the same way as castRay
, i.e., by providing the ray coordinates.
What this method does is calculate the distance a given ray ‘travels’ within the closed surface, i.e., the solid. While that sounds simple its actually rather complicated as VTK only provides a list of intersection points without specifying whether they’re entry or exit points. Combined with the fact that the ‘source’ and/or ‘target’ of a ray may already reside within the surface, this calculation becomes rather convoluted.
Calling this method in the case of the skull mesh as caster.calcDistanceInSolid(pSource, pTarget)
gives us a distance of ca. 8.485
which you can verify by calculating the euclidian distance between the two intersection points we saw before.
The
calcDistanceInSolid
method calculates the total distance ‘travelled’ by a ray and will take into account all intersection points found, i.e., multiple entries and exits. In addition, it will account for the the ‘source’ and ‘target’ points of the ray regardless of whether they were within the surface to begin with or not.
Links & Resources
As my posts are becoming ludicrously long, I decided to start re-listing the links to the various material here so you won’t have to go through the whole post to find them:
Material
Here’s the material used in this post:
- Hollow-sphere example with VTK: IPython Notebook and STL file.
- Hollow-sphere example with
pycaster
: IPython Notebook and STL file. - Human-skull example with
pycaster
: IPython Notebook and STL file.
pycaster
Here are the pages where you can find the pycaster
package:
- PyPI page: https://pypi.python.org/pypi/pycaster
- BitBucket repo: https://bitbucket.org/somada141/pycaster
See also
Check these past posts which were used and referenced today:
- Anaconda: The crème de la crème of Python distros
- IPython Notebook & VTK
- Surface Extraction: Creating a mesh from pixel-data using Python and VTK
Don’t forget: all material I’m presenting in this blog can be found under the PyScience BitBucket repository.
Thus concludes another humble post. I hope you enjoyed the whole ray-casting experience as it can be the cornerstone to a lot of super-interesting ray-tracing projects. Off the top of my head you can write code for ray-tracing renderers, ray-tracing physics simulations in optics and acoustics, while ray-casting and ray-tracing is heavily used in game-development (collision detection, rendering, etc).
However, there’s a fair amount of work/code required to get from this example to a ray-tracer as you need to find the mesh-cells where intersection happens, calculate their normal vectors, calculate the reflected/diffracted ray vectors, etc etc. I’m going to show you a lot of this functionality next week in a post dedicated to ray-tracing with VTK.
The material presented here has been tested extensively so you shouldn’t have any trouble reproducing the whole thing. However, if you do then feel free to drop me a comment here and I’ll try to help.
Thanks for reading!
Pingback: From Ray Casting to Ray Tracing with Python and VTK | PyScience
Hi somada141,
Thanks for your post. I am looking at using vtk with python for a new project. I need an octree structure, but I didn’t know about the vtkOBBTree class until I read your post. I am not sure how much experience you have with it, but would you care to comment on:
1. Speed (of generating the obbtree) and of performing the intersection tests? I guess this should also include converting from vtk data structures to python/numpy types.
2. What happens to the tris that are split between two tree branches? Are they split, or is some other method used?
Thanks for pycaster. I will look into using it for my new project.
Cheers,
Mike
LikeLike
Hey Mike,
Thanks for reading! To be honest I haven’t used the obbTrees for anything but intersection tests but I can safely say that the VTK implementation in the vtkOBBTree is the fastest single-thread implementation you’re gonna find that’s readily available for Python (I looked into quite a bit back when I starting delving into it). Needless to say, nothing implemented in pure-Python will get you comparable speeds. I don’t have any benchmarks lying around but both the ‘BuildLocator’ and the tests themselves happen before you can think (I’ve used it with much finer anatomical models than the skull I showed here and thousands of intersections get tested in a blink of an eye).
The only thing faster IMHO would be parallelized implementations, especially on GPUs. You might want to take a look at Cyril Crassil’s PhD Thesis for that sort of thing: http://maverick.inria.fr/Publications/2011/Cra11/.
Re. the implementation of vtkOBBTree all I have to go with is the docs they give in their docs and the paper the implementation was based on. Sorry I can’t be of more help there 🙂
As for pycaster feel free to rape it to your heart’s content. If you create something beautiful out of it I’d love it if you can drop me a line if only too see what you’ve made :D. I’ve been meaning to make a proper ray-tracer for acoustic simulations based on the code I presented in the Ray-Tracing post but haven’t found the time thus far
Cheers 😀
Adam
LikeLike
Oops sorry just saw the part ’bout NumPy. Personally I’d suggest you try to keep the data in VTK structures as much as you can. The conversion is costly and/or messy (cause either you deep-copy or you may well get the NumPy data gc’ed and all hell breaks loose). After all, if you’re dealing with simple meshes like STLs or OBJs, VTK reads those in no time (way faster than VisVis for example)
LikeLike
Pingback: Volume Rendering with Python and VTK | PyScience
Hello, thanks for your very useful article on raytracing and python. I have been using the route implied by your post to do raycasting using vtkIntersectwithLine and the vtkOBBTree datastructure. However I have not been able to work out any way to pass a list/collection/arrays of lines and have had to settle for using for loops. This has become a large problem as I need to fire millions of rays. Can you give me any advice?
LikeLike
Hey Timothy, well I had a look around and I can’t find any means of ‘batch’ intersecting lines. Unfortunately a loop is about all you can do unless of course you’re willing to dive into the C++ source-code and write an overloaded version of the method that takes an array of line coordinates and returns a corresponding array of intersection points. Failing that I fear you’re stuck with loops.
LikeLike
I understand, thank you for taking the time to look into it.
LikeLike
Hi Timothy,
I had a similar issue, but unfortunately could not use vtk for what I was doing. I ended up writing my own Python octree code, which uses Cython / C++ behind the scenes for speed. See https://github.com/mhogg/pyoctree. This code allows you to pass in an array of rays like you want. It also uses OpenMP to allow multiple cores to speed up some of the C++ looping. I tested it for speed against vtkOBBTree with an about 0.5 million rays and it was faster, but haven’t done extensive benchmarking.
There is an example jupyter notebook that shows passing an array of rays into the tree to find the intersections here:
https://github.com/mhogg/pyoctree/blob/master/Examples/pyoctree-shadowcasting.ipynb
Cheers,
Michael
LikeLike
Brilliant stuff Michael!!! PyPI released and everything, kudos 🙂
If you’d like to showcase your library here feel free to write a blog-post and I’ll give you author-access.
LikeLike
Hi Michael, I’m using your PyOctree code and I have a question.
In:
from pyoctree import pyoctree as ot
tree = ot.PyOctree(pointCoords,connectivity)
what is ‘connectivity’? I read that “connectivity is a Nx3 numpy array of integers (dtype=np.int32) representing the point connectivity of each tri element in the mesh” but I can’t understand.
Could you please explain it to me?
Thanks,
Cheers,
Davide Bassano
LikeLike
Hi Timothy
Trying to use your workflow to get intersection points of non-convex *.stl surface with vertical lines:
p1 = [x,y,99999999.]
p2 = [x,y,-99999999.]
However pointsVTKIntersectionData.GetNumberOfTuples() returns 1 even if there must be two intersection points.
It may be due to the surface is non-convex.
I’ve been trying to use vtkCellLocator before, but it seems to find single intersection point by design.
Is there any other way way to work around this problem?
Thanks
Vadim
LikeLike
Hello,
I’m using pycharm. I added pycaster interpreter/package to my Project Interpreter.
I have problem with this line:
caster = pycaster.rayCaster.fromSTL(“sphereHollow.stl”, scale=1)
because I get this error:
AttributeError: module ‘pycaster’ has no attribute ‘rayCaster’
How can I solve it?
Thanks,
Davide Bassano
LikeLike
Hi Davide, did you import the module through `from pycaster import pycaster` or did you just do `import pycaster`? I just tested the former and it works.
LikeLike
Hi,
thanks for your reply.
I used the code found here http://nbviewer.jupyter.org/urls/bitbucket.org/somada141/pyscience/raw/master/20140910_RayCasting/Material/PythonRayCastingSpherePyCaster.ipynb
so, yes, I wrote from pycaster import pycaster.
Do you know how i could solve this?
Thank you,
Best regards,
Davide Bassano
LikeLike
This is really weird, did you install `pycaster` through `pip` as in `pip install pycaster`?
LikeLike
I installed it in Pycharm from File>Settings>Project Interpreter and then I looked for pycaster and “successfully” installed it.
How can I do it “through `pip` as in `pip install pycaster`” as you are saying?
Thanks
LikeLike
That sounds right but honestly its really hard debugging that sort of thing like this. Can you try changing `from pycaster import pycaster` with a simple `import pycaster`?
LikeLike
I tried writing only ‘import pycaster’ instead of ‘from pycaster import pycaster’ but it’s always showing the same error: module pycaster has no attribute rayCaster
LikeLike
what’s the result of `dir(pycaster)` with both this and the previous way of importing?
LikeLike
I think the problem is that I’m using Python 3.x and pycaster works only with Python 2.x.
I’m right?
LikeLike
Hahaha that should be it 🙂
LikeLike
Well, problem solved: I need something else that will work with Python 3.x.
Thanks for your replies
LikeLike
Hello,
I found intersection points between my ray and my stl.
Is there a way to find/calculate normal vector of intersected faces? (without using pycaster package because I’m using Python 3.6)
Thanks,
Cheers,
Davide Bassano
LikeLike
Otherwise, instead of finding normal vectors, would be useful to, at least, knowing which face (face number) has been intersected by my ray.
Is there a way to do it? (always without pycaster).
Thanks,
Cheers,
Davide Bassano
LikeLike
Hi Davide, well it depends on what you’re using to calculate intersections right? What is that?
LikeLike
Hi, thanks for your reply.
I’m using your code:
def loadSTL(filenameSTL): …..
# Loading and rendering the mesh
mesh = loadSTL(“file.stl”)
pSource = [5, 1, 1]
pTarget = [25, 26, 41]
obbTree = vtk.vtkOBBTree()
obbTree.SetDataSet(mesh)
obbTree.BuildLocator()
pointsVTKintersection = vtk.vtkPoints()
code = obbTree.IntersectWithLine(pSource, pTarget, pointsVTKintersection, None)
pointsVTKIntersectionData = pointsVTKintersection.GetData()
noPointsVTKIntersection = pointsVTKIntersectionData.GetNumberOfTuples()
pointsIntersection = []
for idx in range(noPointsVTKIntersection):
_tup = pointsVTKIntersectionData.GetTuple3(idx)
pointsIntersection.append(_tup)
So I found intersection points but now I need to know the number of intersected faces or, better, the normal vectors of intersected faces. Can I do it?
Thanks,
Cheers,
Davide Bassano
LikeLike
Hey Davide, I just wanted to see whether you’re using vtkObbTree or not, you didn’t need to post all your code 😀
Have you seen my next post after this (https://pyscience.wordpress.com/2014/10/05/from-ray-casting-to-ray-tracing-with-python-and-vtk/)? It covers normal-calculation.
LikeLike
Thanks, I’ll check that next post!
Thank you,
Cheers,
Davide Bassano
LikeLike
Pingback: GETTING THE PYSCIENCE RAY CASTER TO WORK – zulfahmed
Hie, can you please tell me how can I handle the cases in which the ray is tangent to the geometry. In such tangential cases, the “IntersectWithLine” function returns incorrect points.
LikeLike
Tangential to a mesh edge or vertex? Honestly I don’t think the vtkOBBTree can handle those edge cases as it can only detect intersections with an actual cell of the mesh. I believe it’s a cell-locator (see https://lorensen.github.io/VTKExamples/site/Cxx/PolyData/RemoveOutsideSurface/). Alternatively, perhaps you could use an actual collision detector (see https://lorensen.github.io/VTKExamples/site/Python/Visualization/CollisionDetection/) if your application can be performed not by intersecting an infinitesimally thick ray but rather a solid with a finite thickness.
LikeLike