open_vector_tile/open/
vector_feature.rs

1use super::decode_value;
2use crate::{
3    base::{decode_offset, BaseVectorFeature, TessellationWrapper},
4    mapbox::FeatureType as MapboxFeatureType,
5    open::{encode_value, ColumnCacheReader, ColumnCacheWriter},
6    unweave_2d, unweave_3d, zagzig, Point, Point3D, VectorFeatureMethods, VectorGeometry,
7    VectorLine3DWithOffset, VectorLineWithOffset, VectorLines3DWithOffset, VectorLinesWithOffset,
8    VectorPoints, VectorPoints3D,
9};
10use alloc::{rc::Rc, vec, vec::Vec};
11use core::cell::RefCell;
12use pbf::{BitCast, Protobuf};
13use s2json::{Properties, Shape, BBOX};
14use serde::{Deserialize, Serialize};
15
16/// Extent guide for how the geometry data is stored
17#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
18pub enum Extent {
19    /// 512x512
20    Extent512 = 512,
21    /// 1024x1024
22    Extent1024 = 1_024,
23    /// 2048x2048
24    Extent2048 = 2_048,
25    /// 4096x4096 (default)
26    #[default]
27    Extent4096 = 4_096,
28    /// 8_192x8_192
29    Extent8192 = 8_192,
30    /// 16_384x16_384
31    Extent16384 = 16_384,
32}
33impl BitCast for Extent {
34    fn to_u64(&self) -> u64 {
35        match self {
36            Extent::Extent512 => 0,
37            Extent::Extent1024 => 1,
38            Extent::Extent2048 => 2,
39            Extent::Extent4096 => 3,
40            Extent::Extent8192 => 4,
41            Extent::Extent16384 => 5,
42        }
43    }
44
45    fn from_u64(value: u64) -> Self {
46        match value {
47            1 => Extent::Extent1024,
48            2 => Extent::Extent2048,
49            3 => Extent::Extent4096,
50            4 => Extent::Extent8192,
51            5 => Extent::Extent16384,
52            _ => Extent::Extent512,
53        }
54    }
55}
56impl From<usize> for Extent {
57    fn from(extent: usize) -> Self {
58        match extent {
59            512 => Extent::Extent512,
60            1_024 => Extent::Extent1024,
61            2_048 => Extent::Extent2048,
62            4_096 => Extent::Extent4096,
63            8_192 => Extent::Extent8192,
64            16_384 => Extent::Extent16384,
65            _ => Extent::Extent512,
66        }
67    }
68}
69impl From<Extent> for usize {
70    fn from(extent: Extent) -> Self {
71        extent as i32 as usize
72    }
73}
74impl From<Extent> for f64 {
75    fn from(extent: Extent) -> Self {
76        extent as i32 as f64
77    }
78}
79
80/// Open Vector Tile Feature types.
81#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
82pub enum FeatureType {
83    /// Points Feature
84    #[default]
85    Points = 1,
86    /// Lines Feature
87    Lines = 2,
88    /// Polygons Feature
89    Polygons = 3,
90    /// Points3D Feature
91    Points3D = 4,
92    /// Lines3D Feature
93    Lines3D = 5,
94    /// Polygons3D Feature
95    Polygons3D = 6,
96}
97impl BitCast for FeatureType {
98    fn to_u64(&self) -> u64 {
99        (*self) as u64
100    }
101    fn from_u64(value: u64) -> Self {
102        match value {
103            1 => FeatureType::Points,
104            2 => FeatureType::Lines,
105            3 => FeatureType::Polygons,
106            4 => FeatureType::Points3D,
107            5 => FeatureType::Lines3D,
108            6 => FeatureType::Polygons3D,
109            _ => panic!("unknown value: {}", value),
110        }
111    }
112}
113impl From<&MapboxFeatureType> for FeatureType {
114    fn from(mft: &MapboxFeatureType) -> Self {
115        match mft {
116            MapboxFeatureType::Point => FeatureType::Points,
117            MapboxFeatureType::Line => FeatureType::Lines,
118            MapboxFeatureType::Polygon => FeatureType::Polygons,
119            MapboxFeatureType::MultiPolygon => FeatureType::Polygons,
120        }
121    }
122}
123
124/// Open Vector Tile Feature specification
125#[derive(Debug)]
126pub struct OpenVectorFeature {
127    /// the id of the feature
128    pub id: Option<u64>,
129    /// the properties of the feature
130    pub properties: Properties,
131    /// the type of the feature
132    pub r#type: FeatureType,
133    cache: Rc<RefCell<ColumnCacheReader>>,
134    m_shape: Shape,
135    extent: Extent,
136    geometry_indices: Vec<u32>,
137    geometry: Option<VectorGeometry>,
138    single: bool,
139    bbox_index: Option<usize>,
140    has_offsets: bool,
141    has_m_values: bool,
142    indices_index: Option<usize>,
143    tessellation_index: Option<usize>,
144}
145impl OpenVectorFeature {
146    fn _load_geometry_points(&mut self) -> VectorPoints {
147        let mut cache = self.cache.borrow_mut();
148
149        let mut index_pos = 0;
150        let geometry_index = self.geometry_indices[index_pos];
151        index_pos += 1;
152        if self.single {
153            let (a, b) = unweave_2d(geometry_index);
154            vec![Point::new(zagzig(a as u32), zagzig(b as u32))]
155        } else {
156            let mut geometry = cache.get_points(geometry_index as usize);
157
158            if self.has_m_values {
159                let length = geometry.len();
160                geometry.iter_mut().take(length).for_each(|p| {
161                    let value_index = self.geometry_indices[index_pos];
162                    p.m = Some(decode_value(value_index as usize, &self.m_shape, &mut cache));
163                    index_pos += 1;
164                });
165            }
166
167            geometry
168        }
169    }
170
171    fn _load_geometry_points_3d(&mut self) -> VectorPoints3D {
172        let mut cache = self.cache.borrow_mut();
173
174        let mut index_pos = 0;
175        let geometry_index = self.geometry_indices[index_pos];
176        index_pos += 1;
177        if self.single {
178            let (a, b, c) = unweave_3d(geometry_index as u64);
179            vec![Point3D::new(zagzig(a), zagzig(b), zagzig(c))]
180        } else {
181            let mut geometry = cache.get_points_3d(geometry_index as usize);
182
183            if self.has_m_values {
184                let length = geometry.len();
185                geometry.iter_mut().take(length).for_each(|p| {
186                    let value_index = self.geometry_indices[index_pos];
187                    p.m = Some(decode_value(value_index as usize, &self.m_shape, &mut cache));
188                    index_pos += 1;
189                });
190            }
191
192            geometry
193        }
194    }
195
196    fn _load_geometry_lines(&mut self) -> VectorLinesWithOffset {
197        let mut cache = self.cache.borrow_mut();
198
199        let mut res: VectorLinesWithOffset = vec![];
200
201        let mut index_pos = 0;
202        let mut line_count = 1;
203        if !self.single {
204            line_count = self.geometry_indices[index_pos];
205            index_pos += 1;
206        };
207        for _ in 0..line_count {
208            // get offset if it exists
209            let mut offset = 0.0;
210            if self.has_offsets {
211                offset = decode_offset(self.geometry_indices[index_pos]);
212                index_pos += 1;
213            }
214            // get geometry
215            let mut geometry = cache.get_points(self.geometry_indices[index_pos] as usize);
216            index_pos += 1;
217            // inject m values if they exist
218            if self.has_m_values {
219                let length = geometry.len();
220                geometry.iter_mut().take(length).for_each(|p| {
221                    let value_index = self.geometry_indices[index_pos];
222                    p.m = Some(decode_value(value_index as usize, &self.m_shape, &mut cache));
223                    index_pos += 1;
224                });
225            }
226            res.push(VectorLineWithOffset::new(offset, geometry));
227        }
228
229        res
230    }
231
232    fn _load_geometry_lines_3d(&mut self) -> VectorLines3DWithOffset {
233        let mut cache = self.cache.borrow_mut();
234
235        let mut res: VectorLines3DWithOffset = vec![];
236
237        let mut index_pos = 0;
238        let mut line_count = 1;
239        if !self.single {
240            line_count = self.geometry_indices[index_pos];
241            index_pos += 1;
242        };
243        for _ in 0..line_count {
244            // get offset if it exists
245            let mut offset = 0.0;
246            if self.has_offsets {
247                offset = decode_offset(self.geometry_indices[index_pos]);
248                index_pos += 1;
249            }
250            // get geometry
251            let mut geometry = cache.get_points_3d(self.geometry_indices[index_pos] as usize);
252            index_pos += 1;
253            // inject m values if they exist
254            if self.has_m_values {
255                let length = geometry.len();
256                geometry.iter_mut().take(length).for_each(|p| {
257                    let value_index = self.geometry_indices[index_pos];
258                    p.m = Some(decode_value(value_index as usize, &self.m_shape, &mut cache));
259                    index_pos += 1;
260                });
261            }
262            res.push(VectorLine3DWithOffset::new(offset, geometry));
263        }
264
265        res
266    }
267
268    fn _load_geometry_polys(&mut self) -> Vec<VectorLinesWithOffset> {
269        let mut cache = self.cache.borrow_mut();
270
271        let mut res: Vec<VectorLinesWithOffset> = vec![];
272
273        let mut index_pos = 0;
274        let mut poly_count = 1;
275        if !self.single {
276            poly_count = self.geometry_indices[index_pos];
277            index_pos += 1;
278        };
279        for _ in 0..poly_count {
280            let line_count = self.geometry_indices[index_pos];
281            index_pos += 1;
282            let mut lines: VectorLinesWithOffset = vec![];
283            for _ in 0..line_count {
284                // get offset if it exists
285                let mut offset = 0.0;
286                if self.has_offsets {
287                    offset = decode_offset(self.geometry_indices[index_pos]);
288                    index_pos += 1;
289                }
290                // get geometry
291                let mut geometry = cache.get_points(self.geometry_indices[index_pos] as usize);
292                index_pos += 1;
293                // inject m values if they exist
294                if self.has_m_values {
295                    let length = geometry.len();
296                    geometry.iter_mut().take(length).for_each(|p| {
297                        let value_index = self.geometry_indices[index_pos];
298                        p.m = Some(decode_value(value_index as usize, &self.m_shape, &mut cache));
299                        index_pos += 1;
300                    });
301                }
302                lines.push(VectorLineWithOffset::new(offset, geometry));
303            }
304            res.push(lines);
305        }
306
307        res
308    }
309
310    fn _load_geometry_polys_3d(&mut self) -> Vec<VectorLines3DWithOffset> {
311        let mut cache = self.cache.borrow_mut();
312
313        let mut res: Vec<VectorLines3DWithOffset> = vec![];
314
315        let mut index_pos = 0;
316        let mut poly_count = 1;
317        if !self.single {
318            poly_count = self.geometry_indices[index_pos];
319            index_pos += 1;
320        };
321        for _ in 0..poly_count {
322            let line_count = self.geometry_indices[index_pos];
323            index_pos += 1;
324            let mut lines: VectorLines3DWithOffset = vec![];
325            for _ in 0..line_count {
326                // get offset if it exists
327                let mut offset = 0.0;
328                if self.has_offsets {
329                    offset = decode_offset(self.geometry_indices[index_pos]);
330                    index_pos += 1;
331                }
332                // get geometry
333                let mut geometry = cache.get_points_3d(self.geometry_indices[index_pos] as usize);
334                index_pos += 1;
335                // inject m values if they exist
336                if self.has_m_values {
337                    let length = geometry.len();
338                    geometry.iter_mut().take(length).for_each(|p| {
339                        let value_index = self.geometry_indices[index_pos];
340                        p.m = Some(decode_value(value_index as usize, &self.m_shape, &mut cache));
341                        index_pos += 1;
342                    });
343                }
344                lines.push(VectorLine3DWithOffset::new(offset, geometry));
345            }
346            res.push(lines);
347        }
348
349        res
350    }
351}
352impl VectorFeatureMethods for OpenVectorFeature {
353    /// get the id of the feature
354    fn id(&self) -> Option<u64> {
355        self.id
356    }
357
358    /// get the version of the feature
359    fn version(&self) -> u16 {
360        1
361    }
362
363    /// get the extent of the feature
364    fn extent(&self) -> usize {
365        self.extent.into()
366    }
367
368    fn properties(&self) -> Properties {
369        self.properties.clone()
370    }
371
372    /// Create a new OpenVectorFeature
373    fn get_type(&self) -> FeatureType {
374        self.r#type
375    }
376
377    /// get the bbox of the feature
378    fn bbox(&self) -> Option<BBOX> {
379        if let Some(index) = self.bbox_index {
380            let mut cache = self.cache.borrow_mut();
381            Some(cache.get_bbox(index))
382        } else {
383            None
384        }
385    }
386
387    /// whether the feature has m values
388    fn has_m_values(&self) -> bool {
389        self.has_m_values
390    }
391
392    /// whether the feature is a points type
393    fn is_points(&self) -> bool {
394        self.r#type == FeatureType::Points
395    }
396
397    /// whether the feature is a line type
398    fn is_lines(&self) -> bool {
399        self.r#type == FeatureType::Lines
400    }
401
402    /// whether the feature is a polygon type
403    fn is_polygons(&self) -> bool {
404        self.r#type == FeatureType::Polygons
405    }
406
407    /// whether the feature is a points 3D type
408    fn is_points_3d(&self) -> bool {
409        self.r#type == FeatureType::Points3D
410    }
411
412    /// whether the feature is a line 3D type
413    fn is_lines_3d(&self) -> bool {
414        self.r#type == FeatureType::Lines3D
415    }
416
417    /// whether the feature is a polygon 3D type
418    fn is_polygons_3d(&self) -> bool {
419        self.r#type == FeatureType::Polygons3D
420    }
421
422    /// regardless of the type, we return a flattend point array
423    fn load_points(&mut self) -> VectorPoints {
424        match self.load_geometry() {
425            VectorGeometry::VectorPoints(p) => p,
426            VectorGeometry::VectorLines(lines) => {
427                lines.iter().flat_map(|p| p.geometry.clone()).collect()
428            }
429            VectorGeometry::VectorPolys(polys) => polys
430                .iter()
431                .flat_map(|p| p.iter().flat_map(|p| p.geometry[..p.geometry.len() - 1].to_vec()))
432                .collect(),
433            _ => {
434                panic!("unexpected geometry type")
435            }
436        }
437    }
438
439    /// regardless of the type, we return a flattend point array
440    fn load_points_3d(&mut self) -> VectorPoints3D {
441        match self.load_geometry() {
442            VectorGeometry::VectorPoints3D(p) => p,
443            VectorGeometry::VectorLines3D(lines) => {
444                lines.iter().flat_map(|p| p.geometry.clone()).collect()
445            }
446            VectorGeometry::VectorPolys3D(polys) => polys
447                .iter()
448                .flat_map(|p| p.iter().flat_map(|p| p.geometry[..p.geometry.len() - 1].to_vec()))
449                .collect(),
450            _ => {
451                panic!("unexpected geometry type")
452            }
453        }
454    }
455
456    /// an array of lines. The offsets will be set to 0
457    fn load_lines(&mut self) -> VectorLinesWithOffset {
458        match self.load_geometry() {
459            VectorGeometry::VectorLines(lines) => lines,
460            VectorGeometry::VectorPolys(polys) => polys.iter().flat_map(|p| p.clone()).collect(),
461            _ => {
462                panic!("unexpected geometry type")
463            }
464        }
465    }
466
467    /// an array of lines. The offsets will be set to 0
468    fn load_lines_3d(&mut self) -> VectorLines3DWithOffset {
469        match self.load_geometry() {
470            VectorGeometry::VectorLines3D(lines) => lines,
471            VectorGeometry::VectorPolys3D(polys) => polys.iter().flat_map(|p| p.clone()).collect(),
472            _ => {
473                panic!("unexpected geometry type")
474            }
475        }
476    }
477
478    /// returns the indices of the geometry
479    fn read_indices(&mut self) -> Vec<u32> {
480        if self.indices_index.is_none() {
481            return vec![];
482        }
483        let mut cache = self.cache.borrow_mut();
484        cache.get_indices(self.indices_index.unwrap())
485    }
486
487    /// Add tessellation data to the geometry
488    fn add_tessellation(&mut self, geometry: &mut Vec<f64>, multiplier: f64) {
489        let Some(tessellation_index) = self.tessellation_index else {
490            return;
491        };
492        let mut cache = self.cache.borrow_mut();
493        let data = cache.get_points(tessellation_index);
494        for point in data {
495            geometry.push(point.x as f64 * multiplier);
496            geometry.push(point.y as f64 * multiplier);
497        }
498    }
499
500    /// Add 3D tessellation data to the geometry
501    fn add_tessellation_3d(&mut self, geometry: &mut Vec<f64>, multiplier: f64) {
502        let Some(tessellation_index) = self.tessellation_index else {
503            return;
504        };
505        let mut cache = self.cache.borrow_mut();
506        let data = cache.get_points_3d(tessellation_index);
507        for point in data {
508            geometry.push(point.x as f64 * multiplier);
509            geometry.push(point.y as f64 * multiplier);
510            geometry.push(point.z as f64 * multiplier);
511        }
512    }
513
514    /// (flattened geometry & tesslation if applicable, indices)
515    fn load_geometry_flat(&mut self) -> (Vec<f64>, Vec<u32>) {
516        // build a multiplier
517        let multiplier: f64 = 1.0 / f64::from(self.extent);
518        // grab the geometry, flatten it, and mutate to an f64
519        let geometry: Vec<f64> = match self.load_geometry() {
520            VectorGeometry::VectorPolys(polys) => {
521                let mut geo = polys
522                    .iter()
523                    .flat_map(|p| {
524                        p.iter().flat_map(|p| {
525                            p.geometry.clone().into_iter().flat_map(|p| {
526                                vec![p.x as f64 * multiplier, p.y as f64 * multiplier]
527                            })
528                        })
529                    })
530                    .collect();
531                self.add_tessellation(&mut geo, multiplier);
532                geo
533            }
534            VectorGeometry::VectorPolys3D(polys) => {
535                let mut geo = polys
536                    .iter()
537                    .flat_map(|p| {
538                        p.iter().flat_map(|p| {
539                            p.geometry.clone().into_iter().flat_map(|p| {
540                                vec![p.x as f64 * multiplier, p.y as f64 * multiplier]
541                            })
542                        })
543                    })
544                    .collect();
545                self.add_tessellation_3d(&mut geo, multiplier);
546                geo
547            }
548            _ => {
549                panic!("unexpected geometry type")
550            }
551        };
552        // if a poly, check if we should load indices
553        let indices = self.read_indices();
554
555        (geometry, indices)
556    }
557
558    /// load the geometry
559    fn load_geometry(&mut self) -> VectorGeometry {
560        if let Some(geometry) = &self.geometry {
561            return geometry.clone();
562        }
563
564        self.geometry = Some(match self.r#type {
565            FeatureType::Points => VectorGeometry::VectorPoints(self._load_geometry_points()),
566            FeatureType::Points3D => {
567                VectorGeometry::VectorPoints3D(self._load_geometry_points_3d())
568            }
569            FeatureType::Lines => VectorGeometry::VectorLines(self._load_geometry_lines()),
570            FeatureType::Lines3D => VectorGeometry::VectorLines3D(self._load_geometry_lines_3d()),
571            FeatureType::Polygons => VectorGeometry::VectorPolys(self._load_geometry_polys()),
572            FeatureType::Polygons3D => {
573                VectorGeometry::VectorPolys3D(self._load_geometry_polys_3d())
574            }
575        });
576
577        self.load_geometry()
578    }
579}
580
581/// Read a single feature given the encoded data
582pub fn read_feature(
583    data: Vec<u8>,
584    extent: Extent,
585    cache: Rc<RefCell<ColumnCacheReader>>,
586    shape: &Shape,
587    m_shape: Shape,
588) -> OpenVectorFeature {
589    let mut pbf = Protobuf::from_input(data);
590    // pull in the type
591    let r#type: FeatureType = pbf.read_varint();
592    // next the flags
593    let flags: u8 = pbf.read_varint();
594    // read the id if it exists
595    let id: Option<u64> = if flags & 1 > 0 { Some(pbf.read_varint()) } else { None };
596    let has_bbox = flags & (1 << 1) > 0;
597    let has_offsets = (flags & (1 << 2)) > 0;
598    let has_indices = flags & (1 << 3) > 0;
599    let has_tessellation = flags & (1 << 4) > 0;
600    let has_m_values = flags & (1 << 5) > 0;
601    let single = flags & (1 << 6) > 0;
602    // read the properties
603    let value_index: usize = pbf.read_varint();
604    let properties = decode_value(value_index, shape, &mut cache.borrow_mut());
605    // if type is 1 or 4, read geometry as a single index, otherwise as an array
606    let mut geometry_indices: Vec<u32> = vec![];
607    let mut indices_index: Option<usize> = None;
608    let mut tessellation_index: Option<usize> = None;
609    if r#type == FeatureType::Points || r#type == FeatureType::Points3D {
610        if single {
611            geometry_indices.push(pbf.read_varint())
612        } else {
613            geometry_indices = cache.borrow_mut().get_indices(pbf.read_varint());
614        }
615    } else {
616        geometry_indices = cache.borrow_mut().get_indices(pbf.read_varint());
617    }
618    // read indices and tessellation if they exist
619    if r#type == FeatureType::Polygons || r#type == FeatureType::Polygons3D {
620        if has_indices {
621            indices_index = Some(pbf.read_varint());
622        }
623        if has_tessellation {
624            tessellation_index = Some(pbf.read_varint());
625        }
626    }
627    let bbox_index = if has_bbox { Some(pbf.read_varint()) } else { None };
628
629    OpenVectorFeature {
630        id,
631        properties,
632        r#type,
633        cache,
634        m_shape,
635        extent,
636        geometry_indices,
637        geometry: None,
638        single,
639        bbox_index,
640        has_offsets,
641        has_m_values,
642        indices_index,
643        tessellation_index,
644    }
645}
646
647/// Write a single feature to the column cache and return the encoding indexes for lookup
648pub fn write_feature(
649    feature: &BaseVectorFeature,
650    shape: &Shape,
651    m_shape: Option<&Shape>,
652    cache: &mut ColumnCacheWriter,
653) -> Vec<u8> {
654    // write id, type, properties, bbox, geometry, indices, tessellation, mValues
655    let mut pbf = Protobuf::new();
656    // type is just stored as a varint
657    pbf.write_varint(feature.get_type());
658    // store flags if each one exists or not into a single byte
659    let id = feature.id();
660    let has_id: bool = id.is_some();
661    let indices = feature.indices();
662    let has_indices = indices.is_some() && !indices.unwrap().is_empty();
663    let tessellation = feature.tessellation();
664    let has_tessellation = tessellation.is_some() && !tessellation.as_ref().unwrap().is_empty();
665    let has_offsets = feature.has_offsets();
666    let bbox = feature.bbox();
667    let has_bbox = bbox.is_some();
668    let has_m_values = feature.has_m_values();
669    let single = feature.single();
670    let mut flags: u8 = 0;
671    if has_id {
672        flags += 1;
673    }
674    if has_bbox {
675        flags += 1 << 1;
676    }
677    if has_offsets {
678        flags += 1 << 2;
679    }
680    if has_indices {
681        flags += 1 << 3;
682    }
683    if has_tessellation {
684        flags += 1 << 4;
685    }
686    if has_m_values {
687        flags += 1 << 5;
688    }
689    if single {
690        flags += 1 << 6;
691    }
692    pbf.write_varint(flags);
693    // id is stored in unsigned column
694    if has_id {
695        pbf.write_varint(id.unwrap());
696    }
697    // index to values column
698    let value_index = encode_value(feature.properties(), shape, cache);
699    pbf.write_varint(value_index);
700    // geometry
701    let stored_geo = feature.encode_to_cache(cache, m_shape);
702    pbf.write_varint(stored_geo);
703    // indices
704    if has_indices {
705        pbf.write_varint(cache.add_indices(feature.indices().unwrap()));
706    }
707    // tessellation
708    if has_tessellation {
709        match tessellation.unwrap() {
710            TessellationWrapper::Tessellation(t) => pbf.write_varint(cache.add_points(t)),
711            TessellationWrapper::Tessellation3D(t) => pbf.write_varint(cache.add_points_3d(t)),
712        }
713    }
714    // bbox is stored in double column.
715    if has_bbox {
716        pbf.write_varint(cache.add_bbox(bbox.unwrap()));
717    }
718
719    pbf.take()
720}