From c40c21fa82cd47e37e93290dab257eb18c60d26f Mon Sep 17 00:00:00 2001 From: Dar Dahlen Date: Sun, 13 Oct 2024 23:58:34 -0600 Subject: [PATCH] Expose python-rust interface to external libraries (#137) * Expose python-rust interface to external libraries --- Cargo.toml | 2 +- src/kete/rust/covariance.rs | 3 +++ src/kete/rust/elements.rs | 1 + src/kete/rust/fitting.rs | 4 ++++ src/kete/rust/flux/common.rs | 1 + src/kete/rust/flux/mod.rs | 1 + src/kete/rust/flux/models.rs | 6 +++--- src/kete/rust/fovs/checks.rs | 11 ++++++++++ src/kete/rust/fovs/collection.rs | 9 +++++++- src/kete/rust/fovs/definitions.rs | 15 ++++++++++++- src/kete/rust/fovs/mod.rs | 1 + src/kete/rust/frame.rs | 26 ++++++---------------- src/kete/rust/horizons.rs | 2 ++ src/kete/rust/kepler.rs | 1 + src/kete/rust/lib.rs | 36 +++++++++++++++---------------- src/kete/rust/nongrav.rs | 3 +++ src/kete/rust/propagation.rs | 1 + src/kete/rust/simult_states.rs | 3 +++ src/kete/rust/spice/mod.rs | 3 +-- src/kete/rust/spice/tle.rs | 10 --------- src/kete/rust/state.rs | 3 +++ src/kete/rust/state_transition.rs | 2 ++ src/kete/rust/time.rs | 4 ++++ src/kete/rust/vector.rs | 17 +++++++++++++++ 24 files changed, 108 insertions(+), 57 deletions(-) delete mode 100644 src/kete/rust/spice/tle.rs diff --git a/Cargo.toml b/Cargo.toml index b1d6a1b..2317e92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ bincode = {version = "2.0.0-rc.3", features=["derive", "serde"]} [lib] name = "_core" path = "src/kete/rust/lib.rs" -crate-type = ["cdylib"] +crate-type = ["cdylib", "lib"] [workspace] members = ["src/kete_core"] diff --git a/src/kete/rust/covariance.rs b/src/kete/rust/covariance.rs index 121d0d3..e26cdff 100644 --- a/src/kete/rust/covariance.rs +++ b/src/kete/rust/covariance.rs @@ -1,3 +1,5 @@ +//! Covariance matrix representation + use std::{collections::HashMap, fmt::Debug}; use crate::state::PyState; @@ -27,6 +29,7 @@ impl FileIO for Covariance {} #[pymethods] impl Covariance { + /// Create a new covariance object #[new] #[allow(clippy::too_many_arguments)] pub fn new( diff --git a/src/kete/rust/elements.rs b/src/kete/rust/elements.rs index 1ab045c..9b386ba 100644 --- a/src/kete/rust/elements.rs +++ b/src/kete/rust/elements.rs @@ -1,3 +1,4 @@ +//! Python support for orbital elements use kete_core::elements; use kete_core::prelude; use pyo3::{pyclass, pymethods, PyResult}; diff --git a/src/kete/rust/fitting.rs b/src/kete/rust/fitting.rs index 5f339b8..e9a0fe6 100644 --- a/src/kete/rust/fitting.rs +++ b/src/kete/rust/fitting.rs @@ -1,12 +1,16 @@ +//! Basic statistics use kete_core::{fitting, stats}; use pyo3::pyfunction; + +/// Perform a KS test between two vectors of values. #[pyfunction] #[pyo3(name = "ks_test")] pub fn ks_test_py(sample_a: Vec, sample_b: Vec) -> f64 { stats::two_sample_ks_statistic(&sample_a, &sample_b) } +/// Fit the reduced chi squared value for a collection of data with uncertainties. #[pyfunction] #[pyo3(name = "fit_chi2")] pub fn fit_chi2_py(data: Vec, sigmas: Vec) -> f64 { diff --git a/src/kete/rust/flux/common.rs b/src/kete/rust/flux/common.rs index f87d65e..884244c 100644 --- a/src/kete/rust/flux/common.rs +++ b/src/kete/rust/flux/common.rs @@ -419,6 +419,7 @@ pub fn w4_color_correction_py(temp: f64) -> f64 { w4_color_correction(temp) } +/// The normal vectors of the fib lattice #[pyfunction] #[pyo3(name = "fib_lattice_vecs")] pub fn fib_lattice_vecs_py(n_facets: usize) -> Vec<[f64; 3]> { diff --git a/src/kete/rust/flux/mod.rs b/src/kete/rust/flux/mod.rs index bac336a..30eb374 100644 --- a/src/kete/rust/flux/mod.rs +++ b/src/kete/rust/flux/mod.rs @@ -1,3 +1,4 @@ +//! Python support for flux calculations mod common; mod models; mod reflected; diff --git a/src/kete/rust/flux/models.rs b/src/kete/rust/flux/models.rs index 5482392..411a77c 100644 --- a/src/kete/rust/flux/models.rs +++ b/src/kete/rust/flux/models.rs @@ -41,7 +41,7 @@ impl From for PyModelResults { impl PyModelResults { #[new] #[pyo3(signature = (fluxes, thermal_fluxes, hg_fluxes, v_band_magnitude, v_band_flux, magnitudes=None))] - #[allow(clippy::too_many_arguments)] + #[allow(clippy::too_many_arguments, missing_docs)] pub fn new( fluxes: Vec, thermal_fluxes: Vec, @@ -192,7 +192,7 @@ impl From for PyNeatmParams { #[pymethods] impl PyNeatmParams { #[new] - #[allow(clippy::too_many_arguments)] + #[allow(clippy::too_many_arguments, missing_docs)] #[pyo3(signature = (desig, band_wavelength, band_albedos, h_mag=None, diam=None, vis_albedo=None, beaming=None, g_param=None, c_hg=None, emissivity=None, zero_mags=None))] pub fn new( @@ -531,7 +531,7 @@ impl From for PyFrmParams { #[pymethods] impl PyFrmParams { #[new] - #[allow(clippy::too_many_arguments)] + #[allow(clippy::too_many_arguments, missing_docs)] #[pyo3(signature = (desig, band_wavelength, band_albedos, h_mag=None, diam=None, vis_albedo=None, g_param=None, c_hg=None, emissivity=None, zero_mags=None))] pub fn new( diff --git a/src/kete/rust/fovs/checks.rs b/src/kete/rust/fovs/checks.rs index 6b0a9b7..f3a9fa5 100644 --- a/src/kete/rust/fovs/checks.rs +++ b/src/kete/rust/fovs/checks.rs @@ -109,6 +109,17 @@ pub fn fov_checks_py( Ok(visible.into_iter().flatten().collect()) } +/// Check if a list of loaded spice kernel objects are visible in the provided FOVs. +/// +/// Returns only the objects which are visible to the observer, adding a correction +/// for optical light delay. +/// +/// Parameters +/// ---------- +/// obj_ids : +/// Vector of spice kernel IDs to check. +/// fovs : +/// Collection of Field of Views to check. #[pyfunction] #[pyo3(name = "fov_spk_check")] pub fn fov_spk_checks_py(obj_ids: Vec, fovs: FOVListLike) -> Vec { diff --git a/src/kete/rust/fovs/collection.rs b/src/kete/rust/fovs/collection.rs index 3f23158..0514864 100644 --- a/src/kete/rust/fovs/collection.rs +++ b/src/kete/rust/fovs/collection.rs @@ -8,9 +8,12 @@ use std::fs::File; use std::io::{BufReader, BufWriter}; /// Polymorphic support -#[derive(FromPyObject)] +#[derive(FromPyObject, Debug)] pub enum FOVListLike { + /// Vector of allowed FOVs Vec(Vec), + + /// An FOVList which is equivalent. FOVList(FOVList), } @@ -33,6 +36,7 @@ impl FOVListLike { } } +/// A list of FOVs, which can be saved and loaded. #[pyclass(module = "kete", sequence)] #[derive(Debug, Clone)] pub struct FOVList(pub Vec); @@ -40,6 +44,7 @@ pub struct FOVList(pub Vec); #[pymethods] impl FOVList { #[new] + #[allow(missing_docs)] pub fn new(list: Vec) -> Self { FOVList(list) } @@ -53,6 +58,7 @@ impl FOVList { self.0.len() } + #[allow(missing_docs)] pub fn __getitem__(&self, mut idx: isize) -> PyResult { if idx < 0 { idx += self.0.len() as isize; @@ -65,6 +71,7 @@ impl FOVList { Ok(self.0[idx as usize].clone()) } + #[allow(missing_docs)] pub fn __repr__(&self) -> String { format!("FOVList(<{} FOVs>)", self.0.len()) } diff --git a/src/kete/rust/fovs/definitions.rs b/src/kete/rust/fovs/definitions.rs index 6c7dab4..88cc329 100644 --- a/src/kete/rust/fovs/definitions.rs +++ b/src/kete/rust/fovs/definitions.rs @@ -210,7 +210,7 @@ pub struct PyOmniDirectional(pub fov::OmniDirectional); /// Field of views supported by the python interface #[derive(Debug, Clone, FromPyObject)] -#[allow(clippy::upper_case_acronyms)] +#[allow(clippy::upper_case_acronyms, missing_docs)] pub enum AllowedFOV { WISE(PyWiseCmos), NEOS(PyNeosCmos), @@ -223,6 +223,7 @@ pub enum AllowedFOV { } impl AllowedFOV { + #[allow(missing_docs)] pub fn jd(&self) -> f64 { match self { AllowedFOV::NEOS(fov) => fov.0.observer().jd, @@ -236,6 +237,7 @@ impl AllowedFOV { } } + #[allow(missing_docs)] pub fn get_fov(self, idx: Option) -> fov::FOV { let idx = idx.unwrap_or_default(); match self { @@ -250,6 +252,7 @@ impl AllowedFOV { } } + #[allow(missing_docs)] pub fn unwrap(self) -> fov::FOV { match self { AllowedFOV::WISE(fov) => fov::FOV::Wise(fov.0), @@ -263,6 +266,7 @@ impl AllowedFOV { } } + #[allow(missing_docs)] pub fn __repr__(self) -> String { match self { AllowedFOV::WISE(fov) => fov.__repr__(), @@ -309,6 +313,7 @@ impl From for AllowedFOV { #[pymethods] impl PyWiseCmos { + /// Construct a WISE CMOS fov from a pointing vector, rotation and observer state. #[staticmethod] pub fn from_pointing( pointing: VectorLike, @@ -329,6 +334,7 @@ impl PyWiseCmos { )) } + /// Construct a WISE CMOS fov the corners of the FOV and observer state. #[new] pub fn new( corners: [VectorLike; 4], @@ -406,6 +412,7 @@ impl PyWiseCmos { #[pymethods] impl PyGenericRectangle { #[new] + /// Construct a Generic Rectangular FOV from a central vector, rotation, and observer state. pub fn new( pointing: VectorLike, rotation: f64, @@ -496,6 +503,7 @@ impl PyGenericRectangle { #[pymethods] impl PyGenericCone { + /// Construct a Generic Cone FOV from a central vector, angle, and observer state. #[new] pub fn new(pointing: VectorLike, angle: f64, observer: PyState) -> Self { let pointing = pointing.into_vector(observer.frame()); @@ -546,6 +554,7 @@ impl PyGenericCone { #[pymethods] impl PyOmniDirectional { #[new] + #[allow(missing_docs)] pub fn new(observer: PyState) -> Self { PyOmniDirectional(fov::OmniDirectional::new(observer.0)) } @@ -571,6 +580,7 @@ impl PyOmniDirectional { #[allow(clippy::too_many_arguments)] impl PyNeosCmos { #[new] + #[allow(missing_docs)] pub fn new( pointing: VectorLike, rotation: f64, @@ -711,6 +721,7 @@ impl PyNeosCmos { #[pymethods] #[allow(clippy::too_many_arguments)] impl PyNeosVisit { + #[allow(missing_docs)] #[new] pub fn new( x_width: f64, @@ -806,6 +817,7 @@ impl PyNeosVisit { self.0.rotation } + #[allow(missing_docs)] pub fn __len__(&self) -> usize { 4 } @@ -1058,6 +1070,7 @@ impl PyZtfField { .collect() } + #[allow(missing_docs)] pub fn __len__(&self) -> usize { self.0.n_patches() } diff --git a/src/kete/rust/fovs/mod.rs b/src/kete/rust/fovs/mod.rs index c15706c..a68c68d 100644 --- a/src/kete/rust/fovs/mod.rs +++ b/src/kete/rust/fovs/mod.rs @@ -1,3 +1,4 @@ +//! Python support for Fields of View mod checks; mod collection; mod definitions; diff --git a/src/kete/rust/frame.rs b/src/kete/rust/frame.rs index 4aecd2e..e38900d 100644 --- a/src/kete/rust/frame.rs +++ b/src/kete/rust/frame.rs @@ -1,3 +1,4 @@ +//! Python Frame of reference support use kete_core::frames::*; use pyo3::prelude::*; @@ -5,10 +6,15 @@ use pyo3::prelude::*; #[pyclass(frozen, eq, eq_int, name = "Frames", module = "kete")] #[derive(Clone, Copy, Debug, PartialEq)] pub enum PyFrames { + /// Ecliptic Frame Ecliptic, + /// Equatorial Frame Equatorial, + /// Galactic Frame Galactic, + /// FK4 Frame FK4, + /// Undefined Frame Undefined, } @@ -38,26 +44,6 @@ impl From for PyFrames { } } -/// Convert a vector in the input frame to the same vector in the output frame. -#[allow(clippy::too_many_arguments)] -#[pyfunction] -#[pyo3(name = "frame_change")] -pub fn frame_change_py( - states: Vec<[f64; 3]>, - input_frame: PyFrames, - output_frame: PyFrames, -) -> Vec<[f64; 3]> { - states - .into_iter() - .map(|vec| { - Into::::into(input_frame) - .try_vec_frame_change(vec.into(), output_frame.into()) - .unwrap() - .into() - }) - .collect() -} - /// Compute a ECEF position from WCS84 Geodetic latitude/longitude/height. /// /// This returns the X/Y/Z coordinates in km from the geocenter of the Earth. diff --git a/src/kete/rust/horizons.rs b/src/kete/rust/horizons.rs index e5c1fd7..86516a6 100644 --- a/src/kete/rust/horizons.rs +++ b/src/kete/rust/horizons.rs @@ -1,3 +1,4 @@ +//! JPL Horizons data representation use std::fmt::Debug; use crate::covariance::Covariance; @@ -66,6 +67,7 @@ impl FileIO for HorizonsProperties {} #[pymethods] impl HorizonsProperties { + /// Construct a new HorizonsProperties Object #[new] #[allow(clippy::too_many_arguments)] #[pyo3(signature = (desig, group=None, epoch=None, eccentricity=None, inclination=None, diff --git a/src/kete/rust/kepler.rs b/src/kete/rust/kepler.rs index 2f6b8ec..ca4256f 100644 --- a/src/kete/rust/kepler.rs +++ b/src/kete/rust/kepler.rs @@ -1,3 +1,4 @@ +//! Python support for kepler orbit calculations use itertools::Itertools; use kete_core::state::State; use kete_core::{constants, propagation}; diff --git a/src/kete/rust/lib.rs b/src/kete/rust/lib.rs index fe53abf..975c1b7 100644 --- a/src/kete/rust/lib.rs +++ b/src/kete/rust/lib.rs @@ -1,4 +1,5 @@ //! Core kete library code, which are wrappers over the kete_core rust package. +//! Primarily enables python interfaces #![deny( bad_style, @@ -24,22 +25,22 @@ use pyo3::prelude::*; -mod covariance; -mod elements; -mod fitting; -mod flux; -mod fovs; -mod frame; -mod horizons; -mod kepler; -mod nongrav; -mod propagation; -mod simult_states; -mod spice; -mod state; -mod state_transition; -mod time; -mod vector; +pub mod covariance; +pub mod elements; +pub mod fitting; +pub mod flux; +pub mod fovs; +pub mod frame; +pub mod horizons; +pub mod kepler; +pub mod nongrav; +pub mod propagation; +pub mod simult_states; +pub mod spice; +pub mod state; +pub mod state_transition; +pub mod time; +pub mod vector; // Due to the nature of this sort of interface, there is quite a bit of boiler-plate // code which is difficult to avoid. @@ -80,7 +81,6 @@ fn _core(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; - m.add_function(wrap_pyfunction!(frame::frame_change_py, m)?)?; m.add_function(wrap_pyfunction!(frame::wgs_lat_lon_to_ecef, m)?)?; m.add_function(wrap_pyfunction!(frame::ecef_to_wgs_lat_lon, m)?)?; m.add_function(wrap_pyfunction!(frame::calc_obliquity_py, m)?)?; @@ -130,8 +130,6 @@ fn _core(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(spice::daf_header_info_py, m)?)?; m.add_function(wrap_pyfunction!(spice::obs_codes, m)?)?; - m.add_function(wrap_pyfunction!(spice::load_tle, m)?)?; - m.add_function(wrap_pyfunction!(state_transition::compute_stm_py, m)?)?; m.add_function(wrap_pyfunction!(fitting::ks_test_py, m)?)?; diff --git a/src/kete/rust/nongrav.rs b/src/kete/rust/nongrav.rs index 3a56590..0ef3d73 100644 --- a/src/kete/rust/nongrav.rs +++ b/src/kete/rust/nongrav.rs @@ -1,3 +1,4 @@ +//! Python support for non-gravitational forces use kete_core::{errors::Error, propagation::NonGravModel}; use pyo3::{pyclass, pymethods, PyResult}; @@ -22,6 +23,7 @@ pub struct PyNonGravModel(pub NonGravModel); #[pymethods] impl PyNonGravModel { + /// Unused constructor for non-grav models. #[allow(clippy::new_without_default)] #[new] pub fn new() -> PyResult { @@ -158,6 +160,7 @@ impl PyNonGravModel { }) } + /// Text representation of this object pub fn __repr__(&self) -> String { match self.0 { NonGravModel::Dust { beta} => format!( diff --git a/src/kete/rust/propagation.rs b/src/kete/rust/propagation.rs index 99e4dbf..0974f2c 100644 --- a/src/kete/rust/propagation.rs +++ b/src/kete/rust/propagation.rs @@ -1,3 +1,4 @@ +//! Python support for n body propagation use itertools::Itertools; use kete_core::{ errors::Error, diff --git a/src/kete/rust/simult_states.rs b/src/kete/rust/simult_states.rs index 666f4fe..ccdee5f 100644 --- a/src/kete/rust/simult_states.rs +++ b/src/kete/rust/simult_states.rs @@ -1,3 +1,4 @@ +//! Python support for simultaneous States. use kete_core::errors::Error; use kete_core::io::FileIO; use kete_core::simult_states::SimultaneousStates; @@ -114,10 +115,12 @@ impl PySimultaneousStates { Ok(()) } + /// Length of states pub fn __len__(&self) -> usize { self.0.states.len() } + /// Get the Nth state pub fn __getitem__(&self, mut idx: isize) -> PyResult { if idx < 0 { idx += self.0.states.len() as isize; diff --git a/src/kete/rust/spice/mod.rs b/src/kete/rust/spice/mod.rs index 3e947f3..0f1776c 100644 --- a/src/kete/rust/spice/mod.rs +++ b/src/kete/rust/spice/mod.rs @@ -1,12 +1,11 @@ +//! Python support for reading SPICE kernels mod daf; mod pck; mod spk; -mod tle; pub use daf::*; pub use pck::*; pub use spk::*; -pub use tle::*; use pyo3::pyfunction; diff --git a/src/kete/rust/spice/tle.rs b/src/kete/rust/spice/tle.rs deleted file mode 100644 index a9bcd7c..0000000 --- a/src/kete/rust/spice/tle.rs +++ /dev/null @@ -1,10 +0,0 @@ -use pyo3::pyfunction; - -#[pyfunction] -#[pyo3(name = "load_tle")] -pub fn load_tle(line1: &str, line2: &str) { - let elm = sgp4::Elements::from_tle(None, line1.as_bytes(), line2.as_bytes()).unwrap(); - dbg!("{}", elm.epoch()); - let con = sgp4::Constants::from_elements(&elm).unwrap(); - dbg!(con); -} diff --git a/src/kete/rust/state.rs b/src/kete/rust/state.rs index f792ebb..a79cbd4 100644 --- a/src/kete/rust/state.rs +++ b/src/kete/rust/state.rs @@ -1,3 +1,4 @@ +//! Python support for State vectors use crate::elements::PyCometElements; use crate::frame::*; use crate::time::PyTime; @@ -34,6 +35,7 @@ impl From for PyState { #[pymethods] impl PyState { + /// Construct a new State #[new] #[pyo3(signature = (desig, jd, pos, vel, frame=None, center_id=10))] pub fn new( @@ -167,6 +169,7 @@ impl PyState { } } + /// Text representation of the state. pub fn __repr__(&self) -> String { format!( "State(desig={:?}, jd={:?}, pos={:?}, vel={:?}, frame={:?}, center_id={:?})", diff --git a/src/kete/rust/state_transition.rs b/src/kete/rust/state_transition.rs index 1093558..c235ddd 100644 --- a/src/kete/rust/state_transition.rs +++ b/src/kete/rust/state_transition.rs @@ -1,9 +1,11 @@ +//! State Transition matrix computation use kete_core::prelude::*; use kete_core::propagation::compute_state_transition; use pyo3::pyfunction; use crate::time::PyTime; +/// Compute an approximate STM #[pyfunction] #[pyo3(name = "compute_stm")] pub fn compute_stm_py( diff --git a/src/kete/rust/time.rs b/src/kete/rust/time.rs index cf62434..2032b0d 100644 --- a/src/kete/rust/time.rs +++ b/src/kete/rust/time.rs @@ -1,3 +1,5 @@ +//! Python support for time conversions. + use kete_core::{ errors::Error, time::{ @@ -54,6 +56,7 @@ impl From for PyTime { #[pymethods] impl PyTime { + /// Construct a new time object, TDB default. #[new] #[pyo3(signature = (jd, scaling="tdb"))] pub fn new(jd: f64, scaling: &str) -> PyResult { @@ -180,6 +183,7 @@ impl PyTime { Ok(self.0.utc().to_iso()?) } + /// J2000 epoch time. #[staticmethod] pub fn j2000() -> Self { PyTime(Time::::new(2451545.0)) diff --git a/src/kete/rust/vector.rs b/src/kete/rust/vector.rs index 8444e39..0bdd149 100644 --- a/src/kete/rust/vector.rs +++ b/src/kete/rust/vector.rs @@ -1,3 +1,4 @@ +//! Python vector support with frame information. use kete_core::frames::rotate_around; use pyo3::exceptions; use std::f64::consts::FRAC_PI_2; @@ -21,12 +22,14 @@ use pyo3::{PyResult, Python}; #[pyclass(sequence, frozen, module = "kete")] #[derive(Clone, Debug)] pub struct Vector { + /// X/Y/Z numbers of the vector pub raw: [f64; 3], frame: PyFrames, } impl Vector { + /// Construct a new vector pub fn new(raw: [f64; 3], frame: PyFrames) -> Self { Self { raw, frame } } @@ -35,11 +38,15 @@ impl Vector { /// Polymorphic support #[derive(Debug, FromPyObject)] pub enum VectorLike { + /// Vector directly Vec(Vector), + + /// Vector from x/y/z Arr([f64; 3]), } impl VectorLike { + /// Cast VectorLike into a Vector3 pub fn into_vec(self, target_frame: PyFrames) -> Vector3 { match self { VectorLike::Arr(arr) => Vector3::from(arr), @@ -52,6 +59,7 @@ impl VectorLike { } } + /// Cast VectorLike into a python Vector pub fn into_vector(self, target_frame: PyFrames) -> Vector { let vec = self.into_vec(target_frame); Vector { @@ -63,6 +71,7 @@ impl VectorLike { #[pymethods] impl Vector { + /// create new vector #[new] #[pyo3(signature = (raw, frame=None))] pub fn py_new(raw: VectorLike, frame: Option) -> PyResult { @@ -307,6 +316,7 @@ impl Vector { Self::new(rotated.into(), self.frame) } + #[allow(missing_docs)] pub fn __repr__(&self) -> String { // 1e-12 AU is about 15cm, this seems like a reasonable printing resolution let x = (self.raw[0] * 1e12).round() / 1e12 + 0.0; @@ -315,6 +325,7 @@ impl Vector { format!("Vector([{:?}, {:?}, {:?}], {:?})", x, y, z, self.frame) } + #[allow(missing_docs)] pub fn __sub__(&self, other: VectorLike) -> Self { let self_vec = Vector3::from(self.raw); let other_vec = other.into_vec(self.frame()); @@ -322,6 +333,7 @@ impl Vector { Self::new(diff.into(), self.frame) } + #[allow(missing_docs)] pub fn __add__(&self, other: VectorLike) -> Self { let self_vec = Vector3::from(self.raw); let other_vec = other.into_vec(self.frame()); @@ -329,24 +341,29 @@ impl Vector { Self::new(diff.into(), self.frame) } + #[allow(missing_docs)] pub fn __mul__(&self, other: f64) -> Self { let self_vec = Vector3::from(self.raw); Self::new((self_vec * other).into(), self.frame) } + #[allow(missing_docs)] pub fn __truediv__(&self, other: f64) -> Self { let self_vec = Vector3::from(self.raw); Self::new((self_vec / other).into(), self.frame) } + #[allow(missing_docs)] pub fn __neg__(&self) -> Self { Self::new([-self.x(), -self.y(), -self.z()], self.frame) } + #[allow(missing_docs)] pub fn __len__(&self) -> usize { 3 } + #[allow(missing_docs)] pub fn __getitem__(&self, idx: usize) -> PyResult { if idx >= 3 { return Err(PyErr::new::(""));