Math 直线与球体的交点

Math 直线与球体的交点,math,geometry,intersection,Math,Geometry,Intersection,我试图找到球体和直线之间的交点,但老实说,我不知道怎么做。 有人能帮我吗?找到(x,y,z)中描述直线和球体的两个方程的解 可能有0、1或2种解决方案 0表示它们不相交 1表示直线与球体相切 2表示线穿过球体 将线路表示为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(其中

我试图找到球体和直线之间的交点,但老实说,我不知道怎么做。
有人能帮我吗?

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

可能有0、1或2种解决方案

  • 0表示它们不相交
  • 1表示直线与球体相切
  • 2表示线穿过球体

将线路表示为
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)
等于
R^2
时求解
t
R
是球体的半径):

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

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

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

我想你指的是线段(两个端点)。如果您想要一条完整的直线(无限长),则可以沿直线拾取两个点(不要太近),然后使用它们。也让
t
为任何实数,而不仅仅是0和1之间的值


编辑:我修正了
B
的公式。我把信号弄混了。感谢M Katz提到它不起作用。

您可以使用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 
:(试试看!)


在那之后,你可以再次改变你原来的坐标系(一个简单的翻译)

我相信Markus Jarderot的解决方案是不准确的。我不确定问题出在哪里,但我很确定我把它忠实地翻译成了代码,当我试图找到一条已知穿过球体的线段的交点时,我得到了一个否定的判别式(没有解决方案)

我发现:,它给出了一个相似但略有不同的推导

我将其转换为以下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 };
    }
公共静态Point3D[]FindLineSphereIntersections(Point3D linePoint0、Point3D linePoint1、Point3D circleCenter、双圈)
{
// http://www.codeproject.com/Articles/19799/Simple-Ray-Tracing-in-C-Part-II-Triangles-Intersec
双cx=circleCenter.X;
双cy=圆心.Y;
双cz=圆心.Z;
双px=linePoint0.X;
双py=线点0.Y;
双pz=线点0.Z;
双vx=linePoint1.X-px;
双vy=线点1.Y-py;
双vz=linePoint1.Z-pz;
双A=vx*vx+vy*vy+vz*vz;
双B=2.0*(px*vx+py*vy+pz*vz-vx*cx-vy*cy-vz*cz);
双C=px*px-2*px*cx+cx*cx+py*py-2*py*cy+cy*cy+
pz*pz-2*pz*cz+cz*cz-循环*循环;
//判别式
双D=B*B-4*A*C;
if(D<0)
{
返回新的Point3D[0];
}
双t1=(-B-数学Sqrt(D))/(2.0*A);
Point3D解决方案1=新的Point3D(linePoint0.X*(1-t1)+t1*linePoint1.X,
linePoint0.Y*(1-t1)+t1*linePoint1.Y,
linePoint0.Z*(1-t1)+t1*linePoint1.Z);
如果(D==0)
{
返回新的Point3D[]{solution1};
}
双t2=(-B+数学Sqrt(D))/(2.0*A);
Point3D解决方案2=新的Point3D(linePoint0.X*(1-t2)+t2*linePoint1.X,
linePoint0.Y*(1-t2)+t2*linePoint1.Y,
linePoint0.Z*(1-t2)+t2*linePoint1.Z);
//更喜欢线段本身的解决方案
如果(数学绝对值(t1-0.5)<数学绝对值(t2-0.5))
{
返回新的点3D[]{solution1,solution2};
}
返回新的点3D[]{solution2,solution1};
}

这里有一个更简洁的公式,使用内部产品,少于100个LOC,并且没有外部链接。此外,该问题是针对一条直线而不是线段提出的

假设球体的中心位于
C
,半径
r
。该行由
P+l*D
描述,其中
D*D=1
P
C
是点,
D
是向量,
l
是数字


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

,或者您可以找到两者的公式:
直线:

(x-x0)/a=(y-y0)/b=(z-z0)/c
,这是点之间线段的对称方程。
球体:
(x-xc)^2+(y-yc)^2+(z-zc)^2=R^2

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

然后将y和z插入到球面方程中 然后找到x,然后你就可以找到y和z


如果x给你一个假想的结果,这意味着直线和球体不相交。

没有足够的声誉来评论M Katz的答案,但他的答案假设直线可以在每个方向无限延伸。如果只需要直线段的交点,则可以
    x = x0 + Cos[x1] t
    y = y0 + Cos[y1] t
    z = z0 + Cos[z1] t 
    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 };
    }
        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 };
        }
    }
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 };