``pooltool.ptmath.utils`` ========================= .. py:module:: pooltool.ptmath.utils Functions --------- .. py:function:: solve_transcendental(f: collections.abc.Callable[[float], float], a: float, b: float, tol: float = 1e-05, max_iter: int = 100) -> float Solve transcendental equation f(x) = 0 in interval [a, b] using bisection method :param f: A function representing the transcendental equation. :param a: The lower bound of the interval. :param b: The upper bound of the interval. :param tol: The tolerance level for the solution. The function stops when the absolute difference between the upper and lower bounds is less than tol. :param max_iter: The maximum number of iterations to perform. :returns: The approximate root of f within the interval [a, b]. :raises ValueError: If f(a) and f(b) have the same sign, indicating no root within the interval. :raises RuntimeError: If the maximum number of iterations is reached without convergence. .. py:function:: convert_2D_to_3D(array: numpy.typing.NDArray[numpy.float64]) -> numpy.typing.NDArray[numpy.float64] Convert a 2D vector to a 3D vector, setting z=0 .. py:function:: wiggle(x: float, val: float) Vary a float or int x by +- val according to a uniform distribution .. py:function:: are_points_on_same_side(p1, p2, p3, p4) -> bool Are points p3, p4 are on the same side of the line formed by points p1 and p2? Accepts indexable objects. This is a 2D function, but if higher dimensions are provided, that's ok (only the first two dimensions will be used). .. py:function:: find_intersection_2D(l1x: float, l1y: float, l10: float, l2x: float, l2y: float, l20: float) -> tuple[float, float] Find the intersection point of two lines in 2D space The lines are defined by their linear equations in the general form: (l1x)x + (l1y)y + l10 = 0 and (l2x)x + (l2y)y + l20 = 0. :param l1x: The coefficient of x in the first line equation. :param l1y: The coefficient of y in the first line equation. :param l10: The constant term in the first line equation. :param l2x: The coefficient of x in the second line equation. :param l2y: The coefficient of y in the second line equation. :param l20: The constant term in the second line equation. :returns: A tuple (x, y) representing the intersection point if the lines intersect at a single point. Returns None if the lines are parallel or coincident (no unique intersection). .. py:function:: cross(u: numpy.typing.NDArray[numpy.float64], v: numpy.typing.NDArray[numpy.float64]) -> numpy.typing.NDArray[numpy.float64] Compute cross product u x v, where u and v are 3-dimensional vectors (just-in-time compiled) .. py:function:: unit_vector_slow(vector: numpy.typing.NDArray[numpy.float64], handle_zero: bool = False) -> numpy.typing.NDArray[numpy.float64] Returns the unit vector of the vector. "Slow", but supports more than just 3D. :param handle_zero: If True and vector = <0,0,0>, <0,0,0> is returned. .. py:function:: unit_vector(vector: numpy.typing.NDArray[numpy.float64], handle_zero: bool = False) -> numpy.typing.NDArray[numpy.float64] Returns the unit vector of the vector (just-in-time compiled) :param handle_zero: If True and vector = <0,0,0>, <0,0,0> is returned. .. admonition:: Notes - Only supports 3D (for 2D see unit_vector_slow) .. py:function:: angle(v2: numpy.typing.NDArray[numpy.float64], v1: numpy.typing.NDArray[numpy.float64] = np.array([1, 0])) -> float Returns counter-clockwise angle of projections of v1 and v2 onto the x-y plane (just-in-time compiled) .. py:function:: angle_between_vectors(a: numpy.typing.NDArray[numpy.float64], b: numpy.typing.NDArray[numpy.float64]) -> float Compute the angle between two 3D vectors in radians. :returns: The angle between vectors a and b in radians. Can take on values within [0, pi]. .. py:function:: rotation_from_vector_to_vector(a: numpy.typing.NDArray[numpy.float64], b: numpy.typing.NDArray[numpy.float64]) -> scipy.spatial.transform.Rotation Compute the rotation that transforms vector a to vector b. :returns: A scipy Rotation object representing the rotation from a to b. .. py:function:: quaternion_from_vector_to_vector(a: numpy.typing.NDArray[numpy.float64], b: numpy.typing.NDArray[numpy.float64]) -> Any Compute the quaternion representing the rotation from vector a to vector b :param a: Initial 3D vector :param b: Target 3D vector :returns: A quaternion representing the rotation from a to b. .. py:function:: coordinate_rotation(v: numpy.typing.NDArray[numpy.float64], phi: float) -> numpy.typing.NDArray[numpy.float64] Rotate vector/matrix from one frame of reference to another (3D FIXME) (just-in-time compiled) .. py:function:: decompose_normal_tangent(v: numpy.typing.NDArray[numpy.float64], n: numpy.typing.NDArray[numpy.float64], flip_tangent_direction: bool = False) -> tuple[float, float, numpy.typing.NDArray[numpy.float64]] Decomposes a vector into normal and tangent components given the unit normal direction :returns: Tuple of decomposed components and directions, ``(v_n, v_t, t)``. ``v_n`` is the signed component in the normal direction, ``v_t`` is the signed component in the tangent component, and ``t`` is the unit tangent direction. The unit normal direction isn't returned, since it's passed as an argument. .. py:function:: point_on_line_closest_to_point(p1: numpy.typing.NDArray[numpy.float64], p2: numpy.typing.NDArray[numpy.float64], p0: numpy.typing.NDArray[numpy.float64]) -> numpy.typing.NDArray[numpy.float64] Returns point on line defined by points p1 and p2 closest to the point p0 Equations from https://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html .. py:function:: squared_norm3d(vec: numpy.typing.NDArray[numpy.float64]) -> float Calculate the squared norm of a 3D vector .. py:function:: norm3d(vec: numpy.typing.NDArray[numpy.float64]) -> float Calculate the norm of a 3D vector This is ~10x faster than np.linalg.norm >>> import numpy as np >>> from pooltool.ptmath import * >>> vec = np.random.rand(3) >>> norm3d(vec) >>> %timeit np.linalg.norm(vec) >>> %timeit norm3d(vec) 2.65 µs ± 63 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each) 241 ns ± 2.57 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each) .. py:function:: squared_norm2d(vec: numpy.typing.NDArray[numpy.float64]) -> float Calculate the squared norm of a 2D vector .. py:function:: norm2d(vec: numpy.typing.NDArray[numpy.float64]) -> float Calculate the norm of a 2D vector This is faster than np.linalg.norm .. py:function:: is_overlapping(rvw1: numpy.typing.NDArray[numpy.float64], rvw2: numpy.typing.NDArray[numpy.float64], R1: float, R2: float, min_spacer: float = 0.0) -> bool