在圆上两个角度之间行进的最短方向的算法或公式是什么?

8
给定一个360度圆上的两个角度,我们称它们为源角度(Source)和目标角度(Destination)。
例如,源角度可以是120度,目标角度可以是30度。
是否有一种优雅的解决方案来回答从源角度到目标角度的行进方向是更短的,即顺时针方向(增加角度)还是逆时针方向(减小角度)?
例如,在上面给出的角度中,解决方案将是:逆时针旋转。另一方面,如果源角度为350,目标角度为20,则解决方案将是:顺时针旋转。

旅行是绕着圆的周长走吗? - diagonalbatman
是的。只需要方向,不需要距离。 - Karlth
6个回答

16
if ((dest - source + 360) % 360 < 180)
  // clockwise
else
  // anti-clockwise

顺便提一下,你的惯例 顺时针 == “增加角度” 是与 Trigonometry 101 惯例相反的,而后者是全世界通用的,因此会令人感到困惑(至少对我而言如此)。详见这里


虽然三角函数肯定是标准,但在 CSS 中,正旋转是顺时针,负旋转是逆时针。 - Falieson

3

计算差异,然后将其归一化为+/-180。正数表示沿着角度增加的方向旅行(在您的情况下为顺时针方向)。


2
这个解释真的需要代码。仅有这个解释基本上只是重申了问题。 - 1owk3y
1
这要看情况...我说英语。你会说英语,还是某种非常模糊和不明确的方言?我的观点是,OP实际上正在问你如何“计算差异”-这就是问题所在。通过说“将其归一化为+/-180”,缺乏足够的上下文和解释。术语“归一化”字面上有数百种解释。OP已经知道他需要“最短的方向”-你只是在重申问题。如果您需要一个答案示例,请参考NPE下面的答案。谢谢。 - 1owk3y
实际上公正点说,OP没有提到任何编程语言。整个答案可能更适合发布在数学论坛上... - 1owk3y
1
@1owk3y,OP 询问了一对角度。开发人员通常尝试使用象限分析和多个边缘情况来解决此问题,并使自己陷入困境并不罕见。计算差异并将其夹紧到范围内的想法可能对您来说很明显,但对于 OP 来说很可能并不明显,否则他们在原始问题中就会这样说。 - Marcelo Cantos
我现在明白你的想法了,那可能是公平的。不过,为了记录,这比暗示我不懂英语的回应要好得多。 - 1owk3y
显示剩余3条评论

2

这是我用来输出两个带有正负数的度数之间最短距离的函数,它也适用于超出0-360范围的度数。

function shortestDistDegrees(start, stop) {      
  const modDiff = (stop - start) % 360;
  let shortestDistance = 180 - Math.abs(Math.abs(modDiff) - 180);
  return (modDiff + 360) % 360 < 180 ? shortestDistance *= 1 : shortestDistance *= -1;
}

shortestDistDegrees(50, -20)   // Output: -70
shortestDistDegrees(-30, -370) // Output: 20
shortestDistDegrees(160, -710) // Output: -150

1
这是我在游戏中使用的相机算法:
rotSpeed = 0.25;                      //arbitrary speed of rotation

angleDiff      = 180-abs(abs(source-dest)-180);            //find difference and wrap
angleDiffPlus  = 180-abs(abs((source+rotSpeed)-dest)-180); //calculate effect of adding
angleDiffMinus = 180-abs(abs((source-rotSpeed)-dest)-180); //           ... subtracting

if(angleDiffPlus < angleDiff){        //if adding to ∠source reduces difference
    source += rotSpeed;               //add to ∠source
}else if(angleDiffMinus < angleDiff){ //if SUBTRACTING from ∠source reduces difference
    source -= rotSpeed;               //subtract from ∠source
}else{                                //if difference smaller than rotation speed
    source = dest;                    //set ∠source to ∠destination
}

通过“包裹”角度,我们可以计算差异。然后,我们可以测试当前差异与预测之间的差异,以确定哪个方向实际上会减少差异。

0
NPE的回答很好,但是在取模360之前添加360取决于语言,这样做可能会浪费时间。因此
if ((dest - source) % 360 < 180)
  // clockwise
else
  // anti-clockwise

请注意,Mod函数必须返回绝对值。 例如
dest = 5,source = 10
沃尔夫拉姆阿尔法
-5 modulo 360 = 355

Beckhoff的结构化文本实现

LMOD(-5, 360) = -5
LMOD(-5+360, 360) = 355
MODABS(-5, 360) = 355

-4
这里的通用答案是:“模算术”。你可能想要了解一下这个,它很值得。

规范化是一个更好的描述,因为我们正在处理负数。当处理负数时,取模会变得有点模糊。 - Karlth
“规范化”是一个非常通用的术语,无论您将其规范化为+/- 180并与0进行比较(Marcelo Cantos),还是计算模360的差异并将其与180进行比较(aix),都没有关系。 - thiton
真的,但个人而言,当处理通用数字时,我更喜欢使用“标准化”这个术语。当然,这只是一个偏好问题。 - Karlth
当然。我只是想确保你明白算法背后的基本思想 - 在计算环绕空间时,模算术是关键思想。 - thiton
是的,谢谢。我在我的代码中广泛使用模数算术,但我认为需要一次三角学的复习课程。 :) - Karlth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接