pub struct GnssPosition {
pub latitude: f64,
pub longitude: f64,
pub timestamp: DateTime<FixedOffset>,
pub crs: String,
pub metadata: HashMap<String, String>,
pub heading: Option<f64>,
pub distance: Option<f64>,
}Expand description
Represents a single GNSS measurement from a train journey
Each GnssPosition captures a timestamped geographic location with explicit
coordinate reference system (CRS) information. Additional metadata can be
preserved for audit trails and debugging.
§Validation
- Latitude must be in range [-90.0, 90.0]
- Longitude must be in range [-180.0, 180.0]
- Timestamp must include timezone information (RFC3339 format)
§Examples
use tp_lib_core::GnssPosition;
use chrono::{DateTime, FixedOffset};
let timestamp = DateTime::parse_from_rfc3339("2025-12-09T14:30:00+01:00")?;
let position = GnssPosition::new(
50.8503, // latitude
4.3517, // longitude
timestamp,
"EPSG:4326".to_string(),
)?;
assert_eq!(position.latitude, 50.8503);
assert_eq!(position.crs, "EPSG:4326");Fields§
§latitude: f64Latitude in decimal degrees (-90.0 to 90.0)
longitude: f64Longitude in decimal degrees (-180.0 to 180.0)
timestamp: DateTime<FixedOffset>Timestamp with timezone offset (e.g., 2025-12-09T14:30:00+01:00)
crs: StringCoordinate Reference System (e.g., “EPSG:4326” for WGS84)
metadata: HashMap<String, String>Additional metadata from CSV (preserved for output)
heading: Option<f64>Train heading in degrees (0-360), None if not available 0° = North, 90° = East, 180° = South, 270° = West
distance: Option<f64>Distance from previous GNSS position in meters, None if not available or first position
Implementations§
Source§impl GnssPosition
impl GnssPosition
Sourcepub fn new(
latitude: f64,
longitude: f64,
timestamp: DateTime<FixedOffset>,
crs: String,
) -> Result<Self, ProjectionError>
pub fn new( latitude: f64, longitude: f64, timestamp: DateTime<FixedOffset>, crs: String, ) -> Result<Self, ProjectionError>
Create a new GNSS position with validation
Sourcepub fn with_heading_distance(
latitude: f64,
longitude: f64,
timestamp: DateTime<FixedOffset>,
crs: String,
heading: Option<f64>,
distance: Option<f64>,
) -> Result<Self, ProjectionError>
pub fn with_heading_distance( latitude: f64, longitude: f64, timestamp: DateTime<FixedOffset>, crs: String, heading: Option<f64>, distance: Option<f64>, ) -> Result<Self, ProjectionError>
Create a new GNSS position with optional heading and distance
Sourcepub fn validate_heading(&self) -> Result<(), ProjectionError>
pub fn validate_heading(&self) -> Result<(), ProjectionError>
Validate heading if present (must be 0-360°)
Sourcepub fn is_opposite_heading(h1: f64, h2: f64) -> bool
pub fn is_opposite_heading(h1: f64, h2: f64) -> bool
Check if two headings are opposite Returns true if headings are closer to 180° apart than to 0° apart
Logic: Compare distance to 180° shift vs normal distance If shifting by 180° gives smaller circular distance, they’re opposite
Sourcepub fn heading_difference(h1: f64, h2: f64) -> f64
pub fn heading_difference(h1: f64, h2: f64) -> f64
Calculate angular difference between two headings Accounts for circular nature of compass bearings Accounts for possible opposite headings (180° apart)
Sourcepub fn validate_latitude(&self) -> Result<(), ProjectionError>
pub fn validate_latitude(&self) -> Result<(), ProjectionError>
Validate latitude range
Sourcepub fn validate_longitude(&self) -> Result<(), ProjectionError>
pub fn validate_longitude(&self) -> Result<(), ProjectionError>
Validate longitude range
Sourcepub fn validate_timezone(&self) -> Result<(), ProjectionError>
pub fn validate_timezone(&self) -> Result<(), ProjectionError>
Validate timezone is present (type-level guarantee with DateTime<FixedOffset>)
Trait Implementations§
Source§impl Clone for GnssPosition
impl Clone for GnssPosition
Source§fn clone(&self) -> GnssPosition
fn clone(&self) -> GnssPosition
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for GnssPosition
impl Debug for GnssPosition
Source§impl<'de> Deserialize<'de> for GnssPosition
impl<'de> Deserialize<'de> for GnssPosition
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for GnssPosition
impl RefUnwindSafe for GnssPosition
impl Send for GnssPosition
impl Sync for GnssPosition
impl Unpin for GnssPosition
impl UnsafeUnpin for GnssPosition
impl UnwindSafe for GnssPosition
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more