Вот мой предлагаемый подход для определения ближайшего направления компаса к тому, на которое указывает отрезок линии [A, B]
, определяемый его конечными точками point_a
и point_b
:
- Все расчеты производятся в стандартных декартовых координатах, переход на экранные координаты делается в конце. это упрощает подход и делает код пригодным для повторного использования в другом месте.
- Сначала измените источник на
point_a
- второй вычислить угол сегмента линии с x_axis
- определить ближайший пеленг (в стандартных декартовых координатах)
- преобразовать стандартный пеленг в экранные координаты пеленга (горизонтальный флип)
с точками, определенными в экранных координатах (ось Y вниз), вызовите get_bearings(point_a, point_b)
Если точки, определенные в стандартных декартовых координатах (ось Y вверх), вызовите assign_bearing_to_compass(point_a, point_b)
(тесты под кодом показывают результаты использования точек в стандартных координатах и экранных координатах.)
import math
def _change_origin_of_point_b_to_point_a(point_a, point_b):
# uses standard Y axis orientation, not screen orientation
return (point_b[0] - point_a[0], point_b[1] - point_a[1])
def _calc_angle_segment_a_b_with_x_axis(point_a, point_b):
# uses standard Y axis orientation, not screen orientation
xa, ya = point_a
xb, yb = _change_origin_of_point_b_to_point_a(point_a, point_b)
return math.atan2(yb, xb)
def determine_bearing_in_degrees(point_a, point_b):
"""returns the angle in degrees that line segment [point_a, point_b)]
makes with the horizontal X axis
"""
# uses standard Y axis orientation, not screen orientation
return _calc_angle_segment_a_b_with_x_axis(point_a, point_b) * 180 / math.pi
def assign_bearing_to_compass(point_a, point_b):
"""returns the standard bearing of line segment [point_a, point_b)
"""
# uses standard Y axis orientation, not screen orientation
compass = {'W' : [157.5, -157.5],
'SW': [-157.5, -112.5],
'S' : [-112.5, -67.5],
'SE': [-67.5, -22.5],
'E' : [-22.5, 22.5],
"NE": [22.5, 67.5],
'N' : [67.5, 112.5],
'NW': [112.5, 157.5]}
bear = determine_bearing_in_degrees(point_a, point_b)
for direction, interval in compass.items():
low, high = interval
if bear >= low and bear < high:
return direction
return 'W'
def _convert_to_negative_Y_axis(compass_direction):
"""flips the compass_direction horizontally
"""
compass_conversion = {'E' : 'E',
'SE': 'NE',
'S' : 'N',
'SW': 'NW',
'W' : 'W',
"NW": 'SW',
'N' : 'S',
'NE': 'SE'}
return compass_conversion[compass_direction]
def get_bearings(point_a, point_b):
return _convert_to_negative_Y_axis(assign_bearing_to_compass(point_a, point_b))
Тесты:
(с использованием стандартных квадрантов тригонометрического круга)
Квадрант I:
point_a = (0, 0)
points_b = [(1, 0), (1, 3), (1, 2), (1, 1), (2, 1), (3, 1), (0, 1)]
print("point_a, point_b Y_up Y_down (in screen coordinates)")
for point_b in points_b:
print(point_a, ' ', point_b, ' ', assign_bearing_to_compass(point_a, point_b), ' ', get_bearings(point_a, point_b))
полученные результаты:
point_a, point_b Y_up Y_down (in screen coordinates)
(0, 0) (1, 0) E E
(0, 0) (1, 3) N S
(0, 0) (1, 2) NE SE
(0, 0) (1, 1) NE SE
(0, 0) (2, 1) NE SE
(0, 0) (3, 1) E E
(0, 0) (0, 1) N S
Квадрант II:
point_a = (0, 0)
points_b = [(-1, 0), (-1, 3), (-1, 2), (-1, 1), (-2, 1), (-3, 1), (0, 1)]
print("point_a, point_b Y_up Y_down (in screen coordinates)")
for point_b in points_b:
print(point_a, ' ', point_b, ' ', assign_bearing_to_compass(point_a, point_b), ' ', get_bearings(point_a, point_b))
полученные результаты:
point_a, point_b Y_up Y_down (in screen coordinates)
(0, 0) (-1, 0) W W
(0, 0) (-1, 3) N S
(0, 0) (-1, 2) NW SW
(0, 0) (-1, 1) NW SW
(0, 0) (-2, 1) NW SW
(0, 0) (-3, 1) W W
(0, 0) (0, 1) N S
Квадрант III:
point_a = (0, 0)
points_b = [(-1, 0), (-1, -3), (-1, -2), (-1, -1), (-2, -1), (-3, -1), (0, -1)]
print("point_a, point_b Y_up Y_down (in screen coordinates)")
for point_b in points_b:
print(point_a, ' ', point_b, ' ', assign_bearing_to_compass(point_a, point_b), ' ', get_bearings(point_a, point_b))
полученные результаты:
point_a, point_b Y_up Y_down (in screen coordinates)
(0, 0) (-1, 0) W W
(0, 0) (-1, -3) S N
(0, 0) (-1, -2) SW NW
(0, 0) (-1, -1) SW NW
(0, 0) (-2, -1) SW NW
(0, 0) (-3, -1) W W
(0, 0) (0, -1) S N
Квадрант IV:
point_a = (0, 0)
points_b = [(1, 0), (1, -3), (1, -2), (1, -1), (2, -1), (3, -1), (0, -1)]
print("point_a, point_b Y_up Y_down (in screen coordinates)")
for point_b in points_b:
print(point_a, ' ', point_b, ' ', assign_bearing_to_compass(point_a, point_b), ' ', get_bearings(point_a, point_b))
полученные результаты:
point_a, point_b Y_up Y_down (in screen coordinates)
(0, 0) (1, 0) E E
(0, 0) (1, -3) S N
(0, 0) (1, -2) SE NE
(0, 0) (1, -1) SE NE
(0, 0) (2, -1) SE NE
(0, 0) (3, -1) E E
(0, 0) (0, -1) S N
person
Reblochon Masque
schedule
17.09.2017