use super::{EulerParameter, DCM};
use crate::astro::PhysicsResult;
use crate::NaifId;
use nalgebra::Vector3;
use ndarray::{Array1, Array2};
use numpy::{PyArray1, PyArray2, PyReadonlyArray1, PyUntypedArrayMethods};
use pyo3::basic::CompareOp;
use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*;
use pyo3::types::PyType;
#[pymethods]
impl EulerParameter {
#[new]
#[pyo3(signature=(w, x, y, z, from_id, to_id))]
fn py_new(w: f64, x: f64, y: f64, z: f64, from_id: NaifId, to_id: NaifId) -> Self {
Self::new(w, x, y, z, from_id, to_id)
}
#[classmethod]
#[pyo3(name="about_x", signature=(angle_rad, from_id, to_id))]
fn py_about_x(
_cls: &Bound<'_, PyType>,
angle_rad: f64,
from_id: NaifId,
to_id: NaifId,
) -> Self {
Self::about_x(angle_rad, from_id, to_id)
}
#[classmethod]
#[pyo3(name="about_y", signature=(angle_rad, from_id, to_id))]
fn py_about_y(
_cls: &Bound<'_, PyType>,
angle_rad: f64,
from_id: NaifId,
to_id: NaifId,
) -> Self {
Self::about_y(angle_rad, from_id, to_id)
}
#[classmethod]
#[pyo3(name="about_z", signature=(angle_rad, from_id, to_id))]
fn py_about_z(
_cls: &Bound<'_, PyType>,
angle_rad: f64,
from_id: NaifId,
to_id: NaifId,
) -> Self {
Self::about_z(angle_rad, from_id, to_id)
}
#[pyo3(name="derivative", signature=(omega_rad_s))]
fn py_derivative<'py>(&self, omega_rad_s: PyReadonlyArray1<'py, f64>) -> PyResult<Self> {
if omega_rad_s.shape() != [3] {
return Err(PyErr::new::<PyTypeError, _>(
"angular velocity vector omega must be 1x3",
));
}
let omega = Vector3::from_row_iterator(omega_rad_s.as_array().iter().copied());
Ok(self.derivative(omega))
}
#[pyo3(name = "b_matrix")]
fn py_b_matrix<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray2<f64>> {
let b: Vec<f64> = self.b_matrix().transpose().iter().copied().collect();
let b_mat = Array2::from_shape_vec((4, 3), b).unwrap();
PyArray2::<f64>::from_owned_array(py, b_mat)
}
#[pyo3(name = "uvec_angle_rad")]
fn py_uvec_angle_rad<'py>(&self, py: Python<'py>) -> (Bound<'py, PyArray1<f64>>, f64) {
let (uvec, angle) = self.uvec_angle_rad();
let data: Vec<f64> = uvec.iter().copied().collect();
let vec = Array1::from_shape_vec((3,), data).unwrap();
(PyArray1::<f64>::from_owned_array(py, vec), angle)
}
#[pyo3(name = "prv")]
fn py_prv<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray1<f64>> {
let data: Vec<f64> = self.prv().iter().copied().collect();
let vec = Array1::from_shape_vec((3,), data).unwrap();
PyArray1::<f64>::from_owned_array(py, vec)
}
#[pyo3(name = "as_vector")]
fn py_as_vector<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray1<f64>> {
let data: Vec<f64> = self.as_vector().iter().copied().collect();
let vec = Array1::from_shape_vec((3,), data).unwrap();
PyArray1::<f64>::from_owned_array(py, vec)
}
fn to_dcm(&self) -> DCM {
DCM::from(*self)
}
#[getter]
fn get_w(&self) -> f64 {
self.w
}
#[setter]
fn set_w(&mut self, w: f64) {
self.w = w;
}
#[getter]
fn get_x(&self) -> f64 {
self.x
}
#[setter]
fn set_x(&mut self, x: f64) {
self.x = x;
}
#[getter]
fn get_y(&self) -> f64 {
self.y
}
#[setter]
fn set_y(&mut self, y: f64) {
self.y = y;
}
#[getter]
fn get_z(&self) -> f64 {
self.z
}
#[setter]
fn set_z(&mut self, z: f64) {
self.z = z;
}
#[getter]
fn get_to_id(&self) -> NaifId {
self.to
}
#[setter]
fn set_to_id(&mut self, to_id: NaifId) {
self.to = to_id;
}
#[getter]
fn get_from_id(&self) -> NaifId {
self.from
}
#[setter]
fn set_from_id(&mut self, from_id: NaifId) {
self.from = from_id;
}
fn __str__(&self) -> String {
format!("{self}")
}
fn __repr__(&self) -> String {
format!("{self} (@{self:p})")
}
fn __richcmp__(&self, other: &Self, op: CompareOp) -> Result<bool, PyErr> {
match op {
CompareOp::Eq => Ok(self == other),
CompareOp::Ne => Ok(self != other),
_ => Err(PyErr::new::<PyTypeError, _>(format!(
"{op:?} not available"
))),
}
}
fn __mul__(&self, q: Self) -> PhysicsResult<Self> {
*self * q
}
}