• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Open-S2 / open-vector-tile / #67

03 May 2025 04:21AM UTC coverage: 98.815% (+0.1%) from 98.678%
#67

push

Mr Martian
migrate to stable

9510 of 9624 relevant lines covered (98.82%)

68.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.15
/rust/vector_tile.rs
1
use crate::{
2
    VectorGeometry, VectorLines3DWithOffset, VectorLinesWithOffset, VectorPoints, VectorPoints3D,
3
    base::BaseVectorTile,
4
    mapbox::MapboxVectorLayer,
5
    open::{
6
        ColumnCacheReader, ColumnCacheWriter, FeatureType, GridData, ImageData, OpenVectorLayer,
7
        write_layer,
8
    },
9
};
10
use alloc::{collections::BTreeMap, rc::Rc, string::String, vec::Vec};
11
use core::cell::RefCell;
12
use pbf::{ProtoRead, Protobuf};
13
use s2json::{BBOX, Properties};
14

15
/// Methods that all vector features should have
16
pub 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.
48
    fn load_lines(&mut self) -> VectorLinesWithOffset;
49
    /// an array of 3D lines.
50
    fn load_lines_3d(&mut self) -> VectorLines3DWithOffset;
51
    /// an array of polygons.
52
    fn load_polys(&mut self) -> Vec<VectorLinesWithOffset>;
53
    /// an array of 3D polygons.
54
    fn load_polys_3d(&mut self) -> Vec<VectorLines3DWithOffset>;
55
    /// (flattened geometry & tesslation if applicable, indices)
56
    fn load_geometry_flat(&mut self) -> (Vec<f64>, Vec<u32>);
57
    /// load the geometry
58
    fn load_geometry(&mut self) -> VectorGeometry;
59
    /// load the indices
60
    fn read_indices(&mut self) -> Vec<u32>;
61
    /// Add tessellation data to the geometry
62
    fn add_tessellation(&mut self, geometry: &mut Vec<f64>, multiplier: f64);
63
    /// Add 3D tessellation data to the geometry
64
    fn add_tessellation_3d(&mut self, geometry: &mut Vec<f64>, multiplier: f64);
65
}
66

67
/// Methods that all vector layers should have
68
pub trait VectorLayerMethods {
69
    /// the version of the vector tile layer.
70
    fn version(&self) -> u16;
71
    /// the name of the layer
72
    fn name(&self) -> String;
73
    /// the extent of the vector tile (only **512**, **1_024**, **2_048**, **4_096**, and **8_192**
74
    /// are supported for the open spec)
75
    fn extent(&self) -> usize;
76
    /// grab a feature from the layer
77
    fn feature(&mut self, i: usize) -> Option<&mut dyn VectorFeatureMethods>;
78
    /// length (layer count)
79
    fn len(&self) -> usize;
80
    /// empty (layer count is 0)
81
    fn is_empty(&self) -> bool;
82
}
83

84
/// Layer container supporting both mapbox and open vector layers
85
#[derive(Debug)]
86
pub enum VectorLayer {
87
    /// Mapbox vector layer
88
    Mapbox(MapboxVectorLayer),
89
    /// Open vector layer
90
    Open(OpenVectorLayer),
91
}
92
impl VectorLayerMethods for VectorLayer {
93
    fn version(&self) -> u16 {
24✔
94
        match self {
24✔
95
            VectorLayer::Mapbox(layer) => layer.version(),
6✔
96
            VectorLayer::Open(layer) => layer.version(),
18✔
97
        }
98
    }
24✔
99

100
    fn name(&self) -> String {
24✔
101
        match self {
24✔
102
            VectorLayer::Mapbox(layer) => layer.name(),
6✔
103
            VectorLayer::Open(layer) => layer.name(),
18✔
104
        }
105
    }
24✔
106

107
    fn extent(&self) -> usize {
24✔
108
        match self {
24✔
109
            VectorLayer::Mapbox(layer) => layer.extent(),
6✔
110
            VectorLayer::Open(layer) => layer.extent(),
18✔
111
        }
112
    }
24✔
113

114
    fn feature(&mut self, i: usize) -> Option<&mut dyn VectorFeatureMethods> {
45✔
115
        match self {
45✔
116
            VectorLayer::Mapbox(layer) => layer.feature(i),
9✔
117
            VectorLayer::Open(layer) => layer.feature(i),
36✔
118
        }
119
    }
45✔
120

121
    fn len(&self) -> usize {
27✔
122
        match self {
27✔
123
            VectorLayer::Mapbox(layer) => layer.len(),
9✔
124
            VectorLayer::Open(layer) => layer.len(),
18✔
125
        }
126
    }
27✔
127

128
    fn is_empty(&self) -> bool {
6✔
129
        match self {
6✔
130
            VectorLayer::Mapbox(layer) => layer.is_empty(),
3✔
131
            VectorLayer::Open(layer) => layer.is_empty(),
3✔
132
        }
133
    }
6✔
134
}
135

