open_vector_tile/open/
vector_feature.rs

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