2011-05-04 30 views

回答

1

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

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

  • 0意味着它们不相交
  • 1意味着该线的切线球体
  • 2意味着线穿过球体。
2

查找“射线球体相交” - 同一测试用于射线追踪的所有时间,并且有大量在线示例,甚至在stackoverflow上也有quite a few here

13

快速行作为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 

求解tf(t)等于R^2R作为球体的半径):

(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 = 0t。这是一个正常的quadratic equation

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

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

我认为你的意思是一个线段(两个终点)。如果你想要一整行(无限长),那么你可以选择沿线的两个点(不要太靠近),并使用它们。也让t是任意实值,而不仅仅是1.编辑介于0和

我固定公式B。我正在混合的迹象。谢谢M Katz,提到它没有用。

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:(试试吧!)

之后,你可能会再次改变为您的原始坐标系(简单翻译)

7

我相信Markus Jarderot在解决方案中存在不准确的地方。不知道问题出在哪里,但我确信我将它忠实地转化为代码,并且当我试图找到已知交叉成球体的线段的交集时,我得到了否定判别(无解)。

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

我转身到这下面的C#代码和它的工作对我来说:使用内积,小于100条交通线,并没有外部链接

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

[我的回答](http://stackoverflow.com/a/5883559/22364)中'B'的公式是错误的。我现在修好了。 – 2013-07-06 11:54:21

+0

这对我来说非常合适,我也能够快速将其转换为Java。 – 2015-04-22 11:06:16

0

这里有一个更简洁的提法。此外,该问题被要求提供一条线,而不是线段。

假设球体的中心位置为C,半径为r。该行描述为P+l*D,其中D*D=1PC是分,D是一个向量,l是一个数字。

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

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之间的关系。

然后插入y和z到x的球形方程。
然后找到x,然后你可以找到y和z。

如果x给出了一个假想的结果,那就意味着该线和该球体不相交。

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

还有一条评论,我的代码不完整 - 参数化线的定义是0 1 || t2> 1)被更改为(D < 0 || t1 > 1 || t1 < 0 || t2 > 1 || t2 <0)。 – Ashavsky 2015-07-28 14:43:35

+0

感谢您粘贴您的代码。不过我可能会发现一个错误。我正在查看一个线段,该线段开始于一个球体之外并进入一个球体,但交叉点返回null(空数组)。请参阅:http://paste.ofcode.org/aJSjXFpXvvRGf5hYcn8M9Q。我非常感谢对此的评论,谢谢! – 2016-02-23 19:57:15

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 }; 
相关问题