Как “привязать” вектор направления (2D) к компасу (N, NE, E, SE, S, SW, W, NW)?

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

Вопрос

У меня есть куча векторов, перпендикулярных поверхностям окон в программном обеспечении для 3D-моделирования.Спроецированный на плоскость XY, я хотел бы знать, в каком направлении они обращены, переведенный на плоскость 8 координаты по компасу (Север, Северо-Восток, Восток, Юго-Восток, Юг, Юго-Запад, Запад и Северо-Запад).

Векторы работают следующим образом:

  • ось X представляет Восток-Запад (при положительном значении "Восток").
  • ось y представляет Север-Юг (где Север является положительным).
  • таким образом
    • (0, 1) == Север
    • (1, 0) == Восток
    • (0,-1) == Юг
    • (-1,0) == Запад

Учитывая вектор (x, y), я ищу ближайшую из 8 координат компаса.Есть какие-нибудь идеи о том, как сделать это элегантно?

Это было полезно?

Решение

Это работает в 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

Другие советы

Я бы, наверное, просто позвонил атан2() чтобы определить угол курса («рыскание»), а затем использовать последовательность if:s или некоторые математические вычисления, чтобы «привязать» его к углу, кратному 90 градусам.

нет необходимости выполнять функцию 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==0 && y>0) -=> -90 градусов (южная)
  • (x==0 && y<0) -=> 90 градусов (южная)

добавление:Я сообщаю об этом методе только в тех случаях, когда вычисление atan невозможно (например, во встроенной системе))

Мне пришлось немного покопаться.Вот высокооптимизированная процедура, которую я использую (используется в мобильных играх).

входные данные: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

(Векторы для теста могут выглядеть странно выбранными, но я немного изменил их все, чтобы они были четко в одном октанте, а не на точной границе)

Этот не использует atan2 и выполняет в худшем случае 4 сравнения и 2 продукта за вызов.Сравнивая x с y в 4 внутренних блоках (я редактировал только в первом блоке), можно сократить ровно до 4 сравнений и 1 продукта на вызов.

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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top