ovtile/
vector_tile.rs

1use pbf::{ProtoRead, Protobuf};
2
3use alloc::{collections::BTreeMap, rc::Rc, string::String, vec::Vec};
4
5use core::cell::RefCell;
6
7use crate::{
8    base::BaseVectorTile,
9    mapbox::MapboxVectorLayer,
10    open::{
11        write_layer, ColumnCacheReader, ColumnCacheWriter, FeatureType, GridData, ImageData,
12        OpenVectorLayer, Properties,
13    },
14    VectorGeometry, VectorLines3DWithOffset, VectorLinesWithOffset, VectorPoints, VectorPoints3D,
15    BBOX,
16};
17
18/// Methods that all vector features should have
19pub trait VectorFeatureMethods {
20    /// the id of the feature
21    fn id(&self) -> Option<u64>;
22    /// the version of the vector tile
23    fn version(&self) -> u16;
24    /// the properties
25    fn properties(&self) -> Properties;
26    /// the extent
27    fn extent(&self) -> usize;
28    /// the feature type
29    fn get_type(&self) -> FeatureType;
30    /// the bounding box
31    fn bbox(&self) -> Option<BBOX>;
32    /// whether the feature has m values
33    fn has_m_values(&self) -> bool;
34    /// whether the feature is a points type
35    fn is_points(&self) -> bool;
36    /// whether the feature is a line type
37    fn is_lines(&self) -> bool;
38    /// whether the feature is a polygon type
39    fn is_polygons(&self) -> bool;
40    /// whether the feature is a points 3D type
41    fn is_points_3d(&self) -> bool;
42    /// whether the feature is a line 3D type
43    fn is_lines_3d(&self) -> bool;
44    /// whether the feature is a polygon 3D type
45    fn is_polygons_3d(&self) -> bool;
46    /// regardless of the type, we return a flattend point array
47    fn load_points(&mut self) -> VectorPoints;
48    /// regardless of the type, we return a flattend point3D array
49    fn load_points_3d(&mut self) -> VectorPoints3D;
50    /// an array of lines. The offsets will be set to 0
51    fn load_lines(&mut self) -> VectorLinesWithOffset;
52    /// an array of 3D lines. The offsets will be set to 0
53    fn load_lines_3d(&mut self) -> VectorLines3DWithOffset;
54    /// (flattened geometry & tesslation if applicable, indices)
55    fn load_geometry_flat(&mut self) -> (Vec<f64>, Vec<u32>);
56    /// load the geometry
57    fn load_geometry(&mut self) -> VectorGeometry;
58    /// load the indices
59    fn read_indices(&mut self) -> Vec<u32>;
60    /// Add tesselation data to the geometry
61    fn add_tesselation(&mut self, geometry: &mut Vec<f64>, multiplier: f64);
62    /// Add 3D tesselation data to the geometry
63    fn add_tesselation_3d(&mut self, geometry: &mut Vec<f64>, multiplier: f64);
64}
65
66/// Methods that all vector layers should have
67pub trait VectorLayerMethods {
68    /// the version of the vector tile layer.
69    fn version(&self) -> u16;
70    /// the name of the layer
71    fn name(&self) -> String;
72    /// the extent of the vector tile (only **512**, **1_024**, **2_048**, **4_096**, and **8_192**
73    /// are supported for the open spec)
74    fn extent(&self) -> usize;
75    /// grab a feature from the layer
76    fn feature(&mut self, i: usize) -> Option<&mut dyn VectorFeatureMethods>;
77    /// length (layer count)
78    fn len(&self) -> usize;
79    /// empty (layer count is 0)
80    fn is_empty(&self) -> bool;
81}
82
83/// Layer container supporting both mapbox and open vector layers
84#[derive(Debug)]
85pub enum VectorLayer {
86    /// Mapbox vector layer
87    Mapbox(MapboxVectorLayer),
88    /// Open vector layer
89    Open(OpenVectorLayer),
90}
91impl VectorLayerMethods for VectorLayer {
92    fn version(&self) -> u16 {
93        match self {
94            VectorLayer::Mapbox(layer) => layer.version(),
95            VectorLayer::Open(layer) => layer.version(),
96        }
97    }
98
99    fn name(&self) -> String {
100        match self {
101            VectorLayer::Mapbox(layer) => layer.name(),
102            VectorLayer::Open(layer) => layer.name(),
103        }
104    }
105
106    fn extent(&self) -> usize {
107        match self {
108            VectorLayer::Mapbox(layer) => layer.extent(),
109            VectorLayer::Open(layer) => layer.extent(),
110        }
111    }
112
113    fn feature(&mut self, i: usize) -> Option<&mut dyn VectorFeatureMethods> {
114        match self {
115            VectorLayer::Mapbox(layer) => layer.feature(i),
116            VectorLayer::Open(layer) => layer.feature(i),
117        }
118    }
119
120    fn len(&self) -> usize {
121        match self {
122            VectorLayer::Mapbox(layer) => layer.len(),
123            VectorLayer::Open(layer) => layer.len(),
124        }
125    }
126
127    fn is_empty(&self) -> bool {
128        match self {
129            VectorLayer::Mapbox(layer) => layer.is_empty(),
130            VectorLayer::Open(layer) => layer.is_empty(),
131        }
132    }
133}
134
135/// # Open Vector Tile
136///
137/// ## Description
138/// A Vector Tile may parse either Mapbox or OpenVector Tile Layers
139/// The input is an unsigned byte array that has encoded protobuffer messages.
140///
141/// Types of layers include:
142/// - Vector data - vector points, lines, and polygons with 3D coordinates, properties, and/or m-values
143/// - Image data - raster data that is RGB(A) encoded
144/// - Grid data: data that has a max-min range, works much like an image but has floating/double precision point values for each point on the grid
145///
146/// ## Usage
147/// ```rust,ignore
148/// use ovtile::{VectorTile, VectorLayerMethods};
149///
150/// let data: Vec<u8> = vec![];
151/// let mut tile = VectorTile::new(data, None);
152///
153/// // VECTOR API
154///
155/// let landuse = tile.layer("landuse").unwrap();
156///
157/// // grab the first feature
158/// let firstFeature = landuse.feature(0).unwrap();
159/// // grab the geometry
160/// let geometry = firstFeature.load_geometry();
161///
162/// // OR specifically ask for a geometry type
163/// let points = firstFeature.load_points();
164/// let lines = firstFeature.load_lines();
165///
166/// // If you want to take advantage of the pre-tessellated and indexed geometries
167/// // and you're loading the data for a renderer, you can grab the pre-tessellated geometry
168/// let (geometry_flat, indices) = firstFeature.load_geometry_flat();
169///
170/// // IMAGE API
171///
172/// let satellite = tile.images.get("satellite").unwrap();
173/// // grab the image data
174/// let data = &satellite.image;
175///
176/// // GRID API
177///
178/// let elevation = tile.grids.get("elevation").unwrap();
179/// // grab the grid data
180/// let data = &elevation.data;
181/// ```
182#[derive(Debug)]
183pub struct VectorTile {
184    /// the layers in the vector tile
185    pub layers: BTreeMap<String, VectorLayer>,
186    /// indexes to track the layers. Needed for the open spec because we need the cache before we can
187    /// parse layers and features
188    layer_indexes: Vec<usize>,
189    /// the protobuf for the vector tile
190    pbf: Rc<RefCell<Protobuf>>,
191    /// the column cache
192    columns: Option<Rc<RefCell<ColumnCacheReader>>>,
193    /// Gridded data
194    pub grids: BTreeMap<String, GridData>,
195    /// Image data
196    pub images: BTreeMap<String, ImageData>,
197}
198impl VectorTile {
199    /// Create a new vector tile
200    pub fn new(data: Vec<u8>, end: Option<usize>) -> Self {
201        let pbf = Rc::new(RefCell::new(data.into()));
202        let mut vt = VectorTile {
203            pbf: pbf.clone(),
204            columns: None,
205            layer_indexes: Vec::new(),
206            layers: BTreeMap::new(),
207            grids: BTreeMap::new(),
208            images: BTreeMap::new(),
209        };
210
211        pbf.borrow_mut().read_fields(&mut vt, end);
212
213        if !vt.layer_indexes.is_empty() {
214            vt.read_layers();
215        }
216
217        vt
218    }
219
220    /// Read the layers
221    pub fn read_layers(&mut self) -> Option<()> {
222        let layer_indexes = self.layer_indexes.clone();
223        let mut tmp_pbf = self.pbf.borrow_mut();
224        let cache = self.columns.as_ref()?.clone();
225
226        for pos in layer_indexes {
227            tmp_pbf.set_pos(pos);
228            let mut layer = OpenVectorLayer::new(cache.clone());
229            tmp_pbf.read_message(&mut layer);
230            self.layers.insert(layer.name.clone(), VectorLayer::Open(layer));
231        }
232
233        Some(())
234    }
235
236    /// Get a layer given the name
237    pub fn layer(&mut self, name: &str) -> Option<&mut VectorLayer> {
238        self.layers.get_mut(name)
239    }
240}
241impl ProtoRead for VectorTile {
242    fn read(&mut self, tag: u64, pb: &mut Protobuf) {
243        match tag {
244            1 | 3 => {
245                let mut layer = MapboxVectorLayer::new(self.pbf.clone(), tag == 1);
246                pb.read_message(&mut layer);
247                self.layers.insert(layer.name.clone(), VectorLayer::Mapbox(layer));
248            }
249            4 => {
250                // store the position of each layer for later retrieval.
251                // Columns must be prepped before reading the layer.
252                self.layer_indexes.push(pb.get_pos());
253            }
254            5 => {
255                let mut column_reader = ColumnCacheReader::new();
256                pb.read_message(&mut column_reader);
257                self.columns = Some(Rc::new(RefCell::new(column_reader)));
258            }
259            6 => {
260                let mut grid = GridData::default();
261                pb.read_message(&mut grid);
262                self.grids.insert(grid.name.clone(), grid);
263            }
264            7 => {
265                let mut image = ImageData::default();
266                pb.read_message(&mut image);
267                self.images.insert(image.name.clone(), image);
268            }
269            #[tarpaulin::skip]
270            _ => panic!("unknown tag: {}", tag),
271        }
272    }
273}
274
275/// writer for converting a BaseVectorTile to encoded bytes of the Open Vector Tile format
276pub fn write_tile(
277    tile: Option<&mut BaseVectorTile>,
278    images: Option<Vec<&ImageData>>,
279    grids: Option<Vec<&GridData>>,
280) -> Vec<u8> {
281    let mut pbf = Protobuf::new();
282    let mut cache = ColumnCacheWriter::default();
283
284    // first write layers
285    if let Some(tile) = tile {
286        for layer in tile.layers.values_mut() {
287            pbf.write_bytes_field(4, &write_layer(layer, &mut cache));
288        }
289        // now we can write columns
290        pbf.write_message(5, &cache);
291    }
292    // if an image exists, let's write it
293    if let Some(images) = images {
294        for image in images.iter() {
295            pbf.write_message(7, *image);
296        }
297    }
298    // if an gridded data exists, let's write it
299    if let Some(grids) = grids {
300        for grid in grids.iter() {
301            pbf.write_message(6, *grid);
302        }
303    }
304
305    pbf.take()
306}