mbcp/mbcp/mp_math/vector.py
2024-08-27 21:59:04 +08:00

230 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import math
from typing import overload, TYPE_CHECKING
from .mp_math_typing import RealNumber
from .point import Point3
if TYPE_CHECKING:
from .angle import AnyAngle
class Vector3:
def __init__(self, x: float, y: float, z: float):
"""
3维向量
Args:
x: x轴分量
y: y轴分量
z: z轴分量
"""
self.x = x
self.y = y
self.z = z
def cal_angle(self, other: 'Vector3') -> 'AnyAngle':
"""
计算两个向量之间的夹角。
Args:
other: 另一个向量
Returns:
夹角
"""
return AnyAngle(math.acos(self @ other / (self.length * other.length)), is_radian=True)
def is_parallel(self, other: 'Vector3') -> bool:
"""
判断两个向量是否平行。
Args:
other: 另一个向量
Returns:
是否平行
"""
return self.cross(other) == Vector3(0, 0, 0)
def cross(self, other: 'Vector3') -> 'Vector3':
"""
向量积 叉乘v1 cross v2 -> v3
返回如下行列式的结果:
``i j k``
``x1 y1 z1``
``x2 y2 z2``
Args:
other:
Returns:
行列式的结果
"""
return Vector3(self.y * other.z - self.z * other.y,
self.z * other.x - self.x * other.z,
self.x * other.y - self.y * other.x)
def normalize(self):
"""
将向量归一化。
自体归一化,不返回值。
"""
length = self.length
self.x /= length
self.y /= length
self.z /= length
@property
def length(self) -> float:
"""
向量的模。
Returns:
"""
return math.sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2)
@property
def unit(self) -> 'Vector3':
"""
获取该向量的单位向量。
Returns:
单位向量
"""
return self / self.length
@overload
def __add__(self, other: 'Vector3') -> 'Vector3':
...
@overload
def __add__(self, other: 'Point3') -> 'Point3':
...
def __add__(self, other):
"""
V + P -> P\n
V + V -> V
Args:
other:
Returns:
"""
if isinstance(other, Vector3):
return Vector3(self.x + other.x, self.y + other.y, self.z + other.z)
elif isinstance(other, Point3):
return Point3(self.x + other.x, self.y + other.y, self.z + other.z)
else:
raise TypeError(f"unsupported operand type(s) for +: 'Vector3' and '{type(other)}'")
def __eq__(self, other):
"""
判断两个向量是否相等。
Args:
other:
Returns:
是否相等
"""
return self.x == other.x and self.y == other.y and self.z == other.z
def __radd__(self, other: 'Point3') -> 'Point3':
"""
P + V -> P\n
别去点那边实现了。
:param other:
:return:
"""
return Point3(self.x + other.x, self.y + other.y, self.z + other.z)
@overload
def __sub__(self, other: 'Vector3') -> 'Vector3':
...
@overload
def __sub__(self, other: 'Point3') -> "Point3":
...
def __sub__(self, other):
"""
V - P -> P\n
V - V -> V
Args:
other:
Returns:
"""
if isinstance(other, Vector3):
return Vector3(self.x - other.x, self.y - other.y, self.z - other.z)
elif isinstance(other, Point3):
return Point3(self.x - other.x, self.y - other.y, self.z - other.z)
else:
raise TypeError(f"unsupported operand type(s) for -: \"Vector3\" and \"{type(other)}\"")
def __rsub__(self, other: 'Point3'):
"""
P - V -> P
Args:
other:
Returns:
"""
if isinstance(other, Point3):
return Point3(other.x - self.x, other.y - self.y, other.z - self.z)
else:
raise TypeError(f"unsupported operand type(s) for -: '{type(other)}' and 'Vector3'")
@overload
def __mul__(self, other: 'Vector3') -> 'Vector3':
...
@overload
def __mul__(self, other: RealNumber) -> 'Vector3':
...
def __mul__(self, other: 'int | float | Vector3') -> 'Vector3':
"""
数组运算 非点乘。点乘使用@叉乘使用cross。
Args:
other:
Returns:
"""
if isinstance(other, Vector3):
return Vector3(self.x * other.x, self.y * other.y, self.z * other.z)
elif isinstance(other, (float, int)):
return Vector3(self.x * other, self.y * other, self.z * other)
else:
raise TypeError(f"unsupported operand type(s) for *: 'Vector3' and '{type(other)}'")
def __rmul__(self, other: 'RealNumber') -> 'Vector3':
return self.__mul__(other)
def __matmul__(self, other: 'Vector3') -> float:
"""
点乘。
Args:
other:
Returns:
"""
return self.x * other.x + self.y * other.y + self.z * other.z
def __truediv__(self, other: RealNumber) -> 'Vector3':
return Vector3(self.x / other, self.y / other, self.z / other)
def __neg__(self):
return Vector3(-self.x, -self.y, -self.z)
def __repr__(self):
return f"Vector3({self.x}, {self.y}, {self.z})"
def __str__(self):
return f"Vector3({self.x}, {self.y}, {self.z})"
zero_vector3 = Vector3(0, 0, 0)
"""零向量"""
x_axis = Vector3(1, 0, 0)
"""x轴单位向量"""
y_axis = Vector3(0, 1, 0)
"""y轴单位向量"""
z_axis = Vector3(0, 0, 1)
"""z轴单位向量"""