1use crate::config::{LayerGroupCfg, WyrmCfg};
6use crate::error::{Error, Result};
7use crate::geom::GeomTree;
8use crate::layer::LayerDef;
9use mvt::{Layer, MapGrid, Tile, TileId};
10use pointy::{BBox, Transform};
11use std::io::Write;
12use std::time::Instant;
13
14pub struct TileCfg {
16 tile_extent: u32,
18
19 tid: TileId,
21
22 bbox: BBox<f64>,
24
25 transform: Transform<f64>,
27}
28
29struct LayerTree {
31 layer_def: LayerDef,
33
34 tree: GeomTree,
36}
37
38struct LayerGroup {
40 name: String,
42
43 layers: Vec<LayerTree>,
45}
46
47pub struct Wyrm {
55 grid: MapGrid,
57
58 tile_extent: u32,
60
61 groups: Vec<LayerGroup>,
63}
64
65impl TileCfg {
66 pub fn zoom(&self) -> u32 {
68 self.tid.z()
69 }
70
71 pub fn bbox(&self) -> BBox<f64> {
73 self.bbox
74 }
75
76 pub fn transform(&self) -> Transform<f64> {
78 self.transform
79 }
80}
81
82impl LayerGroup {
83 fn new(group: &LayerGroupCfg, wyrm: &WyrmCfg) -> Result<Self> {
85 let name = group.name.to_string();
86 let mut layers = vec![];
87 for layer_cfg in &group.layer {
88 let layer_def = LayerDef::try_from(layer_cfg)?;
89 layers.push(LayerTree::new(layer_def, wyrm)?);
90 }
91 log::info!("{} layers in {group}", layers.len());
92 Ok(LayerGroup { name, layers })
93 }
94
95 pub fn name(&self) -> &str {
97 &self.name
98 }
99
100 fn fetch_tile(&self, tile_cfg: &TileCfg) -> Result<Tile> {
102 let t = Instant::now();
103 let tile = self.query_tile(tile_cfg)?;
104 log::info!(
105 "{}/{}, fetched {} bytes in {:.2?}",
106 self.name(),
107 tile_cfg.tid,
108 tile.compute_size(),
109 t.elapsed()
110 );
111 Ok(tile)
112 }
113
114 fn query_tile(&self, tile_cfg: &TileCfg) -> Result<Tile> {
116 let mut tile = Tile::new(tile_cfg.tile_extent);
117 for layer_tree in &self.layers {
118 let layer = layer_tree.query_tile(&tile, tile_cfg)?;
119 if layer.num_features() > 0 {
120 tile.add_layer(layer)?;
121 }
122 }
123 Ok(tile)
124 }
125
126 fn write_tile<W: Write>(
128 &self,
129 out: &mut W,
130 tile_cfg: TileCfg,
131 ) -> Result<()> {
132 let tile = self.fetch_tile(&tile_cfg)?;
133 if tile.num_layers() > 0 {
134 tile.write_to(out)?;
135 Ok(())
136 } else {
137 log::debug!("tile {} empty (no layers)", tile_cfg.tid);
138 Err(Error::TileEmpty())
139 }
140 }
141}
142
143impl TryFrom<&WyrmCfg> for Wyrm {
144 type Error = Error;
145
146 fn try_from(wyrm_cfg: &WyrmCfg) -> Result<Self> {
147 let grid = MapGrid::default();
149 let mut groups = vec![];
150 for group in &wyrm_cfg.layer_group {
151 groups.push(LayerGroup::new(group, wyrm_cfg)?);
152 }
153 Ok(Wyrm {
154 grid,
155 tile_extent: wyrm_cfg.tile_extent,
156 groups,
157 })
158 }
159}
160
161impl Wyrm {
162 pub fn query_features(&self, bbox: BBox<f64>) -> Result<()> {
164 for group in &self.groups {
165 log::debug!("query_features group: {:?}", group.name);
166 for layer in &group.layers {
167 layer.query_features(bbox)?;
168 }
169 }
170 Ok(())
171 }
172
173 pub fn fetch_tile<W: Write>(
179 &self,
180 out: &mut W,
181 group_name: &str,
182 tid: TileId,
183 ) -> Result<()> {
184 for group in &self.groups {
185 if group_name == group.name() {
186 let tile_cfg = self.tile_config(tid);
187 return group.write_tile(out, tile_cfg);
188 }
189 }
190 log::debug!("unknown group name: {}", group_name);
191 Err(Error::UnknownGroupName())
192 }
193
194 fn tile_config(&self, tid: TileId) -> TileCfg {
196 let tile_extent = self.tile_extent;
197 let mut bbox = self.grid.tile_bbox(tid);
198 let edge = zoom_edge(tid);
200 let edge_x = edge * (bbox.x_max() - bbox.x_min());
201 let edge_y = edge * (bbox.y_max() - bbox.y_min());
202 bbox.extend([
203 (bbox.x_min() - edge_x, bbox.y_min() - edge_y),
204 (bbox.x_max() + edge_x, bbox.y_max() + edge_y),
205 ]);
206 let ts = f64::from(tile_extent);
207 let transform = self.grid.tile_transform(tid).scale(ts, ts);
208 TileCfg {
209 tile_extent,
210 tid,
211 bbox,
212 transform,
213 }
214 }
215}
216
217fn zoom_edge(tid: TileId) -> f64 {
221 match tid.z() {
222 0..=12 => 1.0 / 32.0,
223 13 => 1.0 / 16.0,
224 14 => 1.0 / 8.0,
225 15 => 1.0 / 4.0,
226 16 => 1.0 / 2.0,
227 _ => 1.0,
228 }
229}
230
231impl LayerTree {
232 fn new(layer_def: LayerDef, wyrm: &WyrmCfg) -> Result<Self> {
234 let loam = wyrm.loam_path(layer_def.name());
235 let tree = GeomTree::new(layer_def.geom_tp(), loam)?;
236 Ok(LayerTree { layer_def, tree })
237 }
238
239 fn query_features(&self, bbox: BBox<f64>) -> Result<()> {
241 self.tree.query_features(&self.layer_def, bbox)
242 }
243
244 fn query_tile(&self, tile: &Tile, tile_cfg: &TileCfg) -> Result<Layer> {
246 let layer = tile.create_layer(self.layer_def.name());
247 if self.layer_def.check_zoom(tile_cfg.zoom()) {
248 self.tree.query_tile(&self.layer_def, layer, tile_cfg)
249 } else {
250 Ok(layer)
251 }
252 }
253}