use hifitime::{Duration, Epoch, TimeSeries};
use pyo3::exceptions::PyException;
use pyo3::prelude::*;
use pyo3::types::PyType;
use std::collections::HashMap;
use crate::prelude::{Aberration, Almanac, Frame, Orbit};
use crate::NaifId;
pub use crate::analysis::elements::OrbitalElement;
use crate::analysis::specs::{OrthogonalFrame, Plane};
use crate::math::rotation::DCM;
use super::event::{Event, EventArc, EventDetails, VisibilityArc};
use super::prelude::{ScalarExpr, VectorExpr};
use super::report::PyReportScalars;
use super::specs::{DcmExpr, FrameSpec, StateSpec, StateSpecTrait};
use super::AnalysisError;
#[pymethods]
impl Almanac {
#[pyo3(name = "report_scalars")]
pub fn py_report_scalars(
&self,
py: Python,
report: &PyReportScalars,
time_series: TimeSeries,
) -> Result<HashMap<String, HashMap<String, f64>>, AnalysisError> {
let data = py.detach(|| self.report_scalars(&report.inner, time_series));
let mut rslt = HashMap::new();
for (k, v) in data {
let mut data_epoch_ok = HashMap::new();
for (col, value) in v? {
data_epoch_ok.insert(col, value.unwrap_or(f64::NAN));
}
rslt.insert(k.to_isoformat(), data_epoch_ok);
}
Ok(rslt)
}
#[pyo3(name = "report_events", signature=(state_spec, event, start_epoch, end_epoch))]
#[allow(clippy::identity_op)]
fn py_report_events(
&self,
py: Python,
state_spec: PyStateSpec,
event: &Event,
start_epoch: Epoch,
end_epoch: Epoch,
) -> Result<Vec<EventDetails>, AnalysisError> {
py.detach(|| {
self.report_events(&StateSpec::from(state_spec), event, start_epoch, end_epoch)
})
}
#[pyo3(name = "report_event_arcs")]
fn py_report_event_arcs(
&self,
py: Python,
state_spec: PyStateSpec,
event: &Event,
start_epoch: Epoch,
end_epoch: Epoch,
) -> Result<Vec<EventArc>, AnalysisError> {
py.detach(|| {
self.report_event_arcs(&StateSpec::from(state_spec), event, start_epoch, end_epoch)
})
}
#[pyo3(name = "report_visibility_arcs", signature=(state_spec, location_id, start_epoch, end_epoch, sample_rate, obstructing_body=None))]
#[allow(clippy::too_many_arguments)]
fn py_report_visibility_arcs(
&self,
py: Python,
state_spec: PyStateSpec,
location_id: i32,
start_epoch: Epoch,
end_epoch: Epoch,
sample_rate: Duration,
obstructing_body: Option<Frame>,
) -> Result<Vec<VisibilityArc>, AnalysisError> {
py.detach(|| {
self.report_visibility_arcs(
&StateSpec::from(state_spec),
location_id,
start_epoch,
end_epoch,
sample_rate,
obstructing_body,
)
})
}
}
#[pyclass]
#[pyo3(module = "anise.analysis", name = "ScalarExpr", get_all, set_all)]
pub enum PyScalarExpr {
Constant(f64),
MeanEquatorialRadius {
celestial_object: i32,
},
SemiMajorEquatorialRadius {
celestial_object: i32,
},
SemiMinorEquatorialRadius {
celestial_object: i32,
},
PolarRadius {
celestial_object: i32,
},
Flattening {
celestial_object: i32,
},
GravParam {
celestial_object: i32,
},
Abs(Py<PyScalarExpr>),
Add {
a: Py<PyScalarExpr>,
b: Py<PyScalarExpr>,
},
Mul {
a: Py<PyScalarExpr>,
b: Py<PyScalarExpr>,
},
Negate(Py<PyScalarExpr>),
Invert(Py<PyScalarExpr>),
Sqrt(Py<PyScalarExpr>),
Powi {
scalar: Py<PyScalarExpr>,
n: i32,
},
Powf {
scalar: Py<PyScalarExpr>,
n: f64,
},
Cos(Py<PyScalarExpr>),
Sin(Py<PyScalarExpr>),
Tan(Py<PyScalarExpr>),
Acos(Py<PyScalarExpr>),
Asin(Py<PyScalarExpr>),
Atan2 {
y: Py<PyScalarExpr>,
x: Py<PyScalarExpr>,
},
Modulo {
v: Py<PyScalarExpr>,
m: Py<PyScalarExpr>,
},
Norm(Py<PyVectorExpr>),
NormSquared(Py<PyVectorExpr>),
DotProduct {
a: Py<PyVectorExpr>,
b: Py<PyVectorExpr>,
},
AngleBetween {
a: Py<PyVectorExpr>,
b: Py<PyVectorExpr>,
},
VectorX(Py<PyVectorExpr>),
VectorY(Py<PyVectorExpr>),
VectorZ(Py<PyVectorExpr>),
Element(OrbitalElement),
SolarEclipsePercentage {
eclipsing_frame: Frame,
},
OccultationPercentage {
back_frame: Frame,
front_frame: Frame,
},
BetaAngle(),
LocalSolarTime(),
LocalTimeAscNode(),
LocalTimeDescNode(),
SunAngle {
observer_id: NaifId,
},
AzimuthFromLocation {
location_id: i32,
obstructing_body: Option<Frame>,
},
ElevationFromLocation {
location_id: i32,
obstructing_body: Option<Frame>,
},
RangeFromLocation {
location_id: i32,
obstructing_body: Option<Frame>,
},
RangeRateFromLocation {
location_id: i32,
obstructing_body: Option<Frame>,
},
RicDiff(PyStateSpec),
FovMargin {
instrument_id: i32,
sc_dcm_to_body: Py<PyDcmExpr>,
target: PyStateSpec,
},
FovMarginToLocation {
instrument_id: i32,
sc_dcm_to_body: Py<PyDcmExpr>,
location_id: i32,
},
}
impl Clone for PyScalarExpr {
fn clone(&self) -> Self {
Python::attach(|py| -> PyScalarExpr {
match self {
Self::Constant(c) => Self::Constant(*c),
Self::MeanEquatorialRadius { celestial_object } => Self::MeanEquatorialRadius {
celestial_object: *celestial_object,
},
Self::SemiMajorEquatorialRadius { celestial_object } => {
Self::SemiMajorEquatorialRadius {
celestial_object: *celestial_object,
}
}
Self::SemiMinorEquatorialRadius { celestial_object } => {
Self::SemiMinorEquatorialRadius {
celestial_object: *celestial_object,
}
}
Self::PolarRadius { celestial_object } => Self::PolarRadius {
celestial_object: *celestial_object,
},
Self::Flattening { celestial_object } => Self::Flattening {
celestial_object: *celestial_object,
},
Self::GravParam { celestial_object } => Self::GravParam {
celestial_object: *celestial_object,
},
Self::Abs(v) => Self::Abs(v.clone_ref(py)),
Self::Add { a, b } => Self::Add {
a: a.clone_ref(py),
b: b.clone_ref(py),
},
Self::Mul { a, b } => Self::Mul {
a: a.clone_ref(py),
b: b.clone_ref(py),
},
Self::Negate(s) => Self::Negate(s.clone_ref(py)),
Self::Invert(s) => Self::Invert(s.clone_ref(py)),
Self::Sqrt(s) => Self::Sqrt(s.clone_ref(py)),
Self::Powi { scalar, n } => Self::Powi {
scalar: scalar.clone_ref(py),
n: *n,
},
Self::Powf { scalar, n } => Self::Powf {
scalar: scalar.clone_ref(py),
n: *n,
},
Self::Cos(s) => Self::Cos(s.clone_ref(py)),
Self::Sin(s) => Self::Sin(s.clone_ref(py)),
Self::Tan(s) => Self::Tan(s.clone_ref(py)),
Self::Acos(s) => Self::Acos(s.clone_ref(py)),
Self::Asin(s) => Self::Asin(s.clone_ref(py)),
Self::Atan2 { y, x } => Self::Atan2 {
y: y.clone_ref(py),
x: x.clone_ref(py),
},
Self::Modulo { v, m } => Self::Modulo {
v: v.clone_ref(py),
m: m.clone_ref(py),
},
Self::Norm(v) => Self::Norm(v.clone_ref(py)),
Self::NormSquared(v) => Self::NormSquared(v.clone_ref(py)),
Self::DotProduct { a, b } => Self::DotProduct {
a: a.clone_ref(py),
b: b.clone_ref(py),
},
Self::AngleBetween { a, b } => Self::AngleBetween {
a: a.clone_ref(py),
b: b.clone_ref(py),
},
Self::VectorX(v) => Self::VectorX(v.clone_ref(py)),
Self::VectorY(v) => Self::VectorY(v.clone_ref(py)),
Self::VectorZ(v) => Self::VectorZ(v.clone_ref(py)),
Self::Element(e) => Self::Element(*e),
Self::SolarEclipsePercentage { eclipsing_frame } => Self::SolarEclipsePercentage {
eclipsing_frame: *eclipsing_frame,
},
Self::OccultationPercentage {
back_frame,
front_frame,
} => Self::OccultationPercentage {
back_frame: *back_frame,
front_frame: *front_frame,
},
Self::BetaAngle() => Self::BetaAngle(),
Self::LocalSolarTime() => Self::LocalSolarTime(),
Self::LocalTimeAscNode() => Self::LocalTimeAscNode(),
Self::LocalTimeDescNode() => Self::LocalTimeDescNode(),
Self::SunAngle { observer_id } => Self::SunAngle {
observer_id: *observer_id,
},
Self::AzimuthFromLocation {
location_id,
obstructing_body,
} => Self::AzimuthFromLocation {
location_id: *location_id,
obstructing_body: *obstructing_body,
},
Self::ElevationFromLocation {
location_id,
obstructing_body,
} => Self::ElevationFromLocation {
location_id: *location_id,
obstructing_body: *obstructing_body,
},
Self::RangeFromLocation {
location_id,
obstructing_body,
} => Self::RangeFromLocation {
location_id: *location_id,
obstructing_body: *obstructing_body,
},
Self::RangeRateFromLocation {
location_id,
obstructing_body,
} => Self::RangeRateFromLocation {
location_id: *location_id,
obstructing_body: *obstructing_body,
},
Self::RicDiff(s) => Self::RicDiff(s.clone()),
Self::FovMargin {
instrument_id,
sc_dcm_to_body,
target,
} => Self::FovMargin {
instrument_id: *instrument_id,
sc_dcm_to_body: sc_dcm_to_body.clone_ref(py),
target: target.clone(),
},
Self::FovMarginToLocation {
instrument_id,
sc_dcm_to_body,
location_id,
} => Self::FovMarginToLocation {
instrument_id: *instrument_id,
sc_dcm_to_body: sc_dcm_to_body.clone_ref(py),
location_id: *location_id,
},
}
})
}
}
#[pymethods]
impl PyScalarExpr {
#[pyo3(signature=(orbit, almanac, ab_corr=None))]
fn evaluate(
&self,
orbit: Orbit,
almanac: &Almanac,
ab_corr: Option<Aberration>,
) -> Result<f64, PyErr> {
let py_scalar = self.clone();
let scalar = ScalarExpr::from(py_scalar);
scalar
.evaluate(orbit, ab_corr, almanac)
.map_err(|e| PyException::new_err(e.to_string()))
}
#[classmethod]
fn from_s_expr(_cls: Bound<'_, PyType>, expr: &str) -> Result<Self, PyErr> {
let scalar =
ScalarExpr::from_s_expr(expr).map_err(|e| PyException::new_err(e.to_string()))?;
scalar.try_into()
}
fn to_s_expr(&self) -> Result<String, PyErr> {
let scalar = ScalarExpr::from(self.clone());
scalar
.to_s_expr()
.map_err(|e| PyException::new_err(e.to_string()))
}
}
#[pyclass]
#[pyo3(module = "anise.analysis", name = "VectorExpr", get_all, set_all)]
pub enum PyVectorExpr {
Fixed {
x: f64,
y: f64,
z: f64,
},
Radius(Py<PyStateSpec>),
Velocity(Py<PyStateSpec>),
OrbitalMomentum(Py<PyStateSpec>),
EccentricityVector(Py<PyStateSpec>),
CrossProduct {
a: Py<PyVectorExpr>,
b: Py<PyVectorExpr>,
},
Unit(Py<PyVectorExpr>),
Add {
a: Py<PyVectorExpr>,
b: Py<PyVectorExpr>,
},
Negate(Py<PyVectorExpr>),
VecProjection {
a: Py<PyVectorExpr>,
b: Py<PyVectorExpr>,
},
Project {
v: Py<PyVectorExpr>,
frame: Py<PyOrthogonalFrame>,
plane: Option<Plane>,
},
Rotate {
v: Py<PyVectorExpr>,
dcm: Py<PyDcmExpr>,
},
}
impl Clone for PyVectorExpr {
fn clone(&self) -> Self {
Python::attach(|py| -> PyVectorExpr {
match self {
Self::Fixed { x, y, z } => Self::Fixed {
x: *x,
y: *y,
z: *z,
},
Self::Radius(s) => Self::Radius(s.clone_ref(py)),
Self::Velocity(s) => Self::Velocity(s.clone_ref(py)),
Self::OrbitalMomentum(s) => Self::OrbitalMomentum(s.clone_ref(py)),
Self::EccentricityVector(s) => Self::EccentricityVector(s.clone_ref(py)),
Self::CrossProduct { a, b } => Self::CrossProduct {
a: a.clone_ref(py),
b: b.clone_ref(py),
},
Self::Unit(v) => Self::Unit(v.clone_ref(py)),
Self::Add { a, b } => Self::Add {
a: a.clone_ref(py),
b: b.clone_ref(py),
},
Self::Negate(v) => Self::Negate(v.clone_ref(py)),
Self::VecProjection { a, b } => Self::VecProjection {
a: a.clone_ref(py),
b: b.clone_ref(py),
},
Self::Project { v, frame, plane } => Self::Project {
v: v.clone_ref(py),
frame: frame.clone_ref(py),
plane: *plane,
},
Self::Rotate { v, dcm } => Self::Rotate {
v: v.clone_ref(py),
dcm: dcm.clone_ref(py),
},
}
})
}
}
#[derive(Clone)]
#[pyclass]
#[pyo3(module = "anise.analysis", name = "StateSpec", get_all, set_all)]
pub struct PyStateSpec {
pub target_frame: PyFrameSpec,
pub observer_frame: PyFrameSpec,
pub ab_corr: Option<Aberration>,
}
#[pymethods]
impl PyStateSpec {
#[new]
#[pyo3(signature=(target_frame, observer_frame, ab_corr=None))]
fn new(
target_frame: PyFrameSpec,
observer_frame: PyFrameSpec,
ab_corr: Option<Aberration>,
) -> Self {
Self {
target_frame,
observer_frame,
ab_corr,
}
}
#[classmethod]
fn from_s_expr(_cls: Bound<'_, PyType>, expr: &str) -> Result<Self, PyErr> {
let spec = StateSpec::from_s_expr(expr).map_err(|e| PyException::new_err(e.to_string()))?;
spec.try_into()
}
fn to_s_expr(&self) -> Result<String, PyErr> {
let spec = StateSpec::from(self.clone());
spec.to_s_expr()
.map_err(|e| PyException::new_err(e.to_string()))
}
#[pyo3(name = "evaluate", signature=(epoch, almanac))]
fn py_evaluate(&self, epoch: Epoch, almanac: &Almanac) -> Result<Orbit, PyErr> {
let spec = StateSpec::from(self.clone());
spec.evaluate(epoch, almanac)
.map_err(|e| PyException::new_err(e.to_string()))
}
fn __eq__(&self, other: &Self) -> bool {
let me = StateSpec::from(self.clone());
let other = StateSpec::from(other.clone());
me == other
}
fn __ne__(&self, other: &Self) -> bool {
let me = StateSpec::from(self.clone());
let other = StateSpec::from(other.clone());
me != other
}
}
#[pyclass]
#[pyo3(module = "anise.analysis", name = "FrameSpec", get_all, set_all)]
pub enum PyFrameSpec {
Loaded(Frame),
Manual {
name: String,
defn: Py<PyOrthogonalFrame>,
},
}
impl Clone for PyFrameSpec {
fn clone(&self) -> Self {
Python::attach(|py| -> PyFrameSpec {
match self {
PyFrameSpec::Loaded(frame) => PyFrameSpec::Loaded(*frame),
PyFrameSpec::Manual { name, defn } => {
PyFrameSpec::Manual {
name: name.clone(),
defn: defn.clone_ref(py),
}
}
}
})
}
}
#[pyclass]
#[pyo3(module = "anise.analysis", name = "OrthogonalFrame", get_all, set_all)]
pub enum PyOrthogonalFrame {
XY {
x: Py<PyVectorExpr>,
y: Py<PyVectorExpr>,
},
XZ {
x: Py<PyVectorExpr>,
z: Py<PyVectorExpr>,
},
YZ {
y: Py<PyVectorExpr>,
z: Py<PyVectorExpr>,
},
}
impl Clone for PyOrthogonalFrame {
fn clone(&self) -> Self {
Python::attach(|py| -> PyOrthogonalFrame {
match self {
Self::XY { x, y } => Self::XY {
x: x.clone_ref(py),
y: y.clone_ref(py),
},
Self::XZ { x, z } => Self::XZ {
x: x.clone_ref(py),
z: z.clone_ref(py),
},
Self::YZ { y, z } => Self::YZ {
z: z.clone_ref(py),
y: y.clone_ref(py),
},
}
})
}
}
#[pyclass]
#[pyo3(module = "anise.analysis", name = "DcmExpr", get_all, set_all)]
pub enum PyDcmExpr {
Identity {
from_id: i32,
to_id: i32,
},
R1 {
angle_rad: f64,
from_id: i32,
to_id: i32,
},
R2 {
angle_rad: f64,
from_id: i32,
to_id: i32,
},
R3 {
angle_rad: f64,
from_id: i32,
to_id: i32,
},
Triad {
primary_axis: Py<PyVectorExpr>,
primary_vec: Py<PyVectorExpr>,
secondary_axis: Py<PyVectorExpr>,
secondary_vec: Py<PyVectorExpr>,
from_id: i32,
to_id: i32,
},
Quaternion {
x: f64,
y: f64,
z: f64,
w: f64,
from_id: i32,
to_id: i32,
},
RIC {
state: Py<PyStateSpec>,
from_id: i32,
to_id: i32,
},
VNC {
state: Py<PyStateSpec>,
from_id: i32,
to_id: i32,
},
RCN {
state: Py<PyStateSpec>,
from_id: i32,
to_id: i32,
},
SEZ {
state: Py<PyStateSpec>,
from_id: i32,
to_id: i32,
},
}
impl Clone for PyDcmExpr {
fn clone(&self) -> Self {
Python::attach(|py| -> PyDcmExpr {
match self {
Self::Identity {
from_id: from,
to_id: to,
} => Self::Identity {
from_id: *from,
to_id: *to,
},
Self::R1 {
angle_rad,
from_id: from,
to_id: to,
} => Self::R1 {
angle_rad: *angle_rad,
from_id: *from,
to_id: *to,
},
Self::R2 {
angle_rad,
from_id: from,
to_id: to,
} => Self::R2 {
angle_rad: *angle_rad,
from_id: *from,
to_id: *to,
},
Self::R3 {
angle_rad,
from_id: from,
to_id: to,
} => Self::R3 {
angle_rad: *angle_rad,
from_id: *from,
to_id: *to,
},
Self::Quaternion {
x,
y,
z,
w,
from_id: from,
to_id: to,
} => Self::Quaternion {
x: *x,
y: *y,
z: *z,
w: *w,
from_id: *from,
to_id: *to,
},
Self::RIC {
state,
from_id: from,
to_id: to,
} => Self::RIC {
state: state.clone_ref(py),
from_id: *from,
to_id: *to,
},
Self::RCN {
state,
from_id: from,
to_id: to,
} => Self::RCN {
state: state.clone_ref(py),
from_id: *from,
to_id: *to,
},
Self::VNC {
state,
from_id: from,
to_id: to,
} => Self::VNC {
state: state.clone_ref(py),
from_id: *from,
to_id: *to,
},
Self::SEZ {
state,
from_id: from,
to_id: to,
} => Self::SEZ {
state: state.clone_ref(py),
from_id: *from,
to_id: *to,
},
Self::Triad {
primary_axis,
primary_vec,
secondary_axis,
secondary_vec,
from_id: from,
to_id: to,
} => Self::Triad {
primary_axis: primary_axis.clone_ref(py),
primary_vec: primary_vec.clone_ref(py),
secondary_axis: secondary_axis.clone_ref(py),
secondary_vec: secondary_vec.clone_ref(py),
from_id: *from,
to_id: *to,
},
}
})
}
}
#[pymethods]
impl PyDcmExpr {
#[pyo3(signature=(epoch, almanac))]
fn evaluate(&self, epoch: Epoch, almanac: &Almanac) -> Result<DCM, PyErr> {
let py_dcm = self.clone();
let dcm_expr = DcmExpr::from(py_dcm);
dcm_expr
.evaluate(epoch, almanac)
.map_err(|e| PyException::new_err(e.to_string()))
}
}
impl TryFrom<ScalarExpr> for PyScalarExpr {
type Error = PyErr;
fn try_from(value: ScalarExpr) -> Result<Self, Self::Error> {
Python::attach(|py| -> Result<Self, PyErr> {
match value {
ScalarExpr::BetaAngle => Ok(Self::BetaAngle()),
ScalarExpr::LocalSolarTime => Ok(Self::LocalSolarTime()),
ScalarExpr::LocalTimeAscNode => Ok(Self::LocalTimeAscNode()),
ScalarExpr::LocalTimeDescNode => Ok(Self::LocalTimeDescNode()),
ScalarExpr::Constant(v) => Ok(Self::Constant(v)),
ScalarExpr::SunAngle { observer_id } => Ok(Self::SunAngle { observer_id }),
ScalarExpr::AzimuthFromLocation {
location_id,
obstructing_body,
} => Ok(Self::AzimuthFromLocation {
location_id,
obstructing_body,
}),
ScalarExpr::ElevationFromLocation {
location_id,
obstructing_body,
} => Ok(Self::ElevationFromLocation {
location_id,
obstructing_body,
}),
ScalarExpr::RangeFromLocation {
location_id,
obstructing_body,
} => Ok(Self::RangeFromLocation {
location_id,
obstructing_body,
}),
ScalarExpr::RangeRateFromLocation {
location_id,
obstructing_body,
} => Ok(Self::RangeRateFromLocation {
location_id,
obstructing_body,
}),
ScalarExpr::SolarEclipsePercentage { eclipsing_frame } => {
Ok(Self::SolarEclipsePercentage { eclipsing_frame })
}
ScalarExpr::OccultationPercentage {
back_frame,
front_frame,
} => Ok(Self::OccultationPercentage {
back_frame,
front_frame,
}),
ScalarExpr::Element(e) => Ok(Self::Element(e)),
ScalarExpr::MeanEquatorialRadius { celestial_object } => {
Ok(Self::MeanEquatorialRadius { celestial_object })
}
ScalarExpr::SemiMajorEquatorialRadius { celestial_object } => {
Ok(Self::SemiMajorEquatorialRadius { celestial_object })
}
ScalarExpr::SemiMinorEquatorialRadius { celestial_object } => {
Ok(Self::SemiMinorEquatorialRadius { celestial_object })
}
ScalarExpr::PolarRadius { celestial_object } => {
Ok(Self::PolarRadius { celestial_object })
}
ScalarExpr::Flattening { celestial_object } => {
Ok(Self::Flattening { celestial_object })
}
ScalarExpr::GravParam { celestial_object } => {
Ok(Self::GravParam { celestial_object })
}
ScalarExpr::Norm(v) => Ok(Self::Norm(Py::new(
py,
<VectorExpr as TryInto<PyVectorExpr>>::try_into(v)?,
)?)),
ScalarExpr::NormSquared(v) => Ok(Self::NormSquared(Py::new(
py,
<VectorExpr as TryInto<PyVectorExpr>>::try_into(v)?,
)?)),
ScalarExpr::VectorX(v) => Ok(Self::VectorX(Py::new(
py,
<VectorExpr as TryInto<PyVectorExpr>>::try_into(v)?,
)?)),
ScalarExpr::VectorY(v) => Ok(Self::VectorY(Py::new(
py,
<VectorExpr as TryInto<PyVectorExpr>>::try_into(v)?,
)?)),
ScalarExpr::VectorZ(v) => Ok(Self::VectorZ(Py::new(
py,
<VectorExpr as TryInto<PyVectorExpr>>::try_into(v)?,
)?)),
ScalarExpr::DotProduct { a, b } => Ok(Self::DotProduct {
a: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(a)?)?,
b: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(b)?)?,
}),
ScalarExpr::AngleBetween { a, b } => Ok(Self::AngleBetween {
a: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(a)?)?,
b: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(b)?)?,
}),
ScalarExpr::Negate(v) => Ok(Self::Negate(Py::new(
py,
<ScalarExpr as TryInto<PyScalarExpr>>::try_into(*v)?,
)?)),
ScalarExpr::Invert(v) => Ok(Self::Invert(Py::new(
py,
<ScalarExpr as TryInto<PyScalarExpr>>::try_into(*v)?,
)?)),
ScalarExpr::Cos(v) => Ok(Self::Cos(Py::new(
py,
<ScalarExpr as TryInto<PyScalarExpr>>::try_into(*v)?,
)?)),
ScalarExpr::Sin(v) => Ok(Self::Sin(Py::new(
py,
<ScalarExpr as TryInto<PyScalarExpr>>::try_into(*v)?,
)?)),
ScalarExpr::Tan(v) => Ok(Self::Tan(Py::new(
py,
<ScalarExpr as TryInto<PyScalarExpr>>::try_into(*v)?,
)?)),
ScalarExpr::Acos(v) => Ok(Self::Acos(Py::new(
py,
<ScalarExpr as TryInto<PyScalarExpr>>::try_into(*v)?,
)?)),
ScalarExpr::Asin(v) => Ok(Self::Asin(Py::new(
py,
<ScalarExpr as TryInto<PyScalarExpr>>::try_into(*v)?,
)?)),
ScalarExpr::Sqrt(v) => Ok(Self::Sqrt(Py::new(
py,
<ScalarExpr as TryInto<PyScalarExpr>>::try_into(*v)?,
)?)),
ScalarExpr::Powi { scalar, n } => Ok(Self::Powi {
scalar: Py::new(
py,
<ScalarExpr as TryInto<PyScalarExpr>>::try_into(*scalar)?,
)?,
n,
}),
ScalarExpr::Powf { scalar, n } => Ok(Self::Powf {
scalar: Py::new(
py,
<ScalarExpr as TryInto<PyScalarExpr>>::try_into(*scalar)?,
)?,
n,
}),
ScalarExpr::Abs(v) => Ok(Self::Abs(Py::new(
py,
<ScalarExpr as TryInto<PyScalarExpr>>::try_into(*v)?,
)?)),
ScalarExpr::Add { a, b } => Ok(Self::Add {
a: Py::new(py, <ScalarExpr as TryInto<PyScalarExpr>>::try_into(*a)?)?,
b: Py::new(py, <ScalarExpr as TryInto<PyScalarExpr>>::try_into(*b)?)?,
}),
ScalarExpr::Mul { a, b } => Ok(Self::Mul {
a: Py::new(py, <ScalarExpr as TryInto<PyScalarExpr>>::try_into(*a)?)?,
b: Py::new(py, <ScalarExpr as TryInto<PyScalarExpr>>::try_into(*b)?)?,
}),
ScalarExpr::Atan2 { y, x } => Ok(Self::Atan2 {
y: Py::new(py, <ScalarExpr as TryInto<PyScalarExpr>>::try_into(*y)?)?,
x: Py::new(py, <ScalarExpr as TryInto<PyScalarExpr>>::try_into(*x)?)?,
}),
ScalarExpr::Modulo { v, m } => Ok(Self::Modulo {
v: Py::new(py, <ScalarExpr as TryInto<PyScalarExpr>>::try_into(*v)?)?,
m: Py::new(py, <ScalarExpr as TryInto<PyScalarExpr>>::try_into(*m)?)?,
}),
ScalarExpr::RicDiff(s) => Ok(Self::RicDiff(
<StateSpec as TryInto<PyStateSpec>>::try_into(s.clone())?,
)),
ScalarExpr::FovMargin {
instrument_id,
sc_dcm_to_body,
target,
} => Ok(Self::FovMargin {
instrument_id,
sc_dcm_to_body: Py::new(
py,
<DcmExpr as TryInto<PyDcmExpr>>::try_into(sc_dcm_to_body)?,
)?,
target: <StateSpec as TryInto<PyStateSpec>>::try_into(target)?,
}),
ScalarExpr::FovMarginToLocation {
instrument_id,
sc_dcm_to_body,
location_id,
} => Ok(Self::FovMarginToLocation {
instrument_id,
sc_dcm_to_body: Py::new(
py,
<DcmExpr as TryInto<PyDcmExpr>>::try_into(sc_dcm_to_body)?,
)?,
location_id,
}),
}
})
}
}
impl TryFrom<OrthogonalFrame> for PyOrthogonalFrame {
type Error = PyErr;
fn try_from(value: OrthogonalFrame) -> Result<Self, PyErr> {
Python::attach(|py| -> Result<Self, PyErr> {
match value {
OrthogonalFrame::XY { x, y } => Ok(Self::XY {
x: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(x)?)?,
y: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(y)?)?,
}),
OrthogonalFrame::XZ { x, z } => Ok(Self::XZ {
x: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(x)?)?,
z: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(z)?)?,
}),
OrthogonalFrame::YZ { y, z } => Ok(Self::YZ {
y: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(y)?)?,
z: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(z)?)?,
}),
}
})
}
}
impl TryFrom<VectorExpr> for PyVectorExpr {
type Error = PyErr;
fn try_from(value: VectorExpr) -> Result<Self, PyErr> {
Python::attach(|py| -> Result<Self, PyErr> {
match value {
VectorExpr::Fixed { x, y, z } => Ok(Self::Fixed { x, y, z }),
VectorExpr::CrossProduct { a, b } => Ok(Self::CrossProduct {
a: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(*a)?)?,
b: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(*b)?)?,
}),
VectorExpr::VecProjection { a, b } => Ok(Self::VecProjection {
a: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(*a)?)?,
b: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(*b)?)?,
}),
VectorExpr::Unit(v) => Ok(Self::Unit(Py::new(
py,
<VectorExpr as TryInto<PyVectorExpr>>::try_into(*v)?,
)?)),
VectorExpr::Add { a, b } => Ok(Self::Add {
a: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(*a)?)?,
b: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(*b)?)?,
}),
VectorExpr::Negate(v) => Ok(Self::Negate(Py::new(
py,
<VectorExpr as TryInto<PyVectorExpr>>::try_into(*v)?,
)?)),
VectorExpr::Project { v, frame, plane } => Ok(Self::Project {
v: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(*v)?)?,
frame: Py::new(
py,
<OrthogonalFrame as TryInto<PyOrthogonalFrame>>::try_into(*frame)?,
)?,
plane,
}),
VectorExpr::Rotate { v, dcm } => Ok(Self::Rotate {
v: Py::new(py, <VectorExpr as TryInto<PyVectorExpr>>::try_into(*v)?)?,
dcm: Py::new(py, <DcmExpr as TryInto<PyDcmExpr>>::try_into(*dcm)?)?,
}),
VectorExpr::Radius(spec) => Ok(Self::Radius(Py::new(
py,
<StateSpec as TryInto<PyStateSpec>>::try_into(spec)?,
)?)),
VectorExpr::Velocity(spec) => Ok(Self::Velocity(Py::new(
py,
<StateSpec as TryInto<PyStateSpec>>::try_into(spec)?,
)?)),
VectorExpr::EccentricityVector(spec) => Ok(Self::EccentricityVector(Py::new(
py,
<StateSpec as TryInto<PyStateSpec>>::try_into(spec)?,
)?)),
VectorExpr::OrbitalMomentum(spec) => Ok(Self::OrbitalMomentum(Py::new(
py,
<StateSpec as TryInto<PyStateSpec>>::try_into(spec)?,
)?)),
}
})
}
}
impl TryFrom<StateSpec> for PyStateSpec {
type Error = PyErr;
fn try_from(value: StateSpec) -> Result<Self, PyErr> {
Ok(PyStateSpec {
target_frame: value.target_frame.try_into()?,
observer_frame: value.observer_frame.try_into()?,
ab_corr: value.ab_corr,
})
}
}
impl TryFrom<FrameSpec> for PyFrameSpec {
type Error = PyErr;
fn try_from(value: FrameSpec) -> Result<Self, PyErr> {
Python::attach(|py| -> Result<Self, PyErr> {
Ok(match value {
FrameSpec::Loaded(f) => PyFrameSpec::Loaded(f),
FrameSpec::Manual { name, defn } => PyFrameSpec::Manual {
name,
defn: Py::new(
py,
<OrthogonalFrame as TryInto<PyOrthogonalFrame>>::try_into(*defn)?,
)?,
},
})
})
}
}
impl TryFrom<DcmExpr> for PyDcmExpr {
type Error = PyErr;
fn try_from(value: DcmExpr) -> Result<Self, PyErr> {
Python::attach(|py| -> Result<Self, PyErr> {
match value {
DcmExpr::Identity { from, to } => Ok(PyDcmExpr::Identity {
from_id: from,
to_id: to,
}),
DcmExpr::R1 {
angle_rad,
from,
to,
} => Ok(PyDcmExpr::R1 {
angle_rad,
from_id: from,
to_id: to,
}),
DcmExpr::R2 {
angle_rad,
from,
to,
} => Ok(PyDcmExpr::R2 {
angle_rad,
from_id: from,
to_id: to,
}),
DcmExpr::R3 {
angle_rad,
from,
to,
} => Ok(PyDcmExpr::R3 {
angle_rad,
from_id: from,
to_id: to,
}),
DcmExpr::Quaternion {
x,
y,
z,
w,
from,
to,
} => Ok(PyDcmExpr::Quaternion {
x,
y,
z,
w,
from_id: from,
to_id: to,
}),
DcmExpr::Triad {
primary_axis,
primary_vec,
secondary_axis,
secondary_vec,
from,
to,
} => Ok(PyDcmExpr::Triad {
primary_axis: Py::new(
py,
<VectorExpr as TryInto<PyVectorExpr>>::try_into(*primary_axis)?,
)?,
primary_vec: Py::new(
py,
<VectorExpr as TryInto<PyVectorExpr>>::try_into(*primary_vec)?,
)?,
secondary_axis: Py::new(
py,
<VectorExpr as TryInto<PyVectorExpr>>::try_into(*secondary_axis)?,
)?,
secondary_vec: Py::new(
py,
<VectorExpr as TryInto<PyVectorExpr>>::try_into(*secondary_vec)?,
)?,
from_id: from,
to_id: to,
}),
DcmExpr::RIC { state, from, to } => Ok(PyDcmExpr::RIC {
state: Py::new(py, <StateSpec as TryInto<PyStateSpec>>::try_into(*state)?)?,
from_id: from,
to_id: to,
}),
DcmExpr::RCN { state, from, to } => Ok(PyDcmExpr::RCN {
state: Py::new(py, <StateSpec as TryInto<PyStateSpec>>::try_into(*state)?)?,
from_id: from,
to_id: to,
}),
DcmExpr::VNC { state, from, to } => Ok(PyDcmExpr::VNC {
state: Py::new(py, <StateSpec as TryInto<PyStateSpec>>::try_into(*state)?)?,
from_id: from,
to_id: to,
}),
DcmExpr::SEZ { state, from, to } => Ok(PyDcmExpr::SEZ {
state: Py::new(py, <StateSpec as TryInto<PyStateSpec>>::try_into(*state)?)?,
from_id: from,
to_id: to,
}),
}
})
}
}
impl From<PyScalarExpr> for ScalarExpr {
fn from(value: PyScalarExpr) -> Self {
Python::attach(|py| match value {
PyScalarExpr::Constant(c) => ScalarExpr::Constant(c),
PyScalarExpr::MeanEquatorialRadius { celestial_object } => {
ScalarExpr::MeanEquatorialRadius { celestial_object }
}
PyScalarExpr::SemiMajorEquatorialRadius { celestial_object } => {
ScalarExpr::SemiMajorEquatorialRadius { celestial_object }
}
PyScalarExpr::SemiMinorEquatorialRadius { celestial_object } => {
ScalarExpr::SemiMinorEquatorialRadius { celestial_object }
}
PyScalarExpr::PolarRadius { celestial_object } => {
ScalarExpr::PolarRadius { celestial_object }
}
PyScalarExpr::Flattening { celestial_object } => {
ScalarExpr::Flattening { celestial_object }
}
PyScalarExpr::GravParam { celestial_object } => {
ScalarExpr::GravParam { celestial_object }
}
PyScalarExpr::Element(e) => ScalarExpr::Element(e),
PyScalarExpr::SolarEclipsePercentage { eclipsing_frame } => {
ScalarExpr::SolarEclipsePercentage { eclipsing_frame }
}
PyScalarExpr::OccultationPercentage {
back_frame,
front_frame,
} => ScalarExpr::OccultationPercentage {
back_frame,
front_frame,
},
PyScalarExpr::BetaAngle() => ScalarExpr::BetaAngle,
PyScalarExpr::LocalSolarTime() => ScalarExpr::LocalSolarTime,
PyScalarExpr::LocalTimeAscNode() => ScalarExpr::LocalTimeAscNode,
PyScalarExpr::LocalTimeDescNode() => ScalarExpr::LocalTimeDescNode,
PyScalarExpr::SunAngle { observer_id } => ScalarExpr::SunAngle { observer_id },
PyScalarExpr::AzimuthFromLocation {
location_id,
obstructing_body,
} => ScalarExpr::AzimuthFromLocation {
location_id,
obstructing_body,
},
PyScalarExpr::ElevationFromLocation {
location_id,
obstructing_body,
} => ScalarExpr::ElevationFromLocation {
location_id,
obstructing_body,
},
PyScalarExpr::RangeFromLocation {
location_id,
obstructing_body,
} => ScalarExpr::RangeFromLocation {
location_id,
obstructing_body,
},
PyScalarExpr::RangeRateFromLocation {
location_id,
obstructing_body,
} => ScalarExpr::RangeRateFromLocation {
location_id,
obstructing_body,
},
PyScalarExpr::Abs(v) => ScalarExpr::Abs(Box::new(v.borrow(py).clone().into())),
PyScalarExpr::Add { a, b } => ScalarExpr::Add {
a: Box::new(a.borrow(py).clone().into()),
b: Box::new(b.borrow(py).clone().into()),
},
PyScalarExpr::Mul { a, b } => ScalarExpr::Mul {
a: Box::new(a.borrow(py).clone().into()),
b: Box::new(b.borrow(py).clone().into()),
},
PyScalarExpr::Negate(s) => ScalarExpr::Negate(Box::new(s.borrow(py).clone().into())),
PyScalarExpr::Invert(s) => ScalarExpr::Invert(Box::new(s.borrow(py).clone().into())),
PyScalarExpr::Sqrt(s) => ScalarExpr::Sqrt(Box::new(s.borrow(py).clone().into())),
PyScalarExpr::Powi { scalar, n } => ScalarExpr::Powi {
scalar: Box::new(scalar.borrow(py).clone().into()),
n,
},
PyScalarExpr::Powf { scalar, n } => ScalarExpr::Powf {
scalar: Box::new(scalar.borrow(py).clone().into()),
n,
},
PyScalarExpr::Cos(s) => ScalarExpr::Cos(Box::new(s.borrow(py).clone().into())),
PyScalarExpr::Sin(s) => ScalarExpr::Sin(Box::new(s.borrow(py).clone().into())),
PyScalarExpr::Tan(s) => ScalarExpr::Tan(Box::new(s.borrow(py).clone().into())),
PyScalarExpr::Acos(s) => ScalarExpr::Acos(Box::new(s.borrow(py).clone().into())),
PyScalarExpr::Asin(s) => ScalarExpr::Asin(Box::new(s.borrow(py).clone().into())),
PyScalarExpr::Atan2 { y, x } => ScalarExpr::Atan2 {
y: Box::new(y.borrow(py).clone().into()),
x: Box::new(x.borrow(py).clone().into()),
},
PyScalarExpr::Modulo { v, m } => ScalarExpr::Modulo {
v: Box::new(v.borrow(py).clone().into()),
m: Box::new(m.borrow(py).clone().into()),
},
PyScalarExpr::Norm(v) => ScalarExpr::Norm(v.borrow(py).clone().into()),
PyScalarExpr::NormSquared(v) => ScalarExpr::NormSquared(v.borrow(py).clone().into()),
PyScalarExpr::DotProduct { a, b } => ScalarExpr::DotProduct {
a: a.borrow(py).clone().into(),
b: b.borrow(py).clone().into(),
},
PyScalarExpr::AngleBetween { a, b } => ScalarExpr::AngleBetween {
a: a.borrow(py).clone().into(),
b: b.borrow(py).clone().into(),
},
PyScalarExpr::VectorX(v) => ScalarExpr::VectorX(v.borrow(py).clone().into()),
PyScalarExpr::VectorY(v) => ScalarExpr::VectorY(v.borrow(py).clone().into()),
PyScalarExpr::VectorZ(v) => ScalarExpr::VectorZ(v.borrow(py).clone().into()),
PyScalarExpr::RicDiff(s) => ScalarExpr::RicDiff(s.clone().into()),
PyScalarExpr::FovMargin {
instrument_id,
sc_dcm_to_body,
target,
} => ScalarExpr::FovMargin {
instrument_id,
sc_dcm_to_body: sc_dcm_to_body.borrow(py).clone().into(),
target: target.into(),
},
PyScalarExpr::FovMarginToLocation {
instrument_id,
sc_dcm_to_body,
location_id,
} => ScalarExpr::FovMarginToLocation {
instrument_id,
sc_dcm_to_body: sc_dcm_to_body.borrow(py).clone().into(),
location_id,
},
})
}
}
impl From<PyVectorExpr> for VectorExpr {
fn from(value: PyVectorExpr) -> Self {
Python::attach(|py| match value {
PyVectorExpr::Fixed { x, y, z } => VectorExpr::Fixed { x, y, z },
PyVectorExpr::Radius(spec) => VectorExpr::Radius(spec.borrow(py).clone().into()),
PyVectorExpr::Velocity(spec) => VectorExpr::Velocity(spec.borrow(py).clone().into()),
PyVectorExpr::OrbitalMomentum(spec) => {
VectorExpr::OrbitalMomentum(spec.borrow(py).clone().into())
}
PyVectorExpr::EccentricityVector(spec) => {
VectorExpr::EccentricityVector(spec.borrow(py).clone().into())
}
PyVectorExpr::CrossProduct { a, b } => VectorExpr::CrossProduct {
a: Box::new(a.borrow(py).clone().into()),
b: Box::new(b.borrow(py).clone().into()),
},
PyVectorExpr::VecProjection { a, b } => VectorExpr::VecProjection {
a: Box::new(a.borrow(py).clone().into()),
b: Box::new(b.borrow(py).clone().into()),
},
PyVectorExpr::Add { a, b } => VectorExpr::Add {
a: Box::new(a.borrow(py).clone().into()),
b: Box::new(b.borrow(py).clone().into()),
},
PyVectorExpr::Unit(v) => VectorExpr::Unit(Box::new(v.borrow(py).clone().into())),
PyVectorExpr::Negate(v) => VectorExpr::Negate(Box::new(v.borrow(py).clone().into())),
PyVectorExpr::Project { v, frame, plane } => VectorExpr::Project {
v: Box::new(v.borrow(py).clone().into()),
frame: Box::new(frame.borrow(py).clone().into()),
plane,
},
PyVectorExpr::Rotate { v, dcm } => VectorExpr::Rotate {
v: Box::new(v.borrow(py).clone().into()),
dcm: Box::new(dcm.borrow(py).clone().into()),
},
})
}
}
impl From<PyOrthogonalFrame> for OrthogonalFrame {
fn from(value: PyOrthogonalFrame) -> Self {
Python::attach(|py| match value {
PyOrthogonalFrame::XY { x, y } => OrthogonalFrame::XY {
x: x.borrow(py).clone().into(),
y: y.borrow(py).clone().into(),
},
PyOrthogonalFrame::XZ { x, z } => OrthogonalFrame::XZ {
x: x.borrow(py).clone().into(),
z: z.borrow(py).clone().into(),
},
PyOrthogonalFrame::YZ { y, z } => OrthogonalFrame::YZ {
y: y.borrow(py).clone().into(),
z: z.borrow(py).clone().into(),
},
})
}
}
impl From<PyStateSpec> for StateSpec {
fn from(value: PyStateSpec) -> Self {
StateSpec {
target_frame: value.target_frame.into(),
observer_frame: value.observer_frame.into(),
ab_corr: value.ab_corr,
}
}
}
impl From<PyFrameSpec> for FrameSpec {
fn from(value: PyFrameSpec) -> Self {
match value {
PyFrameSpec::Loaded(frame) => Self::Loaded(frame),
PyFrameSpec::Manual { name, defn } => Python::attach(|py| {
let py_ortho: PyOrthogonalFrame = defn.borrow(py).clone();
Self::Manual {
name,
defn: Box::new(py_ortho.into()),
}
}),
}
}
}
impl From<PyDcmExpr> for DcmExpr {
fn from(value: PyDcmExpr) -> Self {
Python::attach(|py| match value {
PyDcmExpr::Identity {
from_id: from,
to_id: to,
} => DcmExpr::Identity { from, to },
PyDcmExpr::R1 {
angle_rad,
from_id: from,
to_id: to,
} => DcmExpr::R1 {
angle_rad,
from,
to,
},
PyDcmExpr::R2 {
angle_rad,
from_id: from,
to_id: to,
} => DcmExpr::R2 {
angle_rad,
from,
to,
},
PyDcmExpr::R3 {
angle_rad,
from_id: from,
to_id: to,
} => DcmExpr::R3 {
angle_rad,
from,
to,
},
PyDcmExpr::Quaternion {
x,
y,
z,
w,
from_id: from,
to_id: to,
} => DcmExpr::Quaternion {
x,
y,
z,
w,
from,
to,
},
PyDcmExpr::RIC {
state,
from_id: from,
to_id: to,
} => DcmExpr::RIC {
state: Box::new(state.borrow(py).clone().into()),
from,
to,
},
PyDcmExpr::RCN {
state,
from_id: from,
to_id: to,
} => DcmExpr::RCN {
state: Box::new(state.borrow(py).clone().into()),
from,
to,
},
PyDcmExpr::VNC {
state,
from_id: from,
to_id: to,
} => DcmExpr::VNC {
state: Box::new(state.borrow(py).clone().into()),
from,
to,
},
PyDcmExpr::SEZ {
state,
from_id: from,
to_id: to,
} => DcmExpr::SEZ {
state: Box::new(state.borrow(py).clone().into()),
from,
to,
},
PyDcmExpr::Triad {
primary_axis,
primary_vec,
secondary_axis,
secondary_vec,
from_id: from,
to_id: to,
} => DcmExpr::Triad {
primary_axis: Box::new(primary_axis.borrow(py).clone().into()),
primary_vec: Box::new(primary_vec.borrow(py).clone().into()),
secondary_axis: Box::new(secondary_axis.borrow(py).clone().into()),
secondary_vec: Box::new(secondary_vec.borrow(py).clone().into()),
from,
to,
},
})
}
}