Skip to content

Commit

Permalink
Exposing more of WGS84 in the python
Browse files Browse the repository at this point in the history
  • Loading branch information
dahlend committed Oct 1, 2024
1 parent fada65b commit ec6618a
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 84 deletions.
18 changes: 18 additions & 0 deletions src/kete/rust/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,21 @@ pub fn frame_change_py(
pub fn wgs_lat_lon_to_ecef(lat: f64, lon: f64, h: f64) -> (f64, f64, f64) {
geodetic_lat_lon_to_ecef(lat.to_radians(), lon.to_radians(), h)
}

/// Compute WCS84 Geodetic latitude/longitude/height from a ECEF position.
///
/// This returns the lat, lon, and height from the WGS84 oblate Earth.
///
/// Parameters
/// ----------
/// x :
/// ECEF x position in km.
/// y :
/// ECEF y position in km.
/// z :
/// ECEF z position in km.
#[pyfunction]
#[pyo3(name = "ecef_to_wgs_lat_lon")]
pub fn ecef_to_wgs_lat_lon(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
ecef_to_geodetic_lat_lon(x, y, z)
}
1 change: 1 addition & 0 deletions src/kete/rust/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ fn _core(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {

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!(kepler::compute_eccentric_anomaly_py, m)?)?;
m.add_function(wrap_pyfunction!(kepler::propagation_kepler_py, m)?)?;
Expand Down
27 changes: 16 additions & 11 deletions src/kete/rust/spice/pck.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use kete_core::prelude::*;
use kete_core::frames::ecef_to_geodetic_lat_lon;
use kete_core::spice::{get_pck_singleton, get_spk_singleton};
use kete_core::{constants, prelude::*};
use pyo3::{pyfunction, PyResult};

use crate::frame::PyFrames;
use crate::state::PyState;
use crate::vector::Vector;

/// Load all specified files into the PCK shared memory singleton.
#[pyfunction]
Expand Down Expand Up @@ -64,29 +63,35 @@ pub fn pck_earth_frame_py(
Ok(PyState(state))
}

/// Convert a [`State`] to the Earth's surface reference frame.
/// Convert a [`State`] to the Earth's surface lat/lon/height on the WGS84 reference.
///
/// This requires the `earth_000101_*.pck` file to be loaded which contains the
/// instantaneous earth frame information. The one provided by kete has dates from
/// around 2000 to early 2024. New files may be downloaded from the NAIF website for
/// additional precision or years of epoch. The current file is accurate to ~5 cm
/// precision.
/// around 2000 to early 2024, along with predicts into the future. New files may be
/// downloaded from the NAIF website for additional precision or years of epoch.
///
/// Parameters
/// ----------
/// state: State
/// Convert a given state to an geocentered State.
/// Convert the given state to latitude, longitude, and height in km on the WGS84
/// reference.
#[pyfunction]
#[pyo3(name = "pck_state_to_frame")]
pub fn pck_state_to_earth(state: PyState) -> PyResult<Vector> {
#[pyo3(name = "state_to_earth_pos")]
pub fn pck_state_to_earth(state: PyState) -> PyResult<(f64, f64, f64)> {
let pcks = get_pck_singleton().try_read().unwrap();
let state = state.change_center(399)?.as_ecliptic()?;
let frame = pcks.try_get_orientation(3000, state.jd())?;
let mut state = state.0;

state.try_change_frame_mut(frame)?;
let [x, y, z] = state.pos;
let (lat, lon, height) = ecef_to_geodetic_lat_lon(
x * constants::AU_KM,
y * constants::AU_KM,
z * constants::AU_KM,
);

Ok(Vector::new(state.pos, PyFrames::Undefined))
Ok((lat.to_degrees(), lon.to_degrees(), height))
}

/// Reset the contents of the PCK shared memory to the default set of PCK kernels.
Expand Down
2 changes: 2 additions & 0 deletions src/kete/spice.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from .constants import AU_KM
from .cache import download_file, cache_path
from .vector import Frames, State
from ._core import state_to_earth_pos

__all__ = [
"SpkInfo",
Expand All @@ -23,6 +24,7 @@
"kernel_header_comments",
"mpc_code_to_ecliptic",
"earth_pos_to_ecliptic",
"state_to_earth_pos",
"moon_illumination_frac",
]

Expand Down
12 changes: 11 additions & 1 deletion src/kete/vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,20 @@
State,
CometElements,
SimultaneousStates,
wgs_lat_lon_to_ecef,
ecef_to_wgs_lat_lon,
)


__all__ = ["Frames", "Vector", "State", "CometElements", "SimultaneousStates"]
__all__ = [
"Frames",
"Vector",
"State",
"CometElements",
"SimultaneousStates",
"wgs_lat_lon_to_ecef",
"ecef_to_wgs_lat_lon",
]

Vector.dec_dms = property(
fget=lambda self: conversion.dec_degrees_to_dms(self.dec),
Expand Down
22 changes: 11 additions & 11 deletions src/kete_core/src/spice/daf.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/// Support for arbitrary DAF files
/// DAF is a superset which includes SPK and PCK files.
///
/// DAF files are laid out in 1024 Byte "Records"
/// - The first record is header information about the contents of the file.
/// - The following N records are text comments.
/// - Immediately following the comments there is a Summary Record.
///
/// These summary records contain the location information for all the contents
/// of the DAF file.
///
//! Support for arbitrary DAF files
//! DAF is a superset which includes SPK and PCK files.
//!
//! DAF files are laid out in 1024 Byte "Records"
//! - The first record is header information about the contents of the file.
//! - The following N records are text comments.
//! - Immediately following the comments there is a Summary Record.
//!
//! These summary records contain the location information for all the contents
//! of the DAF file.
//!
use super::binary::{
bytes_to_f64, bytes_to_f64_vec, bytes_to_i32, bytes_to_i32_vec, bytes_to_string,
read_bytes_exact, read_f64_vec, read_str,
Expand Down
6 changes: 3 additions & 3 deletions src/kete_core/src/spice/naif_ids.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// List of NAIF ID values.
/// This list is not comprehensive, but is more complete than the C-SPICE
/// implementation.
//! List of NAIF ID values.
//! This list is not comprehensive, but is more complete than the C-SPICE
//! implementation.
use lazy_static::lazy_static;
use serde::Deserialize;

Expand Down
16 changes: 7 additions & 9 deletions src/kete_core/src/spice/pck.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
/// Loading and reading of states from JPL PCK kernel files.
///
/// PCKs are intended to be loaded into a singleton which is accessible via the
/// [`get_pck_singleton`] function defined below. This singleton is wrapped in a RwLock,
/// meaning before its use it must by unwrapped. A vast majority of intended use cases
/// will only be the read case.
/// ```
///
///
//! Loading and reading of states from JPL PCK kernel files.
//!
//! PCKs are intended to be loaded into a singleton which is accessible via the
//! [`get_pck_singleton`] function defined below. This singleton is wrapped in a RwLock,
//! meaning before its use it must by unwrapped. A vast majority of intended use cases
//! will only be the read case.
//!
use super::daf::{DAFType, DafFile};
use super::pck_segments::PckSegment;
use crate::errors::{Error, NeosResult};
Expand Down
30 changes: 15 additions & 15 deletions src/kete_core/src/spice/pck_segments.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
//! Most users should interface with `pck.rs`, not this module.
//!
//! PCK Files are collections of `Segments`, which are ranges of times where the state
//! of an object is recorded. These segments are typically made up of many individual
//! `Records`, with an associated maximum and minimum time where they are valid for.
//!
//! There are unique structs for each possible segment type, not all are currently
//! supported. Each segment type must implement the PCKSegment trait, which allows for
//! the loading and querying of states contained within.
//!
//! <https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/pck.html>
//!
//! There is a lot of repetition in this file, as many of the segment types have very
//! similar internal structures.
//!
use super::daf::DafArray;
/// Most users should interface with `pck.rs`, not this module.
///
/// PCK Files are collections of `Segments`, which are ranges of times where the state
/// of an object is recorded. These segments are typically made up of many individual
/// `Records`, with an associated maximum and minimum time where they are valid for.
///
/// There are unique structs for each possible segment type, not all are currently
/// supported. Each segment type must implement the PCKSegment trait, which allows for
/// the loading and querying of states contained within.
///
/// <https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/pck.html>
///
/// There is a lot of repetition in this file, as many of the segment types have very
/// similar internal structures.
///
use super::interpolation::*;
use super::{jd_to_spice_jd, spice_jds_to_jd};
use crate::errors::Error;
Expand Down
40 changes: 20 additions & 20 deletions src/kete_core/src/spice/spk.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
/// Loading and reading of states from JPL SPK kernel files.
///
/// SPKs are intended to be loaded into a singleton which is accessible via the
/// [`get_spk_singleton`] function defined below. This singleton is wrapped in a RwLock,
/// meaning before its use it must by unwrapped. A vast majority of intended use cases
/// will only be the read case.
///
/// Here is a small worked example:
/// ```
/// use kete_core::spice::get_spk_singleton;
/// use kete_core::frames::Frame;
///
/// // get a read-only reference to the [`SegmentCollection`]
/// let singleton = get_spk_singleton().try_read().unwrap();
///
/// // get the state of 399 (Earth) with respect to the Sun (10)
/// let state = singleton.try_get_state(399, 2451545.0, 10, Frame::Ecliptic);
/// ```
///
///
//! Loading and reading of states from JPL SPK kernel files.
//!
//! SPKs are intended to be loaded into a singleton which is accessible via the
//! [`get_spk_singleton`] function defined below. This singleton is wrapped in a RwLock,
//! meaning before its use it must by unwrapped. A vast majority of intended use cases
//! will only be the read case.
//!
//! Here is a small worked example:
//! ```
//! use kete_core::spice::get_spk_singleton;
//! use kete_core::frames::Frame;
//!
//! // get a read-only reference to the [`SegmentCollection`]
//! let singleton = get_spk_singleton().try_read().unwrap();
//!
//! // get the state of 399 (Earth) with respect to the Sun (10)
//! let state = singleton.try_get_state(399, 2451545.0, 10, Frame::Ecliptic);
//! ```
//!
//!
use super::daf::DafFile;
use super::{spk_segments::*, DAFType};
use crate::errors::Error;
Expand Down
28 changes: 14 additions & 14 deletions src/kete_core/src/spice/spk_segments.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
/// Most users should interface with `spk.rs`, not this module.
///
/// SPK Files are collections of `Segments`, which are ranges of times where the state
/// of an object is recorded. These segments are typically made up of many individual
/// `Records`, with an associated maximum and minimum time where they are valid for.
///
/// There are unique structs for each possible segment type, not all are currently
/// supported. Each segment type must implement the SPKSegment trait, which allows for
/// the loading and querying of states contained within.
///
/// <https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/spk.html#Supported%20Data%20Types>
///
/// There is a lot of repetition in this file, as many of the segment types have very
/// similar internal structures.
//! Most users should interface with `spk.rs`, not this module.
//!
//! SPK Files are collections of `Segments`, which are ranges of times where the state
//! of an object is recorded. These segments are typically made up of many individual
//! `Records`, with an associated maximum and minimum time where they are valid for.
//!
//! There are unique structs for each possible segment type, not all are currently
//! supported. Each segment type must implement the SPKSegment trait, which allows for
//! the loading and querying of states contained within.
//!
//! <https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/spk.html#Supported%20Data%20Types>
//!
//! There is a lot of repetition in this file, as many of the segment types have very
//! similar internal structures.
use super::interpolation::*;
use super::{jd_to_spice_jd, spice_jds_to_jd, DafArray};
use crate::constants::AU_KM;
Expand Down

0 comments on commit ec6618a

Please sign in to comment.