检查3D点是否位于给定的3D线上(两个3D点之间)

时间:2018-01-17 07:58:43

标签: c# c++ graphics geometry

我有两个3D点即。 (x1,y1,z1)和(x2,y2,z2)和3D点(x,y,z)。 我想知道(x,y,z)是否位于连接(x1,y1,z1)和(x2,y2,z2)的线上。

我尝试了以下算法:

    if ((((x - x1) / x2-x1) == ((y - y1) / y2-y1)) && (((x - x1) / x2 - x1) 
== ((z - z1) / z2- z1)) --> then,the 3D Line intersects (x,y,z)

但是,如果我的x1 = x2(或)y1 = y2(或)z1 = z2怎么办?然后我会得到一个错误,说“除以零”是不可能的。

如果有人可以提出一些替代方法,我会很高兴。

先谢谢。

5 个答案:

答案 0 :(得分:1)

我会使用point-line distance测量值,如果距离小于接近零的某个误差阈值,则返回true。

详细说明,我们使用的是由p1p2两个点组成的直线。我们想知道p3是否在线。首先,我们使用点到线距离公式找到d

d = ((p0 - p1).cross(p0 - p2)).length() / (p2 - p1).length()

也就是说,假设您可以使用+-crosslength操作。出于性能原因,您可能更愿意找到d平方。

d2 = ((p0 - p1).cross(p0 - p2)).lengthSquared() / (p2 - p1).lengthSquared()

现在,如果dd2正好为零,那么必须在线上。但这是浮点运算,所以我会根据你的应用允许一点余地。所以从本质上讲,d < 1e6或其他东西应该可以解决问题。

答案 1 :(得分:1)

简单的点积可以很容易地做到这一点......所以让我们考虑一下由两点p0,p1定义的上的任何点p将与任何端点具有相同或负斜率,因此

|dot(p1-p0,p-p0)|/(|p1-p0|*|p-p0|) = 1.0

使浮点数比较更加健壮:

|dot(p1-p0,p-p0)|/(|p1-p0|*|p-p0|) >= 1.0-1e-10;

1e-10足够小的epsilon ...重写代码:

dx=x1-x0;
dy=y1-y0;
dz=z1-z0; 

ex=x-x0;
ey=y-y0;
ez=z-z0;

q =dx*ex;
q+=dy*ey;
q+=dz*zy;
q*=q;
q/=(dx*dx+dy*dy+dz*dz);
q/=(ex*ex+ey*ey+ez*ez);

if (q>=1.0-1e-10) point p(x,y) is on the line
 else p(x,y) is not on line

你可以看到不需要sqrt我们可以比较功率......

但是,您应该在p==p0处理边缘情况,然后使用p1或立即返回true。

如果您只想在线段内部(不在边缘点之外),则需要稍微更改代码

0.0 <= dot(p1-p0,p-p0)/|p-p0| <= 1.0

所以:

dx=x1-x0;
dy=y1-y0;
dz=z1-z0; 

ex=x-x0;
ey=y-y0;
ez=z-z0;

q =dx*ex;
q+=dy*ey;
q+=dz*zy;
if (q<0.0) p(x,y) is not on line
q*=q;
q/=(ex*ex+ey*ey+ez*ez);

if (q<=1.0) point p(x,y) is on the line
 else p(x,y) is not on line

顺便说一下,点积的结果给出了一个向量投影到另一个向量的比率或者它们之间的角度的cos(如果它们被标准化),所以对于平行向量,结果是100%长度或{{ 1}}。如果您使用测角仪和1.0调整1e-10值,您可以将其转换为检测直到线的某个垂直距离的点(对于粗线和/或鼠标选择可能会很方便)。

答案 2 :(得分:0)

正如你自己所指出的那样,以强有力的方式做到这一点并非易事。因此,我建议你不要重新发明轮子并使用几何库。我有使用Wild Magic from geometrictools.com的良好经验。

在您的情况下,要使用的谓词是gte::DCPQuery来获取点和线之间的距离,然后测试它是否足够接近零以达到“在线”的目的。

使用示例如下:

Set Primitive Projections.
Record prod {A B} := pair { fst : A ; snd : B }.
Arguments prod : clear implicits.
Arguments pair {A B}.
Add Printing Let prod.
Notation "x * y" := (prod x y) : type_scope.
Notation "( x , y , .. , z )" := (pair .. (pair x y) .. z) : core_scope.
Hint Resolve pair : core.

(编译器触及的代码注释,旨在显示方法,而不是“分号完美”)。

答案 3 :(得分:0)

要解决上述问题,您需要检查三角形区域,将它们视为三维空间中的3个点。要找到该区域,请查看此link。如果area = 0,则给定的点是共线的。

答案 4 :(得分:0)

如果您不关心性能问题,可以使用空间中段的参数方程。

P(t) = P0 + t(P1 - P0) 其中P0和P1为3d点,t为0到1的参数。

这导致了3个方程式

x(t) = x0 + t(x1 - x0)
y(t) = y0 + t(y1 - y0)
z(t) = z0 + t(z1 - z0)

所以要检查你的(x,y,z)点是否在行中,你可以得到t的初始值,例如 t = (x - x0)/(x1-x0) 然后检查是否满足其他两个方程式

t = (x - x0)/(x1-x0)

if ( (y0 + t(y1-y0) == y) and (z0 + t(z1-z0) == z) ) then
 ---> we are in the line

就像@Jay指出的那样,这是浮点数学,你必须处理一些值的容差。例如,为了测试y可以是 y0 + t(y1-y0)-y&lt; 0.001