How to "snap" a directional (2D) vector to a compass (N, NE, E, SE, S, SW, W, NW)?

I have a set of vectors normal to window surfaces in 3D modeling software. Projected onto the XY-Plane, I would like to know in which direction they are facing, translated into coordinates 8 (north, northeast, east, southeast, south, southwest, west and northwest).

Vectors work as follows:

  • X axis represents East-West (positive with east)
  • the y axis represents North-South (with the North being positive)
  • thus,
    • (0, 1) == North
    • (1, 0) == East
    • (0, -1) == South
    • (- 1.0) == West

Given the vector (x, y), I'm looking for the closest of the 8 compass coordinates. Any ideas on how to do this elegantly?

+5
4

Java, 0... 7 :

import static java.lang.Math.*;    

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

:

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

, atan2(), ( "" ), if: s , "" 90 .

+6

atan.

: y/x . , , /.

x (x > 0)

  • (y/x) > 2.4 - = > 90 ()
  • 2.4 > (y/x) > 0.4 - = > 45 (-)
  • 0.4 > (y/x) > -0.4 - = > 0 ()
  • -0.4 > (y/x) > -2.4 - = > -45 (-)
  • -2.4 > (y/x) - = > 90 ()

x

, , :

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

: , (, ))

. , ( ).

input: x1, y1 =      x2, y2 = (0-7) = 0 = , 1 = -, 2 = ,... ..

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

:

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

( , , , )

+4

This one does not use atan2 and in the worst case has 4 comparisons and 2 products per call. Comparing x with y in 4 indoor units (I edited it only in the first unit), it can be reduced to exactly 4 comparisons and 1 product per call.

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;
}
+3
source

All Articles