Source code for yt.utilities.orientation

import numpy as np

from yt.units.yt_array import YTArray
from yt.utilities.exceptions import YTException


def _aligned(a, b):
    aligned_component = np.abs(np.dot(a, b) / np.linalg.norm(a) / np.linalg.norm(b))
    return np.isclose(aligned_component, 1.0, 1.0e-13)


def _validate_unit_vectors(normal_vector, north_vector):
    # Make sure vectors are unitless
    if north_vector is not None:
        north_vector = YTArray(north_vector, "", dtype="float64")
    if normal_vector is not None:
        normal_vector = YTArray(normal_vector, "", dtype="float64")

    if not np.dot(normal_vector, normal_vector) > 0:
        raise YTException("normal_vector cannot be the zero vector.")
    if north_vector is not None and _aligned(north_vector, normal_vector):
        raise YTException("normal_vector and north_vector cannot be aligned.")

    return normal_vector, north_vector


[docs] class Orientation: def __init__(self, normal_vector, north_vector=None, steady_north=False): r"""An object that returns a set of basis vectors for orienting cameras a data containers. Parameters ---------- normal_vector : array_like A vector normal to the image plane north_vector : array_like, optional The 'up' direction to orient the image plane. If not specified, gets calculated automatically steady_north : bool, optional Boolean to control whether to normalize the north_vector by subtracting off the dot product of it and the normal vector. Makes it easier to do rotations along a single axis. If north_vector is specified, is switched to True. Default: False """ normal_vector, north_vector = _validate_unit_vectors( normal_vector, north_vector ) self.steady_north = steady_north if north_vector is not None: self.steady_north = True self.north_vector = north_vector self._setup_normalized_vectors(normal_vector, north_vector) if self.north_vector is None: self.north_vector = self.unit_vectors[1] def _setup_normalized_vectors(self, normal_vector, north_vector): normal_vector, north_vector = _validate_unit_vectors( normal_vector, north_vector ) # Now we set up our various vectors normal_vector /= np.sqrt(np.dot(normal_vector, normal_vector)) if north_vector is None: vecs = np.identity(3) t = np.cross(normal_vector, vecs).sum(axis=1) ax = t.argmax() east_vector = np.cross(vecs[ax, :], normal_vector).ravel() # self.north_vector must remain None otherwise rotations about a fixed axis # will break. The north_vector calculated here will still be included # in self.unit_vectors. north_vector = np.cross(normal_vector, east_vector).ravel() else: if self.steady_north or (np.dot(north_vector, normal_vector) != 0.0): north_vector = ( north_vector - np.dot(north_vector, normal_vector) * normal_vector ) east_vector = np.cross(north_vector, normal_vector).ravel() north_vector /= np.sqrt(np.dot(north_vector, north_vector)) east_vector /= np.sqrt(np.dot(east_vector, east_vector)) self.normal_vector = normal_vector self.north_vector = north_vector self.unit_vectors = YTArray([east_vector, north_vector, normal_vector], "") self.inv_mat = np.linalg.pinv(self.unit_vectors)