Source code for pyrobopath.tools.linalg
from __future__ import annotations
import numpy as np
import math
from .types import *
[docs]
def unit_vector(vec: NDArray) -> NDArray:
"""Returns the vector of unit magnitude in the direction of vec
:param vec: the vector to normalize
:type vec: NDArray
:return: vector in the direction of `vec` with magnitude 1
:rtype: NDArray
:raises ValueError: if the input vector has zero magnitude
"""
norm = np.linalg.norm(vec)
if norm == 0:
raise ValueError("Cannot normalize a zero vector")
return vec / norm
[docs]
def unit_vector3(vec: NDArray) -> NDArray:
"""A simple unit vector for vectors of length 3"""
return vec / norm3(vec)
[docs]
def unit_vector2(vec: NDArray) -> NDArray:
"""A simple unit vector for vectors of length 3"""
return vec / norm2(vec)
[docs]
def norm3(v: ArrayLike3) -> float:
"""A simple vector norm for vectors of length 3
~2x as fast as np.linalg.norm()
:param v: a three dimensional vector
:type vec: ArrayLike3
:return: the magnitude of the vector v
:rtype: float
"""
radicand = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]
if radicand == 0:
raise ValueError("Cannot normalize a zero vector")
return math.sqrt(radicand)
[docs]
def norm2(v: ArrayLike2) -> float: # 2x as fast as np.linalg.norm()
"""A simple vector norm for vectors of length 3
~2x as fast as np.linalg.norm()
:param v: a two dimensional vector
:type vec: ArrayLike2
:return: the magnitude of the vector v
:rtype: float
"""
radicand = v[0] * v[0] + v[1] * v[1]
if radicand == 0:
raise ValueError("Cannot normalize a zero vector")
return math.sqrt(radicand)
[docs]
def angle_between(v1: NDArray, v2: NDArray) -> float:
"""Compute the angle between two 3D vectors
Uses the arccosine of the dot product of unit vectors
:param v1: the first 3D vector
:type v1: NDArray
:param v2: the second 3D vector
:type v2: NDArray
:return: the angle between v1 and v2 in radians
:rtype: float
"""
v1_u = unit_vector3(v1)
v2_u = unit_vector3(v2)
return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0))