Skip to main content

kasane_logic/spatial_id/flex_id/
impls.rs

1use 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        //空間の情報の書き込み
11        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        //時間の情報があれば書き込み
23        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        // 各端点の値を前計算しておく
135        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        // 結果配列
149        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}