2009-09-17 8 views
5

Mam wiele wektorów normalnych do powierzchni okien w oprogramowaniu do modelowania 3D. Przewiduje płaszczyźnie xy, chciałbym wiedzieć, w jakim kierunku one stoją, tłumaczone na 8 kompas współrzędne (Północna, Północno-Wschodniego, East, South-East, Południe, South-West, West i North-West).Jak "przyciągnąć" wektor kierunkowy (2D) do kompasu (N, NE, E, SE, S, SW, W, NW)?

Wektory działa tak:

  • X reprezentuje Wschód-Zachód (z East jest dodatnia)
  • oś y reprezentuje Północ-Południe (z Północnej jest dodatnia)
  • zatem
    • (0, 1) == Północna
    • (1, 0) == East
    • (0, -1) == południe
    • (-1,0) == Zachód

Biorąc wektor (x, y) szukam najbliższy z 8 współrzędnych kompasu. Wszelkie pomysły, jak to zrobić elegancko?

+0

wszelkie pomysły na prawidłowe oznaczenie tego tagu? Czuję się swobodnie ... –

+1

Nie, w mojej odpowiedzi (1, 0) jest wschód i idzie w lewo, ponieważ robię to matematycznie tutaj. Jest to sprzeczne ze standardowym stosowaniem kątów w nawigacji (0 = północ, zgodnie z ruchem wskazówek zegara). Możesz go dostosować, dodając odpowiednie przesunięcie do +8 i używając znaku - przed atan2. – starblue

+0

Dziękuję za wskazanie tego, że starblue, myliłem się tutaj z moimi szkicami - twoja odpowiedź jest na miejscu! –

Odpowiedz

7

Działa to w Javie, obliczanie wartości 0 ... 7 dla ośmiu kierunkach:

import static java.lang.Math.*;  

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

map wynikowych do kompasu następująco:

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

Najprawdopodobniej zadzwoniłbym pod numer atan2(), aby obliczyć kąt nagłówka ("odchylenie"), a następnie użyć sekwencji if: s lub niektórych matematyki, aby "przyciągnąć" ją do wielokrotności 90 stopni.

+0

dzięki, wygląda obiecująco, sprawdzi to po obiedzie! –

4

nie trzeba zrobić funkcja atan.

jeśli wykonasz: y/x otrzymasz nachylenie linii. Sądząc po uzyskanej liczbie, możesz określić kąt/oś.

dla dodatnich wartości x (x> 0)

  • (y/x)> 2,4 - => 90 ° (North)
  • 2,4> (y/x)> 0,4 ​​- => 45 stopni (zachód)
  • 0,4> (y/x)> -0.4 - => 0 stopni (zachodnia)
  • -0.4> (y/x)> -2,4 - => -45 stopni (zachód)
  • -2.4> (Y/X) - => 90 ° (południowym)

i podobną listę za negatywne X.

i wreszcie przypadki wyjątek:

  • (x == 0 & & y> 0) - => -90 ° (południowym)
  • (x == 0 & & Y < 0) - => 90 ° (południowym)

addendum: Zgłaszam tylko tę metodę, ponieważ przy obliczaniu atanu nie ma wyjścia (na przykład w systemie wbudowanym))

Musiałem trochę się wykopać. Oto wysoce zoptymalizowana rutyna, której używam (używana w grach mobilnych).

wejściowy: x1, y1 = startowy wektora x2, y2 = końcowego wektora wyjścia (0-7) = 0 = północ, zachód 1 = 2 = zachód, ... itd

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

spowoduje to następujący wynik:

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

(wektory do testu może wyglądać dziwnie dobrane, ale manipulowane im wszystko nieco się wyraźnie w jednym oktantu a nie na dokładnym granicy)

+0

Nie widzę, jak może działać ostateczna zoptymalizowana procedura, ponieważ wartość r może z łatwością przekroczyć anonimowy rozmiar tablicy. – GregM

+0

Dobrze zauważył. Naprawiono błąd – Toad

3

Ten nie używa atan2, aw najgorszym przypadku 4 porównania i 2 produkty na połączenie. Porównywanie x do y w 4 wewnętrznych blokach (edytowałem tylko w pierwszym bloku), można zredukować do dokładnie 4 porównań i 1 produktu na połączenie.

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; 
} 
Powiązane problemy