Wie kann man einen Richtungsvektor (2D) an einem Kompass (N, NE, E, SE, S, SW, W, NW) „einrasten“ lassen?

StackOverflow https://stackoverflow.com/questions/1437790

Frage

Ich habe in einer 3D-Modellierungssoftware eine Reihe von Vektoren normal zu Fensteroberflächen.Auf die XY-Ebene projiziert, würde ich gerne wissen, in welche Richtung sie blicken, übersetzt in die 8 Kompasskoordinaten (Norden, Nordost, Ost, Süd-Ost, Süd, Südwesten, Westen Und Nordwest).

Die Vektoren funktionieren folgendermaßen:

  • die X-Achse stellt Ost-West dar (wobei Ost positiv ist)
  • Die Y-Achse stellt Nord-Süd dar (wobei Norden positiv ist).
  • daher
    • (0, 1) == Norden
    • (1, 0) == Osten
    • (0,-1) == Süden
    • (-1,0) == Westen

Bei einem gegebenen Vektor (x, y) suche ich nach der nächstgelegenen der 8 Kompasskoordinaten.Irgendwelche Ideen, wie man das elegant machen kann?

War es hilfreich?

Lösung

Das funktioniert in Java, Wert 0 ... 7 für die acht Richtungen Berechnung:

import static java.lang.Math.*;    

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

Das Ergebnis Karten auf den Kompass wie folgt:

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

Andere Tipps

Ich würde wahrscheinlich tun, nur einen Aufruf an atan2 () die Überschrift Winkel, um herauszufinden, ( „Gieren“ bezeichnet) und dann entweder eine Folge von if benutzen. s oder einige Mathematik zu „schnappen“, es auf ein Vielfaches von 90 Grad

Es ist nicht erforderlich, eine Atan-Funktion auszuführen.

wenn Sie tun:y/x erhalten Sie die Steigung der Linie.Anhand der erhaltenen Zahl können Sie den Winkel/Oktanten bestimmen.

für positive x (x>0)

  • (y/x) > 2,4 -=> 90 Grad (Nord)
  • 2,4 > (y/x) > 0,4 ​​-=> 45 Grad (Nordwesten)
  • 0,4 > (y/x) > -0,4 -=> 0 Grad (West)
  • -0,4 > (y/x) > -2,4 -=> -45 Grad (Südwesten)
  • -2,4 > (y/x) -=> 90 Grad (Süden)

und eine ähnliche Liste für die negativen x

und schließlich die Ausnahmefälle:

  • (x==0 && y>0) -=> -90 Grad (Süden)
  • (x==0 && y<0) -=> 90 Grad (Süden)

Nachtrag:Ich melde diese Methode nur, wenn die Berechnung eines Atan nicht möglich ist (z. B. auf einem eingebetteten System).

Ich musste ein bisschen graben.Hier ist eine hochoptimierte Routine, die ich verwende (in mobilen Spielen verwendet).

Eingang:x1, y1 = Startpunkt des Vektors x2, y2 = Endpunkt der Vektorausgabe (0-7) = 0 = Norden, 1 = Nordwesten, 2 = West, ... usw.

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

Dies führt zu folgender Ausgabe:

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

(Die Vektoren für den Test sehen vielleicht seltsam ausgewählt aus, aber ich habe sie alle ein wenig angepasst, damit sie eindeutig in einem Oktanten und nicht an der genauen Grenze liegen.)

Dies nicht verwendet atan2, und zwar im schlimmsten Fall 4 Vergleiche und 2 Artikel pro Anruf. Vergleicht man x zu y in den 4 inneren Blöcken (I es in dem ersten Block bearbeiten nur), kann es zu genau 4 Vergleichen verringert werden, und 1-Produkt pro Anruf.

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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top