如何将点投影到3D平面上?
我有一个三维点(point_x,point_y,point_z),我想投影到一个三维空间的2D平面,这个平面由一个点坐标(orig_x,orig_y,orig_z)和一个一元垂直vector(normal_dx ,normal_dy,normal_dz)。
我应该如何处理?
1)从你的出发点到兴趣点做一个向量:
v = point-orig (in each dimension);
2)用单位法向量n
取该vector的点积:
dist = vx*nx + vy*ny + vz*nz;
dist =沿着法线的点到面的标量距离
3)用单位法向量乘以距离,从你的点减去该向量。
projected_point = point - dist*normal;
用照片编辑:我修改了一下你的照片。 红色是'v'; 'v'点'正常'=蓝色和绿色的长度(分布在上面)。 蓝色是normal*dist
。 Green = blue * -1
:findplanar_xyz,从point
开始,添加绿色vector。
这非常简单,只需要find从点P
到平面的垂直距离(缩写),然后将 P
平移 回 平面法线方向的垂直距离。 结果是翻译的P
坐在飞机上。
举一个简单的例子(我们可以通过检查来validation):
设n =(0,1,0),P =(10,20,-5)。
投影点应该是(10,10,-5)。 你可以看到,Pproj是从飞机垂直的10个单位,如果它在飞机上,它将有y = 10。
那么我们如何才能find这个分析?
平面方程是Ax + By + Cz + d = 0。 这个方程的意思是“为了使点(x,y,z)在平面内,它必须满足Ax + By + Cz + d = 0” 。
上面绘制的平面的Ax + By + Cz + d = 0方程是什么?
该平面具有正常的n =(0,1,0)。 d可以简单地通过使用已经在飞机上的testing点find:
(0)x + (1)y + (0)z + d = 0
点(0,10,0)在飞机上。 插入上面,我们发现,d = -10。 平面方程是0x + 1y + 0z – 10 = 0(如果你简化,你得到y = 10)。
对d
一个很好的解释是,它说的是垂直距离,你需要将平面沿着它的法线平移以使飞机通过原点 。
无论如何,一旦我们有d
,我们可以通过下面的等式find任何点到飞机的距离:
距飞机有三种可能的结果类别:
- 0:在平面上完全(几乎从不发生浮点不准确问题)
- +1:> 0:平面正面(正常面)
- -1:<0:背后的平面(在正常的反面)
无论如何,
您可以通过上图中的检查来validation其是否正确
仅提供平面原点和法向vector是不够的。 这确实定义了三维平面,但是这并没有定义平面上的坐标系。
认为你可以围绕法向vector旋转你的平面(即将法向量放在原点处并“旋转”)。
然而,你可能会发现投影点到原点的距离(这对旋转显然是不变的)。
从三维点减去原点。 然后用正常的方向做一个交叉产品。 如果你的法向vector被归一化 – 所得的vector长度等于所需的值。
编辑
完整的答案将需要一个额外的参数。 比方说,你也提供了表示飞机上X轴的vector。 所以我们有vectorn和x 。 假设他们正常化。
原点用O表示,你的3D点是p 。
那么你的观点是通过下面的预测:
x =( p – O )点x
y =( p – O )点( n十字)
这个答案是两个现有答案的补充。 我的目的是展示@tmpearce和@bobobobo的解释是如何归结为同一事物的,同时又为那些只想复制最适合他们情况的等式的人提供了快速的答案。
用法线n和点o定义平面的方法
这个方法在@tmpearce的回答中解释了。
给定一个点的正常定义,在平面上有正常的n和o点,可以通过下式find一个点p ',它是最接近给定点p的平面上的点:
1) p '= p – ( n ·( p – o ))* n
用法线n和标量d定义平面的方法
这个方法在@bobobobo的回答中解释了。
给定一个由正常的n和标量d定义的平面,可以通过以下方式find一个点p ',它是最靠近给定点p的平面上的点:
2) p '= p – ( n · p + d )* n
相反,如果你有一个平面的点定义(这个平面是由平面上的法线n和点o定义的)@bobobobobuild议findd :
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
因此,人们可以select将标量d解释为“预先计算”。 我会解释一下:如果一个平面的n和o是已知的,但是o只用来计算n⋅( p – o ),我们也可以用n和d来定义平面,然后计算n⋅p + d ,因为我们刚刚看到,这是一样的事情。
另外对于使用d编程有两个好处:
- 现在发现p是一个更简单的计算,特别是对于计算机。 比较:
- 使用n和o :3次减法+ 3次乘法+ 2次加法
- 使用n和d :0减法+3个乘法+3个加法。
- 使用d限定一个平面的定义只有4个实数(3代表n + 1代表d ),而不是6(3代表n代表o )。 这节省了内存。
令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 + dN
我想你应该稍微改变你描述飞机的方式。 事实上,描述飞机的最好方法是通过vectorn和标量c
( x , n )= c
常数c的(绝对值)是平面离原点的距离 ,等于( P , n ),其中P是平面上的任意点。
所以,让P为你的起点, A '为新点A在飞机上的投影。 你需要做的是find一个这样的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;
注意:如果代替存储c =( P , n )的原点P ,这意味着每个投影基本上减less了25%(如果这个例程在你的代码中被多次使用),你的代码将会保存一个标量积。
设r是投影点, p是投影的结果。 假设c是飞机上的任意点,并且n是飞机的法线(不一定是标准化的)。 写p = r + m d表示一些标量m,如果它们不是解决scheme,将会被认为是不确定的。 由于( p – c )。 因为飞机上的所有点都满足( r – c )的限制,所以n = 0。 n + m( d。n )= 0,所以m = [( c – r )。 n ] / [ d 。 n ]使用点积(。)的地方。 但是,如果d 。 n = 0没有解决scheme。 例如,如果d和n彼此垂直,则没有可用的解决scheme。