标准化0到360之间的方向

问题描述 投票:20回答:8

我正在研究一个简单的旋转程序,它将物体旋转归一化到0到360度之间。我的C#代码似乎正在运行,但我并不完全满意。任何人都可以改进下面的代码,使它更健壮吗?

public void Rotate(int degrees)
    {
        this.orientation += degrees;

        if (this.orientation < 0)
        {
            while (this.orientation < 0)
            {
                this.orientation += 360;
            }
        }
        else if (this.orientation >= 360)
        {
            while (this.orientation >= 360)
            {
                this.orientation -= 360;
            }
        }
    }
c# rotation angle
8个回答
43
投票

使用模运算:

this.orientation += degrees;

this.orientation = this.orientation % 360;

if (this.orientation < 0)
{
    this.orientation += 360;
}

28
投票

这是规范化到任何范围的。用于在[-180,180],[0,180]或[0,360]之间归一化。

(虽然它是用C ++编写的)

//Normalizes any number to an arbitrary range 
//by assuming the range wraps around when going below min or above max 
double normalise( const double value, const double start, const double end ) 
{
  const double width       = end - start   ;   // 
  const double offsetValue = value - start ;   // value relative to 0

  return ( offsetValue - ( floor( offsetValue / width ) * width ) ) + start ;
  // + start to reset back to start of original range
}

对于整数

//Normalizes any number to an arbitrary range 
//by assuming the range wraps around when going below min or above max 
int normalise( const int value, const int start, const int end ) 
{
  const int width       = end - start   ;   // 
  const int offsetValue = value - start ;   // value relative to 0

  return ( offsetValue - ( ( offsetValue / width ) * width ) ) + start ;
  // + start to reset back to start of original range
}

所以基本相同,但没有底线。我个人使用的版本是适用于所有数字类型的通用版本,它还使用重新定义的版本,在整数类型的情况下不执行任何操作。


18
投票

这可以简化为以下内容。

public void Rotate (int degrees) {
    this.orientation = (this.orientation + degrees) % 360;
    if (this.orientation < 0) this.orientation += 360;
}

C#遵循与C和C ++相同的规则,i % 360将为-359359提供任意整数的值,然后第二行是确保它在0到359的范围内(包括0和359)。

如果你想要狡猾,你可以把它降到一行:

    this.orientation = (this.orientation + (degrees % 360) + 360) % 360;

这会在所有情况下保持积极,但这是一个讨厌的黑客,以保存一行代码,所以我不会这样做,但我会解释它。

degrees % 360您将得到-359359之间的数字。添加360将修改1719之间的范围。如果orientation已经是正数,那么添加它将保证它仍然是,并且最终的% 360将通过0将其带回359

至少,您可以简化代码,因为可以组合ifs和whiles。例如,这两行中的条件结果:

if (this.orientation < 0)
while (this.orientation < 0)

总是一样的,所以你不需要周围的if

所以,为此,你可以这样做:

public void Rotate (int degrees) {
    this.orientation += degrees;
    while (this.orientation <   0) this.orientation += 360;
    while (this.orientation > 359) this.orientation -= 360;
}

但我仍然会去模数版,因为它避免了循环。当用户输入360,000,000,000用于轮换时,这将是非常重要的(他们会这样做,相信我),然后发现他们必须在您的代码磨损时提早吃午餐:-)


9
投票

重新定向圆形值的公式,即保持0到359之间的角度是:

angle + Math.ceil( -angle / 360 ) * 360

换角方向的广义公式可以是:

angle + Math.ceil( (-angle+shift) / 360 ) * 360

其中shift的值表示循环移位,例如我希望-179到180的值然后它可以表示为:angle + Math.ceil((-angle-179)/ 360)* 360


8
投票

我在AS3中很快就嘲笑了这个,但是应该可以工作(你可能需要在角度上使用+=

private Number clampAngle(Number angle)
{
    return (angle % 360) + (angle < 0 ? 360 : 0);
}

4
投票

我更喜欢避免循环,条件,任意偏移(3600)和Math.____()调用:

var degrees = -123;
degrees = (degrees % 360 + 360) % 360;
// degrees: 237

0
投票

添加360度的任意倍数,在这些倍数之间可能存在您的输入值(将其置于零以上),然后将剩余的百分比取下,如下所示

angle = 382;
normalized_angle = (angle+3600) %360;
//result = 22

上述情况可以将输入角度降至-3600。您可以添加任意数字(360的倍数),这将使输入值成为正值。

通常在动画期间,您之前的帧/步长值可能已经被上一步标准化,因此您只需添加360就可以了:

normalized_angle = (angle+360) %360;

0
投票

将角度(度)标准化为区间[0,360>时,方便的功能:

float normalize_angle(float angle)
{
    float k = angle;

    while(k < 0.0)
        k += 360.0;
    while(k >= 360.0)
        k -= 360.0;
    return k;
}
© www.soinside.com 2019 - 2024. All rights reserved.