无限圆柱体和 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 = 4
和 5
存在交点,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% 完美,但已经非常接近了。图中的洋红色点都是可以计算的,也就是说黄线是可以计算的。看黄线是否与圆柱相交,简单易行。
- 获取圆柱轴位置到圆平面的垂直方向。
- 将其与圆柱轴交叉以获得水平十字准线。
- 将其与圆柱轴交叉以获得垂直十字准线。
- 在两个方向上沿垂直十字准线以其半径偏移圆柱轴。
- 将两个轴(射线)与椭圆的两个端点的圆平面相交。
- 我们现在基本上是二维的:
- 这两点在圆的平面上。将它们连接起来作为椭圆的长轴。
- 找到该直线上离圆心最近的点。映射到圆半径。
- 从圆心到椭圆心取直线。映射到圆半径。
- 这两个位置的中心就是图片中的洋红色点。映射到圆半径。
- 这个位置的圆心是黄线。将它与圆柱相交。
我正在尝试确定无限圆柱体和圆在 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 = 4
和 5
存在交点,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% 完美,但已经非常接近了。图中的洋红色点都是可以计算的,也就是说黄线是可以计算的。看黄线是否与圆柱相交,简单易行。
- 获取圆柱轴位置到圆平面的垂直方向。
- 将其与圆柱轴交叉以获得水平十字准线。
- 将其与圆柱轴交叉以获得垂直十字准线。
- 在两个方向上沿垂直十字准线以其半径偏移圆柱轴。
- 将两个轴(射线)与椭圆的两个端点的圆平面相交。
- 我们现在基本上是二维的:
- 这两点在圆的平面上。将它们连接起来作为椭圆的长轴。
- 找到该直线上离圆心最近的点。映射到圆半径。
- 从圆心到椭圆心取直线。映射到圆半径。
- 这两个位置的中心就是图片中的洋红色点。映射到圆半径。
- 这个位置的圆心是黄线。将它与圆柱相交。