ovtile/open/
vector_feature.rs

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