I\'m looking for an algorithm that determines the near and far intersection points between a line segment and an axis-aligned box.
Here is my method definition:
Here is another highly-efficient and elegant solution.
It's written in C++ but is trivially translatable to Python (per links to this thread from other SO questions) or C# (per original PO). It assumes an access to a 3D vector class/struct, here Vector3f, with basic algebraic operations/operators defined. In C++, something like Eigen::Vector3f can be used; in Python, a simple NumPy array can be used; and in C# the Vector3 can probably be used.
The routine is optimized to check for intersections with multiple grid-aligned boxes.
Definition of the segment class with simple endpoint-based constructor:
class Segment {
public:
Segment(const Vector3f& startPoint, const Vector3f& endPoint) :
origin(startPoint), direction(endPoint - startPoint),
inverseDirection(Vector3f(1.0) / direction),
sign{(inverseDirection.x < 0),(inverseDirection.y < 0),(inverseDirection.z < 0)}
{}
float length(){
return sqrtf(direction.x * direction.x + direction.y * direction.y +
direction.z * direction.z);
}
Vector3f origin, endpoint, direction;
Vector3f inverseDirection;
int sign[3];
};
Actual routine that performs the check:
bool SegmentIntersectsGridAlignedBox3D(Segment segment, Vector3f boxMin, Vector3f boxMax){
float tmin, tmax, tymin, tymax, tzmin, tzmax;
Vector3f bounds[] = {boxMin, boxMax};
tmin = (bounds[segment.sign[0]].x - segment.origin.x) * segment.inverseDirection.x;
tmax = (bounds[1 - segment.sign[0]].x - segment.origin.x) * segment.inverseDirection.x;
tymin = (bounds[segment.sign[1]].y - segment.origin.y) * segment.inverseDirection.y;
tymax = (bounds[1 - segment.sign[1]].y - segment.origin.y) * segment.inverseDirection.y;
if ((tmin > tymax) || (tymin > tmax)){
return false;
}
if (tymin > tmin) {
tmin = tymin;
}
if (tymax < tmax){
tmax = tymax;
}
tzmin = (bounds[segment.sign[2]].z - segment.origin.z) * segment.inverseDirection.z;
tzmax = (bounds[1 - segment.sign[2]].z - segment.origin.z) * segment.inverseDirection.z;
if ((tmin > tzmax) || (tzmin > tmax)){
return false;
}
if (tzmin > tmin){
tmin = tzmin;
}
if (tzmax < tmax){
tmax = tzmax;
}
// this last check is different from the 'ray' case in below references:
// we need to check that the segment is on the span of the line
// that intersects the box
return !(tmax < 0.0f || tmin > 1.0f);
}
Credit for this answer mostly goes to scratchpixel.com and the author of this tutorial, which is based on:
Williams, Amy, Steve Barrus, R. Keith Morley, and Peter Shirley. "An efficient and robust ray-box intersection algorithm." Journal of graphics tools 10, no. 1 (2005): 49-54 link
You can find a very detailed explanation of the code in this tutorial.
All I did was slightly modify the code to address the segment-along-ray rather than ray intersection problem.