import numpy as np
[docs]class Vector:
"""
A class for representing Cartesian vectors with ``x``, ``y`` and ``z``
components that are either ``float`` or ``numpy.array`` objects of
identical size.
Attributes
----------
x : float or numpy.ndarray
The x component(s)
y : float or numpy.ndarray
The y component(s)
z : float or numpy.ndarray
The z component(s)
"""
[docs] def __init__(self, x, y, z):
"""
A class for representing Cartesian vectors with ``x``, ``y`` and ``z``
components that are either ``float`` or ``numpy.array`` objects of
identical size.
Parameters
----------
x : float or numpy.ndarray
The x component(s)
y : float or numpy.ndarray
The y component(s)
z : float or numpy.ndarray
The z component(s)
"""
self.x = x
self.y = y
self.z = z
def angular_distance(self, other):
"""
Compute angular distance between points on the sphere, following:
https://en.wikipedia.org/wiki/Great-circle_distance
Parameters
----------
other : mpas_tools.vector.Vector
The vector to compute the angular distance to
Returns
-------
angularDistance : numpy.ndarray
The angular distance (in radians) between segments of the transect.
"""
angular_distance = np.arctan2(self.cross(other).mag(), self.dot(other))
return angular_distance
@staticmethod
def intersects(a1, a2, b1, b2):
"""
Based on https://stackoverflow.com/a/26669130/7728169
Determine if the great circle arc from ``a1`` to ``a2`` intersects that
from ``b1`` to ``b2``.
Parameters
----------
a1 : mpas_tools.vector.Vector
Cartesian coordinates of the end point of a great circle arc.
The types of the attributes ``x``, ``y``, and ``z`` must either be
``numpy.arrays`` of identical size for all 4 vectors (in which case
intersections are found element-wise), or scalars for
at least one of either ``a1`` and ``a2`` or ``b1`` and ``b2``.
a2 : mpas_tools.vector.Vector
Cartesian coordinates of the other end point of a great circle arc.
b1 : mpas_tools.vector.Vector
Cartesian coordinates of an end point of a second great circle arc.
b2 : mpas_tools.vector.Vector
Cartesian coordinates of the other end point of the second great
circle arc.
Returns
-------
intersect : numpy.ndarray
A boolean array of the same size as ``a1`` and ``a2`` or ``b1`` and
``b2``, whichever is greater, indicating if the particular pair of
arcs intersects
"""
return np.logical_and(Vector.straddles(a1, a2, b1, b2),
Vector.straddles(b1, b2, a1, a2))
@staticmethod
def intersection(a1, a2, b1, b2):
"""
Based on https://stackoverflow.com/a/26669130/7728169
Find the intersection point as a unit vector between great circle arc
from ``a1`` to ``a2`` and from ``b1`` to ``b2``. The arcs should have
already have been found to intersect by calling ``intersects()``
Parameters
----------
a1 : mpas_tools.vector.Vector
Cartesian coordinates of the end point of a great circle arc.
The types of the attributes ``x``, ``y``, and ``z`` must either be
``numpy.arrays`` of identical size for all 4 vectors (in which case
intersections are found element-wise), or scalars for
at least one of either ``a1`` and ``a2`` or ``b1`` and ``b2``.
a2 : mpas_tools.vector.Vector
Cartesian coordinates of the other end point of a great circle arc.
b1 : mpas_tools.vector.Vector
Cartesian coordinates of an end point of a second great circle arc.
b2 : mpas_tools.vector.Vector
Cartesian coordinates of the other end point of the second great
circle arc.
Returns
-------
points : mpas_tools.vector.Vector
An array of Cartesian points *on the unit sphere* indicating where
the arcs intersect
"""
points = (a1.cross(a2)).cross(b1.cross(b2))
s = np.sign(Vector.det(a1, b1, b2))/points.mag()
points = Vector(s*points.x, s*points.y, s*points.z)
return points
@staticmethod
def straddles(a1, a2, b1, b2):
"""
Based on https://stackoverflow.com/a/26669130/7728169
Determines if the great circle segment determined by (a1, a2)
straddles the great circle determined by (b1, b2)
Parameters
----------
a1: mpas_tools.vector.Vector
Cartesian coordinates of first end point of first great circle arc.
The types of the attributes ``x``, ``y``, and ``z`` must either be
``numpy.arrays`` of identical size for all 4 vectors (in which case
intersections are found element-wise), or scalars for
at least one of either the ``a``s or the ``b``s.
a2 : mpas_tools.vector.Vector
Second end point of first great circle arc.
b1 : mpas_tools.vector.Vector
First end point of second great circle arc.
b2 : mpas_tools.vector.Vector
Second end point of second great circle arc.
Returns
-------
straddle : numpy.ndarray
A boolean array of the same size as the ``a``s or the ``b``s, whichever
is greater, indicating if the great circle segment determined by
(a1, a2) straddles the great circle determined by (b1, b2)
"""
return Vector.det(a1, b1, b2) * Vector.det(a2, b1, b2) < 0
def dot(self, other):
"""
Compute the dot product between this vector and ``other``.
Parameters
----------
other : mpas_tools.vector.Vector
The other vector
Returns
-------
dot_product : numpy.ndarray
The dot product
"""
return self.x * other.x + self.y * other.y + self.z * other.z
def cross(self, other):
"""
Compute the dot product between this vector and ``other``.
Parameters
----------
other : mpas_tools.vector.Vector
The other vector
Returns
-------
cross_product : mpas_tools.vector.Vector
The cross product
"""
return Vector(self.y * other.z - self.z * other.y,
self.z * other.x - self.x * other.z,
self.x * other.y - self.y * other.x)
@staticmethod
def det(v1, v2, v3):
"""
The determinant of the matrix defined by the three ``Vector`` objects
Parameters
----------
v1 : mpas_tools.vector.Vector
First row of the matrix
v2 : mpas_tools.vector.Vector
Second row
v3 : mpas_tools.vector.Vector
Third row
Returns
-------
determinant : numpy.ndarray
The determinant of the matrix
"""
return v1.dot(v2.cross(v3))
def mag(self):
"""
The magnitude of the vector
Returns
-------
magnitude : numpy.ndarray
The magnitude of the vector
"""
return np.sqrt(self.dot(self))