Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 两条三维线段交点的求法_C#_Math - Fatal编程技术网

C# 两条三维线段交点的求法

C# 两条三维线段交点的求法,c#,math,C#,Math,查找两条二维线段的交点很容易。但是,恐怕找不到两条三维线段的交点 在C#中,最好是找到两条3D线段交点的算法是什么 我找到了一个新的。但我不相信这个解决方案,因为它会优先选择某个平面(看看在“实现”部分下实现perp的方式,它会优先选择z平面。任何通用算法都不能假设任何平面方向或偏好) 有更好的解决办法吗 但是,恐怕找不到两条三维线段的交点 我想是的。可以使用与二维(或任何其他标注)中完全相同的方式找到交点。唯一的区别是,由此产生的线性方程组更可能没有解(这意味着直线不相交) 您可以手工求解一般

查找两条二维线段的交点很容易。但是,恐怕找不到两条三维线段的交点

在C#中,最好是找到两条3D线段交点的算法是什么

我找到了一个新的。但我不相信这个解决方案,因为它会优先选择某个平面(看看在“实现”部分下实现
perp
的方式,它会优先选择
z平面
。任何通用算法都不能假设任何平面方向或偏好)

有更好的解决办法吗

但是,恐怕找不到两条三维线段的交点

我想是的。可以使用与二维(或任何其他标注)中完全相同的方式找到交点。唯一的区别是,由此产生的线性方程组更可能没有解(这意味着直线不相交)

您可以手工求解一般方程,只需使用您的解决方案,或使用编程方式求解,例如…

我找到了一个解决方案:

这个想法是利用向量代数,使用
交叉
来简化问题,直到这个阶段:

a (V1 X V2) = (P2 - P1) X V2
并计算
a


请注意,此实现不需要任何平面或轴作为参考

大多数三维线不相交。一种可靠的方法是在两条三维直线之间找到最短的直线。如果最短直线的长度为零(或距离小于指定的公差),则知道两条原始直线相交

查找方法总结/解释如下:

在下面的内容中,一条线将由其上的两个点定义,a 由点P1和P2定义的线“a”上的点有一个方程式

Pa = P1 + mua (P2 - P1)
类似地,第二条直线“b”上的点由点P4和P4定义 将写为

Pb = P3 + mub (P4 - P3)
mua和mub的值范围从负到正无穷大。 P1 P2和P3 P4之间的线段具有其相应的mu 介于0和1之间

有两种方法可以找到两条直线之间的最短线段 “a”和“b”行

方法一:

第一个是写下行的长度 将两条线连接起来,然后找出最小值。就是, 尽量减少以下情况

|| Pb - Pa ||^2
代入这些线的方程式得到

|| P1 - P3 + mua (P2 - P1) - mub (P4 - P3) ||^2
然后可以在(x,y,z)组件中展开上述内容

至少要满足以下条件,即 关于mua和mub的值必须为零。。。上述功能仅具有以下功能: 一个最小值,没有其他最小值或最大值。这两个方程可以 对于mua和mub,通过 将μ的值代入直线的原始方程

方法二:

另一种方法是,给出完全相同的方程 认识到两条线路之间的最短线段 垂直于这两条线。这让我们可以写两篇文章 点积方程

(Pa - Pb) dot (P2 - P1) = 0
(Pa - Pb) dot (P4 - P3) = 0
根据直线方程展开这些方程

( P1 - P3 + mua (P2 - P1) - mub (P4 - P3) ) dot (P2 - P1) = 0
( P1 - P3 + mua (P2 - P1) - mub (P4 - P3) ) dot (P4 - P3) = 0
用坐标(x,y,z)展开这些。。。 结果如下

d1321 + mua d2121 - mub d4321 = 0
d1343 + mua d4321 - mub d4343 = 0
在哪里

dmnop = (xm - xn)(xo - xp) + (ym - yn)(yo - yp) + (zm - zn)(zo - zp)
注意,dmnop=dopmn

最后,对mua进行求解,得到

mua = ( d1343 d4321 - d1321 d4343 ) / ( d2121 d4343 - d4321 d4321 )
而后面的替换会产生mub

mub = ( d1343 + mua d4321 ) / d4343
该方法是一种优秀的几何资源。站点已经被重新组织,所以向下滚动找到主题。

<代码> //此代码在C++中为我工作在2D和3D中。
// This code in C++ works for me in 2d and 3d

