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
Normalise orientation between 0 and 360
提问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 % 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.
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 % 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
.
从degrees % 360
你会得到之间的数字-359
和359
。添加360
会将范围修改为介于1
和之间719
。如果orientation
已经是正数,添加 this 将保证它仍然是,最后% 360
将它带回0
通过359
.
At a bare minimum, you could simplify your code since the if
s and while
s can be combined. For example, the result of the conditions in these two lines:
在裸露的最低限度,你可以简化你的代码,因为if
S和while
S可结合。例如,这两行条件的结果:
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);
}