Static Intersection Test Between Cylinder and Sphere

Determining whether a sphere and a cylinder intersects is best done by finding the closest point to the sphere's center within the cylinder.

This point can be located by first taking the closest point to the sphere's center on the cylinder's z axis (that is piercing through the cylinder like the axle a wheel). From this point, an perpendicular line is followed towards the sphere's center, limited to either the distance of the sphere's center or the cylinder's radius, whichever is closer. Finally, cap the new points position on the Z axis back into the cylinder's length and you've got your closest point.

As usual, compare the distance from the sphere's center to the closest point with the radius of the sphere and you know whether the two volumes intersects or whether they don't.

/// <summary>Tests whether a cylinder is touching a sphere</summary>
/// <param name="cylinderOrientation">Orientation matrix for the cylinder</param>
/// <param name="cylinderRadius">The cylinder's radius</param>
/// <param name="cylinderLength">The cylinder's length</param>
/// <param name="sphereCenter">Location of the sphere's center</param>
/// <param name="sphereRadius">The sphere's radius</param>
/// <returns>True if the objects are touching each other</returns>
public static bool CheckContact(
  Matrix33 cylinderOrientation, double cylinderRadius, double cylinderLength,
  Vector3 sphereCenter, double sphereRadius
) {
  double cylinderExtents = cylinderLength / 2.0;
  double cylinderRadius2 = cylinderRadius * cylinderRadius;

  // Determine the sphere's center in the cylinder's relative orientation
  Vector3 localSphereCenter = new Vector3(
    Vector3.DotProduct(sphereCenter, cylinderOrientation.Right),
    Vector3.DotProduct(sphereCenter, cylinderOrientation.Up),
    Vector3.DotProduct(sphereCenter, cylinderOrientation.Into)
  );

  // We'll take the point on the cylinder's Z axis closest to the sphere...
  Vector3 axisPoint = new Vector3(0.0, 0.0, localSphereCenter.Z);

  // ...walk towards the sphere as far as the cylinder's radius permits...
  Vector3 radiusPoint = localSphereCenter - axisPoint;
  if(radiusPoint.SquaredLength > cylinderRadius2)
    radiusPoint = axisPoint + Vector3.Normalize(radiusPoint) * cylinderRadius;
  else
    radiusPoint = axisPoint + radiusPoint;

  // ...and finally clamp this to the cylinder length to obtain the closest point
  Vector3 closestPoint = new Vector3(
    radiusPoint.X,
    radiusPoint.Y,
    UncheckedScalarMath.Instance.Clamp(radiusPoint.Z, -cylinderExtents, +cylinderExtents)
  );

  // If the closest point is within the sphere's radius, we've got a collision
  return (closestPoint - localSphereCenter).SquaredLength < (sphereRadius * sphereRadius);
}