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))