数值稳定角平分线算法

Gam*_*per 5 c++ math

有没有数值稳定的角平分线算法?

\n\n

问题如下:

\n\n
    \n
  • 给定三个向量(二维)A,B,C
  • \n
  • 求角 B 的平分线(AB 和 BC 之间的角)
  • \n
\n\n

实际上我是按以下方式计算的:

\n\n
    \n
  • 标准化AB
  • \n
  • 标准化BC
  • \n
  • 查找 (AB+CD)/2f(中点)
  • \n
  • 平分线是 B 和中点之间的线。
  • \n
\n\n

我的方法的问题是,当角度几乎为 180\xc2\xb0(AB 几乎平行于 BC)时,平分线非常不准确(当然是因为中点几乎与 B 重合)。当前的算法非常不准确,有时生成的平分线几乎与其他两条线段之一平行。

\n\n

是的,不存在“转换”问题,所有计算都是以单精度浮点完成的。

\n

Soo*_*nts 3

它\xe2\x80\x99并不是微不足道的。让\xe2\x80\x99s 表示两个边缘向量是a 和b:

\n\n
float2 a = A - B;\nfloat2 b = C - B;\n
Run Code Online (Sandbox Code Playgroud)\n\n
    \n
  1. 计算点积float dp = dot( a, b )

  2. \n
  3. 标准化两个向量:

  4. \n
\n\n
float2 a_norm = normalize( a );\nfloat2 b_norm = normalize( b );\n
Run Code Online (Sandbox Code Playgroud)\n\n
    \n
  1. 检查点积的符号位。当dp为非负数时,\nreturn normalize( a_norm + b_norm );则\xe2\x80\x99 就完成了。

  2. \n
  3. 当点积为负时,输入向量之间存在钝角。\n在这种情况下应用 na\xc3\xafve 公式会降低数值精度。\n需要另一种方法。

  4. \n
\n\n
float2 c = normalize( a_norm - b_norm );\nfloat dir = dot( a, rotate90( b ) );\nreturn ( dir < 0 ) ? rotate90( c ) : rotate270( c );\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,-而不是+,这才是精度获胜的原因。a当和之间的角度b大于 90\xc2\xb0 时,a和之间的角度-b小于 90\xc2\xb0,且 的长度a_norm - b_norm足以给出准确的方向。之后我们只需将其沿正确的方向旋转 90\xc2\xb0 即可。

\n\n

PS 将 2D 向量旋转 90\xc2\xb0 的倍数是无损操作。\n这里\xe2\x80\x99s 为rotate90 和rotate270 函数的伪代码:

\n\n
float2 rotate90( float2 vec )\n{\n    return float2( vec.y, -vec.x );\n}\nfloat2 rotate270( float2 vec )\n{\n    return float2( -vec.y, vec.x );\n}\n
Run Code Online (Sandbox Code Playgroud)\n