gistools/geometry/
mod.rs

1extern crate alloc;
2
3/// Global conversion tool
4pub mod convert;
5/// All geometry types and structs
6pub mod geo;
7/// All S2 tooling
8pub mod s2;
9/// All simplify tooling
10pub mod simplify;
11/// Tile Structure
12pub mod tile;
13/// All utility tools
14pub mod util;
15/// All values types and structs
16pub mod values;
17/// All WM tooling
18pub mod wm;
19
20pub use convert::*;
21pub use geo::*;
22pub use s2::*;
23pub use simplify::*;
24pub use tile::*;
25pub use util::*;
26pub use values::*;
27pub use wm::*;
28
29use serde::{Deserialize, Serialize};
30
31use alloc::collections::BTreeMap;
32use alloc::string::String;
33use alloc::string::ToString;
34use alloc::vec::Vec;
35
36/// All projections that can be used
37#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
38pub enum Projection {
39    /// S2
40    S2,
41    /// WM
42    WM,
43}
44
45//? S2 specific type
46
47/// Cube-face on the S2 sphere
48#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
49pub enum Face {
50    /// Face 0
51    Face0 = 0,
52    /// Face 1
53    Face1 = 1,
54    /// Face 2
55    Face2 = 2,
56    /// Face 3
57    Face3 = 3,
58    /// Face 4
59    Face4 = 4,
60    /// Face 5
61    Face5 = 5,
62}
63impl From<Face> for u8 {
64    fn from(face: Face) -> Self {
65        face as u8
66    }
67}
68impl From<u8> for Face {
69    fn from(face: u8) -> Self {
70        match face {
71            1 => Face::Face1,
72            2 => Face::Face2,
73            3 => Face::Face3,
74            4 => Face::Face4,
75            5 => Face::Face5,
76            _ => Face::Face0,
77        }
78    }
79}
80
81//? FeatureCollections
82
83/// WM FeatureCollection
84#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
85pub struct FeatureCollection<M = ()> {
86    /// Type will always be "FeatureCollection"
87    #[serde(rename = "type")]
88    pub _type: String,
89    /// Collection of WM features
90    pub features: Vec<WMFeature<M>>,
91    /// Attribution data
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub attributions: Option<Attributions>,
94    /// Bounding box
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub bbox: Option<BBox>,
97}
98impl<M> FeatureCollection<M> {
99    /// Create a new FeatureCollection
100    pub fn new(attributions: Option<Attributions>) -> Self {
101        Self {
102            _type: "FeatureCollection".to_string(),
103            features: Vec::new(),
104            attributions,
105            bbox: None,
106        }
107    }
108
109    /// update the bounding box
110    pub fn update_bbox(&mut self, bbox: BBox) {
111        let mut self_bbox = self.bbox.unwrap_or_default();
112        self_bbox = self_bbox.merge(&bbox);
113        self.bbox = Some(self_bbox);
114    }
115}
116
117/// S2 FeatureCollection
118#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
119pub struct S2FeatureCollection<M = ()> {
120    /// Type will always be "S2FeatureCollection"
121    #[serde(rename = "type")]
122    pub _type: String,
123    /// Collection of S2 features
124    pub features: Vec<S2Feature<M>>,
125    /// Track the faces that were used to generate the features
126    pub faces: Vec<Face>,
127    /// Attribution data
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub attributions: Option<Attributions>,
130    /// Bounding box
131    #[serde(skip_serializing_if = "Option::is_none")]
132    pub bbox: Option<BBox>,
133}
134impl<M> S2FeatureCollection<M> {
135    /// Create a new S2FeatureCollection
136    pub fn new(attributions: Option<Attributions>) -> Self {
137        Self {
138            _type: "S2FeatureCollection".to_string(),
139            features: Vec::new(),
140            faces: Vec::new(),
141            attributions,
142            bbox: None,
143        }
144    }
145
146    /// update the bounding box
147    pub fn update_bbox(&mut self, bbox: BBox) {
148        let mut self_bbox = self.bbox.unwrap_or_default();
149        self_bbox = self_bbox.merge(&bbox);
150        self.bbox = Some(self_bbox);
151    }
152
153    /// Add a face, ensuring it is unique
154    pub fn add_face(&mut self, face: Face) {
155        if !self.faces.contains(&face) {
156            self.faces.push(face);
157        }
158    }
159}
160
161//? Features
162
163/// Component to build an WM Feature
164#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
165pub struct Feature<M = ()> {
166    /// Type will always be "Feature"
167    #[serde(rename = "type")]
168    pub _type: String,
169    /// Unique identifier
170    #[serde(skip_serializing_if = "Option::is_none")]
171    pub id: Option<u64>,
172    /// Properties of the feature
173    pub properties: Properties,
174    /// Geometry of the feature
175    pub geometry: Geometry,
176    /// Metadata of the feature
177    #[serde(skip_serializing_if = "Option::is_none")]
178    pub metadata: Option<M>,
179}
180impl<M> Feature<M> {
181    /// Create a new Feature
182    pub fn new(
183        id: Option<u64>,
184        properties: Properties,
185        geometry: Geometry,
186        metadata: Option<M>,
187    ) -> Self {
188        Self { _type: "Feature".to_string(), id, properties, geometry, metadata }
189    }
190}
191
192/// Component to build an WM or S2 Vector Feature
193#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
194pub struct VectorFeature<M = ()> {
195    /// Type will always be "VectorFeature"
196    #[serde(rename = "type")]
197    pub _type: String,
198    /// Unique identifier
199    #[serde(skip_serializing_if = "Option::is_none")]
200    pub id: Option<u64>,
201    /// Face of the feature
202    pub face: Face,
203    /// Properties of the feature
204    pub properties: Properties,
205    /// Geometry of the feature
206    pub geometry: VectorGeometry,
207    /// Metadata of the feature
208    #[serde(skip_serializing_if = "Option::is_none")]
209    pub metadata: Option<M>,
210}
211impl<M> VectorFeature<M> {
212    /// Create a new VectorFeature in the WM format
213    pub fn new_wm(
214        id: Option<u64>,
215        properties: Properties,
216        geometry: VectorGeometry,
217        metadata: Option<M>,
218    ) -> Self {
219        Self {
220            _type: "VectorFeature".to_string(),
221            face: 0.into(),
222            id,
223            properties,
224            geometry,
225            metadata,
226        }
227    }
228
229    /// Create a new VectorFeature in the WM format
230    pub fn new_s2(
231        id: Option<u64>,
232        face: Face,
233        properties: Properties,
234        geometry: VectorGeometry,
235        metadata: Option<M>,
236    ) -> Self {
237        Self { _type: "S2Feature".to_string(), face, id, properties, geometry, metadata }
238    }
239
240    /// Create a new VectorFeature using an input VectorFeature. Assign new geometry if provided
241    pub fn from_vector_feature(feature: &VectorFeature<M>, geometry: Option<VectorGeometry>) -> Self
242    where
243        M: Clone,
244    {
245        Self {
246            _type: feature._type.clone(),
247            id: feature.id,
248            face: feature.face,
249            properties: feature.properties.clone(),
250            geometry: geometry.unwrap_or(feature.geometry.clone()),
251            metadata: feature.metadata.clone(),
252        }
253    }
254}
255
256/// Component to build an S2 Feature. Uses VectorFeature but "face" property is applicable
257pub type S2Feature<M = ()> = VectorFeature<M>;
258
259//? Utility types
260
261/// Attribution data is stored in an object.
262/// The key is the name of the attribution, and the value is the href link
263/// e.g. { "Open S2": "https://opens2.com/legal/data" }
264pub type Attributions = BTreeMap<String, String>;
265
266/// Either an S2 or WM FeatureCollection
267#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
268pub enum FeatureCollections<M = ()> {
269    /// An WM FeatureCollection
270    FeatureCollection(FeatureCollection<M>),
271    /// An S2 FeatureCollection
272    S2FeatureCollection(S2FeatureCollection<M>),
273}
274
275/// Either an S2 or WM Feature
276#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
277pub enum Features<M = ()> {
278    /// An WM Feature
279    Feature(Feature<M>),
280    /// An WM Vector Feature
281    VectorFeature(VectorFeature<M>),
282    /// An S2 Feature
283    S2Feature(S2Feature<M>),
284}
285
286/// Either an WM Feature or an WM Vector Feature
287#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
288pub enum WMFeature<M = ()> {
289    /// An WM Feature
290    Feature(Feature<M>),
291    /// An WM Vector Feature
292    VectorFeature(VectorFeature<M>),
293}
294
295/// All major S2JSON types
296#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
297pub enum JSONCollection<M = ()> {
298    /// An WM FeatureCollection
299    FeatureCollection(FeatureCollection<M>),
300    /// An S2 FeatureCollection
301    S2FeatureCollection(S2FeatureCollection<M>),
302    /// An WM Feature
303    Feature(Feature<M>),
304    /// An WM or S2 Vector Feature
305    VectorFeature(VectorFeature<M>),
306}
307
308#[cfg(test)]
309mod tests {
310    use super::*;
311
312    #[test]
313    fn face() {
314        let face = Face::Face0;
315        assert_eq!(u8::from(face), 0);
316        let face = Face::Face1;
317        assert_eq!(u8::from(face), 1);
318        let face = Face::Face2;
319        assert_eq!(u8::from(face), 2);
320        let face = Face::Face3;
321        assert_eq!(u8::from(face), 3);
322        let face = Face::Face4;
323        assert_eq!(u8::from(face), 4);
324        let face = Face::Face5;
325        assert_eq!(u8::from(face), 5);
326
327        assert_eq!(Face::Face0, Face::from(0));
328        assert_eq!(Face::Face1, Face::from(1));
329        assert_eq!(Face::Face2, Face::from(2));
330        assert_eq!(Face::Face3, Face::from(3));
331        assert_eq!(Face::Face4, Face::from(4));
332        assert_eq!(Face::Face5, Face::from(5));
333    }
334}