curve intersection with volume in animation nodes

How can we detect the intersection of a spline with a volume? I've been trying to create edges from the splines to detect the crossing between lines and planes but I'm not sure if thats the correct approach.

What I am trying to accomplish is to detect where a curve enters and exits a volume, any ideas?

EDIT

I'm trying to reproduce the solution but I found that my evaluation spline node doesn't look like yours, it actually has the parameters from "Get spline samples" node, but also differs in its outputs. Checked hidden parameters but all is unhidden.

EDIT

seems "get spline samples" does the job fine. Might be a custom naming issue

EDIT 2

After downloading @Omar Ahmad blend file I noticed that this method is far more efficient but still produces inconsistent results. When a play with the spline points moving them around and increasing all evaluate and get sample nodes to resolution up to 5000 the problem persists. I'm sorry if I'm being too strict with this detail (which could be due to a resolution factor) but is very important for me this works as foreseeable as posible. Here the screenshot showing the problem:

• Try to reduce the Jump Width, i.e. the value added to the parameter after one intersection. – binweg Oct 7 '18 at 12:25

Spline Marching

Theory

Spline marching is a technique in which you move along the spline in discrete steps until you intersect a polygon. One determines—or guesstimate—if one hit a polygon if the distance between the current position and the nearest surface point is less than some small value epsilon. In which case, one can raycast along the tangent at the current spline point or project on the surface of the mesh to get a rather accurate intersection, this argument is supported by the fact that for some small step size, the spline becomes almost linear, that is, straight. However, the final raycast or projection may not be needed as we might see.

Marching using a constant step size is not very efficient, to understand why, consider the situation where the step size is 0.1 unit and the start of the spline is 10 units away from the mesh, then to intersect the mesh, one would need at least 100 steps. A better approach would be to make the step size variable, that is, large in size when you know the mesh is far away and small in size when you know the mesh is near because a large step size near the mesh might pass it without reporting any intersection. So in conclusion, we need the largest step size that is guaranteed not to make the point pass the mesh. The euclidean distance between the current spline point and the nearest surface point is the length of the shortest path, meaning that this distance if used as the step size is guaranteed not to make the point pass the mesh.

Implementation

We construct a loop with an initially zero float input that represents the initial parameter of the spline point, the loop also takes the length of the spline, a BVH tree representing the mesh, the spline itself and a small float input epsilon. In the loop, we evaluate the spline at the parameter and find the distance between the spline point and the nearest surface point on the mesh, this distance is then normalized by divided it by the spline length to remap it to the parameter range [0,1]. The normalized distance is added to the input parameter and the result is assigned to the initial parameter input. What we just did is effectively moving the spline point along the spline based on the distance to the nearest surface point by incrementing its parameter. Finally, we check if the distance is larger than epsilon and break the loop otherwise. The output shall be the input initial parameter which is, when the loop break, the parameter of the spline point whose computed distance is less than epsilon, on other words, the parameter of the point we consider an intersection.

Basically we keep increasing the parameter until we find an intersection. The number of iterations in this case act as the number of steps after which the loops gives up on finding intersections. To try the loop, we set the initial parameter to zero, epsilon to 0.001 and compute the parameter of the intersection, we then evaluate the spline at the computed parameter to get:

Which is the intersection we expected. If we increased the initial parameter to 0.5, that is, the marching should start from the middle of the spline, we get:

Which is the intersection we expected. If we increase the initial parameter further to 0.75, the loop will execute to the maximum iteration because there are no intersection from this point onward, to avoid this, we are going to implement another condition to check if the end of the spline was reached and break the loop then.

Now the loop is working perfectly. Next step is to implement a loop that generates all intersections automatically. This loop is simple and very similar to the one we create before, we basically find an intersection using the march loop, append it, add a small value jump width to the initial parameter and reassign it. The loop breaks if the parameter became more than 1.

Which gives us exactly what we want.

This method is better because it is significantly faster in most cases (the example intersections described above only needed about 4 BVH surface projection), it is consistent so results are exactly as you expect it and it is controllable.

Note:

It is essential that the Evaluate Spline and Get Spline Length nodes to have high resolutions in the Advanced Node Settings this ensures our calculations are accurate as possible.

Blend File:

• @JuanManuelLynch binweg is right, the Jump Width should be reduced in this case. Did that solve the problem? – Omar Emara Oct 7 '18 at 12:37

Naively intersecting lines with planes could be problematic as the Intersect Line Plane node, or the Python function behind it, considers the plane to be infinite. Therefore, as a second step, you would have to check if the intersection really is on the polygon.

I suggest using the BVHTree > Ray Cast node instead.

With the Evaluate Spline node (for Aimation Nodes v2.1; Get Spline Samples for AN v2.0) and two different slices of the node's Locations list – vectors[:-1] and vectors[1:] – I create small line segments along the spline.

start vector and end vector of these segments (as iterators) as well as the BVH Tree of the object (as parameter) are fed into a loop. Within this loop I call Ray Cast with a maximum distance of the segments' lengths and a minimum distance of zero. (The minimum distance by default is 0.001 or something which might result in some missed intersections.)

With the Condition input of the loop's Vector List output I collect all location vectors of ray casts that resulted in a hit.

The Ray Cast node also has a Normal output that lets you align objects on the face where there is an intersection – e.g. by using the Direction to Rotation node. If you also want to distinguish entries into and exits from the volume then you can calculate the angles between the normal and the segment and check if it's smaller or larger than 90°.

• Good solution. It is worth noting that the Hit boolean can be used directly as the condition of appending. The Vector List Generator has a hidden condition input. This will be more speed and memory efficient. – Omar Emara Oct 2 '18 at 15:36
• Done, indeed nice solution – Juan Manuel Lynch Oct 2 '18 at 17:05
• @OmarAhmad Thank you for the reminder. Apart from the mentioned reasons for using the condition it looks definitely more clean now. – binweg Oct 2 '18 at 19:01
• @JuanManuelLynch Sorry for the confusion. I was using Animation Nodes version 2.1 and in this version Evaluate Spline has been merged with Get Spline Samples. – binweg Oct 2 '18 at 19:05