Intersection between a line and a sphere

前端 未结 8 2209
无人及你
无人及你 2021-02-09 05:51

I\'m trying to find the point of intersection between a sphere and a line but honestly, I don\'t have any idea of how to do so. Could anyone help me on this one ?

相关标签:
8条回答
  • 2021-02-09 06:24

    Express the line as an function of t:

    { x(t) = x0*(1-t) + t*x1
    { y(t) = y0*(1-t) + t*y1
    { z(t) = z0*(1-t) + t*z1
    

    When t = 0, it will be at one end-point (x0,y0,z0). When t = 1, it will be at the other end-point (x1,y1,z1).

    Write a formula for the distance to the center of the sphere (squared) in t (where (xc,yc,zc) is the center of the sphere):

    f(t) = (x(t) - xc)^2 + (y(t) - yc)^2 + (z(t) - zc)^2
    

    Solve for t when f(t) equals R^2 (R being the radius of the sphere):

    (x(t) - xc)^2 + (y(t) - yc)^2 + (z(t) - zc)^2 = R^2
    
    A = (x0-xc)^2 + (y0-yc)^2 + (z0-zc)^2 - R^2
    B = (x1-xc)^2 + (y1-yc)^2 + (z1-zc)^2 - A - C - R^2
    C = (x0-x1)^2 + (y0-y1)^2 + (z0-z1)^2
    

    Solve A + B*t + C*t^2 = 0 for t. This is a normal quadratic equation.

    You can get up to two solutions. Any solution where t lies between 0 and 1 are valid.

    If you got a valid solution for t, plug it in the first equations to get the point of intersection.

    I assumed you meant a line segment (two end-points). If you instead want a full line (infinite length), then you could pick two points along the line (not too close), and use them. Also let t be any real value, not just between 0 and 1.

    Edit: I fixed the formula for B. I was mixing up the signs. Thanks M Katz, for mentioning that it didn't work.

    0 讨论(0)
  • 2021-02-09 06:32

    I believe there is an inaccuracy in the solution by Markus Jarderot. Not sure what the problem is, but I'm pretty sure I translated it faithfully to code, and when I tried to find the intersection of a line segment known to cross into a sphere, I got a negative discriminant (no solutions).

    I found this: http://www.codeproject.com/Articles/19799/Simple-Ray-Tracing-in-C-Part-II-Triangles-Intersec, which gives a similar but slightly different derivation.

    I turned that into the following C# code and it works for me:

        public static Point3D[] FindLineSphereIntersections( Point3D linePoint0, Point3D linePoint1, Point3D circleCenter, double circleRadius )
        {
            // http://www.codeproject.com/Articles/19799/Simple-Ray-Tracing-in-C-Part-II-Triangles-Intersec
    
            double cx = circleCenter.X;
            double cy = circleCenter.Y;
            double cz = circleCenter.Z;
    
            double px = linePoint0.X;
            double py = linePoint0.Y;
            double pz = linePoint0.Z;
    
            double vx = linePoint1.X - px;
            double vy = linePoint1.Y - py;
            double vz = linePoint1.Z - pz;
    
            double A = vx * vx + vy * vy + vz * vz;
            double B = 2.0 * (px * vx + py * vy + pz * vz - vx * cx - vy * cy - vz * cz);
            double C = px * px - 2 * px * cx + cx * cx + py * py - 2 * py * cy + cy * cy +
                       pz * pz - 2 * pz * cz + cz * cz - circleRadius * circleRadius;
    
            // discriminant
            double D = B * B - 4 * A * C;
    
            if ( D < 0 )
            {
                return new Point3D[ 0 ];
            }
    
            double t1 = ( -B - Math.Sqrt ( D ) ) / ( 2.0 * A );
    
            Point3D solution1 = new Point3D( linePoint0.X * ( 1 - t1 ) + t1 * linePoint1.X,
                                             linePoint0.Y * ( 1 - t1 ) + t1 * linePoint1.Y,
                                             linePoint0.Z * ( 1 - t1 ) + t1 * linePoint1.Z );
            if ( D == 0 )
            {
                return new Point3D[] { solution1 };
            }
    
            double t2 = ( -B + Math.Sqrt( D ) ) / ( 2.0 * A );
            Point3D solution2 = new Point3D( linePoint0.X * ( 1 - t2 ) + t2 * linePoint1.X,
                                             linePoint0.Y * ( 1 - t2 ) + t2 * linePoint1.Y,
                                             linePoint0.Z * ( 1 - t2 ) + t2 * linePoint1.Z );
    
            // prefer a solution that's on the line segment itself
    
            if ( Math.Abs( t1 - 0.5 ) < Math.Abs( t2 - 0.5 ) )
            {
                return new Point3D[] { solution1, solution2 };
            }
    
            return new Point3D[] { solution2, solution1 };
        }
    
    0 讨论(0)
  • 2021-02-09 06:32

    I don't have the reputation to comment on Ashavsky's solution, but the check at the end needed a bit more tweaking.

    if (D < 0)
        return new Point3D[0];
    else if ((t1 > 1 || t1 < 0) && (t2 > 1 || t2 < 0))
        return new Point3D[0];
    else if (!(t1 > 1 || t1 < 0) && (t2 > 1 || t2 < 0))
        return new [] { solution1 };
    else if ((t1 > 1 || t1 < 0) && !(t2 > 1 || t2 < 0))
        return new [] { solution2 };
    else if (D == 0)
        return new [] { solution1 };
    else
        return new [] { solution1, solution2 };
    
    0 讨论(0)
  • 2021-02-09 06:33

    Find the solution of the two equations in (x,y,z) describing the line and the sphere.

    There may be 0, 1 or 2 solutions.

    • 0 implies they don't intersect
    • 1 implies the line is a tangent to the sphere
    • 2 implies the line passes through the sphere.
    0 讨论(0)
  • 2021-02-09 06:39

    Here's a more concise formulation using inner products, less than 100 LOCs, and no external links. Also, the question was asked for a line, not a line segment.

    Assume that the sphere is centered at C with radius r. The line is described by P+l*D where D*D=1. P and C are points, D is a vector, l is a number.

    We set PC = P-C, pd = PC*D and s = pd*pd - PC*PC + r*r. If s < 0 there are no solutions, if s == 0 there is just one, otherwise there are two. For the solutions we set l = -pd +- sqrt(s), then plug into P+l*D.

    0 讨论(0)
  • 2021-02-09 06:40

    You may use Wolfram Alpha to solve it in the coordinate system where the sphere is centered.

    In this system, the equations are:

    Sphere:

         x^2 + y^2 + z^2 = r^2  
    

    Straight line:

        x = x0 + Cos[x1] t
        y = y0 + Cos[y1] t
        z = z0 + Cos[z1] t 
    

    Then we ask Wolfram Alpha to solve for t: (Try it!)

    and after that you may change again to your original coordinate system (a simple translation)

    0 讨论(0)
提交回复
热议问题