Normalise orientation between 0 and 360

2019-03-08 15:33发布

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?

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

8条回答
虎瘦雄心在
2楼-- · 2019-03-08 16:05

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

var degrees = -123;
degrees = (degrees % 360 + 360) % 360;
// degrees: 237
查看更多
在下西门庆
3楼-- · 2019-03-08 16:10

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

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

查看更多
不美不萌又怎样
4楼-- · 2019-03-08 16:10

Function that comes handy when normalizing angles (degrees) into interval [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;
}
查看更多
Root(大扎)
5楼-- · 2019-03-08 16:14

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 % 360 will give you a value between -359 and 359 for any integer, then the second line is to ensure it's in the range 0 through 359 inclusive.

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 will explain it.

From degrees % 360 you will get a number between -359 and 359. Adding 360 will modify the range to between 1 and 719. If orientation is already positive, adding this will guarantee it still is, and the final % 360 will bring it back to the range 0 through 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:

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

is always the same, hence you don't need the surrounding 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 still go 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 will do this, believe me) and then find they have to take an early lunch while your code grinds away :-)

查看更多
Rolldiameter
6楼-- · 2019-03-08 16:14

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

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.

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:

normalized_angle = (angle+360) %360;
查看更多
Juvenile、少年°
7楼-- · 2019-03-08 16:17

Use modulo arithmetic:

this.orientation += degrees;

this.orientation = this.orientation % 360;

if (this.orientation < 0)
{
    this.orientation += 360;
}
查看更多
登录 后发表回答