ovtile/base/
vector_feature.rs

1use crate::{
2    mapbox::MapboxVectorFeature,
3    open::{
4        encode_value, ColumnCacheWriter, FeatureType, LineStringMValues, Properties, Shape, Value,
5    },
6    weave_2d, weave_3d, zigzag, BBox, BBox3D, Point, Point3D, VectorFeatureMethods, VectorGeometry,
7    VectorLines3DWithOffset, VectorLinesWithOffset, VectorPoints, VectorPoints3D, BBOX,
8};
9
10use alloc::vec::Vec;
11
12use libm::round;
13
14/// Vector Feature functions that are common to all vector features
15pub trait VectorFeature {
16    /// Get the type of the vector feature
17    fn get_type(&self) -> FeatureType;
18    /// Get the properties of the vector feature
19    fn properties(&self) -> &Properties;
20    /// true if the feature has BBox
21    fn has_bbox(&self) -> bool;
22    /// true if the feature has offsets
23    fn has_offsets(&self) -> bool;
24    /// true if the feature has M values
25    fn has_m_values(&self) -> bool;
26    /// Get the geometry of the feature
27    fn load_geometry(&self) -> VectorGeometry;
28    /// Get the M values of the feature
29    fn m_values(&self) -> Option<LineStringMValues>;
30    /// Encode the feature to cache
31    fn encode_to_cache(&self, cache: &mut ColumnCacheWriter, m_shape: Option<&Shape>) -> usize;
32}
33
34//? Points & Points3D
35
36/// Base Vector Points Feature
37#[derive(Default, Debug, Clone, PartialEq)]
38pub struct BaseVectorPointsFeature {
39    /// Unique ID
40    pub id: Option<u64>,
41    /// Geometry
42    pub geometry: VectorPoints,
43    /// Properties
44    pub properties: Properties,
45    /// BBox
46    pub bbox: Option<BBox>,
47}
48impl BaseVectorPointsFeature {
49    /// Create a new BaseVectorPointsFeature
50    pub fn new(
51        id: Option<u64>,
52        geometry: VectorPoints,
53        properties: Properties,
54        bbox: Option<BBox>,
55    ) -> Self {
56        Self { id, geometry, properties, bbox }
57    }
58}
59impl VectorFeature for BaseVectorPointsFeature {
60    /// Get the type of the feature
61    fn get_type(&self) -> FeatureType {
62        FeatureType::Points
63    }
64
65    /// Get the properties of the feature
66    fn properties(&self) -> &Properties {
67        &self.properties
68    }
69
70    /// true if the feature has BBox
71    fn has_bbox(&self) -> bool {
72        self.bbox.is_some()
73    }
74
75    /// Points do not have this feature, so return false
76    fn has_offsets(&self) -> bool {
77        false
78    }
79
80    /// Points do not have this feature, so return false
81    fn has_m_values(&self) -> bool {
82        self.geometry.iter().any(|g| g.m.is_some())
83    }
84
85    fn load_geometry(&self) -> VectorGeometry {
86        VectorGeometry::VectorPoints(self.geometry.clone())
87    }
88
89    fn m_values(&self) -> Option<LineStringMValues> {
90        if !self.has_m_values() {
91            return None;
92        }
93        Some(
94            self.geometry
95                .iter()
96                .map(|g| {
97                    // grab the m values, if they exist otherwise return default
98                    g.m.clone().unwrap_or_default()
99                })
100                .collect(),
101        )
102    }
103
104    fn encode_to_cache(&self, cache: &mut ColumnCacheWriter, m_shape: Option<&Shape>) -> usize {
105        let geometry = &self.geometry;
106        if geometry.len() == 1 {
107            let point = &geometry[0];
108            weave_2d(zigzag(point.x) as u16, zigzag(point.y) as u16) as usize
109        } else {
110            let mut indices: Vec<u32> = Vec::new();
111            indices.push(cache.add_points(geometry.to_vec()) as u32);
112            // store the mvalues indexes if they exist
113            if let (Some(m_values), Some(shape)) = (self.m_values(), m_shape) {
114                for m in m_values {
115                    indices.push(encode_value(&m, shape, cache) as u32);
116                }
117            }
118            cache.add_indices(indices)
119        }
120    }
121}
122/// Base Vector Points Feature
123#[derive(Default, Debug, Clone, PartialEq)]
124pub struct BaseVectorPoints3DFeature {
125    /// Unique ID
126    pub id: Option<u64>,
127    /// Geometry
128    pub geometry: VectorPoints3D,
129    /// Properties
130    pub properties: Properties,
131    /// BBox
132    pub bbox: Option<BBox3D>,
133}
134impl BaseVectorPoints3DFeature {
135    /// Create a new BaseVectorPoints3DFeature
136    pub fn new(
137        id: Option<u64>,
138        geometry: VectorPoints3D,
139        properties: Properties,
140        bbox: Option<BBox3D>,
141    ) -> Self {
142        Self { id, geometry, properties, bbox }
143    }
144}
145impl VectorFeature for BaseVectorPoints3DFeature {
146    /// Get the type of the feature
147    fn get_type(&self) -> FeatureType {
148        FeatureType::Points3D
149    }
150
151    /// Get the properties of the feature
152    fn properties(&self) -> &Properties {
153        &self.properties
154    }
155
156    /// true if the feature has BBox
157    fn has_bbox(&self) -> bool {
158        self.bbox.is_some()
159    }
160
161    /// Points do not have this feature, so return false
162    fn has_offsets(&self) -> bool {
163        false
164    }
165
166    /// Points do not have this feature, so return false
167    fn has_m_values(&self) -> bool {
168        self.geometry.iter().any(|g| g.m.is_some())
169    }
170
171    fn load_geometry(&self) -> VectorGeometry {
172        VectorGeometry::VectorPoints3D(self.geometry.clone())
173    }
174
175    fn m_values(&self) -> Option<LineStringMValues> {
176        if !self.has_m_values() {
177            return None;
178        }
179        Some(self.geometry.iter().map(|g| g.m.clone().unwrap_or_default()).collect())
180    }
181
182    fn encode_to_cache(&self, cache: &mut ColumnCacheWriter, m_shape: Option<&Shape>) -> usize {
183        let geometry = &self.geometry;
184        if geometry.len() == 1 {
185            let point = &geometry[0];
186            weave_3d(zigzag(point.x) as u16, zigzag(point.y) as u16, zigzag(point.z) as u16)
187                as usize
188        } else {
189            let mut indices: Vec<u32> = Vec::new();
190            indices.push(cache.add_points_3d(geometry.to_vec()) as u32);
191            // store the mvalues indexes if they exist
192            if let (Some(m_values), Some(shape)) = (self.m_values(), m_shape) {
193                for m in m_values {
194                    indices.push(encode_value(&m, shape, cache) as u32);
195                }
196            }
197            cache.add_indices(indices)
198        }
199    }
200}
201
202//? Lines & Lines3D
203
204/// Base Vector Line Feature
205#[derive(Default, Debug, Clone, PartialEq)]
206pub struct BaseVectorLinesFeature {
207    /// Unique ID
208    pub id: Option<u64>,
209    /// Geometry
210    pub geometry: VectorLinesWithOffset,
211    /// Properties
212    pub properties: Properties,
213    /// BBox
214    pub bbox: Option<BBox>,
215}
216impl BaseVectorLinesFeature {
217    /// Create a new BaseVectorLinesFeature
218    pub fn new(
219        id: Option<u64>,
220        geometry: VectorLinesWithOffset,
221        properties: Properties,
222        bbox: Option<BBox>,
223    ) -> Self {
224        Self { id, geometry, properties, bbox }
225    }
226}
227impl VectorFeature for BaseVectorLinesFeature {
228    /// Get the type of the feature
229    fn get_type(&self) -> FeatureType {
230        FeatureType::Lines
231    }
232
233    /// Get the properties of the feature
234    fn properties(&self) -> &Properties {
235        &self.properties
236    }
237
238    /// true if the feature has BBox
239    fn has_bbox(&self) -> bool {
240        self.bbox.is_some()
241    }
242
243    /// Points do not have this feature, so return false
244    fn has_offsets(&self) -> bool {
245        self.geometry.iter().any(|g| g.has_offset())
246    }
247
248    /// Points do not have this feature, so return false
249    fn has_m_values(&self) -> bool {
250        self.geometry.iter().any(|g| g.has_m_values())
251    }
252
253    fn load_geometry(&self) -> VectorGeometry {
254        VectorGeometry::VectorLines(self.geometry.to_vec())
255    }
256
257    fn m_values(&self) -> Option<LineStringMValues> {
258        if !self.has_m_values() {
259            return None;
260        }
261        Some(self.geometry.iter().flat_map(|g| g.m_values().unwrap_or_default()).collect())
262    }
263
264    fn encode_to_cache(&self, cache: &mut ColumnCacheWriter, m_shape: Option<&Shape>) -> usize {
265        let geometry = &self.geometry;
266        let mut indices: Vec<u32> = Vec::new();
267        if geometry.len() != 1 {
268            indices.push(geometry.len() as u32)
269        }
270        for line in geometry {
271            if line.has_offset() {
272                indices.push(encode_offset(line.offset));
273            }
274            indices.push(cache.add_points(line.geometry.clone()) as u32);
275            // store the mvalues indexes if they exist
276            if self.has_m_values() {
277                if let (Some(m_values), Some(shape)) = (line.m_values(), m_shape) {
278                    for m in m_values {
279                        indices.push(encode_value(&m, shape, cache) as u32);
280                    }
281                } else if let (None, Some(shape)) = (line.m_values(), m_shape) {
282                    for _ in 0..line.geometry.len() {
283                        indices.push(encode_value(&Value::default(), shape, cache) as u32);
284                    }
285                }
286            }
287        }
288        cache.add_indices(indices)
289    }
290}
291
292/// Base Vector Line 3D Feature
293#[derive(Default, Debug, Clone, PartialEq)]
294pub struct BaseVectorLines3DFeature {
295    /// Unique ID
296    pub id: Option<u64>,
297    /// Geometry
298    pub geometry: VectorLines3DWithOffset,
299    /// Properties
300    pub properties: Properties,
301    /// BBox
302    pub bbox: Option<BBox3D>,
303}
304impl BaseVectorLines3DFeature {
305    /// Create a new BaseVectorLines3DFeature
306    pub fn new(
307        id: Option<u64>,
308        geometry: VectorLines3DWithOffset,
309        properties: Properties,
310        bbox: Option<BBox3D>,
311    ) -> Self {
312        Self { id, geometry, properties, bbox }
313    }
314}
315impl VectorFeature for BaseVectorLines3DFeature {
316    /// Get the type of the feature
317    fn get_type(&self) -> FeatureType {
318        FeatureType::Lines3D
319    }
320
321    /// Get the properties of the feature
322    fn properties(&self) -> &Properties {
323        &self.properties
324    }
325
326    /// true if the feature has BBox
327    fn has_bbox(&self) -> bool {
328        self.bbox.is_some()
329    }
330
331    /// Points do not have this feature, so return false
332    fn has_offsets(&self) -> bool {
333        self.geometry.iter().any(|g| g.has_offset())
334    }
335
336    /// Points do not have this feature, so return false
337    fn has_m_values(&self) -> bool {
338        self.geometry.iter().any(|g| g.has_m_values())
339    }
340
341    fn load_geometry(&self) -> VectorGeometry {
342        VectorGeometry::VectorLines3D(self.geometry.to_vec())
343    }
344
345    fn m_values(&self) -> Option<LineStringMValues> {
346        if !self.has_m_values() {
347            return None;
348        }
349        Some(self.geometry.iter().flat_map(|g| g.m_values().unwrap_or_default()).collect())
350    }
351
352    fn encode_to_cache(&self, cache: &mut ColumnCacheWriter, m_shape: Option<&Shape>) -> usize {
353        let geometry = &self.geometry;
354        let mut indices: Vec<u32> = Vec::new();
355        if geometry.len() != 1 {
356            indices.push(geometry.len() as u32)
357        }
358        for line in geometry {
359            if line.has_offset() {
360                indices.push(encode_offset(line.offset));
361            }
362            indices.push(cache.add_points_3d(line.geometry.clone()) as u32);
363            // store the mvalues indexes if they exist
364            if self.has_m_values() {
365                if let (Some(m_values), Some(shape)) = (line.m_values(), m_shape) {
366                    for m in m_values {
367                        indices.push(encode_value(&m, shape, cache) as u32);
368                    }
369                } else if let (None, Some(shape)) = (line.m_values(), m_shape) {
370                    for _ in 0..line.geometry.len() {
371                        indices.push(encode_value(&Value::default(), shape, cache) as u32);
372                    }
373                }
374            }
375        }
376        cache.add_indices(indices)
377    }
378}
379
380//? Polygons & Polygons3D
381
382/// Base Vector Polygon Feature
383#[derive(Default, Debug, Clone, PartialEq)]
384pub struct BaseVectorPolysFeature {
385    /// Unique ID
386    pub id: Option<u64>,
387    /// Geometry
388    pub geometry: Vec<VectorLinesWithOffset>,
389    /// Properties
390    pub properties: Properties,
391    /// BBox
392    pub bbox: Option<BBox>,
393    /// Tesselation
394    pub tesselation: Vec<Point>,
395    /// Indices
396    pub indices: Vec<u32>,
397}
398impl BaseVectorPolysFeature {
399    /// Create a new BaseVectorPolysFeature
400    pub fn new(
401        id: Option<u64>,
402        geometry: Vec<VectorLinesWithOffset>,
403        properties: Properties,
404        bbox: Option<BBox>,
405        indices: Vec<u32>,
406        tesselation: Vec<Point>,
407    ) -> Self {
408        Self { id, geometry, properties, bbox, indices, tesselation }
409    }
410}
411impl VectorFeature for BaseVectorPolysFeature {
412    /// Get the type of the feature
413    fn get_type(&self) -> FeatureType {
414        FeatureType::Polygons
415    }
416
417    /// Get the properties of the feature
418    fn properties(&self) -> &Properties {
419        &self.properties
420    }
421
422    /// true if the feature has BBox
423    fn has_bbox(&self) -> bool {
424        self.bbox.is_some()
425    }
426
427    /// Points do not have this feature, so return false
428    fn has_offsets(&self) -> bool {
429        self.geometry.iter().any(|g| g.iter().any(|l| l.has_offset()))
430    }
431
432    /// Points do not have this feature, so return false
433    fn has_m_values(&self) -> bool {
434        self.geometry.iter().any(|g| g.iter().any(|l| l.has_m_values()))
435    }
436
437    fn load_geometry(&self) -> VectorGeometry {
438        VectorGeometry::VectorPolys(self.geometry.iter().map(|line| line.to_vec()).collect())
439    }
440
441    fn m_values(&self) -> Option<LineStringMValues> {
442        if !self.has_m_values() {
443            return None;
444        }
445        Some(
446            self.geometry
447                .iter()
448                .flat_map(|g| g.iter().flat_map(|l| l.m_values().unwrap_or_default()))
449                .collect(),
450        )
451    }
452
453    fn encode_to_cache(&self, cache: &mut ColumnCacheWriter, m_shape: Option<&Shape>) -> usize {
454        let geometry = &self.geometry;
455        let mut indices: Vec<u32> = Vec::new();
456        if geometry.len() != 1 {
457            indices.push(geometry.len() as u32)
458        }
459        for poly in geometry {
460            indices.push(poly.len() as u32);
461            for line in poly {
462                if line.has_offset() {
463                    indices.push(encode_offset(line.offset));
464                }
465                indices.push(cache.add_points(line.geometry.clone()) as u32);
466                // store the mvalues indexes if they exist
467                if self.has_m_values() {
468                    if let (Some(m_values), Some(shape)) = (line.m_values(), m_shape) {
469                        for m in m_values {
470                            indices.push(encode_value(&m, shape, cache) as u32);
471                        }
472                    } else if let (None, Some(shape)) = (line.m_values(), m_shape) {
473                        for _ in 0..line.geometry.len() {
474                            indices.push(encode_value(&Value::default(), shape, cache) as u32);
475                        }
476                    }
477                }
478            }
479        }
480        cache.add_indices(indices)
481    }
482}
483
484/// Base Vector Polygon Feature
485#[derive(Default, Debug, Clone, PartialEq)]
486pub struct BaseVectorPolys3DFeature {
487    /// Unique ID
488    pub id: Option<u64>,
489    /// Geometry
490    pub geometry: Vec<VectorLines3DWithOffset>,
491    /// Properties
492    pub properties: Properties,
493    /// BBox
494    pub bbox: Option<BBox3D>,
495    /// Tesselation
496    pub tesselation: Vec<Point3D>,
497    /// Indices
498    pub indices: Vec<u32>,
499}
500impl BaseVectorPolys3DFeature {
501    /// Create a new BaseVectorPolys3DFeature
502    pub fn new(
503        id: Option<u64>,
504        geometry: Vec<VectorLines3DWithOffset>,
505        properties: Properties,
506        bbox: Option<BBox3D>,
507        indices: Vec<u32>,
508        tesselation: Vec<Point3D>,
509    ) -> Self {
510        Self { id, geometry, properties, bbox, indices, tesselation }
511    }
512}
513impl VectorFeature for BaseVectorPolys3DFeature {
514    /// Get the type of the feature
515    fn get_type(&self) -> FeatureType {
516        FeatureType::Polygons3D
517    }
518
519    /// Get the properties of the feature
520    fn properties(&self) -> &Properties {
521        &self.properties
522    }
523
524    /// true if the feature has BBox
525    fn has_bbox(&self) -> bool {
526        self.bbox.is_some()
527    }
528
529    /// Points do not have this feature, so return false
530    fn has_offsets(&self) -> bool {
531        self.geometry.iter().any(|g| g.iter().any(|l| l.has_offset()))
532    }
533
534    /// Points do not have this feature, so return false
535    fn has_m_values(&self) -> bool {
536        self.geometry.iter().any(|g| g.iter().any(|l| l.has_m_values()))
537    }
538
539    fn load_geometry(&self) -> VectorGeometry {
540        VectorGeometry::VectorPolys3D(self.geometry.iter().map(|line| line.to_vec()).collect())
541    }
542
543    fn m_values(&self) -> Option<LineStringMValues> {
544        if !self.has_m_values() {
545            return None;
546        }
547        Some(
548            self.geometry
549                .iter()
550                .flat_map(|g| g.iter().flat_map(|l| l.m_values().unwrap_or_default()))
551                .collect(),
552        )
553    }
554
555    fn encode_to_cache(&self, cache: &mut ColumnCacheWriter, m_shape: Option<&Shape>) -> usize {
556        let geometry = &self.geometry;
557        let mut indices: Vec<u32> = Vec::new();
558        if geometry.len() != 1 {
559            indices.push(geometry.len() as u32)
560        }
561        for poly in geometry {
562            indices.push(poly.len() as u32);
563            for line in poly {
564                if line.has_offset() {
565                    indices.push(encode_offset(line.offset));
566                }
567                indices.push(cache.add_points_3d(line.geometry.clone()) as u32);
568                // store the mvalues indexes if they exist
569                if self.has_m_values() {
570                    if let (Some(m_values), Some(shape)) = (line.m_values(), m_shape) {
571                        for m in m_values {
572                            indices.push(encode_value(&m, shape, cache) as u32);
573                        }
574                    } else if let (None, Some(shape)) = (line.m_values(), m_shape) {
575                        for _ in 0..line.geometry.len() {
576                            indices.push(encode_value(&Value::default(), shape, cache) as u32);
577                        }
578                    }
579                }
580            }
581        }
582        cache.add_indices(indices)
583    }
584}
585
586/// Tesselation Wrapper to handle both 2D and 3D cases
587#[derive(Debug, Clone, PartialEq)]
588pub enum TesselationWrapper {
589    /// 2D tesselation
590    Tesselation(Vec<Point>),
591    /// 3D tesselation
592    Tesselation3D(Vec<Point3D>),
593}
594impl TesselationWrapper {
595    /// check the length of the tesselation
596    pub fn len(&self) -> usize {
597        match self {
598            TesselationWrapper::Tesselation(points) => points.len(),
599            TesselationWrapper::Tesselation3D(points) => points.len(),
600        }
601    }
602
603    /// check if the tesselation is empty
604    pub fn is_empty(&self) -> bool {
605        match self {
606            TesselationWrapper::Tesselation(points) => points.is_empty(),
607            TesselationWrapper::Tesselation3D(points) => points.is_empty(),
608        }
609    }
610}
611
612/// A type that encompasses all vector tile feature types
613#[derive(Debug, Clone, PartialEq)]
614pub enum BaseVectorFeature {
615    /// Points
616    BaseVectorPointsFeature(BaseVectorPointsFeature),
617    /// Lines
618    BaseVectorLinesFeature(BaseVectorLinesFeature),
619    /// Polygons
620    BaseVectorPolysFeature(BaseVectorPolysFeature),
621    /// 3D Points
622    BaseVectorPoints3DFeature(BaseVectorPoints3DFeature),
623    /// 3D Lines
624    BaseVectorLines3DFeature(BaseVectorLines3DFeature),
625    /// 3D Polygons
626    BaseVectorPolys3DFeature(BaseVectorPolys3DFeature),
627}
628impl BaseVectorFeature {
629    /// check if the feature geometry has a single length
630    pub fn single(&self) -> bool {
631        match self {
632            BaseVectorFeature::BaseVectorPointsFeature(f) => f.geometry.len() == 1,
633            BaseVectorFeature::BaseVectorLinesFeature(f) => f.geometry.len() == 1,
634            BaseVectorFeature::BaseVectorPolysFeature(f) => f.geometry.len() == 1,
635            BaseVectorFeature::BaseVectorPoints3DFeature(f) => f.geometry.len() == 1,
636            BaseVectorFeature::BaseVectorLines3DFeature(f) => f.geometry.len() == 1,
637            BaseVectorFeature::BaseVectorPolys3DFeature(f) => f.geometry.len() == 1,
638        }
639    }
640
641    /// get the feature properties
642    pub fn properties(&self) -> &Properties {
643        match self {
644            BaseVectorFeature::BaseVectorPointsFeature(f) => f.properties(),
645            BaseVectorFeature::BaseVectorLinesFeature(f) => f.properties(),
646            BaseVectorFeature::BaseVectorPolysFeature(f) => f.properties(),
647            BaseVectorFeature::BaseVectorPoints3DFeature(f) => f.properties(),
648            BaseVectorFeature::BaseVectorLines3DFeature(f) => f.properties(),
649            BaseVectorFeature::BaseVectorPolys3DFeature(f) => f.properties(),
650        }
651    }
652
653    /// check if the feature has m values
654    pub fn has_m_values(&self) -> bool {
655        match self {
656            BaseVectorFeature::BaseVectorPointsFeature(f) => f.has_m_values(),
657            BaseVectorFeature::BaseVectorLinesFeature(f) => f.has_m_values(),
658            BaseVectorFeature::BaseVectorPolysFeature(f) => f.has_m_values(),
659            BaseVectorFeature::BaseVectorPoints3DFeature(f) => f.has_m_values(),
660            BaseVectorFeature::BaseVectorLines3DFeature(f) => f.has_m_values(),
661            BaseVectorFeature::BaseVectorPolys3DFeature(f) => f.has_m_values(),
662        }
663    }
664
665    /// get the feature m values
666    pub fn m_values(&self) -> Option<LineStringMValues> {
667        match self {
668            BaseVectorFeature::BaseVectorPointsFeature(f) => f.m_values(),
669            BaseVectorFeature::BaseVectorLinesFeature(f) => f.m_values(),
670            BaseVectorFeature::BaseVectorPolysFeature(f) => f.m_values(),
671            BaseVectorFeature::BaseVectorPoints3DFeature(f) => f.m_values(),
672            BaseVectorFeature::BaseVectorLines3DFeature(f) => f.m_values(),
673            BaseVectorFeature::BaseVectorPolys3DFeature(f) => f.m_values(),
674        }
675    }
676
677    /// get the feature type
678    pub fn get_type(&self) -> FeatureType {
679        match self {
680            BaseVectorFeature::BaseVectorPointsFeature(f) => f.get_type(),
681            BaseVectorFeature::BaseVectorLinesFeature(f) => f.get_type(),
682            BaseVectorFeature::BaseVectorPolysFeature(f) => f.get_type(),
683            BaseVectorFeature::BaseVectorPoints3DFeature(f) => f.get_type(),
684            BaseVectorFeature::BaseVectorLines3DFeature(f) => f.get_type(),
685            BaseVectorFeature::BaseVectorPolys3DFeature(f) => f.get_type(),
686        }
687    }
688
689    /// get the feature id
690    pub fn id(&self) -> Option<u64> {
691        match self {
692            BaseVectorFeature::BaseVectorPointsFeature(f) => f.id,
693            BaseVectorFeature::BaseVectorLinesFeature(f) => f.id,
694            BaseVectorFeature::BaseVectorPolysFeature(f) => f.id,
695            BaseVectorFeature::BaseVectorPoints3DFeature(f) => f.id,
696            BaseVectorFeature::BaseVectorLines3DFeature(f) => f.id,
697            BaseVectorFeature::BaseVectorPolys3DFeature(f) => f.id,
698        }
699    }
700
701    /// get the feature indices
702    pub fn indices(&self) -> Option<Vec<u32>> {
703        match self {
704            BaseVectorFeature::BaseVectorPolysFeature(f) => Some(f.indices.clone()),
705            BaseVectorFeature::BaseVectorPolys3DFeature(f) => Some(f.indices.clone()),
706            _ => None,
707        }
708    }
709
710    /// get the feature tesselation
711    pub fn tesselation(&self) -> Option<TesselationWrapper> {
712        match self {
713            BaseVectorFeature::BaseVectorPolysFeature(f) => {
714                Some(TesselationWrapper::Tesselation(f.tesselation.clone()))
715            }
716            BaseVectorFeature::BaseVectorPolys3DFeature(f) => {
717                Some(TesselationWrapper::Tesselation3D(f.tesselation.clone()))
718            }
719            _ => None,
720        }
721    }
722
723    /// get the feature bbox
724    pub fn bbox(&self) -> Option<BBOX> {
725        match self {
726            BaseVectorFeature::BaseVectorPointsFeature(f) => f.bbox.map(BBOX::BBox),
727            BaseVectorFeature::BaseVectorLinesFeature(f) => f.bbox.map(BBOX::BBox),
728            BaseVectorFeature::BaseVectorPolysFeature(f) => f.bbox.map(BBOX::BBox),
729            BaseVectorFeature::BaseVectorPoints3DFeature(f) => f.bbox.map(BBOX::BBox3D),
730            BaseVectorFeature::BaseVectorLines3DFeature(f) => f.bbox.map(BBOX::BBox3D),
731            BaseVectorFeature::BaseVectorPolys3DFeature(f) => f.bbox.map(BBOX::BBox3D),
732        }
733    }
734
735    /// check if the feature has offsets
736    pub fn has_offsets(&self) -> bool {
737        match self {
738            BaseVectorFeature::BaseVectorLinesFeature(f) => f.has_offsets(),
739            BaseVectorFeature::BaseVectorLines3DFeature(f) => f.has_offsets(),
740            BaseVectorFeature::BaseVectorPolysFeature(f) => f.has_offsets(),
741            BaseVectorFeature::BaseVectorPolys3DFeature(f) => f.has_offsets(),
742            _ => false,
743        }
744    }
745
746    /// encode the feature to cache
747    pub fn encode_to_cache(&self, cache: &mut ColumnCacheWriter, m_shape: Option<&Shape>) -> usize {
748        match self {
749            BaseVectorFeature::BaseVectorPointsFeature(f) => f.encode_to_cache(cache, m_shape),
750            BaseVectorFeature::BaseVectorLinesFeature(f) => f.encode_to_cache(cache, m_shape),
751            BaseVectorFeature::BaseVectorPolysFeature(f) => f.encode_to_cache(cache, m_shape),
752            BaseVectorFeature::BaseVectorPoints3DFeature(f) => f.encode_to_cache(cache, m_shape),
753            BaseVectorFeature::BaseVectorLines3DFeature(f) => f.encode_to_cache(cache, m_shape),
754            BaseVectorFeature::BaseVectorPolys3DFeature(f) => f.encode_to_cache(cache, m_shape),
755        }
756    }
757}
758impl From<&mut MapboxVectorFeature> for BaseVectorFeature {
759    fn from(mvt: &mut MapboxVectorFeature) -> Self {
760        let id = mvt.id;
761        let properties: Properties = (&mvt.properties).into();
762        let indices = mvt.read_indices();
763        let mut tesselation_floats: Vec<f64> = Vec::new();
764        mvt.add_tesselation(&mut tesselation_floats, 1.0);
765        // convert an flat array of f64 to groups of 2 making a Point (convert to a Vec<Point>)
766        let tesselation = tesselation_floats
767            .chunks(2)
768            .map(|chunk| Point::new(chunk[0] as i32, chunk[1] as i32))
769            .collect();
770
771        match mvt.load_geometry() {
772            VectorGeometry::VectorPoints(geo) => BaseVectorFeature::BaseVectorPointsFeature(
773                BaseVectorPointsFeature::new(id, geo, properties, None),
774            ),
775            VectorGeometry::VectorLines(geo) => BaseVectorFeature::BaseVectorLinesFeature(
776                BaseVectorLinesFeature::new(id, geo, properties, None),
777            ),
778            VectorGeometry::VectorPolys(geo) => BaseVectorFeature::BaseVectorPolysFeature(
779                BaseVectorPolysFeature::new(id, geo, properties, None, indices, tesselation),
780            ),
781            #[tarpaulin::skip]
782            _ => panic!("unexpected geometry type"),
783        }
784    }
785}
786
787/// Encode offset values into a signed integer to reduce byte cost without too much loss
788pub fn encode_offset(offset: f64) -> u32 {
789    round(offset * 1_000.0) as u32
790}
791
792/// Decode offset from a signed integer into a float or double
793pub fn decode_offset(offset: u32) -> f64 {
794    (offset as f64) / 1_000.0
795}