1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//! `CPosition` — a geographic coordinate.
/// A geographic position (latitude/longitude in decimal degrees).
///
/// Unlike the other API types this is an **owned value**, not a borrowed
/// handle: EuroScope's `CPosition` is a plain lat/lon pair, so we copy it out.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Position {
/// Latitude in decimal degrees (north positive).
pub latitude: f64,
/// Longitude in decimal degrees (east positive).
pub longitude: f64,
}
impl Position {
/// Construct from decimal degrees.
pub fn new(latitude: f64, longitude: f64) -> Self {
Self {
latitude,
longitude,
}
}
/// Parse EuroScope coordinate strings, e.g.
/// `Position::from_strings("E019.17.35.260", "N047.25.24.615")`. Note the
/// **longitude-then-latitude** argument order (matching the SDK). Returns
/// `None` if either string is malformed.
pub fn from_strings(longitude: &str, latitude: &str) -> Option<Self> {
let lon_c = std::ffi::CString::new(longitude).ok()?;
let lat_c = std::ffi::CString::new(latitude).ok()?;
let (mut lat, mut lon) = (0.0_f64, 0.0_f64);
// SAFETY: valid NUL-terminated strings and out-param slots.
let ok = unsafe {
euroscope_sys::es_position_from_strings(
lon_c.as_ptr(),
lat_c.as_ptr(),
&raw mut lat,
&raw mut lon,
)
};
ok.then_some(Self {
latitude: lat,
longitude: lon,
})
}
/// Great-circle distance to another position, in nautical miles, using
/// EuroScope's formula.
pub fn distance_to(self, other: Self) -> f64 {
// SAFETY: pure computation, no pointers involved.
unsafe {
euroscope_sys::es_position_distance(
self.latitude,
self.longitude,
other.latitude,
other.longitude,
)
}
}
/// Magnetic heading (degrees) from this position to another, corrected by
/// the sector file's magnetic variation.
pub fn direction_to(self, other: Self) -> f64 {
// SAFETY: pure computation, no pointers involved.
unsafe {
euroscope_sys::es_position_direction(
self.latitude,
self.longitude,
other.latitude,
other.longitude,
)
}
}
}