import typing
import numpy as np
from aerocaps.geom.point import Point3D, Origin3D, Point2D, Origin2D
from aerocaps.units.length import Length
from aerocaps.units.unit import Unit
__all__ = [
"Vector2D",
"Vector3D",
"IHat2D",
"JHat2D",
"IHat3D",
"JHat3D",
"KHat3D"
]
[docs]
class Vector2D:
[docs]
def __init__(self, p0: Point2D, p1: Point2D):
self.p0 = p0
self.p1 = p1
def value(self):
return [self.p1.x - self.p0.x, self.p1.y - self.p0.y]
def normalized_value(self) -> typing.List[float]:
mag = self.mag()
return [xy / mag for xy in self.value()]
def get_normalized_vector(self) -> "Vector2D":
return Vector2D.from_array(np.array(self.normalized_value()))
def scale(self, factor: float) -> "Vector2D":
return Vector2D(self.p0, factor * (self.p1 - self.p0))
def as_array(self):
return np.array([xyz.m for xyz in self.value()])
@classmethod
def from_array(cls, arr: np.ndarray):
return cls(p0=Origin2D(), p1=Point2D.from_array(arr))
def is_zero_vector(self) -> bool:
return np.all(np.isclose(self.as_array(), 0.0))
def dot(self, other: "Vector2D") -> float or Unit:
A = self.value()
B = other.value()
return A[0] * B[0] + A[1] * B[1]
def mag(self) -> Length:
return Length(m=np.sqrt(np.sum(self.as_array()**2)))
def __mul__(self, other):
if isinstance(other, float) or isinstance(other, int):
return Vector2D.from_array(other * self.as_array())
raise NotImplementedError(f"Vector scaling is currently only implemented for int and float data")
def __rmul__(self, other):
if isinstance(other, float) or isinstance(other, int):
return Vector2D.from_array(other * self.as_array())
raise NotImplementedError(f"Vector scaling is currently only implemented for int and float data")
[docs]
class Vector3D:
[docs]
def __init__(self, p0: Point3D, p1: Point3D):
self.p0 = p0
self.p1 = p1
def value(self):
return [self.p1.x - self.p0.x, self.p1.y - self.p0.y, self.p1.z - self.p0.z]
def normalized_value(self) -> typing.List[float]:
mag = self.mag()
return [xyz / mag for xyz in self.value()]
def get_normalized_vector(self) -> "Vector3D":
return Vector3D.from_array(np.array(self.normalized_value()))
def scale(self, factor: float) -> "Vector3D":
return Vector3D(self.p0, factor * (self.p1 - self.p0))
def as_array(self):
return np.array([xyz.m for xyz in self.value()])
def is_zero_vector(self) -> bool:
return np.all(np.isclose(self.as_array(), 0.0))
@classmethod
def from_array(cls, arr: np.ndarray):
return cls(p0=Origin3D(), p1=Point3D.from_array(arr))
def cross(self, other: "Vector3D") -> "Vector3D":
return Vector3D(p0=Origin3D(),
p1=Point3D.from_array(
np.cross(self.as_array(), other.as_array())
))
def dot(self, other: "Vector3D") -> float or Unit:
A = self.value()
B = other.value()
return A[0] * B[0] + A[1] * B[1] + A[2] * B[2]
def mag(self) -> Length:
return Length(m=np.sqrt(np.sum(self.as_array()**2)))
def __mul__(self, other):
if isinstance(other, float) or isinstance(other, int):
return Vector3D.from_array(other * self.as_array())
raise NotImplementedError(f"Vector scaling is currently only implemented for int and float data")
def __rmul__(self, other):
if isinstance(other, float) or isinstance(other, int):
return Vector3D.from_array(other * self.as_array())
raise NotImplementedError(f"Vector scaling is currently only implemented for int and float data")
[docs]
class IHat2D(Vector2D):
[docs]
def __init__(self):
super().__init__(p0=Origin2D(), p1=Point2D.from_array(np.array([1.0, 0.0])))
[docs]
class JHat2D(Vector2D):
[docs]
def __init__(self):
super().__init__(p0=Origin2D(), p1=Point2D.from_array(np.array([0.0, 1.0])))
[docs]
class IHat3D(Vector3D):
[docs]
def __init__(self):
super().__init__(p0=Origin3D(), p1=Point3D.from_array(np.array([1.0, 0.0, 0.0])))
[docs]
class JHat3D(Vector3D):
[docs]
def __init__(self):
super().__init__(p0=Origin3D(), p1=Point3D.from_array(np.array([0.0, 1.0, 0.0])))
[docs]
class KHat3D(Vector3D):
[docs]
def __init__(self):
super().__init__(p0=Origin3D(), p1=Point3D.from_array(np.array([0.0, 0.0, 1.0])))