如何在3D平面上投射点?

时间:2012-03-07 16:39:16

标签: c++ c

我有一个3D点(point_x,point_y,point_z),我想把它投影到3D空间的2D平面上,其中(平面)由点坐标(orig_x,orig_y,orig_z)和一元垂直定义vector(normal_dx,normal_dy,normal_dz)。

我该如何处理?enter image description here

7 个答案:

答案 0 :(得分:76)

1)从orig点到感兴趣点制作一个向量:

v = point-orig (in each dimension);

2)使用单位法线向量n

取该向量的点积

dist = vx*nx + vy*ny + vz*nz; dist =沿正常点的点到平面的标量距离

3)将单位法线向量乘以距离,并从该点中减去该向量。

projected_point = point - dist*normal;

用图片编辑: 我已经修改了你的图片了。红色是v; vnormal =蓝色和绿色的长度(dist以上)。蓝色是normal*distGreen = blue * -1:要查找planar_xyz,请从point开始并添加绿色矢量。

enter image description here

答案 1 :(得分:37)

这非常简单,您只需要找到从点|_到平面的垂直(此处为P}),然后 translate {{ 1}} 返回垂直距离在平面法线方向。结果是翻译的P位于平面中。

举一个简单的例子(我们可以通过检查来验证):

设置n =(0,1,0),P =(10,20,-5)。

enter image description here

投影点应为(10,10,-5)。你可以通过检查看到Pproj是垂直于平面的10个单位,如果它在平面上,它将具有y = 10.

那么我们如何从分析中找到它呢?

平面方程是Ax + By + Cz + d = 0。这个等式意味着“为了使点(x,y,z)在平面内,它必须满足Ax + By + Cz + d = 0”

上面绘制的平面的Ax + By + Cz + d = 0等式是什么?

飞机正常n =(0,1,0)。只需使用已在平面中的测试点

即可找到d
P

点(0,10,0)在平面内。在上面插入,我们发现,d = -10。然后平面方程为0x + 1y + 0z - 10 = 0(如果简化,则得y = 10)。

(0)x + (1)y + (0)z + d = 0 的一个很好的解释是它说明了你需要将平面沿着法线平移以使平面穿过原点的垂直距离。

无论如何,一旦我们有d,我们就可以通过以下等式找到任何点到飞机的距离:

enter image description here

| _距离飞机有三种可能的结果类别:

  • 0:完全打开飞机(几乎不会发生浮点不准确问题)
  • +1:> 0:在飞机前方(正常方向)
  • -1:< 0:在飞机后面(ON OPPOSITE SIDE OF NORMAL)

反正

enter image description here

您可以通过上图中的检查验证其正确无法

答案 2 :(得分:10)

仅提供平面原点和法向量是不够的。这确实定义了3d平面,但是这并没有定义平面上的坐标系。

认为您可以围绕法线向量围绕法线向量旋转平面(即将法线向量放在原点并“旋转”)。

然而,您可以找到投影点到原点的距离(显然对旋转不变)。

从3d点减去原点。然后用正常方向做一个十字产品。如果您的法向量被归一化 - 结果向量的长度等于所需的值。

修改

完整的答案需要一个额外的参数。比如说,您还提供了表示飞机上x轴的矢量。 所以我们有矢量 n x 。假设他们已经正常化了。

原点用 O 表示,你的3D点是 p

然后您的观点将通过以下方式进行预测:

x =( p - O )dot x

y =( p - O )点( n 交叉 x

答案 3 :(得分:9)

这个答案是对现有两个答案的补充。 我的目的是展示@tmpearce和@bobobobo的解释是如何归结为同样的事情,同时为那些只想复制最适合他们情况的方程式的人提供快速答案。

由普通 n 和点 o

定义的平面的方法

@tmpearce的答案解释了这种方法。

给定平面 n 并指向 o 的平面的点法线定义,点 p < / strong>',作为最接近给定点 p 的平面上的点,可以通过以下方式找到:

1) p '= p - ( n ⋅( p - o ))* n

由普通 n 和标量 d

定义的平面的方法

@bobobobo在答案中解释了这种方法。

给定由正常 n 和标量 d 定义的平面,点 p ',是最接近给定的平面上的点点 p ,可以通过以下方式找到:

2) p '= p - ( n p + d )* n

如果你有一个点 - 法线的平面定义(平面由普通 n 定义,并指向 o on飞机)@bobobobo建议找到 d

3) d = - n o

并将其插入等式2.这得到:

4) p '= p - ( n p - n o )* n

关于差异的说明

仔细研究等式1和4.通过比较它们,你会发现等式1使用 n ⋅( p - o )等式2使用 n p - n o 。这实际上是写下同样事情的两种方式:

5) n ⋅( p - o )= n p - n o = n p + d

因此可以选择将标量 d 解释为“预先计算”。我将解释:如果已知飞机的 n o ,但 o 仅用于计算 n ⋅( p - o ), 我们也可以通过 n d 定义平面并计算 n p + d < / em>相反,因为我们刚刚看到那是同一件事。

此外,使用 d 进行编程有两个好处:

  1. 现在查找 p '是一个更简单的计算,特别是对于计算机。相比:
    • 使用 n o :3次减法+ 3次乘法+ 2次添加
    • 使用 n d :0次减法+3次乘法+3次加法。
  2. 使用 d 将平面的定义限制为仅4个实数( n 为3 d 为1),而不是6 (3 n + 3 o )。这样可以节省内存。

答案 4 :(得分:1)

设V =(orig_x,orig_y,orig_z) - (point_x,point_y,point_z)

N =(normal_dx,normal_dy,normal_dz)

设d = V.dotproduct(N);

预测点P = V + d.N

答案 5 :(得分:1)

我认为你应该稍微改变你描述飞机的方式。实际上,描述平面的最佳方式是通过向量 n 和标量 c

x n )= c

常数c的(绝对值)是距离原点的平面的距离,等于( P n ),其中 P 是飞机上的任何一点。

所以,让 P 成为你的 orig 点, A '是新点的投影 A 在飞机上。您需要做的是找到 a ,使 A '= A - a * n 满足以下等式:飞机,即

A - a * n n )=( P n

解决一个问题,你找到了

a =( A n ) - ( P n )=( A n ) - c

给出了

A '= A - [( A n ) - c] n < /强>

使用您的姓名,内容为

c = orig_x*normal_dx + orig_y*normal_dy+orig_z*normal_dz;
a = point_x*normal_dx + point_y*normal_dy + point_z*normal_dz - c;
planar_x = point_x - a*normal_dx;
planar_y = point_y - a*normal_dy;
planar_z = point_z - a*normal_dz;

注意:如果代替 orig P ,您的代码将保存一个标量产品c =( P n ),这意味着每次投影基本上减少了25%的翻牌(如果你的代码多次使用这个例程)。

答案 6 :(得分:0)

r 成为投影点, p 是投影的结果。设 c 为平面上的任意点,让 n 为平面的法线(不一定标准化)。对某些标量m写 p = r + m d 如果它们不是解,则会看到它们是不确定的。 由于( p - c )。 n = 0,因为飞机上的所有点都满足此限制( r - c )。 n + m( d n )= 0,因此m = [(<强> c - r )。 n ] / [ d n ]其中的点使用产品(。)。但是如果 d n = 0则没有解决方案。例如,如果 d n 彼此垂直,则没有可用的解决方案。