open_vector_tile/
vector_tile.rs

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