Определение направления 2D вектора с 8 дискретными направлениями (горизонтальное, вертикальное и диагонали)

У меня есть вход джойстика, это вектор. Диапазон значений вектора определяет окружность в прямоугольнике, который охватывает -1, -1 до +1, +1.

Я хочу знать, к какому из 8 возможных направлений подходит вектор. Не беспокойтесь о случае, когда вектор равен (0, 0), я буду разбираться с этим отдельно. Как я могу это сделать?

Примечание: это для игры, поэтому эта функция будет запускаться очень часто. Помогло бы что-нибудь для ускорения функции, например, я знаю, что могу использовать скалярное произведение и триггер, чтобы определить угол между моим вектором и каждым вектором направления, однако мне интересно, можно ли что-то сделать лучше, если мне не нужно точный угол.

3 ответа

Решение

Представьте квадрат внутри квадрата -1.1, где позиция палки (X) находится на одной из сторон:

+-----------------+  +-----------------+
|                 |  |                 |
|                 |  |                 |
|          X      |  |    +-----X-+    |
|                 |  |    |       |    |
|        O        |  |    |   O   |    |
|                 |  |    |       |    |
|                 |  |    +-------+    |
|                 |  |                 |
|                 |  |                 |
+-----------------+  +-----------------+

Вам просто нужно выяснить, на какой стороне находятся координаты, и проверить, ближе ли это к центру стороны или углу. Если внутренний квадрат слишком мал, вы можете считать палочку центрированной.

Что-то вроде:

Public enum Direction {
  None,
  LeftUp, Up, RightUp, Right, RightDown, Down, LeftDown, Left
}

public Direction GetDirection(double x, double y) {
  double absX = Math.Abs(x);
  double absY = Math.Abs(y);
  if (absX < 0.1 && absY < 0.1) {
    // close to center
    return Direction.None;
  }
  if (absX > absY) {
    // vertical side
    double half = absX * 0.4142;
    if (x > 0) {
      // left side
      if (y > half) return Direction.LeftDown;
      if (y < -half) return Diretion.LeftUp;
      return Direction.Left;
    } else {
      // right side
      if (y > half) return Direction.RightDown;
      if (y < -half) return Direction.RightUp;
      return Direction.Right;
    }
  } else {
    // horisontal side
    double half = absY * 0.4142;
    if (y > 0) {
      // bottom
      if (x > half) return Direction.RightDown;
      if (x < -half) return Direction.LeftDown;
      return Direction.Down;
    } else {
      // top
      if (x > half) return Direction.RightUp;
      if (x < -half) return Direction.LeftUp;
      return Direction.Up;
    }
  }
}

Никакой тригонометрии, только простые сравнения, поэтому все должно быть довольно быстро.:)

(Хотя я использовал тригонометрию для вычисления точки 0,4142, которая является загаром (22,5), или положения на стороне, где угол равен 45/2.)

sin a / cos a = tan a,

и у тебя есть

Y = грех

X = cos a

Итак, примените функцию обратной касательной к Y/X, и вы получите угол.

РЕДАКТИРОВАТЬ: в полном круге, есть два угла с одинаковым значением касательной (a а также a + pi). Используйте знаки X и Y, чтобы определить, какой из них является действительным.

Вы можете использовать готовую таблицу приближений tan^-1. Должно быть очень быстро вычислять угол на основе размера вашего входного вектора, и вам, вероятно, не понадобится очень большое разрешение в таблице (на самом деле, если вам нужно только 8 дискретных направлений, 8 записей в вашей таблице будет достаточно).

Другие вопросы по тегам