Search code examples
mathgeometrycomputational-geometrygeometry-surface

Intersection of an infinite cylinder and circle in 3D space


I'm trying to determine if an infinite cylinder and circle intersect in 3D space. This has been asked here: Finding the intersection of the Circle and Infinite Cylinder in 3D space

However, only a mathematician can understand the response by Yves Daoust. There is another response by MBo, which I have coded (below). Unfortunately, testing shows that it doesn't work properly. I'm looking for help with this that a non-mathematician can understand. Thanks in advance!

// cylinderLoc = infinite cylinder location (any location on the cylinder axis)
// cylinderDir = infinite cylinder direction (normalized)
// cylinderRadius = infinite cylinder radius
// circleLoc = circle location (circle center)
// circleDir = circle direction (normalized direction of the circle plane)
// circleRadius = circle radius
bool cylinderIntersectCircle(
    Vector3 cylinderLoc, Vector3 cylinderDir, double cylinderRadius,
    Vector3 circleLoc, Vector3 circleDir, double circleRadius)
{
    // get the perpendicular distance from the circle center to the cylinder axis
    Vector3 diff = Vector3.Subtract(circleLoc, cylinderLoc);
    diff = Vector3.Cross(cylinderDir, diff);
    double distance = diff.Length(); // the length is also called the magnitude

    // get the dot product (cosine) between the cylinder and circle directions
    double dot = Vector3.Dot(cylinderDir, circleDir);

    // determine if the cylinder and circle intersect
    return (distance <= cylinderRadius + circleRadius * Abs(dot));
}

UPDATE: Here is a picture showing what might make is simpler. I need that "sweet spot" where the circle rim is deepest into the footprint that the cylinder has on the circle's plane. The direction from the circle center that takes it closest to the cylinder footprint. Cylinder / circle intersection

UPDATE 2: Here are some sample numbers for MBo to see that demonstrate his algorithm returning false when it should return true. Below it is a picture of the result. I made each object a different color to help. The camera is rotated 180 degrees for a better view (looking at the back). The green frame is "distance". The blue frame is "cylinderRadius + circleRadius * Abs(dot)".

cylinderLoc = ( 0.0, 0.0, 0.0 )
cylinderDir = ( 0.0, 1.0, 0.0 )
cylinderRadius = 0.3

circleLoc = ( -0.25, 0.0, -0.5 )
circleDir = ( -0.6, -0.5, 0.6245 )
circleRadius = 0.45
// get the perpendicular distance from the circle center to the cylinder axis
Vector3 diff = Vector3.Subtract(circleLoc, cylinderLoc);
// ---> diff = ( -0.25, 0.0, -0.5 ) - ( 0.0, 0.0, 0.0 )
// ---> diff = ( -0.25, 0.0, -0.5 )
diff = Vector3.Cross(cylinderDir, diff);
// ---> diff = cross(( 0.0, 1.0, 0.0 ), ( -0.25, 0.0, -0.5 ))
// ---> cross.x = 1.0 * -0.5  -  0.0  * 0.0   = -0.5
// ---> cross.y = 0.0 * -0.25 - -0.5  * 0.0   =  0.0
// ---> cross.z = 0.0 *  0.0  - -0.25 * 1.0   =  0.25
// ---> diff = ( -0.5, 0.0, 0.25 ));
double distance = diff.Length(); // the length is also called the magnitude
// ---> distance = Sqrt(-0.5 * -0.5 + 0.0 * 0.0 + 0.25 * 0.25)
// ---> distance = Sqrt(0.25 + 0.0 + 0.0625)
// ---> distance = Sqrt(0.3125)
// ---> distance = 0.55901699437494742410229341718282 (0.559 is close enough)

// get the dot product (cosine) between the cylinder and circle directions
double dot = Vector3.Dot(cylinderDir, circleDir);
// ---> dot = dot((0.0, 1.0, 0.0), (-0.6, -0.5, 0.6245))
// ---> dot = 0.0 * -0.6 + 1.0 * -0.5 + 0.0 * 0.6245
// ---> dot = -0.5

// determine if the cylinder and circle intersect
return (distance <= cylinderRadius + circleRadius * Abs(dot));
// ---> return (0.559 <= 0.3 + 0.45 * Abs(-0.5));
// ---> return (0.559 <= 0.525);
// ---> This returns false, but the circle does in fact intersect the cylinder.

enter image description here


Solution

  • A picture says a thousand words. This is what I have come up with for now. It's not 100% perfect, but it's pretty close. The magenta dots in the picture can all be calculated, meaning that the yellow lines can be calculated. Simply see if the yellow line intersects the cylinder, which is easy to do.

    • Get the perpendicular direction from the cylinder axis location to the plane of the circle.
    • Cross it with the cylinder axis to get the horizontal crosshair.
    • Cross that with the cylinder axis to get the vertical crosshair.
    • Offset the cylinder axis by its radius along the vertical crosshair in both directions.
    • Intersect both axis (rays) with the plane of the circle for the two end points of the ellipse.
    • We are essentially in 2D now:
    • These two points are on the plane of the circle. Connect them for the long axis of the ellipse.
    • Find the closest point on that line to the circle center. Map it to the circle radius.
    • Take the line from the circle center to the ellipse center. Map it to the circle radius.
    • The center of these two locations is the magenta dot in the picture. Map it to the circle radius.
    • The circle center to this location is the yellow line. Intersect it with the cylinder.

    enter image description here