from __future__ import annotations
import numpy as np
from fibomat.linalg.vectors import VectorLike, Vector
[docs]def make_perp_vector(vec: VectorLike) -> Vector:
vec = Vector(vec)
return Vector(-vec.y, vec.x)
[docs]class GeomLine:
[docs] def __init__(self, direction: VectorLike, support: VectorLike):
self._direction = np.asarray(Vector(direction))
self._support = np.asarray(Vector(support))
if np.allclose(self._direction, 0.):
raise RuntimeError('direction must not be the null vector.')
[docs] @classmethod
def make_bisector(cls, p_0: VectorLike, p_1: VectorLike):
p_0 = Vector(p_0)
p_1 = Vector(p_1)
return cls(p_1 - p_0, (p_0 + p_1) / 2)
[docs] @classmethod
def make_perp_bisector(cls, p_0: VectorLike, p_1: VectorLike):
p_0 = Vector(p_0)
p_1 = Vector(p_1)
return cls(make_perp_vector(p_1 - p_0), (p_0 + p_1) / 2)
def __call__(self, u):
return self._support + u * self._direction
[docs] def parallel_to(self, other: GeomLine):
return np.isclose(
np.dot(
self._direction / np.linalg.norm(self._direction),
other._direction / np.linalg.norm(other._direction)
), 1.
)
[docs] def intersect_at_param(self, other: GeomLine):
m = np.array([self._direction, -other._direction]).T
b = other._support - self._support
res = np.linalg.solve(m, b)
return res[0]
[docs] def intersect_at(self, other: GeomLine):
res = self.intersect_at_param(other)
return self._support + res * self._direction
[docs] def find_param(self, point: VectorLike):
point = Vector(point)
if np.isclose(self._direction[0], 0.):
if not np.isclose(point.x, self._support[0]):
raise ValueError('point lies not on GeomLine.')
s = (point.y - self._support[1]) / self._direction[1]
elif np.isclose(self._direction[1], 0.):
if not np.isclose(point.y, self._support[1]):
raise ValueError('point lies not on GeomLine.')
s = (point.x - self._support[0]) / self._direction[0]
else:
s_0 = (point.x - self._support[0]) / self._direction[0]
s_1 = (point.y - self._support[1]) / self._direction[1]
if not np.isclose(s_0, s_1):
raise ValueError('point lies not on GeomLine.')
s = s_0
return s