Source code for pythagoras.r3.vector

from dataclasses import dataclass
from math import cos, hypot, sin
from typing import Self

__all__ = ["Vector3D", "dist3"]


[docs] @dataclass class Vector3D: """ Three-dimensional vector with common operations. Attributes: x: :math:`x` component of the vector. y: :math:`y` component of the vector. z: :math:`z` component of the vector. """ x: float y: float z: float
[docs] @classmethod def from_two_points( cls, p1: tuple[float, float, float], p2: tuple[float, float, float] ) -> Self: """ Constructor for the vector that joins two points. Parameters: p1: Initial point. p2: End point. Returns: The vector that goes from `p1` to `p2`. """ return cls(p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2])
[docs] @classmethod def cylindrical(cls, r: float, theta: float, z: float) -> Self: """ Constructs a vector expressed in cylindrical coordinates. Parameters: r: Magnitude of the projection of the vector onto the :math:`xy` plane. theta: Angle of the projection onto the :math:`xy` plane with respect to the positive :math:`x`-axis. z: :math:`z` component of the vector. Returns: The corresponding vector. """ return cls(r * cos(theta), r * sin(theta), z)
[docs] @classmethod def spherical(cls, rho: float, phi: float, theta: float) -> Self: """ Constructs a vector expressed in spherical coordinates. Parameters: rho: Magnitude of the vector. phi: Angle formed with the positive :math:`z` axis. theta: Angle of the projection onto the :math:`xy` plane with respect to the positive :math:`x`-axis. Returns: The corresponding vector. """ return cls( rho * sin(phi) * cos(theta), rho * sin(phi) * sin(theta), rho * cos(theta) )
def __call__(self) -> tuple[float, float, float]: """Converts the coordinates of the vector to a point.""" return (self.x, self.y, self.z) def __add__(self, other: Self) -> Self: return self.__class__(self.x + other.x, self.y + other.y, self.z + other.z) def __iadd__(self, other: Self) -> Self: self.x += other.x self.y += other.y self.z += other.z return self def __sub__(self, other: Self) -> Self: return self.__class__(self.x - other.x, self.y - other.y, self.z - other.z) def __isub__(self, other: Self) -> Self: self.x -= other.x self.y -= other.y self.z -= other.z return self def __mul__(self, alpha: float) -> Self: return self.__class__(self.x * alpha, self.y * alpha, self.z * alpha) def __rmul__(self, alpha: float) -> Self: return self * alpha def __imul__(self, alpha: float) -> Self: self.x *= alpha self.y *= alpha self.z *= alpha return self def __truediv__(self, alpha: float) -> Self: return self.__class__(self.x / alpha, self.y / alpha, self.z / alpha) def __itruediv__(self, alpha: float) -> Self: self.x /= alpha self.y /= alpha self.z /= alpha return self def __matmul__(self, other: Self) -> float: """Standard inner product.""" return self.x * other.x + self.y * other.y + self.z * other.z def __xor__(self, other: Self) -> Self: """Cross product.""" return self.__class__( 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 __ixor__(self, other: Self) -> Self: x, y, z = self.x, self.y, self.z self.x = y * other.z - z * other.y self.y = z * other.x - x * other.z self.z = x * other.y - y * other.x return self def __neg__(self) -> Self: return self.__class__(-self.x, -self.y, -self.z) def __abs__(self) -> float: """Magnitude of the vector.""" return hypot(self.x, self.y, self.z) def __or__(self: Self, other: Self) -> bool: """Check whether two vectors are parallel.""" if self() == (0, 0) or other() == (0, 0): return False if self.x == 0 and other.x != 0: return False if self.y == 0 and other.y != 0: return False if self.z == 0 and other.z != 0: return False qs = [ o / s for s, o in ((self.x, other.x), (self.y, other.y), (self.z, other.z)) if s != 0 ] return all(qi == qs[0] for qi in qs) @property def unitary(self) -> Self: """ Vector normalized to have unit norm. """ return self / abs(self)
[docs] def dist3(p1: tuple[float, float, float], p2: tuple[float, float, float]) -> float: r""" Computes the Euclidean distance between two points in :math:`\mathbf R^3`. Parameters: p1: First point. p2: Second point. """ return hypot(p1[0] - p2[0], p1[1] - p2[1], p1[2] - p2[2])