Math 投影到二维平面以进行重心计算

Math 投影到二维平面以进行重心计算,math,graphics,collision-detection,3d,Math,Graphics,Collision Detection,3d,我有三个顶点组成三维空间中的平面/多边形,v0、v1和v2 为了计算这个平面上一个三维点的重心坐标,我必须首先将平面和点投影到二维空间 在拖网之后,我对如何计算二维空间的重心坐标有了很好的理解,但我一直在寻找将三维点投影到合适的二维平面的最佳方法 有人向我建议,实现这一点的最佳方法是“以最小投影放下轴”。如果不测试在每个世界轴(xy、yz、xz)上投影时形成的多边形的面积,我如何确定哪个投影最好(面积最大),因此最适合计算最精确的重心坐标?我不确定该建议是否真的是最好的。投影到包含三角形的平面并

我有三个顶点组成三维空间中的平面/多边形,v0、v1和v2

为了计算这个平面上一个三维点的重心坐标,我必须首先将平面和点投影到二维空间

在拖网之后,我对如何计算二维空间的重心坐标有了很好的理解,但我一直在寻找将三维点投影到合适的二维平面的最佳方法


有人向我建议,实现这一点的最佳方法是“以最小投影放下轴”。如果不测试在每个世界轴(xy、yz、xz)上投影时形成的多边形的面积,我如何确定哪个投影最好(面积最大),因此最适合计算最精确的重心坐标?

我不确定该建议是否真的是最好的。投影到包含三角形的平面并不太难。我假设p实际上在那个平面上

设d1=sqrt((v1-v0)。(v1-v0))-即距离v0-v1。 同样,设d2=sqrt((v2-v0)。(v2-v0))

v0->(0,0)
v1->(d1,0)

那v2呢?你知道距离v0-v2=d2。你所需要的只是角度v1-v0-v2。(v1-v0)。(v2-v0)=d1 d2 cos(θ)。Wlog您可以将v2视为具有正y

然后对p应用一个类似的过程,但有一个例外:你不一定认为它有正y。相反,您可以通过取(v1-v0)x(v2-v0)的符号来检查它是否具有与v2相同的y符号。(v1-v0)x(p-v0)



作为替代解决方案,您可以在四面体的情况下使用上的线性代数解算器,将四面体v0+(v1-v0)x(v2-v0)作为第四个顶点,并在必要时进行归一化。

您不需要确定最佳区域以找到合适的投影

完全没有必要找到“最好”的投影,只要一个足够好的投影,并且投影到2D时不会退化为直线


编辑-由于退化情况而删除的算法,我没有想到按照OP的要求在3D空间中计算重心坐标的示例。给定:

  • 定义三角形的三维点v0、v1、v2
  • 位于由v0、v1和v2定义的平面上以及由相同点跨越的三角形内的3D点p
“x”表示两个3D向量之间的叉积。
“len”表示三维向量的长度。
“u”、“v”、“w”是分别属于v0、v1和v2的重心坐标

triArea =   len((v1 - v0) x (v2 - v0)) * 0.5
u =       ( len((v1 - p ) x (v2 - p )) * 0.5 ) / triArea
v =       ( len((v0 - p ) x (v2 - p )) * 0.5 ) / triArea
w =       ( len((v0 - p ) x (v1 - p )) * 0.5 ) / triArea

=> p == u * v0 + v * v1 + w * v2
叉积的定义如下:

v0 x v1 := { v0.y * v1.z - v0.z * v1.y,
             v0.z * v1.x - v0.x * v1.z,
             v0.x * v1.y - v0.y * v1.x }
更新:不管怎样,这种方法并不适用于所有情况

我想我已经找到了解决这个问题的有效办法

注:我需要投影到二维空间,而不是使用三维重心坐标,因为我面临着使最有效的算法成为可能的挑战。寻找合适的投影平面所产生的额外开销应仍然小于使用更复杂的操作(如sqrt或sin()cos()函数)时产生的开销(我想我可以使用sin/cos的查找表,但这会增加内存占用,并破坏此赋值的目的)

我的第一次尝试是在多边形的每个轴上找到最小/最大值之间的增量,然后用最小的增量消除该轴。然而,正如@PeterTaylor所建议的,在某些情况下,当投影到2D空间时,删除具有最小三角形的轴可以生成直线而不是三角形这很糟糕