136
/// # Open Vector Tile
137
///
138
/// ## Description
139
/// A Vector Tile may parse either Mapbox or OpenVector Tile Layers
140
/// The input is an unsigned byte array that has encoded protobuffer messages.
141
///
142
/// Types of layers include:
143
/// - Vector data - vector points, lines, and polygons with 3D coordinates, properties, and/or m-values
144
/// - Image data - raster data that is RGB(A) encoded
145
/// - 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
146
///
147
/// ## Usage
148
/// ```rust,ignore
149
/// use ovtile::{VectorTile, VectorLayerMethods};
150
///
151
/// let data: Vec<u8> = vec![];
152
/// let mut tile = VectorTile::new(data, None);
153
///
154
/// // VECTOR API
155
///
156
/// let landuse = tile.layer("landuse").unwrap();
157
///
158
/// // grab the first feature
159
/// let firstFeature = landuse.feature(0).unwrap();
160
/// // grab the geometry
161
/// let geometry = firstFeature.load_geometry();
162
///
163
/// // OR specifically ask for a geometry type
164
/// let points = firstFeature.load_points();
165
/// let lines = firstFeature.load_lines();
166
///
167
/// // If you want to take advantage of the pre-tessellated and indexed geometries
168
/// // and you're loading the data for a renderer, you can grab the pre-tessellated geometry
169
/// let (geometry_flat, indices) = firstFeature.load_geometry_flat();
170
///
171
/// // IMAGE API
172
///
173
/// let satellite = tile.images.get("satellite").unwrap();
174
/// // grab the image data
175
/// let data = &satellite.image;
176
///
177
/// // GRID API
178
///
179
/// let elevation = tile.grids.get("elevation").unwrap();
180
/// // grab the grid data
181
/// let data = &elevation.data;
182
/// ```
183
#[derive(Debug)]
184
pub struct VectorTile {
185
    /// the layers in the vector tile
186
    pub layers: BTreeMap<String, VectorLayer>,
187
    /// indexes to track the layers. Needed for the open spec because we need the cache before we can
188
    /// parse layers and features
189
    layer_indexes: Vec<usize>,
190
    /// the protobuf for the vector tile
191
    pbf: Rc<RefCell<Protobuf>>,
192
    /// the column cache
193
    columns: Option<Rc<RefCell<ColumnCacheReader>>>,
194
    /// Gridded data
195
    pub grids: BTreeMap<String, GridData>,
196
    /// Image data
197
    pub images: BTreeMap<String, ImageData>,
198
}
199
impl VectorTile {
200
    /// Create a new vector tile
201
    pub fn new(data: Vec<u8>, end: Option<usize>) -> Self {
24✔
202
        let pbf = Rc::new(RefCell::new(data.into()));
24✔
203
        let mut vt = VectorTile {
24✔
204
            pbf: pbf.clone(),
24✔
205
            columns: None,
24✔
206
            layer_indexes: Vec::new(),
24✔
207
            layers: BTreeMap::new(),
24✔
208
            grids: BTreeMap::new(),
24✔
209
            images: BTreeMap::new(),
24✔
210
        };
24✔
211

24✔
212
        pbf.borrow_mut().read_fields(&mut vt, end);
24✔
213

24✔
214
        if !vt.layer_indexes.is_empty() {
24✔
215
            vt.read_layers();
9✔
216
        }
15✔
217

218
        vt
24✔
219
    }
24✔
220

221
    /// Read the layers
222
    pub fn read_layers(&mut self) -> Option<()> {
9✔
223
        let layer_indexes = self.layer_indexes.clone();
9✔
224
        let mut tmp_pbf = self.pbf.borrow_mut();
9✔
225
        let cache = self.columns.as_ref()?.clone();
9✔
226

227
        for pos in layer_indexes {
30✔
228
            tmp_pbf.set_pos(pos);
21✔
229
            let mut layer = OpenVectorLayer::new(cache.clone());
21✔
230
            tmp_pbf.read_message(&mut layer);
21✔
231
            self.layers.insert(layer.name.clone(), VectorLayer::Open(layer));
21✔
232
        }
21✔
233

234
        Some(())
9✔
235
    }
9✔
236

237
    /// Get a layer given the name
238
    pub fn layer(&mut self, name: &str) -> Option<&mut VectorLayer> {
27✔
239
        self.layers.get_mut(name)
27✔
240
    }
27✔
241
}
242
impl ProtoRead for VectorTile {
243
    fn read(&mut self, tag: u64, pb: &mut Protobuf) {
45✔
244
        match tag {
45✔
245
            1 | 3 => {
9✔
246
                let mut layer = MapboxVectorLayer::new(self.pbf.clone(), tag == 1);
9✔
247
                pb.read_message(&mut layer);
9✔
248
                self.layers.insert(layer.name.clone(), VectorLayer::Mapbox(layer));
9✔
249
            }
9✔
250
            4 => {
21✔
251
                // store the position of each layer for later retrieval.
21✔
252
                // Columns must be prepped before reading the layer.
21✔
253
                self.layer_indexes.push(pb.get_pos());
21✔
254
            }
21✔
255
            5 => {
9✔
256
                let mut column_reader = ColumnCacheReader::new();
9✔
257
                pb.read_message(&mut column_reader);
9✔
258
                self.columns = Some(Rc::new(RefCell::new(column_reader)));
9✔
259
            }
9✔
260
            6 => {
3✔
261
                let mut grid = GridData::default();
3✔
262
                pb.read_message(&mut grid);
3✔
263
                self.grids.insert(grid.name.clone(), grid);
3✔
264
            }
3✔
265
            7 => {
3✔
266
                let mut image = ImageData::default();
3✔
267
                pb.read_message(&mut image);
3✔
268
                self.images.insert(image.name.clone(), image);
3✔
269
            }
3✔
270
            _ => panic!("unknown tag: {}", tag),
×
271
        }
272
    }
45✔
273
}
274

