quaternion - transform rotation c#
Normalizar orientación entre 0 y 360. (8)
Estoy trabajando en una rutina de rotación simple que normaliza una rotación de objetos entre 0 y 360 grados. Mi código C # parece estar funcionando pero no estoy del todo contento con él. ¿Alguien puede mejorar el código a continuación para hacerlo un poco más sólido?
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;
}
}
}
Agregue cualquier múltiplo de 360 grados entre los cuales podrían estar los valores de entrada posibles (para llevarlo por encima de cero), y simplemente tome el restante con%, como este
angle = 382;
normalized_angle = (angle+3600) %360;
//result = 22
El caso anterior puede tomar ángulos de entrada hasta -3600. Puede agregar cualquier número (múltiplo de 360) locamente alto que haría que el valor de entrada fuera positivo primero.
Por lo general, durante una animación, su valor de fotograma / paso anterior probablemente ya se habrá normalizado en el paso anterior, por lo que estará listo simplemente agregando 360:
normalized_angle = (angle+360) %360;
De alguna manera me burlé de esto rápidamente en AS3, pero debería funcionar (es posible que necesites +=
en el ángulo)
private Number clampAngle(Number angle)
{
return (angle % 360) + (angle < 0 ? 360 : 0);
}
Este es uno que normaliza a cualquier rango. Útil para normalizar entre [-180,180], [0,180] o [0,360].
(aunque está en 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 }
Para 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 }
Así que básicamente lo mismo pero sin suelo. La versión que uso personalmente es una genérica que funciona para todos los tipos numéricos y también utiliza un piso redefinido que no hace nada en caso de tipos integrales.
Esto se puede simplificar a lo siguiente.
public void Rotate (int degrees) {
this.orientation = (this.orientation + degrees) % 360;
if (this.orientation < 0) this.orientation += 360;
}
C # sigue las mismas reglas que C y C ++ y i % 360
le dará un valor entre -359
y 359
para cualquier entero, luego la segunda línea es para asegurarse de que esté en el rango de 0 a 359, ambos inclusive.
Si quisieras ser shifty, podrías reducirlo a una línea:
this.orientation = (this.orientation + (degrees % 360) + 360) % 360;
lo que lo mantendría positivo en todas las condiciones, pero es un truco desagradable para guardar una línea de código, así que no lo haría, pero lo explicaré.
De degrees % 360
obtendrá un número entre -359
y 359
. La adición de 360
modificará el rango entre 1
y 719
. Si la orientation
ya es positiva, agregar esto garantizará que aún lo sea, y el % 360
final lo devolverá al rango de 0
a 359
.
Como mínimo , puede simplificar su código, ya while
se pueden combinar if
s y while
s. Por ejemplo, el resultado de las condiciones en estas dos líneas:
if (this.orientation < 0)
while (this.orientation < 0)
Siempre es lo mismo, por lo tanto no necesitas el entorno if
.
Entonces, para ese fin, podrías hacer:
public void Rotate (int degrees) {
this.orientation += degrees;
while (this.orientation < 0) this.orientation += 360;
while (this.orientation > 359) this.orientation -= 360;
}
pero todavía me gustaría ir a la versión de módulo, ya que evita los bucles. Esto será importante cuando un usuario ingrese 360,000,000,000 para la rotación (y lo harán , créanme) y luego descubren que tienen que tomar un almuerzo temprano mientras su código se aleja :-)
Función que resulta útil al normalizar ángulos (grados) en el intervalo [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;
}
La fórmula para reorientar los valores circulares, es decir, para mantener el ángulo entre 0 y 359 es:
angle + Math.ceil( -angle / 360 ) * 360
La fórmula generalizada para cambiar la orientación del ángulo puede ser:
angle + Math.ceil( (-angle+shift) / 360 ) * 360
en el que el valor de desplazamiento representa un cambio circular, por ejemplo, quiero valores de -179 a 180, luego se puede representar como: angle + Math.ceil ((-angle-179) / 360) * 360
Prefiero evitar bucles, condicionales, compensaciones arbitrarias (3600) y llamadas Math.____()
:
var degrees = -123;
degrees = (degrees % 360 + 360) % 360;
// degrees: 237
Usar modulo aritmético:
this.orientation += degrees;
this.orientation = this.orientation % 360;
if (this.orientation < 0)
{
this.orientation += 360;
}