旋转 - 在达到所需角度时查找

时间:2012-05-30 16:15:39

标签: c# math rotation

场合

我已经在这个问题上打了一段时间了。基本上,我有一个角度 r (弧度),我想要改变到所需的角度 wr (弧度)在模拟的每个步骤中以设定的速度 dr (弧度/秒)。因此,我需要为每一步,我有一个新的角度 nr ,其中 nr = r + dr * dt dt 是增量时间自上一步以来。

角度在[-pi,pi]空间中,delta角由最短的转向方式决定。对于每个步骤,将delta角度添加到当前旋转,包裹到[-pi,pi]并存储为新角度。

由于我的步数没有达到无限精度,我显然 - 实际上 - 从未直接达到所需的角度,因此我需要找到所需的旋转时间 - 并且交叉 - 然后停止旋转并将角度设置为所需的角度。在伪代码中:

if rotationSpeed!= 0
     angle = WrapRotation(angle + rotationSpeed * deltaTime)
     if desiredAngle has been reached or crossed
       angle = desiredAngle
       rotationSpeed = 0

问题

在几乎所有情况下,这很容易做到,但当你有一个高或低的角度(接近-pi或pi)并且新角度带你穿过“边界”时,可以说,事情变得复杂。我的所有尝试都未能涵盖当前,先前和所需轮换的所有可能情况。所以我问你是否碰巧知道解决方案?

如果需要,我附上了我的代码(C#):

// Sets the desired rotation and rotation speed in radians/second:
public void SetRotation(float rotation, float speed)
{
        desiredRotation = MathHelper.WrapAngle(rotation);
        if (desiredRotation != this.rotation)
        {
            // Determine the shortest way to turn (indicated by the sign of speed)
            float a = desiredRotation - this.rotation;
            if (a > Math.PI) a -= 2 * (float)Math.PI;
            if (a < -Math.PI) a += 2 * (float)Math.PI;

            desiredRotationSpeed = a < 0 ? -speed : speed;
        }
 }

 // Update is called per each step. Takes in the amount of seconds since the last call.
 public void Update(float seconds)
 {
        /* Other stuff */
        if (desiredRotationSpeed != 0)
        {
            float delta = desiredRotationSpeed * seconds;
            rotation = MathHelper.WrapAngle(rotation + delta);
            if( /* This is the part I'm struggling with. */ )
            {
                desiredRotationSpeed = 0f;
                rotation = desiredRotation;
            }
        }
        /* Other stuff */
 }

在正常情况下(非循环行为),以下工作:

if (Math.Abs(value - desiredValue) < Math.Abs(deltaValue))
    /* Desired has been reached. Do stuff! */

所以澄清一下。我想找到所需的角度被击中(并且由于精度而超过),这样我就可以将当前角度设置为所需的角度,然后停止旋转。

非常感谢你的帮助!我觉得这真的有一个简单的解决方案! :3

2 个答案:

答案 0 :(得分:2)

为什么交叉所需的轮换?为什么不将delta计算为当前角度和所需角度之间的角度的最小值以及您想要移动的delta?这样,最后一步就会让你达到所需的角度。

我还会更改您的代码,以便SetRotation除了存储desiredRotationspeed两个值之外什么都不做,然后Update中的计算可以将所需的角度与当前角度,计算差值,将速度值x限制为秒数,然后移动该数量(使用适当的方向+ ve或-ve的if语句)。

答案 1 :(得分:0)

感谢Ian Mercer,我想出了该怎么做。

与普通号码一样:

if (Math.Abs(value - desiredValue) < Math.Abs(deltaValue)) 
    /* Desired has been reached. Do stuff! */ 

我只需要一些三角法来找到角度之间的最小角度。将两个角度看作从向量指向的向量(或者更确切地说是两个向量,它们之间的角度和x轴),最小的角度很容易找到。请考虑以下事项:

Math.Atan2(Math.Sin(toAngle - fromAngle), Math.Cos(toAngle - fromAngle))

这会给我最小的角度。找出何时停止旋转只是看看旋转距离是否大于两个角度之间的最小距离/角度。

对上面的代码进行以下更改将解决问题:

  double distance = Math.Atan2(Math.Sin(desiredRotation - rotation),
       Math.Cos(desiredRotation - rotation));
  if(Math.Abs(distance) < Math.Abs(delta))
  {
       desiredRotationSpeed = 0f;
       rotation = desiredRotation;
  }

我希望我已经为这个问题咨询过亲爱的George Pólya。感谢大家的帮助,我需要朝着正确的方向努力!