线与球体之间的交点

时间:2011-05-04 12:13:51

标签: math geometry intersection

我正试图找到一个球体和一条线之间的交点,但老实说,我不知道该怎么做。 有人可以帮我这个吗?

9 个答案:

答案 0 :(得分:14)

将该行表示为t

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

t = 0时,它将位于一个终点(x0,y0,z0)。当t = 1时,它将位于另一个终点(x1,y1,z1)

t(xc,yc,zc)是球体的中心)中写出距球体中心的距离公式(平方):

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

t等于f(t)R^2是球体的半径)时,求解R

(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

A + B*t + C*t^2 = 0解决t。这是正常的quadratic equation

您最多可以获得两种解决方案。 t介于0和1之间的任何解决方案都是有效的。

如果您获得了t的有效解决方案,请将其插入第一个方程式以获得交叉点。

我认为你的意思是一个线段(两个端点)。如果你想要一个完整的线(无限长度),那么你可以沿着线选择两个点(不是太近),并使用它们。同时让t为任何实际值,而不仅仅是0到1之间。

修改:我修改了B的公式。我正在混淆迹象。谢谢M Katz提到它不起作用。

答案 1 :(得分:7)

我相信Markus Jarderot解决方案存在不准确之处。不确定问题是什么,但我很确定我忠实地将它翻译成代码,当我试图找到已知交叉到球体的线段的交集时,我得到了否定的判别(没有解决方案)。 / p>

我发现了这个:http://www.codeproject.com/Articles/19799/Simple-Ray-Tracing-in-C-Part-II-Triangles-Intersec,它提供了类似但略有不同的推导。

我将其转换为以下C#代码,它适用于我:

    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 };
    }

答案 2 :(得分:4)

没有足够的声誉来评论M Katz的回答,但他的回答是假设该线可以在每个方向无限地继续。如果只需要SEGMENT的交叉点,则需要t1和t2小于1(基于参数化方程的定义)。请在下面的C#中查看我的答案:

        public static Point3D[] FindLineSphereIntersections(Point3D linePoint0, Point3D linePoint1, Point3D circleCenter, double circleRadius)
    {

        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;

        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);

        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);

        if (D < 0 || t1 > 1 || t2 >1)
        {
            return new Point3D[0];
        }
        else if (D == 0)
        {
            return new [] { solution1 };
        }
        else
        {
            return new [] { solution1, solution2 };
        }
    }

答案 3 :(得分:2)

查找“光线球体交叉点” - 在光线跟踪中一直使用相同的测试,并且在线有大量示例,甚至在堆栈溢出时也是quite a few here

答案 4 :(得分:2)

您可以使用Wolfram Alpha在球体居中的坐标系中求解它。

在这个系统中,方程是:

球体:

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

直线:

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

Then we ask Wolfram Alpha to solve for t :(试试吧!)

然后您可以再次更改为原始坐标系(简单翻译)

答案 5 :(得分:1)

在(x,y,z)中找到描述直线和球体的两个方程的解。

可能有0,1或2个解决方案。

  • 0表示它们不相交
  • 1表示该线是球体的切线
  • 2表示线穿过球体。

答案 6 :(得分:0)

这里使用内部产品,少于100个LOC,没有外部链接,这是一个更简洁的表述。此外,还询问了一条线,而不是线段。

假设球体以C为中心,半径为r。该行由P+l*D D*D=1描述。 PC是积分,D是向量,l是数字。

我们设置了PC = P-Cpd = PC*Ds = pd*pd - PC*PC + r*r。如果s < 0没有解决方案,如果s == 0只有一个,否则有两个。对于我们设置l = -pd +- sqrt(s)的解决方案,然后插入P+l*D

答案 7 :(得分:0)

或者你可以找到两者的公式:
line:(x-x0)/a=(y-y0)/b=(z-z0)/c,它们是您可以找到的点之间的线段的对称方程 球体:(x-xc)^2+(y-yc)^2+(z-zc)^2 = R^2

使用对称方程找到x和y以及x和z之间的关系。

然后用x表示y和z到球体的等式中 然后找到x,然后你就可以找到y和z。

如果x给出了一个虚构的结果,这意味着线和球体不相交。

答案 8 :(得分:0)

我没有对Ashavsky的解决方案发表评论的声誉,但最后的检查需要更多调整。

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 };