275
/// writer for converting a BaseVectorTile to encoded bytes of the Open Vector Tile format
276
pub fn write_tile(
15✔
277
    tile: Option<&mut BaseVectorTile>,
15✔
278
    images: Option<Vec<&ImageData>>,
15✔
279
    grids: Option<Vec<&GridData>>,
15✔
280
) -> Vec<u8> {
15✔
281
    let mut pbf = Protobuf::new();
15✔
282
    let mut cache = ColumnCacheWriter::default();
15✔
283

284
    // first write layers
285
    if let Some(tile) = tile {
15✔
286
        for layer in tile.layers.values_mut() {
21✔
287
            pbf.write_bytes_field(4, &write_layer(layer, &mut cache));
21✔
288
        }
21✔
289
        // now we can write columns
290
        pbf.write_message(5, &cache);
9✔
291
    }
6✔
292
    // if an gridded data exists, let's write it
293
    if let Some(grids) = grids {
15✔
294
        for grid in grids.iter() {
3✔
295
            pbf.write_message(6, *grid);
3✔
296
        }
3✔
297
    }
12✔
298
    // if an image exists, let's write it
299
    if let Some(images) = images {
15✔
300
        for image in images.iter() {
3✔
301
            pbf.write_message(7, *image);
3✔
302
        }
3✔
303
    }
12✔
304

305
    pbf.take()
15✔
306
}
15✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc