2009-09-17 6 views
5

Tengo un grupo de vectores normales a las superficies de las ventanas en un software de modelado 3D. Proyectada al plano xy, me gustaría saber en qué dirección se enfrentan, traducido a la 8 brújula coordenadas (Norte, Noreste, Medio, Sudeste, Sur, South-West, West y North-West).Cómo "ajustar" un vector direccional (2D) a una brújula (N, NE, E, SE, S, SW, W, NW)?

Los vectores de trabajo así:

eje
  • la X representa este-oeste (con este ser positivo)
  • el eje y representa Norte-Sur (con el norte de ser positivo)
  • tanto
    • (0, 1) == Norte
    • (1, 0) == Este
    • (0, -1) == Sur
    • (-1,0) == West

dado un vector (x, y) Busco el más cercano de los 8 coordenadas de la brújula. ¿Alguna idea sobre cómo hacer esto elegantemente?

+0

alguna idea sobre cómo etiquetar esto correctamente? siéntase libre ... –

+1

No, en mi respuesta (1, 0) está al este y va en sentido contrario a las agujas del reloj, ya que estoy haciendo las cosas matemáticamente aquí. Esto está en desacuerdo con el uso estándar de los ángulos en la navegación (0 = norte, en el sentido de las agujas del reloj). Puede adaptarlo agregando un desplazamiento apropiado al +8 y usando a - en frente del atan2. – starblue

+0

Gracias por señalar que starblue, me estoy confundiendo con mis bocetos aquí - ¡tu respuesta es perfecta! –

Respuesta

7

Esto funciona en Java, el cálculo de un valor de 0 ... 7 para las ocho direcciones:

import static java.lang.Math.*;  

int compass = (((int) round(atan2(y, x)/(2 * PI/8))) + 8) % 8; 

Los mapas de resultados al compás de la siguiente manera:

0 => E 
1 => NE 
2 => N 
3 => NW 
4 => W 
5 => SW 
6 => S 
7 => SE 
6

que probablemente sólo hacer una llamada a atan2() de averiguar el ángulo de rumbo ("guiñada"), y luego utilizar una secuencia de if: s o algunos de matemáticas de "chasquido" a un múltiplo de 90 grados.

+0

¡gracias, parece prometedor, lo verificará después del almuerzo! –

4

hay necesidad de hacer una función atan

si lo hace: y/x obtendrá la pendiente de la línea. A juzgar por el número que obtienes, puedes determinar el ángulo/octante.

para de positivos x (x> 0)

  • (y/x)> 2.4 - => 90 grados (norte)
  • 2.4> (y/x)> 0,4 ​​- => 45 grados (noroeste)
  • 0.4> (y/x)> -0.4 - => 0 grados (West)
  • -0,4> (y/x)> -2,4 - => -45 grados (sudoeste)
  • -2.4> (y/x) - => 90 grados (sur)

y una lista similar para de las x negativas

y, finalmente, los casos de excepción:

  • (x == 0 & & y> 0) - => -90 grados (sur)
  • (x == 0 & & y < 0) - => 90 grados (sur)

adición: Sólo informar de este método para el cálculo de valores atan es un no ir (por ejemplo, en un sistema embebido))

tuve que cavar un poco. Aquí hay una rutina altamente optimizada que uso (utilizada en juegos móviles).

de entrada: x1, y1 = punto inicial del vector de x2, y2 = punto final del vector salida (0-7) = 0 = norte, noroeste 1 =, 2 = oeste, etc ...

int CalcDir(int x1, int y1, int x2, int y2) 
{ 
     int dx = x2 - x1, dy = y2 - y1; 
     int adx = (dx<0)?-dx:dx, ady = (dy<0)?-dy:dy, r; 
     r=(dy>0?4:0)+(dx>0?2:0)+(adx>ady?1:0); 
     r=(int []){2,3,1,0,5,4,6,7}[r]; 
     return r; 
} 

void CalcDirTest(){ 
     int t = CalcDir(0, 0, 10, 1); 
     printf("t = %d",t); 
     t = CalcDir(0, 0, 9, 10); 
     printf("t = %d",t); 
     t = CalcDir(0, 0, -1, 10); 
     printf("t = %d",t); 
     t = CalcDir(0, 0, -10, 9); 
     printf("t = %d",t); 
     t = CalcDir(0, 0, -10, -1); 
     printf("t = %d",t); 
     t = CalcDir(0, 0, -9, -10); 
     printf("t = %d",t); 
     t = CalcDir(0, 0, 1, -10); 
     printf("t = %d",t); 
     t = CalcDir(0, 0, 10, -9); 
     printf("t = %d",t); 
} 

Esto resultará en la siguiente salida:

t = 7 
t = 6 
t = 5 
t = 4 
t = 3 
t = 2 
t = 1 
t = 0 

(los vectores para la prueba puede tener un aspecto elegido de manera singular, pero yo les ajustado todo un poco que sea claramente en un octante y no en la frontera exacta)

+0

No veo cómo puede funcionar la rutina optimizada final, ya que el valor de r puede exceder fácilmente el tamaño de matriz anónima. – GregM

+0

Bien manchado. Solucionado el error – Toad

3

Éste no usa atan2, y en el peor de los casos tiene 4 comparaciones y 2 productos por llamada. Al comparar x a y en los 4 bloques internos (lo edité solo en el primer bloque), se puede reducir a exactamente 4 comparaciones y 1 producto por llamada.

int compass(double x,double y) 
{ 
    double t = 0.392699082; // tan(M_PI/8.0); 

    if (x>=0) 
    { 
    if (y>=0) 
    { 
     if (x>y) { if (y<t*x) return E_COMPASS; } 
     else { if (x<t*y) return N_COMPASS; } 
     return NE_COMPASS; 
    } 
    else 
    { 
     if (-y<t*x) return E_COMPASS; 
     if (x<-t*y) return S_COMPASS; 
     return SE_COMPASS; 
    } 
    } 
    else 
    { 
    if (y>=0) 
    { 
     if (y<-t*x) return W_COMPASS; 
     if (-x<t*y) return N_COMPASS; 
     return NW_COMPASS; 
    } 
    else 
    { 
     if (-y<-t*x) return W_COMPASS; 
     if (-x<-t*y) return S_COMPASS; 
     return SW_COMPASS; 
    } 
    } 
    return E_COMPASS; 
} 
Cuestiones relacionadas