109 lines
3.9 KiB
Python
109 lines
3.9 KiB
Python
import math
|
|
from Angle import Angle
|
|
from Vector import Vector3
|
|
|
|
class Direction:
|
|
"""! A direction using angles
|
|
|
|
* The horizontal angle ranging from -180 (inclusive) to 180 (exclusive)
|
|
degrees which is a rotation in the horizontal plane
|
|
* A vertical angle ranging from -90 (inclusive) to 90 (exclusive) degrees
|
|
which is the rotation in the up/down direction applied after the horizontal
|
|
rotation has been applied.
|
|
The angles are automatically normalized to stay within the abovenmentioned
|
|
ranges.
|
|
"""
|
|
def __init__(self, horizontal=Angle(), vertical=Angle()):
|
|
"""! Create a new direction
|
|
@param horizontal The horizontal angle
|
|
@param vertical The vertical angle.
|
|
"""
|
|
## horizontal angle, range in degrees = (-180..180]
|
|
self.horizontal: Angle = horizontal
|
|
## vertical angle, range in degrees = (-90..90]
|
|
self.vertical: Angle = vertical
|
|
|
|
self.Normalize()
|
|
|
|
@staticmethod
|
|
def Degrees(horizontal: float, vertical: float):
|
|
"""! Create a direction using angle values in degrees
|
|
@param horizontal The horizontal angle in degrees
|
|
@param vertical The vertical angle in degrees
|
|
@return The direction
|
|
"""
|
|
direction = Direction(Angle.Degrees(horizontal), Angle.Degrees(vertical))
|
|
return direction
|
|
@staticmethod
|
|
def Radians(horizontal: float, vertical: float):
|
|
"""! Create a direction using angle values in radians
|
|
@param horizontal The horizontal angle in radians
|
|
@param vertical The vertical angle in radians
|
|
@return The direction
|
|
"""
|
|
direction = Direction(Angle.Radians(horizontal), Angle.Radians(vertical))
|
|
return direction
|
|
|
|
def FromVector3(v: Vector3):
|
|
d = Direction(
|
|
horizontal = Angle.Atan2(v.right, v.forward),
|
|
vertical = Angle.Degrees(-90) - Angle.Acos(v.up)
|
|
)
|
|
return d;
|
|
def ToVector3(self) -> Vector3:
|
|
"""! Convert the direction to a Vector3 coordinate
|
|
@return The vector coordinate
|
|
"""
|
|
verticalRad = (math.pi / 2) - self.vertical.InRadians()
|
|
horizontalRad = self.horizontal.InRadians()
|
|
|
|
cosVertical = math.cos(verticalRad)
|
|
sinVertical = math.sin(verticalRad)
|
|
cosHorizontal = math.cos(horizontalRad)
|
|
sinHorizontal = math.sin(horizontalRad)
|
|
|
|
right = sinVertical * sinHorizontal
|
|
up = cosVertical
|
|
forward = sinVertical * cosHorizontal
|
|
return Vector3(right, up, forward)
|
|
|
|
def __eq__(self, direction):
|
|
"""! Test whether this direction is equal to another direction
|
|
@param direction The direction to compare to
|
|
@return True when the direction angles are equal, false otherwise.
|
|
"""
|
|
return (self.horizontal == direction.horizontal and
|
|
self.vertical == direction.vertical)
|
|
|
|
def __neg__(self):
|
|
"""! Negate/reverse the direction
|
|
@return The reversed direction.
|
|
"""
|
|
h: Angle = self.horizontal + Angle.Degrees(-180)
|
|
v: Angle = -self.vertical
|
|
return Direction(h, v)
|
|
def Inverse(self):
|
|
"""! This is a synonym for negation
|
|
"""
|
|
return -self
|
|
|
|
def Normalize(self):
|
|
"""! Normalize this vector to the specified ranges
|
|
@note Should not be needed but available in case it is.
|
|
"""
|
|
v = self.vertical.InDegrees()
|
|
deg180 = Angle.Degrees(-180)
|
|
if v > 90 or v < -90:
|
|
self.horizontal += deg180
|
|
self.vertical = deg180 - self.vertical
|
|
|
|
def __repr__(self):
|
|
return f"Direction(x={self.horizontal}, y={self.vertical})"
|
|
|
|
Direction.zero = Direction.Degrees(0, 0)
|
|
Direction.forward = Direction.Degrees(0, 0)
|
|
Direction.backward = Direction.Degrees(-180, 0)
|
|
Direction.up = Direction.Degrees(0, 90)
|
|
Direction.down = Direction.Degrees(0, -90)
|
|
Direction.left = Direction.Degrees(-90, 0)
|
|
Direction.right = Direction.Degrees(90, 0) |