Source code for irfpy.jna.frame1

r''' A frame definition.  JNA frame and SC frame is supported.

JNA frame and SC frame conversion is supported.
Since they are rigidly related, implementation is simple.

*   Xjna = Xsc
*   Yjna = Zsc
*   Zjna = -Ysc

.. note::

    The definition of JNA frame (frame1) differs from the
    definition of JNA frame (:mod:`irfpy.jna.frame0`).
    (It has flipped 180 degrees around y.)

There is also a definition of angles: |theta| and |phi|.
This is based on the CENA definition (:ref:`sara:cenacalrep`).
The functions :func:`jna2angles` and :func:`angles2jna` will
convert them each other.

.. |theta| replace:: :math:`\theta`
.. |phi| replace:: :math:`\phi`
'''

import math
import numpy
import numpy as np
from irfpy.util.vector3d import Vector3d

[docs]def jna2nsc(vec): ''' JNA to SC. :param vec: Vector in JNA frame. (3,) or (3, N) shaped numpy array. >>> r_jna = np.array([1, 3, 5]) >>> r_nsc = jna2nsc(r_jna) >>> print(r_nsc) [ 1 -5 3] Multiple vector conversion is supported. Shape should be (3, N), where N is the number of vectors. The returned is also (3, N) shape. >>> rs_jna = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]) >>> print(rs_jna.shape) (3, 5) >>> rs_nsc = jna2nsc(rs_jna) >>> print(rs_nsc.shape) (3, 5) >>> print(rs_nsc[:, 0]) [ 1 -11 6] ''' if np.array(vec).shape[0] != 3: raise IndexError('The vec should have shape (3,) or (3, N)') return np.array([vec[0], -vec[2], vec[1]])
[docs]def nsc2jna(vec): ''' SC frame vector, vec, is converted to JNA frame. :param vec: Vector in NSC frame. (3,) or (3, N) shaped numpy array. >>> r_jna = np.array([-1, 2, 8]) >>> r_nsc = nsc2jna(r_jna) >>> print(r_nsc) [-1 8 -2] ''' if np.array(vec).shape[0] != 3: raise IndexError('The vec should have shape (3,) or (3, N)') return np.array([vec[0], vec[2], -vec[1]])
[docs]def jna2sc(vec): ''' Conversion from JNA frame to Spacecraft frame. Input is a Vector3d instance or array-like. Return is Vector3d or numpy.array. >>> vjna = Vector3d(1,2,3) # v is in the JNA frame >>> vsc = jna2sc(vjna) >>> print(vsc.x, vsc.y, vsc.z) 1 -3 2 >>> vjna = [-1, -2, -3] >>> vsc = jna2sc(vjna) # Return is numpy.array >>> print(vsc.shape) (3,) >>> print(vsc) [-1 3 -2] ''' if isinstance(vec, Vector3d): sc = Vector3d(vec.x, -vec.z, vec.y) else: sc = numpy.array([vec[0], -vec[2], vec[1]]) return sc
[docs]def sc2jna(vec): ''' Conversion from SC frame to JNA frame. Input is a Vector3d instance or array-like. Return is Vector3d or numpy.array. >>> vsc = Vector3d(1,2,3) >>> vjna = sc2jna(vsc) >>> print(vjna.x, vjna.y, vjna.z) 1 3 -2 >>> vsc = [-1, -2, -3] >>> vjna = sc2jna(vsc) # Return is numpy.array >>> print(vjna.shape) (3,) >>> print(vjna) [-1 -3 2] ''' if isinstance(vec, Vector3d): jna = Vector3d(vec.x, vec.z, -vec.y) else: jna = numpy.array([vec[0], vec[2], -vec[1]]) return jna
[docs]def get_sc2jna_matrix(): ''' >>> vsc = [-1, -2, -3] >>> m = get_sc2jna_matrix() >>> print(m.dot(vsc)) [-1 -3 2] ''' return numpy.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]])
[docs]def jna2angles2(xarr, yarr, zarr): ''' Return the JNA-angle from vector See definition of angle in :func:`jna2angles`. :param xarr: X cooridnates (array also acceptable) :param yarr: Y cooridnates (array also acceptable) :param zarr: Z cooridnates (array also acceptable) >>> theta, phi = jna2angles2([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, -1]) >>> theta = np.rad2deg(theta) >>> phi = np.rad2deg(phi) >>> print('%.2f %.2f %.2f %.2f' % (theta[0], theta[1], theta[2], theta[3])) 0.00 0.00 -90.00 90.00 >>> print('%.2f %.2f %.2f %.2f' % (phi[0], phi[1], phi[2], phi[3])) 90.00 0.00 0.00 0.00 ''' x = np.array(xarr) y = np.array(yarr) z = np.array(zarr) r = np.sqrt(x * x + y * y + z * z) x = x / r y = y / r z = z / r theta = np.pi / 2. - np.arccos(-z) phi = np.arctan2(x, y) return theta, phi
[docs]def jna2angles(vec, degrees=False): ''' Conversion in JNA frame from a vector to SC frame in angles. The input is array-like or Vector3d instance. The output is a pair of the angle, (|theta|, |phi|), defined as follows. The unit is the radian unless degrees argument is set. |theta| is defined as follows: |theta| =0 is in x-y plane of JNA frame and positive for negative Z. |phi| is define as follows: +y is 0, and +x is 90 degrees. >>> jna2angles([1, 0, 0], degrees=True) (0.0, 90.0) >>> jna2angles([0, 1, 0], degrees=True) (0.0, 0.0) >>> jna2angles([0, 0, 1], degrees=True) (-90.0, 0.0) >>> jna2angles([0, 0, -1], degrees=True) (90.0, 0.0) ''' x = vec[0] y = vec[1] z = vec[2] v = Vector3d(x, y, z) v.normalize() minus_z = Vector3d(0, 0, -1) theta = math.pi/2. - v.angle(minus_z) phi = math.atan2(x, y) if degrees: theta = theta * 180 / math.pi phi= phi * 180 / math.pi return (theta, phi)
[docs]def angles2jna(theta, phi, degrees=False, vector3d=False): ''' Conversion from angles to vectors for JNA frame. See :meth:`jna2angles` for definition of angles. Input is two angles. If degrees is set, the given angles are considered as in degrees. Otherwise, they are considered as radians. Output is the instance of numpy.array for default, or irfpy.util.vector3d.Vector3d if vector3d option is set. >>> v = angles2jna(0, 90, degrees=True, vector3d=True) >>> v_exp = Vector3d(1, 0, 0) >>> v_exp.sub(v) >>> print(v_exp.length() < 1e-5) True >>> v = angles2jna(0, 0, degrees=True, vector3d=True) >>> v_exp = Vector3d(0, 1, 0) >>> v_exp.sub(v) >>> print(v_exp.length() < 1e-5) True >>> v = angles2jna(-90, 0, degrees=True, vector3d=True) >>> v_exp = Vector3d(0, 0, 1) >>> v_exp.sub(v) >>> print(v_exp.length() < 1e-5) True >>> v = angles2jna(90, 0, degrees=True, vector3d=True) >>> v_exp = Vector3d(0, 0, -1) >>> v_exp.sub(v) >>> print(v_exp.length() < 1e-5) True ''' t = theta p = phi if degrees: t = t * math.pi / 180. p = p * math.pi / 180. z = -math.sin(t) y = math.cos(t) * math.cos(p) x = math.cos(t) * math.sin(p) if vector3d: return Vector3d(x, y, z) else: return numpy.array([x, y, z])