kasane_logic/spatial_id/flex_id/
impls.rs1use std::fmt;
2
3use crate::{
4 Coordinate, Ecef, Error, F_MAX, F_MIN, FlexId, SpatialId, SpatialIdError, TemporalId, XY_MAX,
5 spatial_id::helpers,
6};
7
8impl fmt::Display for FlexId {
9 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
10 write!(
12 f,
13 "{}/{}|{}/{}|{}/{}",
14 self.f_zoomlevel,
15 self.f_index,
16 self.x_zoomlevel,
17 self.x_index,
18 self.y_zoomlevel,
19 self.y_index
20 )?;
21
22 if !self.temporal_id.is_whole() {
24 write!(f, "_{}", self.temporal_id)?;
25 };
26 Ok(())
27 }
28}
29
30impl SpatialId for FlexId {
31 fn f_min(&self) -> i32 {
32 F_MIN[self.f_zoomlevel as usize]
33 }
34
35 fn f_max(&self) -> i32 {
36 F_MAX[self.f_zoomlevel as usize]
37 }
38
39 fn x_max(&self) -> u32 {
40 XY_MAX[self.x_zoomlevel as usize]
41 }
42
43 fn y_max(&self) -> u32 {
44 XY_MAX[self.y_zoomlevel as usize]
45 }
46
47 fn move_f(&mut self, by: i32) -> Result<(), crate::Error> {
48 let new = self.f_index.checked_add(by).ok_or_else(|| {
49 Error::from(SpatialIdError::FOutOfRange {
50 f: if by >= 0 { i32::MAX } else { i32::MIN },
51 z: self.f_zoomlevel,
52 })
53 })?;
54
55 if new < self.f_min() || new > self.f_max() {
56 return Err(SpatialIdError::FOutOfRange {
57 f: new,
58 z: self.f_zoomlevel,
59 }
60 .into());
61 }
62
63 self.f_index = new;
64 Ok(())
65 }
66
67 fn move_x(&mut self, by: i32) {
68 let max_len = (self.x_max() + 1) as i32;
69 let new = (self.x_index as i32 + by).rem_euclid(max_len);
70 self.x_index = new as u32;
71 }
72
73 fn move_y(&mut self, by: i32) -> Result<(), crate::Error> {
74 let new = if by >= 0 {
75 self.y_index.checked_add(by as u32).ok_or_else(|| {
76 Error::from(SpatialIdError::YOutOfRange {
77 y: u32::MAX,
78 z: self.y_zoomlevel,
79 })
80 })?
81 } else {
82 self.y_index
83 .checked_sub(by.unsigned_abs())
84 .ok_or(SpatialIdError::YOutOfRange {
85 y: self.y_min(),
86 z: self.y_zoomlevel,
87 })?
88 };
89
90 if new > self.y_max() {
91 return Err(SpatialIdError::YOutOfRange {
92 y: new,
93 z: self.y_zoomlevel,
94 }
95 .into());
96 }
97
98 self.y_index = new;
99
100 Ok(())
101 }
102
103 fn length_f_meters(&self) -> f64 {
104 2_f64.powi(25 - self.f_zoomlevel() as i32)
105 }
106
107 fn length_x_meters(&self) -> f64 {
108 let ecef: Ecef = self.spatial_center().into();
109 let r = (ecef.x() * ecef.x() + ecef.y() * ecef.y()).sqrt();
110 r * 2.0 * std::f64::consts::PI / (2_i32.pow(self.x_zoomlevel() as u32) as f64)
111 }
112
113 fn length_y_meters(&self) -> f64 {
114 let ecef: Ecef = self.spatial_center().into();
115 let r = (ecef.x() * ecef.x() + ecef.y() * ecef.y()).sqrt();
116 r * 2.0 * std::f64::consts::PI / (2_i32.pow(self.y_zoomlevel() as u32) as f64)
117 }
118
119 fn spatial_center(&self) -> crate::Coordinate {
120 unsafe {
121 Coordinate::new_unchecked(
122 helpers::latitude(self.y_index as f64 + 0.5, self.y_zoomlevel),
123 helpers::longitude(self.x_index as f64 + 0.5, self.x_zoomlevel),
124 helpers::altitude(self.f_index as f64 + 0.5, self.f_zoomlevel),
125 )
126 }
127 }
128
129 fn spatial_vertices(&self) -> [crate::Coordinate; 8] {
130 let xs = [self.x_index as f64, self.x_index as f64 + 1.0];
131 let ys = [self.y_index as f64, self.y_index as f64 + 1.0];
132 let fs = [self.f_index as f64, self.f_index as f64 + 1.0];
133
134 let lon2 = [
136 helpers::longitude(xs[0], self.x_zoomlevel),
137 helpers::longitude(xs[1], self.x_zoomlevel),
138 ];
139 let lat2 = [
140 helpers::latitude(ys[0], self.y_zoomlevel),
141 helpers::latitude(ys[1], self.y_zoomlevel),
142 ];
143 let alt2 = [
144 helpers::altitude(fs[0], self.f_zoomlevel),
145 helpers::altitude(fs[1], self.f_zoomlevel),
146 ];
147
148 let mut out = [Coordinate::default(); 8];
150
151 let mut i = 0;
152 for f_i in 0..2 {
153 for y_i in 0..2 {
154 for x_i in 0..2 {
155 out[i]
156 .set_longitude(lon2[x_i])
157 .expect("longitude must be within valid range");
158 out[i]
159 .set_latitude(lat2[y_i])
160 .expect("latitude must be within valid range");
161 out[i]
162 .set_altitude(alt2[f_i])
163 .expect("altitude must be within valid range");
164 i += 1;
165 }
166 }
167 }
168
169 out
170 }
171
172 fn temporal(&self) -> &TemporalId {
173 &self.temporal_id
174 }
175
176 fn temporal_mut(&mut self) -> &mut TemporalId {
177 &mut self.temporal_id
178 }
179}