open_vector_tile/base/
vector_feature.rs

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