// assume Coord has members x(), y() and z() and supports arithmetic operations
// that is Coord u + Coord v = u.x() + v.x(), u.y() + v.y(), u.z() + v.z()

inline Point
dot(const Coord& u, const Coord& v) 
{
return u.x() * v.x() + u.y() * v.y() + u.z() * v.z();   
}

inline Point
norm2( const Coord& v )
{
return v.x() * v.x() + v.y() * v.y() + v.z() * v.z();
}

inline Point
norm( const Coord& v ) 
{
return sqrt(norm2(v));
}

inline
Coord
cross( const Coord& b, const Coord& c) // cross product
{
return Coord(b.y() * c.z() - c.y() * b.z(), b.z() * c.x() - c.z() * b.x(), b.x() *  c.y() - c.x() * b.y());
}

bool 
intersection(const Line& a, const Line& b, Coord& ip)
// http://mathworld.wolfram.com/Line-LineIntersection.html
// in 3d; will also work in 2d if z components are 0
{
Coord da = a.second - a.first; 
Coord db = b.second - b.first;
    Coord dc = b.first - a.first;

if (dot(dc, cross(da,db)) != 0.0) // lines are not coplanar
    return false;

Point s = dot(cross(dc,db),cross(da,db)) / norm2(cross(da,db));
if (s >= 0.0 && s <= 1.0)
{
    ip = a.first + da * Coord(s,s,s);
    return true;
}

return false;
}
//假设Coord有成员x()、y()和z(),并支持算术运算 //这就是坐标u+coordv=u.x()+v.x(),u.y()+v.y(),u.z()+v.z() 内联点 dot(恒坐标和u、恒坐标和v) { 返回u.x()*v.x()+u.y()*v.y()+u.z()*v.z(); } 内联点 norm2(const Coord&v) { 返回v.x()*v.x()+v.y()*v.y()+v.z()*v.z(); } 内联点 标准(施工协调与验证) { 返回sqrt(norm2(v)); } 内联 坐标 交叉(常数坐标和b,常数坐标和c)//交叉积 { 返回坐标(b.y()*c.z()-c.y()*b.z(),b.z()*c.x()-c.z()*b.x(),b.x()*c.y()-c.x()*b.y()); } 布尔 交叉口(常数线和a、常数线和b、坐标和ip) // http://mathworld.wolfram.com/Line-LineIntersection.html //在3d中;如果z组件为0,也将在二维中工作 { 坐标da=一秒-一秒; 坐标db=b.秒-b.第一; 坐标dc=b.first-a.first; if(dot(dc,cross(da,db))!=0.0)//直线不共面 返回false; 点s=点(交叉点(直流,分贝),交叉点(直流,分贝))/norm2(交叉点(直流,分贝)); 如果(s>=0.0&&s我尝试过,但实际上每次都不起作用,这我可以解释。基于,让我们以这两条线段为例ABCD

var s = Vector3.Dot(Vector3.Cross(dc, db), Vector3.Cross(da, db)) / Norm2(Vector3.Cross(da, db));

var t = Vector3.Dot(Vector3.Cross(dc, da), Vector3.Cross(da, db)) / Norm2(Vector3.Cross(da, db));
A=(2,1,5),B=(1,2,5)和C=(2,1,3)和D=(2,1,2)

当您尝试获取交点时,它可能会告诉您这是点A(不正确)或没有交点(正确)。这取决于您放置这些线段的顺序

x=A+(B-A)s
x=C+(D-C)t

Bill为s求解,但从未求解t。既然您希望交点位于两条线段上,st都必须来自区间。在我的示例中,实际情况是只有s如果来自该区间和tis-2。A位于CD定义的直线上,但不在线段CD

var s = Vector3.Dot(Vector3.Cross(dc, db), Vector3.Cross(da, db)) / Norm2(Vector3.Cross(da, db));

var t = Vector3.Dot(Vector3.Cross(dc, da), Vector3.Cross(da, db)) / Norm2(Vector3.Cross(da, db));
其中da是B-A,db是D-C,dc是C-A,我只是保留了Bill提供的名称

然后就像我说的,你必须检查st是否都来自,你可以计算t
if ((s >= 0 && s <= 1) && (k >= 0 && k <= 1))
{
   Vector3 res = new Vector3(this.A.x + da.x * s, this.A.y + da.y * s, this.A.z + da.z * s);
}