【问题标题】:Rotation - Finding when desired angle is reached旋转 - 寻找达到所需角度的时间
【发布时间】:2012-06-04 22:01:25
【问题描述】:

情况

我一直在思考这个问题有一段时间了。基本上,我有一个角度r (弧度),我想将其更改为所需的角度wr (弧度) em> 在模拟的每个步骤中,以设定的速度dr (弧度/秒)。因此,我需要对于每一步,我都有一个新角度 nr,其中 nr = r + dr * dtdt 是增量时间从上一步开始。

角度在空间 [-pi, pi] 中,增量角度由最短的转弯方式决定。对于每一步,增量角度都被添加到当前旋转中,包裹到 [-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

【问题讨论】:

  • 你能用“角度”这个词代替“旋转”吗?当您使用“旋转”时,听起来您在谈论动词名称,而不是角度。哦,顺便说一句,这很重要,您的相等性检查需要自定义,以便您可以自己设置所需的准确性等。否则你可能永远不会达到停止条件。或者我只是对你想要做什么感到困惑。对不起。
  • 确实如此。现在将它们中的许多更改为角度并保持旋转以进行旋转动作。此外,这正是我想要帮助的。我真的不知道如何检测由于旋转的循环性质而发生的停止条件。边界 -pi/pi 对我来说是令人困惑的。我计算每一步的新角度,并且需要确定我是否已经越过(或达到)所需的角度。对不起,我只是觉得这个很难解释! :)

标签: c# math rotation


【解决方案1】:

你为什么交叉想要的旋转?为什么不将 delta 计算为当前角度和所需角度之间的角度与您要移动的 delta 之间的最小值?这样,最后一步会将您移动到所需的角度。

我还会更改您的代码,以便SetRotation 只存储两个值desiredRotationspeed,然后Update 中的计算可以将所需角度与当前角度进行比较,计算差异,将其限制为速度值 x 秒数,然后移动该量(使用适当的 if 语句表示方向 +ve 或 -ve)。

【讨论】:

  • 是的,我试过了,但我真的不知道如何找到最短的角度。考虑一下:当所需角度为 -2 弧度且当前角度为 PI 弧度时,最短的转弯方式为正,约为 1.14 弧度。我不太确定如何计算我猜的两个角度之间的实际距离。
  • 谢谢!这让我想到了正确的方向!将尽快用我的回答更新这个问题! :)
【解决方案2】:

感谢 Ian Mercer,我知道该怎么做。

与普通号码一样:

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

我只需要一些三角函数来找到角度之间的最小角度。将这两个角度视为从 origo 指向的向量(或者更确切地说是两个向量,它们与 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。感谢人们的帮助,我需要朝着正确的方向前进!

【讨论】:

猜你喜欢
  • 2013-02-13
  • 1970-01-01
  • 2018-06-27
  • 1970-01-01
  • 2013-11-05
  • 1970-01-01
  • 2012-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多