如何找到0到180和-180到0的最近角度

时间:2015-03-06 23:12:27

标签: java algorithm

例如我当前的角度位置是170,我点击对象将其旋转到-170度,这里的问题是在178,179,180之后,下一个数字是-180,-179,-178和等......

即使在数字上170度仍远离-170度,但在视觉上它们看起来很近,一个物体旋转最长的路径才能达到这个数字,例如:

if(currentAngle < targetAngle)
{
   currentAngle += 1;

}

if(currentAngle > targetAngle)
{
  currentAngle -= 1;
}
这样我可以达到目标角度,但是如何在180和-180之间跨越这个障碍,也许有一个公式呢?

更新

    onclick() {
                        double angle = Math.atan2(dy, dx);
                        targetAngle = (int)Math.toDegrees(angle); //180 to //-179
    }

onFrame() {

 //here happens the animation

      if(currentAngle < targetAngle)
      {

          currentAngle +=1;

      }

      if(currentAngle > targetAngle)
      {
          currentAngle -= 1;
      }
}

现在如果我现在处于-179角度,我点击160度角度,它应该向左旋转到达那个角度尽可能快,但在我的情况下,它向右旋转(这是更长的),那是因为它被限制在-180到179之间,因此如何突破极限并从179变为-180,-181,-182 ......如果你明白我的意思

enter image description here

1)我的点击处理程序:

onClick() { 

double angle = Math.atan2(dy, dx);
                    angle = (int)Math.toDegrees(angle);
                    Log.d("test", "angler:" + angle);
                    if(angle < 0)
                    angle += 360;
}

所以在这里我使用角度+ = 360将度数转换为正数,然后:

2)我的onFrame处理程序:

onFrame() {

       if(currentAngle != angle)
        {

            if(angle < currentAngle)
            {
                currentAngle -= 5;
            }
            else
            {
                currentAngle += 5;
            }
          int diff = Math.abs(angle - currentAngle);
            if(diff <= 5)
            {
                currentAngle = angle; // if its near we put it exact to that angle
            }
            invalidate(); //update the view
        }


}

这就是我所拥有的一切

3 个答案:

答案 0 :(得分:3)

正如您在问题中定义currentAngle一样,其值按升序排列:

0,1,2,...,180,-179,-178,...,0

这意味着对你而言,-179大于179,因此算术比较对你不起作用。首先,您必须将这些数字转换为如下所示的范围:

0,1,2,...,180181182,...,359

您可以使用以下公式:

if(angle < 0)
    angle += 360

现在你可以找到两个角度之间的区别(比如说angle1angle2):

abs(angle1 - angle2)

或者如果你想越过0,那么这样做:

360 - abs(angle1 - angle2)

为了给你这两个角度之间的最短距离,你可以采取这样的最小距离:

min(abs(angle1 - angle2), 360 - abs(angle1 - angle2))

答案 1 :(得分:1)

请注意,我假设您的角度介于0到359之间,而不是负面。

这里有两个不同的问题。

  1. 给定currentAngletargetAngle,如何确定旋转方向,这将导致以最短帧数完成旋转?
  2. 我们如何处理角度从359到0/360的边界条件?
  3. 解决方案

    问题1主要在@ ellitron的答案中解决,但你必须将这些部分分开来确定移动currentAngle的方向。问题2需要一个360的mod,它在每次更新currentAngle后处理负数,而this answer为我们提供了一个很好的技巧。

    if (currentAngle - targetAngle == 0) return;
    
    if (Math.abs(currentAngle - targetAngle) < 180) {
        // Rotate current directly towards target.
        if (currentAngle < targetAngle) currentAngle++;
        else currentAngle--;
    } else {
        // Rotate the other direction towards target.
        if (currentAngle < targetAngle) currentAngle--;
        else currentAngle++;
    }
    currentAngle = ((currentAngle % 360) + 360) % 360;
    

    为了将来参考,以下是如何在渲染环境之外测试此代码的方法。我们可以简单地传入两个命令行参数,并从输出中确定我们是否以正确的方式旋转。

    public class Angle {
    public static void main(String[] args) {
        int currentAngle = Integer.parseInt(args[0]);
        int targetAngle = Integer.parseInt(args[1]);
    
        while (currentAngle - targetAngle != 0) {
            if (Math.abs(currentAngle - targetAngle) < 180) {
                // Rotate current directly towards target.
                if (currentAngle < targetAngle) currentAngle++;
                else currentAngle--;
            } else {
                // Rotate the other direction towards target.
                if (currentAngle < targetAngle) currentAngle--;
                else currentAngle++;
            }
            currentAngle = ((currentAngle % 360) + 360) % 360;
            System.out.printf("CurrentAngle = %d, targetAngle = %d\n", 
                currentAngle, targetAngle);
        }
    
    }
    }
    

答案 2 :(得分:0)

我对旋转动画有同样的问题。从1到-1,它会通过长度为358的大弧,但长度为2的小弧。反之亦然。但是想象一下它得到的值是0、100、200、300、0、100、200、300,依此类推...为了使动画平滑,它必须经过0、100、200、300、360、460的值,560、660,..因此,如果仅顺时针旋转,角度将增加。

查看此算法:

class RotAngle
{
    double oldAngle = 0; //old angle modulo 360
    int rot = 0; //this is current spin count (times 360 degrees)

    public double Rotate(double angle)
    {
        double currAngle = ((angle % 360) + 360) % 360;
        //if you enter only positive angles (angle % 360) will do
        //((angle % 360) + 360) % 360 is needed for negative angles

        double diff_2 = 2 * (oldAngle - currAngle); 

        /* mathematically is equal to: old + 360 - current < current - old */
        /* so closer is one rotation less */
        if (diff_2 < -360) rot--;

        /* opposite: 360 + current - old < old - current -> one rotation more is closer */
        if (diff_2 > 360) rot++;

        oldAngle = currAngle;

        return rot * 360 + currAngle;
    }
}