kasane_logic/geometry/point/ecef/
impls.rs1use std::{fmt, ops::Sub};
2
3use crate::{
4 Coordinate, Ecef, Error, MAX_ZOOM_LEVEL, Point, SpatialIdError, WGS84_A, WGS84_E2, WGS84_F,
5 geometry::traits::CoverSingleIds,
6};
7
8impl fmt::Debug for Ecef {
9 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
10 f.debug_struct("Ecef")
11 .field("x", &self.x)
12 .field("y", &self.y)
13 .field("z", &self.z)
14 .finish()
15 }
16}
17
18impl TryFrom<Ecef> for Coordinate {
19 type Error = Error;
20 fn try_from(value: Ecef) -> Result<Self, Self::Error> {
22 let x = value.x;
23 let y = value.y;
24 let z = value.z;
25
26 let lon = y.atan2(x);
27 let p = (x * x + y * y).sqrt();
28
29 let mut lat = (z / p).atan2(1.0 - WGS84_F);
31 let mut h = 0.0;
32
33 for _ in 0..10 {
34 let sin_lat = lat.sin();
35 let n = WGS84_A / (1.0 - WGS84_E2 * sin_lat * sin_lat).sqrt();
36 h = p / lat.cos() - n;
37
38 let new_lat = (z + WGS84_E2 * n * sin_lat).atan2(p);
39
40 if (new_lat - lat).abs() < 1e-12 {
41 lat = new_lat;
42 break;
43 }
44 lat = new_lat;
45 }
46
47 Coordinate::new(lat.to_degrees(), lon.to_degrees(), h)
48 }
49}
50
51impl Point for Ecef {}
52
53impl Sub for Ecef {
54 type Output = Self;
55
56 fn sub(self, other: Self) -> Self::Output {
57 Self {
58 x: self.x - other.x,
59 y: self.y - other.y,
60 z: self.z - other.z,
61 }
62 }
63}
64
65impl CoverSingleIds for Ecef {
66 fn cover_single_ids(
67 &self,
68 z: u8,
69 ) -> Result<impl Iterator<Item = crate::SingleId>, crate::Error> {
70 if z > MAX_ZOOM_LEVEL as u8 {
71 return Err(SpatialIdError::ZOutOfRange { z }.into());
72 }
73 Ok(std::iter::once(self.single_id(z)?))
74 }
75}