因此,我修改后的解决方案如下……

  • 找到多边形{abs(v1.x-v0.x)、abs(v2.x-v1.x)、abs(v0.x-v2.x)}的每个轴上的每个子增量,这将导致每个轴上有3个标量值
  • 接下来,将这些定标器值相乘以计算分数。重复此操作,计算每个轴的分数。(这样,任何0个三角形都会强制分数为0,自动消除该轴,避免三角形退化)
  • 消除得分最低的轴以形成投影,例如,如果得分最低的轴在x轴上,则投影到y-z平面上

  • 我还没有时间对这种方法进行单元测试,但在初步测试之后,它似乎工作得相当好。我很想知道这是否是最好的方法?

    警告-我所知道的关于使用重心坐标和使用矩阵解线性方程的几乎每一件事都是昨晚学的,因为我发现这个问题非常有趣。因此,以下可能是错误的,错误的,错误的-但我输入的一些测试值似乎确实有效。 小伙子们,姑娘们,如果我把事情搞砸了,请随便把它拆开——但事情还是这样

    在3D空间中寻找重心坐标(在维基百科的帮助下)

    鉴于:

    v0 = (x0, y0, z0)
    v1 = (x1, y1, z1)
    v2 = (x2, y2, z2)
    
    p = (xp, yp, zp)
    
    找到重心坐标: 点p相对于由v0、v1和v2定义的三角形的b0、b1和b2

    知道:

    xp = b0*x0 + b1*x1 + b2*x2
    yp = b0*y0 + b1*y1 + b2*y2
    zp = b0*z0 + b1*z1 + b2*z2
    
    可以写成

    [xp]      [x0]      [x1]      [x2]
    [yp] = b0*[y0] + b1*[y1] + b2*[y2]
    [zp]      [z0]      [z1]      [z2]
    

    重新安排为

                       -1
    [b0]   [x0  x1  x2]     [xp]
    [b1] = [y0  y1  y2]   . [yp]
    [b2]   [z0  z1  z2]     [zp]
    
    3x3矩阵的行列式为:

    det = x0(y1*z2 - y2*z1) + x1(y2*z0 - z2*y0) + x2(y0*z1 - y1*z0)
    
    它的伴随物是

    [y1*z2-y2*z1  x2*z1-x1*z2  x1*y2-x2*y1]
    [y2*z0-y0*z2  x0*z2-x2*z0  x2*y0-x0*y2]
    [y0*z1-y1*z0  x1*z0-x0*z1  x0*y1-x1*y0]
    
    给予:

    [b0]     [y1*z2-y2*z1  x2*z1-x1*z2  x1*y2-x2*y1]   [xp]
    [b1] = ( [y2*z0-y0*z2  x0*z2-x2*z0  x2*y0-x0*y2] . [yp] ) / det
    [b2]     [y0*z1-y1*z0  x1*z0-x0*z1  x0*y1-x1*y0]   [zp]
    
    如果需要测试三角形上的多个点,请停在此处。计算三角形的上述3x3矩阵一次(也除以行列式),然后将结果点积到每个点,得到每个点的重心坐标

    如果每个三角形只做一次,那么这里是上面的乘法(由Maxima提供):

    这是相当多的加法、减法和乘法-三个除法-但没有SQRT或trig函数。这显然比纯2D计算耗时更长,但取决于投影启发法和计算的复杂性,这可能是最快的路线

    正如我提到的——我不知道我在说什么——但也许这会奏效,或者也许其他人可以过来纠正我的错误
    [b0]     [y1*z2-y2*z1  x2*z1-x1*z2  x1*y2-x2*y1]   [xp]
    [b1] = ( [y2*z0-y0*z2  x0*z2-x2*z0  x2*y0-x0*y2] . [yp] ) / det
    [b2]     [y0*z1-y1*z0  x1*z0-x0*z1  x0*y1-x1*y0]   [zp]
    
    b0 = ((x1*y2-x2*y1)*zp+xp*(y1*z2-y2*z1)+yp*(x2*z1-x1*z2)) / det
    b1 = ((x2*y0-x0*y2)*zp+xp*(y2*z0-y0*z2)+yp*(x0*z2-x2*z0)) / det
    b2 = ((x0*y1-x1*y0)*zp+xp*(y0*z1-y1*z0)+yp*(x1*z0-x0*z1)) / det
    
    e1 = v1-v0
    e2 = v2-v0
    
    r = normalise(e1)
    n = normalise(cross(e1,e2))
    u = normalise(n X r)
    
    temp = p-v0
    
    pd.x = dot(temp, r)
    pd.y = dot(temp, u)
    pd.z = dot(temp, n)