1use crate::{
2 geometry::{
3 CellId, ConvertFeature, ConvertVectorFeatureS2, ConvertVectorFeatureWM, S2CellId,
4 SimplifyVectorGeometry, build_sq_dists, clip_features, convert,
5 },
6 parsers::FeatureReader,
7};
8use alloc::{
9 collections::{BTreeMap, BTreeSet},
10 string::{String, ToString},
11 vec,
12 vec::Vec,
13};
14use s2json::{
15 Axis, Face, Feature, JSONCollection, MValue, Projection, Properties, VectorFeature,
16 VectorGeometry, VectorPoint,
17};
18use serde::{Deserialize, Serialize};
19
20pub trait HasLayer {
22 fn get_layer(&self) -> Option<String>;
24}
25impl HasLayer for () {
26 fn get_layer(&self) -> Option<String> {
27 None
28 }
29}
30impl HasLayer for MValue {
31 fn get_layer(&self) -> Option<String> {
32 let layer = self.get("layer");
33 match layer {
34 Some(l) => l.to_prim()?.to_string(),
35 _ => None,
36 }
37 }
38}
39
40#[derive(Debug, Clone, PartialEq)]
42pub struct Tile<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
43 pub id: CellId,
45 pub layers: BTreeMap<String, Layer<M, P, D>>,
47 pub transformed: bool,
49}
50impl<M: HasLayer + Clone, P: Clone + Default, D: Clone + Default> Tile<M, P, D> {
51 pub fn new(id: CellId) -> Self {
53 Self { id, layers: BTreeMap::new(), transformed: false }
54 }
55
56 pub fn len(&self) -> usize {
58 self.layers.len()
59 }
60
61 pub fn is_empty(&self) -> bool {
63 for layer in self.layers.values() {
64 if !layer.features.is_empty() {
65 return false;
66 }
67 }
68
69 true
70 }
71
72 pub fn add_reader<R>(&mut self, reader: R, layer: Option<String>)
74 where
75 R: FeatureReader<M, P, D>,
76 {
77 for feature in reader.iter() {
78 self.add_feature(feature, layer.clone());
79 }
80 }
81
82 pub fn add_feature(&mut self, feature: VectorFeature<M, P, D>, layer: Option<String>) {
84 let layer_name = feature
85 .metadata
86 .as_ref()
87 .and_then(|meta| meta.get_layer()) .or(layer) .unwrap_or_else(|| "default".to_string()); let layer = self.layers.entry(layer_name.clone()).or_insert(Layer::new(layer_name));
92 layer.features.push(feature);
93 }
94
95 pub fn transform(&mut self, tolerance: f64, maxzoom: Option<u8>) {
99 if self.transformed || self.id.is_face() {
100 self.transformed = true;
101 return;
102 }
103
104 let (_, zoom, i, j) = self.id.to_face_ij();
105 for layer in self.layers.values_mut() {
106 for feature in layer.features.iter_mut() {
107 feature.geometry.simplify(tolerance, zoom, maxzoom);
108 feature.geometry.transform(zoom.into(), i as f64, j as f64)
109 }
110 }
111
112 self.transformed = true;
113 }
114
115 pub fn split(&mut self, buffer: Option<f64>) -> TileChildren<M, P, D> {
117 let buffer = buffer.unwrap_or(0.0625);
118 let (face, zoom, i, j) = self.id.to_face_ij();
119 let [bl_id, br_id, tl_id, tr_id] = S2CellId::children_ij(face, zoom, i, j);
120 let mut children = TileChildren {
121 bottom_left: Tile::new(bl_id),
122 bottom_right: Tile::new(br_id),
123 top_left: Tile::new(tl_id),
124 top_right: Tile::new(tr_id),
125 };
126 let scale = (1 << zoom) as f64;
127 let k1 = 0.;
128 let k2 = 0.5;
129 let k3 = 0.5;
130 let k4 = 1.;
131 let i = i as f64;
132 let j = j as f64;
133
134 let mut tl: Option<Vec<VectorFeature<M, P, D>>>;
135 let mut bl: Option<Vec<VectorFeature<M, P, D>>>;
136 let mut tr: Option<Vec<VectorFeature<M, P, D>>>;
137 let mut br: Option<Vec<VectorFeature<M, P, D>>>;
138
139 for (name, layer) in self.layers.iter_mut() {
140 let features = &layer.features;
141 let left = clip_features(features, scale, i - k1, i + k3, Axis::X, buffer);
142 let right = clip_features(features, scale, i + k2, i + k4, Axis::X, buffer);
143
144 if let Some(left) = left {
145 bl = clip_features(&left, scale, j - k1, j + k3, Axis::Y, buffer);
146 tl = clip_features(&left, scale, j + k2, j + k4, Axis::Y, buffer);
147 if let Some(bl) = bl {
148 for d in bl {
149 children.bottom_left.add_feature(d, Some(name.to_string()));
150 }
151 }
152 if let Some(tl) = tl {
153 for d in tl {
154 children.top_left.add_feature(d, Some(name.to_string()));
155 }
156 }
157 }
158
159 if let Some(right) = right {
160 br = clip_features(&right, scale, j - k1, j + k3, Axis::Y, buffer);
161 tr = clip_features(&right, scale, j + k2, j + k4, Axis::Y, buffer);
162 if let Some(br) = br {
163 for d in br {
164 children.bottom_right.add_feature(d, Some(name.to_string()));
165 }
166 }
167 if let Some(tr) = tr {
168 for d in tr {
169 children.top_right.add_feature(d, Some(name.to_string()));
170 }
171 }
172 }
173 }
174
175 children
176 }
177}
178
179#[derive(Debug)]
181pub struct TileChildren<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
182 pub bottom_left: Tile<M, P, D>,
184 pub bottom_right: Tile<M, P, D>,
186 pub top_left: Tile<M, P, D>,
188 pub top_right: Tile<M, P, D>,
190}
191
192#[derive(Debug, Clone, PartialEq)]
194pub struct Layer<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
195 pub name: String,
197 pub features: Vec<VectorFeature<M, P, D>>,
199}
200impl<M, P: Clone + Default, D: Clone + Default> Layer<M, P, D> {
201 pub fn new(name: String) -> Self {
203 Self { name, features: vec![] }
204 }
205}
206
207#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
209pub struct TileStoreOptions {
210 pub projection: Option<Projection>,
212 pub minzoom: Option<u8>,
214 pub maxzoom: Option<u8>,
216 pub index_maxzoom: Option<u8>,
218 pub tolerance: Option<f64>,
221 pub buffer: Option<f64>,
223}
224
225#[derive(Debug, Clone, PartialEq)]
227pub struct TileStore<
228 M: HasLayer + Clone = (),
229 P: Clone + Default = Properties,
230 D: Clone + Default = MValue,
231> {
232 pub minzoom: u8,
234 pub maxzoom: u8,
236 pub faces: BTreeSet<Face>,
238 pub index_maxzoom: u8,
240 pub tolerance: f64,
242 pub buffer: f64,
244 pub tiles: BTreeMap<CellId, Tile<M, P, D>>,
246 pub projection: Projection,
248}
249impl<M: HasLayer + Clone, P: Clone + Default, D: Clone + Default> Default for TileStore<M, P, D> {
250 fn default() -> Self {
251 Self {
252 minzoom: 0,
253 maxzoom: 14,
254 faces: BTreeSet::<Face>::new(),
255 index_maxzoom: 4,
256 tolerance: 3. / 4_096.,
257 buffer: 0.0625,
258 tiles: BTreeMap::<CellId, Tile<M, P, D>>::new(),
259 projection: Projection::S2,
260 }
261 }
262}
263impl<M: HasLayer + Clone, P: Clone + Default, D: Clone + Default> TileStore<M, P, D>
264where
265 VectorFeature<M, P, D>: ConvertVectorFeatureWM<M, P, D> + ConvertVectorFeatureS2<M, P, D>,
266 Feature<M, P, D>: ConvertFeature<M, P, D>,
267{
268 pub fn new(data: JSONCollection<M, P, D>, options: TileStoreOptions) -> Self {
270 let mut tile_store = Self {
271 minzoom: options.minzoom.unwrap_or(0),
272 maxzoom: options.maxzoom.unwrap_or(14),
273 faces: BTreeSet::<Face>::new(),
274 index_maxzoom: options.index_maxzoom.unwrap_or(4),
275 tolerance: options.tolerance.unwrap_or(3.) / 4_096.,
276 buffer: options.buffer.unwrap_or(64.),
277 tiles: BTreeMap::<CellId, Tile<M, P, D>>::new(),
278 projection: options.projection.unwrap_or(Projection::S2),
279 };
280 debug_assert!(
282 tile_store.minzoom <= tile_store.maxzoom
283 && tile_store.maxzoom > 0
284 && tile_store.maxzoom <= 20,
285 "maxzoom should be in the 0-20 range"
286 );
287 let features: Vec<VectorFeature<M, P, D>> =
289 convert(tile_store.projection, &data, Some(true), Some(true));
290 features.into_iter().for_each(|feature| tile_store.add_feature(feature));
291 for i in 0..6 {
292 tile_store.split_tile(CellId::from_face(i), None, None);
293 }
294
295 tile_store
296 }
297
298 fn add_feature(&mut self, mut feature: VectorFeature<M, P, D>) {
300 let face: u8 = feature.face.into();
301 let tile = self.tiles.entry(CellId::from_face(face)).or_insert_with(|| {
302 self.faces.insert(feature.face);
303 Tile::new(CellId::from_face(face))
304 });
305 build_sq_dists(&mut feature.geometry, self.tolerance, Some(self.maxzoom));
307
308 tile.add_feature(feature, None);
309 }
310
311 fn split_tile(&mut self, start_id: CellId, end_id: Option<CellId>, end_zoom: Option<u8>) {
313 let TileStore { buffer, tiles, tolerance, maxzoom, index_maxzoom, .. } = self;
314 let end_zoom = end_zoom.unwrap_or(*maxzoom);
315 let mut stack: Vec<CellId> = vec![start_id];
316 while !stack.is_empty() {
318 let stack_id = stack.pop();
320 if stack_id.is_none() {
321 break;
322 }
323 let tile = tiles.get_mut(&stack_id.unwrap());
324 if tile.is_none() {
326 continue;
327 }
328 let tile = tile.unwrap();
329 if tile.is_empty() || tile.transformed {
330 continue;
331 }
332 let tile_zoom = tile.id.level();
333 if tile_zoom >= *maxzoom || (end_id.is_none() && tile_zoom >= *index_maxzoom) || (end_id.is_some() && (tile_zoom > end_zoom || !tile.id.contains(end_id.unwrap())))
339 {
340 continue;
341 }
342
343 let TileChildren {
345 bottom_left: bl_id,
346 bottom_right: br_id,
347 top_left: tl_id,
348 top_right: tr_id,
349 } = tile.split(Some(*buffer));
350 tile.transform(*tolerance, Some(*maxzoom));
352 stack.extend(vec![bl_id.id, br_id.id, tl_id.id, tr_id.id]);
354 tiles.insert(bl_id.id, bl_id);
356 tiles.insert(br_id.id, br_id);
357 tiles.insert(tl_id.id, tl_id);
358 tiles.insert(tr_id.id, tr_id);
359 }
360 }
361
362 pub fn get_tile(&mut self, id: CellId) -> Option<&Tile<M, P, D>> {
364 let zoom = id.level();
365 let face = id.face();
366 if !(0..=20).contains(&zoom) || !self.faces.contains(&face.into()) {
368 return None;
369 }
370
371 let mut p_id = id;
373 while !self.tiles.contains_key(&p_id) && !p_id.is_face() {
374 p_id = p_id.parent(None);
375 }
376 self.split_tile(p_id, Some(id), Some(zoom));
378
379 self.tiles.get(&id)
381 }
382}
383
384pub trait TransformVectorGeometry<M: Clone + Default = MValue> {
386 fn transform(&mut self, zoom: f64, ti: f64, tj: f64);
388}
389impl<M: Clone + Default> TransformVectorGeometry<M> for VectorGeometry<M> {
390 fn transform(&mut self, zoom: f64, ti: f64, tj: f64) {
392 let zoom = (1 << (zoom as u64)) as f64;
393 match self {
394 VectorGeometry::Point(p) => p.coordinates.transform(zoom, ti, tj),
395 VectorGeometry::LineString(l) | VectorGeometry::MultiPoint(l) => {
396 l.coordinates.iter_mut().for_each(|p| p.transform(zoom, ti, tj))
397 }
398 VectorGeometry::MultiLineString(l) | VectorGeometry::Polygon(l) => l
399 .coordinates
400 .iter_mut()
401 .for_each(|l| l.iter_mut().for_each(|p| p.transform(zoom, ti, tj))),
402 VectorGeometry::MultiPolygon(l) => l.coordinates.iter_mut().for_each(|p| {
403 p.iter_mut().for_each(|l| l.iter_mut().for_each(|p| p.transform(zoom, ti, tj)))
404 }),
405 }
406 }
407}
408impl<M: Clone + Default> TransformVectorGeometry<M> for VectorPoint<M> {
409 fn transform(&mut self, zoom: f64, ti: f64, tj: f64) {
411 self.x = self.x * zoom - ti;
412 self.y = self.y * zoom - tj;
413 }
414}