无限圆柱体和 3D 圆的交点 space

Intersection of an infinite cylinder and circle in 3D space

我正在尝试确定无限圆柱体和圆在 3D 空间中是否相交 space。这已被问到这里:

然而,只有数学家才能理解 Yves Daoust 的回答。 MBo 有另一个回复,我已经对其进行了编码(如下)。不幸的是,测试表明它不能正常工作。我正在寻求非数学家可以理解的帮助。提前致谢!

// cylinderLoc = infinite cylinder location (any location on the cylinder axis)
// cylinderDir = infinite cylinder direction (normalized)
// cylinderRadius = infinite cylinder radius
// circleLoc = circle location (circle center)
// circleDir = circle direction (normalized direction of the circle plane)
// circleRadius = circle radius
bool cylinderIntersectCircle(
    Vector3 cylinderLoc, Vector3 cylinderDir, double cylinderRadius,
    Vector3 circleLoc, Vector3 circleDir, double circleRadius)
{
    // get the perpendicular distance from the circle center to the cylinder axis
    Vector3 diff = Vector3.Subtract(circleLoc, cylinderLoc);
    diff = Vector3.Cross(cylinderDir, diff);
    double distance = diff.Length(); // the length is also called the magnitude

    // get the dot product (cosine) between the cylinder and circle directions
    double dot = Vector3.Dot(cylinderDir, circleDir);

    // determine if the cylinder and circle intersect
    return (distance <= cylinderRadius + circleRadius * Abs(dot));
}

更新:这是一张图片,显示可能会更简单。我需要 "sweet spot" 圆圈边缘最深地进入圆柱体在圆平面上的足迹。从圆心开始的方向最接近圆柱足迹。

更新 2:这是 MBo 的一些样本数字,可以看到这些数字证明了他的算法 return 在应该 return 为真时为假。下面是结果的图片。我为每个对象制作了不同的颜色以提供帮助。摄像头旋转 180 度以获得更好的视野(从背面看)。绿框是"distance"。蓝框是"cylinderRadius + circleRadius * Abs(dot)".

cylinderLoc = ( 0.0, 0.0, 0.0 )
cylinderDir = ( 0.0, 1.0, 0.0 )
cylinderRadius = 0.3

circleLoc = ( -0.25, 0.0, -0.5 )
circleDir = ( -0.6, -0.5, 0.6245 )
circleRadius = 0.45
// get the perpendicular distance from the circle center to the cylinder axis
Vector3 diff = Vector3.Subtract(circleLoc, cylinderLoc);
// ---> diff = ( -0.25, 0.0, -0.5 ) - ( 0.0, 0.0, 0.0 )
// ---> diff = ( -0.25, 0.0, -0.5 )
diff = Vector3.Cross(cylinderDir, diff);
// ---> diff = cross(( 0.0, 1.0, 0.0 ), ( -0.25, 0.0, -0.5 ))
// ---> cross.x = 1.0 * -0.5  -  0.0  * 0.0   = -0.5
// ---> cross.y = 0.0 * -0.25 - -0.5  * 0.0   =  0.0
// ---> cross.z = 0.0 *  0.0  - -0.25 * 1.0   =  0.25
// ---> diff = ( -0.5, 0.0, 0.25 ));
double distance = diff.Length(); // the length is also called the magnitude
// ---> distance = Sqrt(-0.5 * -0.5 + 0.0 * 0.0 + 0.25 * 0.25)
// ---> distance = Sqrt(0.25 + 0.0 + 0.0625)
// ---> distance = Sqrt(0.3125)
// ---> distance = 0.55901699437494742410229341718282 (0.559 is close enough)

// get the dot product (cosine) between the cylinder and circle directions
double dot = Vector3.Dot(cylinderDir, circleDir);
// ---> dot = dot((0.0, 1.0, 0.0), (-0.6, -0.5, 0.6245))
// ---> dot = 0.0 * -0.6 + 1.0 * -0.5 + 0.0 * 0.6245
// ---> dot = -0.5

// determine if the cylinder and circle intersect
return (distance <= cylinderRadius + circleRadius * Abs(dot));
// ---> return (0.559 <= 0.3 + 0.45 * Abs(-0.5));
// ---> return (0.559 <= 0.525);
// ---> This returns false, but the circle does in fact intersect the cylinder.

我已经进行了快速测试 - Delphi 中我在引用主题中的回答的文字实现看起来是正确的。

圆柱半径2沿OX,圆心在by=5

对于沿 OX 法线的圆(平行圆柱,代码中注释为 bdx、bdy),圆半径 br = 45 存在交点,br = 2 没有交点。

对于倾斜 45 度的圆法线(代码中的 bdx, bdy = 0.707),圆半径 br = 5 存在交点,br = 2, 4 不存在交点(在最后一种情况下,圆半径的投影变为 ~2.8 < 3).

你能用相同的数据集检查你的函数吗?
你的方向向量真的归一化了吗?

另请注意,此方法仅给出相交事实,对于最近的点,我们应该多做一些工作。

var
  ax, ay, az, bx, by, bz: Double;
  adx, ady, adz, bdx, bdy, bdz, ar, br: Double;
  cdx, cdy, cdz, vpx, vpy, vpz, vplen: Double;
  adot: Double;
begin
  ax := 0;
  ay := 0;
  az := 0;
  bx := 3;
  by := 5;
  bz := 0;
  adx := 1;
  ady := 0;
  adz := 0;
  bdx := 0.7071;
  bdy := 0.7071;
  //bdx := 1
  //bdy := 0;
  bdz := 0;
  ar := 2;
  br := 5; //2,4
  cdx := bx - ax;
  cdy := by - ay;
  cdz := bz - az;
  vpx := ady * cdz - adz * cdy;
  vpy := adz * cdx - adx * cdz;
  vpz := adx * cdy - ady * cdx;
  vplen := sqrt(vpx * vpx + vpy * vpy + vpz * vpz);
  adot := Abs(adx * bdx + ady * bdy + adz * bdz);
  if vplen <= ar + br * adot then
    Caption := 'Intersection'
  else
    Caption := 'No';

一张图说一千个字。这就是我现在想出的。它不是 100% 完美,但已经非常接近了。图中的洋红色点都是可以计算的,也就是说黄线是可以计算的。看黄线是否与圆柱相交,简单易行。

  • 获取圆柱轴位置到圆平面的垂直方向。
  • 将其与圆柱轴交叉以获得水平十字准线。
  • 将其与圆柱轴交叉以获得垂直十字准线。
  • 在两个方向上沿垂直十字准线以其半径偏移圆柱轴。
  • 将两个轴(射线)与椭圆的两个端点的圆平面相交。
  • 我们现在基本上是二维的:
  • 这两点在圆的平面上。将它们连接起来作为椭圆的长轴。
  • 找到该直线上离圆心最近的点。映射到圆半径。
  • 从圆心到椭圆心取直线。映射到圆半径。
  • 这两个位置的中心就是图片中的洋红色点。映射到圆半径。
  • 这个位置的圆心是黄线。将它与圆柱相交。