我正在研究一个简单的旋转程序,它将物体旋转归一化到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;
}
}
}
使用模运算:
this.orientation += degrees;
this.orientation = this.orientation % 360;
if (this.orientation < 0)
{
this.orientation += 360;
}
这是规范化到任何范围的。用于在[-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 }
所以基本相同,但没有底线。我个人使用的版本是适用于所有数字类型的通用版本,它还使用重新定义的版本,在整数类型的情况下不执行任何操作。
这可以简化为以下内容。
public void Rotate (int degrees) {
this.orientation = (this.orientation + degrees) % 360;
if (this.orientation < 0) this.orientation += 360;
}
C#遵循与C和C ++相同的规则,i % 360
将为-359
和359
提供任意整数的值,然后第二行是确保它在0到359的范围内(包括0和359)。
如果你想要狡猾,你可以把它降到一行:
this.orientation = (this.orientation + (degrees % 360) + 360) % 360;
这会在所有情况下保持积极,但这是一个讨厌的黑客,以保存一行代码,所以我不会这样做,但我会解释它。
从degrees % 360
您将得到-359
和359
之间的数字。添加360
将修改1
和719
之间的范围。如果orientation
已经是正数,那么添加它将保证它仍然是,并且最终的% 360
将通过0
将其带回359
。
至少,您可以简化代码,因为可以组合if
s和while
s。例如,这两行中的条件结果:
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用于轮换时,这将是非常重要的(他们会这样做,相信我),然后发现他们必须在您的代码磨损时提早吃午餐:-)
重新定向圆形值的公式,即保持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
我在AS3中很快就嘲笑了这个,但是应该可以工作(你可能需要在角度上使用+=
)
private Number clampAngle(Number angle)
{
return (angle % 360) + (angle < 0 ? 360 : 0);
}
我更喜欢避免循环,条件,任意偏移(3600)和Math.____()
调用:
var degrees = -123;
degrees = (degrees % 360 + 360) % 360;
// degrees: 237
添加360度的任意倍数,在这些倍数之间可能存在您的输入值(将其置于零以上),然后将剩余的百分比取下,如下所示
angle = 382;
normalized_angle = (angle+3600) %360;
//result = 22
上述情况可以将输入角度降至-3600。您可以添加任意数字(360的倍数),这将使输入值成为正值。
通常在动画期间,您之前的帧/步长值可能已经被上一步标准化,因此您只需添加360就可以了:
normalized_angle = (angle+360) %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;
}