【问题标题】:Is there a fast way to calculate the smallest delta between two rotation values?有没有一种快速的方法来计算两个旋转值之间的最小增量?
【发布时间】:2011-01-12 05:29:42
【问题描述】:

有两种观点:

viewAviewB。两者都是旋转的。

旋转的坐标系很奇怪:它从 0 到 179,999999 或 -179,99999 度。所以本质上 179,99999 和 -179,99999 非常接近!

我想计算这些旋转之间的度数或弧度。

例如:

viewA 旋转 20 度

viewB 旋转 30 度

我可以这样做:rotationB - rotationA = 10。

但是这个公式的问题:

viewA 旋转 179 度 viewB 旋转 -179 度

那会出错:rotationB - rotationA = -179 - 179 = -358

358 是完全错误的,因为它们在现实中非常接近。所以我可以做的一件事可能是检查绝对结果值是否大于 180,如果是,则以相反的方式计算它以获得短的真实增量。但我觉得这是完全错误和糟糕的,因为可能存在浮点错误和不精确。因此,如果两个视图基本上以 179,99999999999 度旋转,如果幸运的话,我可能会得到一个奇怪的 180 或 0。

也许有一个天才式的数学公式与 PI、正弦或其他有用的东西来解决这个问题?

【问题讨论】:

    标签: iphone cocoa-touch math uikit rotation


    【解决方案1】:

    编辑:原始答案(使用 Mod)是错误的。在某些情况下会给出 180 - 正确答案(例如角度 30 和 -20 会给出 130 的答案,而不是 50 的正确答案):

    所有场景的两个正确答案:

    如果 A1A2 是两个角度(介于 -179.99999 和 179.99999 之间, Abs 表示取绝对值, 它们之间的角距离,表示为:

    Angle between = 180 - Abs(Abs(A1 - A2) - 180)

    或者,使用 C 风格的三元运算符:

    Angle between = A1 < 180 + A2? A1 - A2: 360 + A1 - A2
    

    【讨论】:

    • 我对 Modulus 的缩写...即除法并仅返回余数...
    • 我建议修改您的答案并删除您原来的不正确部分。我们有答案历史记录,因此我们可以稍后查看。它现在只会分散注意力。
    • @Simucal,谢谢,不知道...认为将原来的错误答案留在那里会减轻对 cme​​ts 的困惑...
    • @Charles Bretana,我明白你在说什么。然而,当我看你的“答案”时,我并不关心它的历史。我只关心它是问题答案的规范,最完美的形式。几个月后,当人们来看这个问题并回答时,有一个简洁明了的答案是有意义的。
    • @openfrog Abs()Min() 一样快,所以实际上这比我的回答要慢一些
    【解决方案2】:

    从您最近提出的问题来看,您可能想阅读unit circle。这是三角学中的一个基本概念,也是使用 CGAffineTransforms 或 CATransform3Ds 进行旋转时计算角度的方式。

    基本上,单位圆从 0 到 360 度,或 0 到 2 * pi(M_PI 是 iPhone 上使用的常数)弧度。任何大于 360 度的角度都等于该角度减去 360 度的倍数。例如,740 度与 380 度相同,这与 20 度相同,当涉及到旋转这么多的物体的结束位置时。

    同样,负度数与将 360 度数添加到负度数相同。 -20 度与 340 度相同。

    这些计算背后没有任何魔法,您只需要注意物体何时穿过圆上的 0 / 360 度点。在您描述的情况下,您可以将 360 添加到任何负值以以正角度表示它们。减去角度时,如果结束角度小于起始角度,则可能还需要在结果中加上 360 度,以说明与单位圆上的零点相交。

    【讨论】:

      【解决方案3】:

      让我们再试一次:
      A和B之间有两个角。其中一个是

      θ1 = A - B

      另一个是

      θ2 = 360 - θ1

      所以只取这两者中的最小值。

      【讨论】:

      • 请注意,如果您允许超出 -180 θ = (A-B) mod 360
      【解决方案4】:

      除了Brad Larson's excellent answer,我还要补充一点,你可以这样做:

      CGFloat adjustAngle(angle) { return fmod(angle + 180.0, 360.0); }
      ...
      CGFloat difference = fmod(adjustAngle(angle1) - adjustAngle(angle2), 360.0);
      

      【讨论】:

        【解决方案5】:

        取差值,加 360,然后按 360 取模。

        【讨论】:

        • @Charles:即使角度是 160 和 -30?
        • 嗯,不,但是您的规则需要处理任何可能的角度,不是吗??例如,使用 50 和 -30,您无需添加任何内容...
        • @Charles:而 360 的 mod 在有意义的地方取消了添加 360。
        • @Ignatio,好吧,我错了,通过任何方式修改都不会总是有效...查看我编辑的答案...
        猜你喜欢
        • 1970-01-01
        • 2021-09-13
        • 1970-01-01
        • 2018-02-13
        • 1970-01-01
        • 2011-09-24
        • 2012-11-10
        • 1970-01-01
        • 2013-05-10
        相关资源
        最近更新 更多