C# 在 0 到 360 之间标准化方向

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1628386/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 19:31:34  来源:igfitidea点击:

Normalise orientation between 0 and 360

c#rotationangle

提问by JuniorDeveloper

I'm working on a simple rotate routine which normalizes an objects rotation between 0 and 360 degrees. My C# code seems to be working but I'm not entirely happy with it. Can anyone improve on the code below making it a bit more robust?

我正在研究一个简单的旋转例程,它将对象旋转标准化为 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;
            }
        }
    }

回答by tvanfosson

Use modulo arithmetic:

使用模运算:

this.orientation += degrees;

this.orientation = this.orientation % 360;

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

回答by paxdiablo

This can be simplified to the following.

这可以简化为以下内容。

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

C# follows the same rules as C and C++ and i % 360will give you a value between -359and 359for any integer, then the second line is to ensure it's in the range 0 through 359 inclusive.

C# 遵循与 C 和 C++ 相同的规则,并且i % 360会为您提供介于-359和之间359的任何整数的值,然后第二行是确保它在 0 到 359 的范围内(包括 0 到 359)。

If you wanted to be shifty, you could get it down to one line:

如果你想变得狡猾,你可以把它归结为一行:

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

which would keep it positive under all conditions but that's a nasty hack for saving one line of code, so I wouldn't do it, but I willexplain it.

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

From degrees % 360you will get a number between -359and 359. Adding 360will modify the range to between 1and 719. If orientationis already positive, adding this will guarantee it still is, and the final % 360will bring it back to the range 0through 359.

degrees % 360你会得到之间的数字-359359。添加360会将范围修改为介于1和之间719。如果orientation已经是正数,添加 this 将保证它仍然是,最后% 360将它带回0通过359.

At a bare minimum, you could simplify your code since the ifs and whiles can be combined. For example, the result of the conditions in these two lines:

在裸露的最低限度,你可以简化你的代码,因为ifS和whileS可结合。例如,这两行条件的结果:

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

is alwaysthe same, hence you don't need the surrounding if.

总是一样的,因此你不需要周围if

So, to that end, you could do:

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

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

but I'd stillgo for the modulus version since it avoids loops. This will be important when a user enters 360,000,000,000 for the rotation (and they willdo this, believe me) and then find they have to take an early lunch while your code grinds away :-)

但我仍然会选择模数版本,因为它避免了循环。这将是重要的,当一个用户在旋转进入3600亿(他们做到这一点,相信我),然后发现他们有而你的代码研磨掉采取早午餐:-)

回答by enzuguri

I sort of quickly mocked this up in AS3, but should work (you may need +=on the angle)

我在 AS3 中快速模拟了这个,但应该可以工作(你可能需要+=角度)

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

回答by QBziZ

This is one that normalizes to any range. Useful for normalizing between [-180,180], [0,180] or [0,360].

这是一个标准化到任何范围。用于在 [-180,180]、[0,180] 或 [0,360] 之间进行标准化。

( it's in C++ though )

(虽然它在 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
}

For ints

对于整数

//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
}

So basically the same but without the floor. The version I personally use is a generic one that works for all numeric types and it also uses a redefined floor that does nothing in case of integral types.

所以基本相同,但没有发言权。我个人使用的版本是适用于所有数字类型的通用版本,它也使用重新定义的地板,在整数类型的情况下不做任何事情。

回答by sergio

Add any multiple of 360 degrees between which your possible input values could be (to take it above zero), and just take the remaining with %, like this

添加您可能的输入值可能是的 360 度的任何倍数(使其高于零),然后用 % 取余数,就像这样

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

The case above can take input angles down to -3600. You can add any number (multiple of 360) crazily high that would make the input value positive first.

上面的情况可以将输入角度降低到 -3600。您可以疯狂地添加任何数字(360 的倍数),这将使输入值首先为正。

Usually during an animation, your previous frame/step value would probably be already normalized by the previous step, so you'll be good to go by just adding 360:

通常在动画过程中,您的前一帧/步长值可能已经被上一步标准化了,因此您只需添加 360 即可:

normalized_angle = (angle+360) %360;

回答by Saad Ahmed

formula for re-orienting circular values i.e to keep angle between 0 and 359 is:

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

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

generalized formula for shifting angle orientation can be:

平移角度定向的通用公式可以是:

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

in which value of shift represent circular shift for e.g I want values in -179 to 180 then it can be represented as: angle + Math.ceil( (-angle-179) / 360 ) * 360

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

回答by Ronnie Overby

I prefer to avoid loops, conditionals, arbitrary offsets (3600), and Math.____()calls:

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

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

回答by Emil

Function that comes handy when normalizing angles (degrees) into interval [0, 360> :

将角度(度)归一化为区间 [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;
}

回答by Kris Krej

I'd recommend making separate function for normalizing angle - it's a cleaner solution.

我建议为标准化角度制作单独的功能 - 这是一个更清洁的解决方案。

public static float NormalizeEulerAngle(float angle){
    var normalized = angle % 360;
    if(normalized < 0)
        normalized += 360;
    return normalized;
}

Fiddle proving that such function works as intended: https://dotnetfiddle.net/Vh4CUa

小提琴证明这样的功能按预期工作:https: //dotnetfiddle.net/Vh4CUa

And then you can use it like here:

然后你可以像这里一样使用它:

public void Rotate(int degrees){
    orientation = NormalizeEulerAngle(orientation + degrees);
}