utiles_core/
tile_like.rs

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