有数值稳定的角平分线算法吗?
问题如下:
实际上,我计算它的方式如下:
我的方法的问题是,当夹角接近180°(AB几乎平行于BC)时,平分线非常不准确(当然,因为中点几乎与B重合)。目前的算法是如此不准确,有时得到的平分线几乎平行于其他两个段中的一个。
是的,没有“转换”问题,所有的计算都是用单精度浮点进行的。
发布于 2020-04-19 08:11:19
这可不是小事。假设两个边向量是a和b:
float2 a = A - B;
float2 b = C - B;
float dp = dot( a, b )
float2 a_norm = normalize( a );
float2 b_norm = normalize( b );
dp
是非负值时,return normalize( a_norm + b_norm );
和您就完成了.float2 c = normalize( a_norm - b_norm );
float dir = dot( a, rotate90( b ) );
return ( dir < 0 ) ? rotate90( c ) : rotate270( c );
注意,-
而不是+
,这才是精确取胜的原因。当a
与b
的夹角大于90°时,a
与-b
的夹角小于90°,a_norm - b_norm
的长度足以给出精确的方向。我们只需要把它旋转90度,然后,在正确的方向。
将二维矢量按90°倍数旋转是无损运算。下面是rotate90和rotate270函数的伪代码:
float2 rotate90( float2 vec )
{
return float2( vec.y, -vec.x );
}
float2 rotate270( float2 vec )
{
return float2( -vec.y, vec.x );
}
发布于 2017-04-16 02:23:21
如果你把BA旋转+90°,BC旋转-90°,你可以使用角度平分线保持不变。
所以,如果情况稳定,即BA和BC的点积是正的,就使用原来的公式。
如果为负值,则对BA (x,y) -> (-y,x)
和BC
(x,y) -> (y,-x)
应用旋转,这也会使点乘积变为正。像以前一样处理新的向量。
如果你尝试这一点,你会注意到,在向量之间的角-90°中,现在发生了平分线方向的跳跃。这是不可能避免这种跳转,因为一个连续的平分线将只有在两个回合后(固定BA和移动C)相同。
发布于 2017-04-16 01:36:30
您可以很简单地通过以下方法找到二分法向量:
∥BC∥ * BA + ∥BA∥ * BC
但是,在ABC共线或接近共线的情况下,这在数值上也不会稳定。更好的方法是通过点积找到AB和BC之间的夹角。
cos θ = (BA · BC) / (∥BC∥ * ∥BA∥)
即使在共线情况下也会产生正确的角度。
https://stackoverflow.com/questions/43435055
复制