''' Vector (numpy array) related functions
Vector tools for numpy array.
Most of the funcitons (are intended to) support the
2-D (or >2-D) array, namely, (N, 3) (or (N0, N1, ..., 3)) array.
Related modules:
- :mod:`irfpy.util.cone`
.. codeauthor:: Yoshifumi Futaana
.. autosummary::
distance_to_cylinder_center
cone_angle
'''
import numpy as np
[docs]def distance_to_cylinder_center(vector, center_axis, cylinder_center=(0, 0, 0)):
r""" Calculate the distance to the center axis of the cylinder.
Calculate the distance between a given vector, **v**,
and the center of the given cylinder.
The cylinder is defined by a vector, cylinder_center **p**,
together with the axis vector, center_axis **n**.
:param vector: Vector(s) for which the distance(s) are calculated. (3,) or (..., 3) array.
:keyword cylinder_center: Specifies the center of the cylinder. A single point on the axis. (3,) array
:param cylinder_axis: Specifies the axis vector of the cylinder. A single vector. (3,) array.
Examples follow.
>>> p = (2, 1, 0)
>>> n = (0, 0.5, 0)
>>> v = (0, 0, 0)
>>> distance_to_cylinder_center(v, n, cylinder_center=p)
2.0
>>> v = (2, 0, 0)
>>> distance_to_cylinder_center(v, n, cylinder_center=p)
0.0
>>> v = [(0, 0, 0), (0, 1, 0), (1, 0, 0), (0, 0, 1)]
>>> distance_to_cylinder_center(v, n, cylinder_center=p) # doctest: +NORMALIZE_WHITESPACE
array([2. , 2. , 1. , 2.23606798])
The implementaion is as follows.
First, the cylinder_center is translated to the origin (0, 0, 0).
The transformation does not change the center axis, **n**, but
the given vector **v** is converted to :math:`\vec{v}' = \vec{v} - \vec{p}`.
The distance *d* is now calculated by :math:`d = |v'| \sin\alpha` where :math:`\alpha` is
the angle between the **v'** and **n** vectors.
Thus, :math:`\cos\alpha = \vec{v'}\cdot{n} / |v'||n|`, and therefore, the distance is
.. math::
d = |v'| \sin\alpha = |v'| \sqrt{1 - \cos^2\alpha} \\
= \sqrt{|v'|^2 - \frac{\vec{n}\cdot\vec{v'}}{|n|^2}}
"""
p = np.array(cylinder_center)
n = np.array(center_axis)
v = np.array(vector)
nn = n # (3,)
vv = v - p # (3,) or (..., 3)
nnvv = vv.dot(nn) # (1,) or (...)
rr2 = vv[..., 0] ** 2 + vv[..., 1] ** 2 + vv[..., 2] ** 2
nn2 = (nn ** 2).sum()
x2 = rr2 - (nnvv ** 2) / nn2
x = np.sqrt(x2)
return x
[docs]def cone_angle(vector, cone_axis, cone_center=(0, 0, 0)):
""" Return cone angle in radians.
:param vector: Vector for input. (3, ) or (..., 3) array
:param cone_axis: Vector of the axis, along the line.
:param cone_center: The top of the cone.
:return: The cone angle in radians. Scalar or (...) shaped.
>>> p = (1, 3, 0)
>>> a = (0, 2, 0)
>>> v = (1, 0, 0)
>>> print(np.rad2deg(cone_angle(v, a, cone_center=p)))
180.0
>>> v = (1, 4, 0)
>>> print(np.rad2deg(cone_angle(v, a, cone_center=p)))
0.0
>>> v = [(1, 0, 0), (1, 1, 0), (1, 2, 0), (1, 4, 0), (2, 3, 0)]
>>> print(np.rad2deg(cone_angle(v, a, cone_center=p))) # doctest: +NORMALIZE_WHITESPACE
[180. 180. 180. 0. 90.]
>>> v = [2, 3, 0]
"""
v = np.array(vector)
n = np.array(cone_axis)
p = np.array(cone_center)
vv = v - p
n = n / np.sqrt((n ** 2).sum())
return np.arccos(np.clip(vv.dot(n), -1, 1))