【问题标题】:How to project a point onto a plane in 3D?如何将点投影到 3D 平面上?
【发布时间】:2012-03-07 16:39:16
【问题描述】:

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

我该如何处理?

【问题讨论】:

  • 请参阅“正交投影”部分:en.wikipedia.org/wiki/3D_projection
  • 从下面的答案看来,您要从这个投影中寻找什么结果令人困惑:它是平面上离您感兴趣的点最近的 3D 点吗?它是平面坐标系中的二维点吗?还有什么?
  • 我似乎很清楚,他想在平面上找到最接近 (point_x, point_y, point_z) 的点;即图中标记为 (planar_x, plane_y, plane_z) 的点。 (全局坐标系中的所有坐标。)因此我相信@tmpearce的答案是正确的。

标签: c++ c


【解决方案1】:

1) 从您的orig 点创建一个向量到兴趣点:

v = point-orig (in each dimension);

2) 取该向量与单位法向量n的点积:

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

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

projected_point = point - dist*normal;

用图片编辑: 我稍微修改了你的图片。红色是vv dot normal = 蓝色和绿色的长度(dist 以上)。蓝色是normal*distGreen = blue * -1 :要找到plane_xyz,从point 开始并添加绿色向量。

【讨论】:

  • 错了。想象一下,这个点正好在平面原点的“上方”。那么(1)的结果正好指向法线向量。用法线向量点它会产生非零结果。但这是错误的!漂浮在平面原点“上方”的 3D 点投影到 (0,0)
  • 需要的是叉积,而不是点。但这还不够。请阅读我的回答
  • @valdo 取决于您是想要与平面最近的距离还是垂直点。我将他的帖子解释为想要最近的点。
  • 好吧,如果是这样 - 你是对的。但我以另一种方式解释它。 “投影”一词通常表示在平面上获得2个坐标。不过,让问题作者决定他/她的意思。
  • 您需要合并d 以获得从点到平面的垂直距离,否则您假设平面通过原点。
【解决方案2】:

这真的很简单,你要做的就是找到从点P到平面的垂直距离(这里缩写|_),然后平移 P 返回垂直距离平面法线方向。结果是翻译后的P 坐在飞机上。

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

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

投影点应为 (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:

(0)x + (1)y + (0)z + d = 0

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

d 的一个很好的解释是它谈到了您需要沿其法线平移平面以使平面通过原点的垂直距离

无论如何,一旦我们有了d,我们可以通过以下等式找到any 点到平面的|_ 距离:

|_ 到平面的距离有 3 类可能的结果:

  • 0:完全在平面上(几乎从不会出现浮点不准确问题)
  • +1: >0: 在平面的前面(正常侧)
  • -1:

不管怎样,

您可以通过上图中的检查来验证其是否正确

【讨论】:

  • @bobobobo:你写的“...just add -10...”让我很困惑。你不明确地np + d的结果乘以-1,只是为了写add 而不是 。 :P 我花了一些时间来解释你的答案,所以我会为其他人总结一下。给定一个由法线 n 和标量 d 定义的平面,平面上最靠近给定点 p 的点 p' b> 可以通过以下方式找到: 1) p' = p - (np + d) * n 如果平面是由普通 n 和平面上的一个点定义的 o 您建议使用:2 ) d = -no
【解决方案3】:

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

法线n和点o定义的平面的方法

@tmpearce 在回答中解释了这种方法。

给定一个平面的点法线定义,平面上有法线n和平面上的点o,一个点p',是平面上最靠近给定点 p 的点,可以通过以下方式找到:

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

由普通n和标量d定义的平面的方法

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

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

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

如果你有一个平面的点法线定义(平面由法线n和点o定义飞机)@bobobobo 建议找到 d:

3) d = -no

并将其代入等式 2。得到:

4) p' = p - (np - no) * n

关于差异的说明

仔细看看方程 1 和 4。通过比较它们,你会发现方程 1 使用 n ⋅ (p - o) 其中等式 2 使用 np - no。这实际上是写同一件事的两种方式:

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

因此可以选择将标量 d 解释为好像它是“预计算”。我解释一下:如果一个飞机的no已知,而o只用于计算n ⋅ (p - o), 我们不妨用 nd 定义平面并计算 np + d 相反,因为我们刚刚看到这是同一件事。

另外对于使用d进行编程还有两个好处:

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

【讨论】:

    【解决方案4】:

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

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

    但是,您可能会找到投影点到原点的距离(这显然与旋转无关)。

    从 3d 点减去原点。然后用法线方向做叉积。如果您的法线向量被归一化 - 结果向量的长度等于所需的值。

    编辑

    完整的答案需要一个额外的参数。比如说,您还提供了表示平面上 x 轴的向量。 所以我们有向量 nx。假设它们是标准化的。

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

    那么你的观点是通过以下方式预测的:

    x = (p - O) 点 x

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

    【讨论】:

    • :你是对的,点在平面上方,并且垂直于它。所以,你说做“point-orig”,然后将前一个向量与法线相乘,结果是什么我要吗?
    • 只是为了向未来的读者澄清:n 交叉 x 结果为 y,以防您有 y 代替 n。到 2D 的投影只是归一化轴方向上的点积投影。
    【解决方案5】:

    令 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

    【讨论】:

    • 不完全:在最后一步之前一切都很好,但是你想要点 - d*N
    • 我的第一步是:V = (orig_x,orig_y,orig_z) - (point_x,point_y,point_z)。所以我的基点是“点”而不是原点..所以,我应该添加..
    • d.N 是点积还是叉积?
    【解决方案6】:

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

    (x, n) = c

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

    所以,让 P 成为您的 原点,而 A' 成为新点 A 的投影上飞机。你需要做的是找到 a 使得 A' = A - a*n 满足方程飞机,也就是

    (A - a*n, n) = (P, n强>)

    求解a,你会发现

    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, 而不是 origP,您的代码将保存一个标量产品n),这意味着每次投影的失败次数基本上减少了 25%(以防此例程在您的代码中多次使用)。

    【讨论】:

      【解决方案7】:

      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 则无解。例如,如果 dn 相互垂直,则没有可用的解决方案。

      【讨论】:

        猜你喜欢
        • 2018-06-13
        • 2023-03-08
        • 1970-01-01
        • 2017-10-06
        • 1970-01-01
        • 2017-10-04
        • 1970-01-01
        • 2011-11-25
        • 1970-01-01
        相关资源
        最近更新 更多