open_vector_tile/base/
vector_feature.rs

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