utiles_core/
tile_like.rs

1use crate::bbox::WebBBox;
2use crate::{flipy, xyz2rmid, BBox, LngLat, Tile, TileZBox};
3
4#[cfg(feature = "pmtiles")]
5use crate::pmtiles;
6
7/// Trait def for tile-like objects/structs/things/whatevers
8pub trait TileLike {
9    /// x coordinate (column)
10    fn x(&self) -> u32;
11
12    /// y coordinate (row -- flipped for TMS)
13    fn y(&self) -> u32;
14
15    /// z coordinate (zoom level)
16    fn z(&self) -> u8;
17
18    /// zoom level
19    #[must_use]
20    fn zoom(&self) -> u8 {
21        self.z()
22    }
23
24    /// x coordinate
25    fn yflip(&self) -> u32 {
26        flipy(self.y(), self.z())
27    }
28
29    /// both bc I keep forgetting which is which
30    fn flipy(&self) -> u32 {
31        flipy(self.y(), self.z())
32    }
33
34    fn yup(&self) -> u32 {
35        flipy(self.y(), self.z())
36    }
37
38    fn xyz_str_fslash(&self) -> String {
39        format!("{}/{}/{}", self.x(), self.y(), self.z())
40    }
41
42    fn zxy_str_fslash(&self) -> String {
43        format!("{}/{}/{}", self.z(), self.x(), self.y())
44    }
45
46    fn xyz_str_sep(&self, sep: &str) -> String {
47        format!("{}{}{}{}{}", self.x(), sep, self.y(), sep, self.z())
48    }
49
50    fn zxy_str_sep(&self, sep: &str) -> String {
51        format!("{}{}{}{}{}", self.z(), sep, self.x(), sep, self.y())
52    }
53
54    /// Return Tile struct
55    #[must_use]
56    fn tile(&self) -> Tile {
57        Tile::new(self.x(), self.y(), self.z())
58    }
59
60    /// Return if the tile is valid (x, y is in bounds for zoom level z)
61    #[must_use]
62    fn valid(&self) -> bool {
63        crate::valid(self.x(), self.y(), self.z())
64    }
65
66    /// Return the ul (upper left) corner of the tile
67    #[must_use]
68    fn ul(&self) -> LngLat {
69        crate::ul(self.x(), self.y(), self.z())
70    }
71
72    /// Return the ur (upper right) corner of the tile
73    #[must_use]
74    fn ur(&self) -> LngLat {
75        crate::ul(self.x() + 1, self.y(), self.z())
76    }
77
78    /// Return the lr (lower right) corner of the tile
79    #[must_use]
80    fn lr(&self) -> LngLat {
81        crate::ul(self.x() + 1, self.y() + 1, self.z())
82    }
83
84    /// Return the ll (lower left) corner of the tile
85    #[must_use]
86    fn ll(&self) -> LngLat {
87        crate::ul(self.x(), self.y() + 1, self.z())
88    }
89
90    /// Return the quadkey for the tile
91    #[must_use]
92    fn quadkey(&self) -> String {
93        crate::xyz2quadkey(self.x(), self.y(), self.z())
94    }
95
96    /// Return the quadkey for the tile (alias for quadkey)
97    #[must_use]
98    fn qk(&self) -> String {
99        crate::xyz2quadkey(self.x(), self.y(), self.z())
100    }
101
102    /// Return the pmtile-id for the tile
103    #[cfg(feature = "pmtiles")]
104    #[must_use]
105    fn pmtileid(&self) -> u64 {
106        pmtiles::xyz2pmid(self.x(), self.y(), self.z())
107    }
108
109    /// Return the pmtile id
110    #[cfg(feature = "pmtiles")]
111    #[must_use]
112    fn pmid(&self) -> u64 {
113        self.pmtileid()
114    }
115
116    /// Return the row major id for the tile
117    #[must_use]
118    fn row_major_id(&self) -> u64 {
119        xyz2rmid(self.x(), self.y(), self.z())
120    }
121
122    /// Return the row major id for the tile (alias for `row_major_id`)
123    #[must_use]
124    fn rmid(&self) -> u64 {
125        self.row_major_id()
126    }
127
128    /// Return the geo-bbox tuple for the tile (west, south, east, north)
129    #[must_use]
130    fn bbox(&self) -> (f64, f64, f64, f64) {
131        let ul = self.ul();
132        let lr = self.lr();
133        (ul.lng(), lr.lat(), lr.lng(), ul.lat())
134    }
135
136    #[must_use]
137    fn geobbox(&self) -> BBox {
138        let ul = self.ul();
139        let lr = self.lr();
140        BBox::new(ul.lng(), lr.lat(), lr.lng(), ul.lat())
141    }
142
143    #[must_use]
144    fn webbbox(&self) -> WebBBox {
145        self.geobbox().into()
146    }
147
148    #[must_use]
149    fn bbox_string(&self) -> String {
150        let (w, s, e, n) = self.bbox();
151        format!("[{w},{s},{e},{n}]")
152    }
153
154    /// Return the center of the tile as a `LngLat`
155    #[must_use]
156    fn center(&self) -> LngLat {
157        let ul = self.ul();
158        let lr = self.lr();
159        LngLat::new((ul.lng() + lr.lng()) / 2.0, (ul.lat() + lr.lat()) / 2.0)
160    }
161
162    /// Return json array string for tile with spaces after commas
163    #[must_use]
164    fn json_arr(&self) -> String {
165        format!("[{}, {}, {}]", self.x(), self.y(), self.z())
166    }
167
168    /// Return json array string for tile with no spaces after commas
169    #[must_use]
170    fn json_arr_min(&self) -> String {
171        format!("[{},{},{}]", self.x(), self.y(), self.z())
172    }
173
174    /// Return json object string for tile
175    #[must_use]
176    fn json_obj(&self) -> String {
177        format!(
178            "{{\"x\":{}, \"y\":{}, \"z\":{}}}",
179            self.x(),
180            self.y(),
181            self.z()
182        )
183    }
184
185    /// Return json object string for tile
186    #[must_use]
187    fn json(&self) -> String {
188        self.json_obj()
189    }
190
191    /// Return tuple string for tile `(x, y, z)`
192    #[must_use]
193    fn tuple_string(&self) -> String {
194        format!("({}, {}, {})", self.x(), self.y(), self.z())
195    }
196
197    /// Return sql `WHERE` clause for querying mbtiles (y is up)
198    #[must_use]
199    fn mbtiles_sql_where(&self) -> String {
200        // classic mbtiles sqlite query:
201        // 'SELECT tile_data FROM tiles WHERE zoom_level = ? AND tile_column = ? AND tile_row = ?',
202
203        // flip y for tms (default for mbtiles)
204        format!(
205            "(zoom_level = {} AND tile_column = {} AND tile_row = {})",
206            self.z(),
207            self.x(),
208            flipy(self.y(), self.z())
209        )
210    }
211
212    /// return zbox for tile-like
213    #[must_use]
214    fn zbox(&self) -> TileZBox {
215        TileZBox::from_tile(self)
216    }
217
218    /// Return children-zbox for tile-like at optional depth (default 1)
219    #[must_use]
220    fn children_zbox(&self, depth: Option<u8>) -> TileZBox {
221        let d = depth.unwrap_or(1);
222        let target_zoom = self.z() + d;
223        let mut zbox = TileZBox::from_tile(self);
224        while zbox.z() < target_zoom {
225            zbox = zbox.zoom_in();
226        }
227        zbox
228    }
229}