1use pbf::{BitCast, ProtoRead, ProtoWrite, Protobuf, Type};
2
3use crate::{
4 base::{BaseVectorFeature, TesselationWrapper},
5 command_encode,
6 open::{FeatureType as OpenFeatureType, Properties as OpenProperties},
7 zigzag, CustomOrdWrapper, Point, VectorFeatureMethods, VectorGeometry, VectorLineWithOffset,
8 VectorLines3DWithOffset, VectorLinesWithOffset, VectorPoints, VectorPoints3D, BBOX,
9};
10
11use core::cell::RefCell;
12
13use alloc::collections::BTreeMap;
14use alloc::rc::Rc;
15use alloc::string::String;
16use alloc::vec;
17use alloc::vec::Vec;
18
19#[derive(Debug)]
21pub struct MapboxVectorFeature {
22 pub id: Option<u64>,
24 pub version: u16,
26 pub properties: Properties,
28 pub extent: usize,
30 pub r#type: FeatureType,
32 pub is_s2: bool,
35 indices_index: Option<usize>,
36 indices: Option<Vec<u32>>,
37 geometry_index: usize,
38 geometry: Option<VectorGeometry>,
39 tesselation_index: Option<usize>,
40 keys: Rc<RefCell<Vec<String>>>,
41 values: Rc<RefCell<Vec<Value>>>,
42 pbf: Rc<RefCell<Protobuf>>,
43}
44impl MapboxVectorFeature {
45 pub fn new(
47 pbf: Rc<RefCell<Protobuf>>,
48 is_s2: bool,
49 extent: usize,
50 version: u16,
51 keys: Rc<RefCell<Vec<String>>>,
52 values: Rc<RefCell<Vec<Value>>>,
53 ) -> MapboxVectorFeature {
54 MapboxVectorFeature {
55 id: None,
56 version,
57 properties: Properties::new(),
58 extent,
59 r#type: FeatureType::Point,
60 is_s2,
61 indices_index: None,
63 indices: None,
64 geometry_index: 0,
65 geometry: None,
66 tesselation_index: None,
67 keys,
68 values,
69 pbf,
70 }
71 }
72}
73impl VectorFeatureMethods for MapboxVectorFeature {
74 fn id(&self) -> Option<u64> {
76 self.id
77 }
78
79 fn version(&self) -> u16 {
81 self.version
82 }
83
84 fn properties(&self) -> OpenProperties {
86 (&self.properties).into()
87 }
88
89 fn extent(&self) -> usize {
91 self.extent
92 }
93
94 fn get_type(&self) -> OpenFeatureType {
96 (&self.r#type).into()
97 }
98
99 fn bbox(&self) -> Option<BBOX> {
101 None
102 }
103
104 fn has_m_values(&self) -> bool {
106 false
107 }
108
109 fn is_points(&self) -> bool {
111 self.r#type == FeatureType::Point
112 }
113
114 fn is_lines(&self) -> bool {
116 self.r#type == FeatureType::Line
117 }
118
119 fn is_polygons(&self) -> bool {
121 self.r#type == FeatureType::Polygon || self.r#type == FeatureType::MultiPolygon
122 }
123
124 fn is_points_3d(&self) -> bool {
126 false
127 }
128
129 fn is_lines_3d(&self) -> bool {
131 false
132 }
133
134 fn is_polygons_3d(&self) -> bool {
136 false
137 }
138
139 fn load_points(&mut self) -> VectorPoints {
141 match self.load_geometry() {
142 VectorGeometry::VectorPoints(p) => p,
143 VectorGeometry::VectorLines(lines) => {
144 lines.iter().flat_map(|p| p.geometry.clone()).collect()
145 }
146 VectorGeometry::VectorPolys(polys) => polys
147 .iter()
148 .flat_map(|p| p.iter().flat_map(|p| p.geometry[..p.geometry.len() - 1].to_vec()))
149 .collect(),
150 #[tarpaulin::skip]
151 _ => panic!("unexpected geometry type"),
152 }
153 }
154
155 #[tarpaulin::skip]
156 fn load_points_3d(&mut self) -> VectorPoints3D {
157 panic!("unexpected geometry type")
158 }
159
160 fn load_lines(&mut self) -> VectorLinesWithOffset {
162 match self.load_geometry() {
163 VectorGeometry::VectorLines(lines) => lines,
164 VectorGeometry::VectorPolys(polys) => polys.iter().flat_map(|p| p.clone()).collect(),
165 #[tarpaulin::skip]
166 _ => panic!("unexpected geometry type"),
167 }
168 }
169
170 #[tarpaulin::skip]
172 fn load_lines_3d(&mut self) -> VectorLines3DWithOffset {
173 panic!("unexpected geometry type")
174 }
175
176 fn load_geometry_flat(&mut self) -> (Vec<f64>, Vec<u32>) {
178 let multiplier: f64 = 1.0 / self.extent as f64;
180 let mut geometry: Vec<f64> = match self.load_geometry() {
182 VectorGeometry::VectorPolys(polys) => polys
183 .iter()
184 .flat_map(|p| {
185 p.iter().flat_map(|p| {
186 p.geometry
187 .clone()
188 .into_iter()
189 .flat_map(|p| vec![p.x as f64 * multiplier, p.y as f64 * multiplier])
190 })
191 })
192 .collect(),
193 #[tarpaulin::skip]
194 _ => panic!("unexpected geometry type"),
195 };
196 let indices = self.read_indices();
198 self.add_tesselation(&mut geometry, multiplier);
200
201 (geometry, indices)
202 }
203
204 fn load_geometry(&mut self) -> VectorGeometry {
206 if let Some(geometry) = &self.geometry {
207 return geometry.clone();
208 }
209
210 let mut pbf = self.pbf.borrow_mut();
211 pbf.set_pos(self.geometry_index);
212
213 let end: usize = pbf.read_varint::<usize>() + pbf.get_pos();
214 let mut cmd: usize = 1;
215 let mut length: isize = 0;
216 let mut x: i32 = 0;
217 let mut y: i32 = 0;
218
219 let mut points: VectorPoints = vec![];
220 let mut lines: VectorLinesWithOffset = vec![];
221 let mut polys: Vec<VectorLinesWithOffset> = vec![];
222
223 while pbf.get_pos() < end {
224 if length <= 0 {
225 let cmd_len: usize = pbf.read_varint();
226 cmd = cmd_len & 0x7;
227 length = (cmd_len >> 3) as isize;
228 }
229
230 length -= 1;
231
232 if cmd == 1 || cmd == 2 {
233 x += pbf.read_s_varint::<i32>();
234 y += pbf.read_s_varint::<i32>();
235
236 if cmd == 1 {
237 if !points.is_empty() && self.r#type != FeatureType::Point {
239 lines.push((&points[..]).into());
240 points = vec![];
241 }
242 }
243 points.push(Point::new(x, y));
244 } else if cmd == 4 {
245 if !points.is_empty() {
247 lines.push((&points[..]).into());
248 }
249 polys.push(lines);
250 lines = vec![];
251 points = vec![];
252 } else if cmd == 7 {
253 if !points.is_empty() {
255 points.push(points[0].clone());
256 lines.push((&points[..]).into());
257 points = vec![];
258 }
259 } else {
260 #[tarpaulin::skip]
261 panic!("unknown cmd: {}", cmd);
262 }
263 }
264
265 let geometry = if self.r#type == FeatureType::Point {
266 VectorGeometry::VectorPoints(points)
267 } else {
268 if !points.is_empty() {
269 lines.push(VectorLineWithOffset::new(0.0, points.clone()));
270 }
271 if self.r#type == FeatureType::Line {
272 VectorGeometry::VectorLines(lines)
273 } else if (self.r#type == FeatureType::MultiPolygon
274 || self.r#type == FeatureType::Polygon)
275 && !self.is_s2
276 {
277 VectorGeometry::VectorPolys(classify_rings(&lines))
278 } else {
279 VectorGeometry::VectorPolys(polys)
280 }
281 };
282
283 self.geometry = Some(geometry.clone());
284 geometry
285 }
286
287 fn read_indices(&mut self) -> Vec<u32> {
289 if let Some(indices) = &self.indices {
290 return indices.clone();
291 } else if self.indices_index.is_none() {
292 return vec![];
293 }
294
295 let mut pbf = self.pbf.borrow_mut();
296 pbf.set_pos(self.indices_index.unwrap());
297
298 let mut curr: i32 = 0;
299 let end = pbf.read_varint::<usize>() + pbf.get_pos();
300 let mut indices: Vec<u32> = vec![];
302 while pbf.get_pos() < end {
303 curr += pbf.read_s_varint::<i32>();
304 indices.push(curr as u32);
305 }
306
307 self.indices = Some(indices.clone());
308 indices
309 }
310
311 fn add_tesselation(&mut self, geometry: &mut Vec<f64>, multiplier: f64) {
313 if self.tesselation_index.is_none() {
314 return;
315 }
316
317 let mut pbf = self.pbf.borrow_mut();
318 pbf.set_pos(self.tesselation_index.unwrap());
319
320 let end = pbf.read_varint::<usize>() + pbf.get_pos();
321 let mut x = 0;
322 let mut y = 0;
323 while pbf.get_pos() < end {
324 x += pbf.read_s_varint::<i32>();
325 y += pbf.read_s_varint::<i32>();
326 geometry.push(x as f64 * multiplier);
327 geometry.push(y as f64 * multiplier);
328 }
329 }
330
331 #[tarpaulin::skip]
333 fn add_tesselation_3d(&mut self, _geometry: &mut Vec<f64>, _multiplier: f64) {
334 panic!("unexpected geometry type")
335 }
336}
337impl ProtoRead for MapboxVectorFeature {
338 fn read(&mut self, tag: u64, pb: &mut Protobuf) {
339 if self.is_s2 {
340 match tag {
341 15 => self.id = Some(pb.read_varint::<u64>()),
342 1 => {
343 let end = pb.get_pos() + pb.read_varint::<usize>();
344
345 while pb.get_pos() < end {
346 let key = &self.keys.borrow()[pb.read_varint::<usize>()];
347 let value = &self.values.borrow()[pb.read_varint::<usize>()];
348
349 self.properties.insert(key.clone(), value.clone());
350 }
351 }
352 2 => self.r#type = pb.read_varint::<FeatureType>(),
353 3 => self.geometry_index = pb.get_pos(),
354 4 => self.indices_index = Some(pb.get_pos()),
355 5 => self.tesselation_index = Some(pb.get_pos()),
356 #[tarpaulin::skip]
357 _ => panic!("unknown tag: {}", tag),
358 }
359 } else {
360 match tag {
361 1 => self.id = Some(pb.read_varint::<u64>()),
362 2 => {
363 let end = pb.get_pos() + pb.read_varint::<usize>();
364
365 while pb.get_pos() < end {
366 let key = &self.keys.borrow()[pb.read_varint::<usize>()];
367 let value = &self.values.borrow()[pb.read_varint::<usize>()];
368
369 self.properties.insert(key.clone(), value.clone());
370 }
371 }
372 3 => self.r#type = pb.read_varint::<FeatureType>(),
373 4 => self.geometry_index = pb.get_pos(),
374 5 => self.indices_index = Some(pb.get_pos()),
375 6 => self.tesselation_index = Some(pb.get_pos()),
376 #[tarpaulin::skip]
377 _ => panic!("unknown tag: {}", tag),
378 }
379 }
380 }
381}
382
383fn classify_rings(rings: &VectorLinesWithOffset) -> Vec<VectorLinesWithOffset> {
384 let mut polygons: Vec<VectorLinesWithOffset> = vec![];
385 let mut polygon: VectorLinesWithOffset = vec![];
386 let mut ccw: Option<bool> = None;
387
388 let mut i: usize = 0;
389 while i < rings.len() {
390 let area = signed_area(&rings[i].geometry);
391 if area == 0 {
392 continue;
393 }
394 if ccw.is_none() {
395 ccw = Some(area < 0);
396 }
397
398 if ccw.is_some() && ccw.unwrap() == (area < 0) {
399 if !polygon.is_empty() {
401 polygons.push(polygon.clone());
402 polygon = vec![];
403 }
404 polygon.push(rings[i].clone());
405 } else {
406 polygon.push(rings[i].clone());
408 }
409
410 i += 1
411 }
412 if !polygon.is_empty() {
413 polygons.push(polygon.clone());
414 }
415
416 polygons
417}
418
419fn signed_area(ring: &[Point]) -> i32 {
420 let mut sum: i32 = 0;
421 let mut i: usize = 0;
422 let mut j = ring.len() - 1;
423 while i < ring.len() {
424 let p1 = &ring[i];
425 let p2 = &ring[j];
426 sum += (p2.x - p1.x) * (p1.y + p2.y);
427
428 j = i;
429 i += 1;
430 }
431
432 sum
433}
434
435#[derive(Debug, Clone, PartialEq)]
437pub enum FeatureType {
438 Point = 1,
440 Line = 2,
442 Polygon = 3,
444 MultiPolygon = 4,
446}
447impl From<OpenFeatureType> for FeatureType {
448 fn from(value: OpenFeatureType) -> Self {
449 match value {
450 OpenFeatureType::Points => FeatureType::Point,
451 OpenFeatureType::Lines => FeatureType::Line,
452 OpenFeatureType::Polygons => FeatureType::MultiPolygon,
453 #[tarpaulin::skip]
454 _ => panic!("unknown value: {:?}", value),
455 }
456 }
457}
458impl BitCast for FeatureType {
459 fn to_u64(&self) -> u64 {
460 (*self).clone() as u64
461 }
462 fn from_u64(value: u64) -> Self {
463 match value {
464 1 => FeatureType::Point,
465 2 => FeatureType::Line,
466 3 => FeatureType::Polygon,
467 4 => FeatureType::MultiPolygon,
468 #[tarpaulin::skip]
469 _ => panic!("unknown value: {}", value),
470 }
471 }
472}
473
474#[derive(Debug, Clone, PartialEq, Ord, PartialOrd, Eq)]
477pub enum Value {
478 String(String),
480 UInt(u64),
482 SInt(i64),
484 Float(CustomOrdWrapper<f32>),
486 Double(CustomOrdWrapper<f64>),
488 Bool(bool),
490 Null,
492}
493impl ProtoRead for Value {
494 fn read(&mut self, tag: u64, pb: &mut Protobuf) {
495 match tag {
496 0 => *self = Value::Null,
497 1 => *self = Value::String(pb.read_string()),
498 2 => *self = Value::Float(CustomOrdWrapper(pb.read_varint::<f32>())),
499 3 => *self = Value::Double(CustomOrdWrapper(pb.read_varint::<f64>())),
500 5 => *self = Value::UInt(pb.read_varint::<u64>()),
501 4 | 6 => *self = Value::SInt(pb.read_s_varint::<i64>()),
502 7 => *self = Value::Bool(pb.read_varint::<bool>()),
503 #[tarpaulin::skip]
504 _ => *self = Value::Null,
505 }
506 }
507}
508impl ProtoWrite for Value {
509 fn write(&self, pbf: &mut Protobuf) {
510 match self {
511 Value::Null => pbf.write_field(0, Type::None),
512 Value::String(value) => pbf.write_string_field(1, value),
513 Value::Float(value) => pbf.write_varint_field(2, value.0),
514 Value::Double(value) => pbf.write_varint_field(3, value.0),
515 Value::UInt(value) => pbf.write_varint_field(5, *value),
516 Value::SInt(value) => pbf.write_s_varint_field(6, *value),
517 Value::Bool(value) => pbf.write_varint_field(7, *value),
518 }
519 }
520}
521
522pub type Properties = BTreeMap<String, Value>;
525
526pub fn write_feature(
528 feature: &BaseVectorFeature,
529 keys: &mut BTreeMap<String, usize>,
530 values: &mut BTreeMap<Value, usize>,
531 mapbox_support: bool,
532) -> Vec<u8> {
533 let mut pbf = Protobuf::new();
534
535 let properties: Properties = feature.properties().clone().into();
536 if let Some(id) = feature.id() {
537 pbf.write_varint_field(if mapbox_support { 1 } else { 15 }, id);
538 }
539 pbf.write_bytes_field(
540 if mapbox_support { 2 } else { 1 },
541 &write_properties(&properties, keys, values),
542 );
543 let _type: FeatureType = feature.get_type().into();
544 pbf.write_varint_field(if mapbox_support { 3 } else { 2 }, _type);
545 let written = write_geometry(feature, mapbox_support);
547 pbf.write_bytes_field(if mapbox_support { 4 } else { 3 }, &written);
548 if let Some(indices) = feature.indices() {
550 pbf.write_bytes_field(if mapbox_support { 5 } else { 4 }, &write_indices(&indices));
551 }
552 if let Some(TesselationWrapper::Tesselation(tess)) = feature.tesselation() {
554 pbf.write_bytes_field(if mapbox_support { 6 } else { 5 }, &write_tesselation(&tess));
555 }
556
557 pbf.take()
558}
559
560fn write_properties(
562 properties: &Properties,
563 keys: &mut BTreeMap<String, usize>,
564 values: &mut BTreeMap<Value, usize>,
565) -> Vec<u8> {
566 let mut pbf = Protobuf::new();
567
568 for (key, value) in properties {
569 let key_length = keys.len();
570 let key_index = keys.entry(key.clone()).or_insert(key_length);
571 pbf.write_varint(*key_index);
572 let value_length = values.len();
573 let value_index = values.entry(value.clone()).or_insert(value_length);
574 pbf.write_varint(*value_index);
575 }
576
577 pbf.take()
578}
579
580fn write_indices(indices: &[u32]) -> Vec<u8> {
582 let mut pbf = Protobuf::new();
583
584 let mut curr: i32 = 0;
585 for index in indices {
586 let d_curr = (*index as i32) - curr;
587 pbf.write_varint(zigzag(d_curr));
588 curr += d_curr;
589 }
590
591 pbf.take()
592}
593
594fn write_tesselation(geometry: &[Point]) -> Vec<u8> {
596 let mut pbf = Protobuf::new();
597 let mut x = 0;
598 let mut y = 0;
599 for point in geometry {
600 let dx = point.x - x;
601 let dy = point.y - y;
602 pbf.write_varint(zigzag(dx));
603 pbf.write_varint(zigzag(dy));
604 x += dx;
605 y += dy;
606 }
607
608 pbf.take()
609}
610
611fn write_geometry(feature: &BaseVectorFeature, mapbox_support: bool) -> Vec<u8> {
613 use BaseVectorFeature::*;
614 let mut pbf = Protobuf::new();
615 match feature {
616 BaseVectorPointsFeature(points) => write_geometry_points(&points.geometry, &mut pbf),
617 BaseVectorLinesFeature(lines) => write_geometry_lines(&lines.geometry, &mut pbf),
618 BaseVectorPolysFeature(polys) => {
619 write_geometry_polys(&polys.geometry, &mut pbf, mapbox_support)
620 }
621 #[tarpaulin::skip]
622 _ => panic!("unknown feature type: {:?}", feature.get_type()),
623 };
624 pbf.take()
625}
626
627fn write_geometry_points(points: &[Point], pbf: &mut Protobuf) {
629 let mut x = 0;
630 let mut y = 0;
631
632 for point in points {
633 pbf.write_varint(command_encode(1, 1)); let dx = point.x - x;
637 let dy = point.y - y;
638 pbf.write_varint(zigzag(dx));
639 pbf.write_varint(zigzag(dy));
640 x += dx;
642 y += dy;
643 }
644}
645
646fn write_geometry_lines(lines: &[VectorLineWithOffset], pbf: &mut Protobuf) {
648 let mut x = 0;
649 let mut y = 0;
650
651 for line in lines {
652 let line_geo = &line.geometry;
653 pbf.write_varint(command_encode(1, 1)); let line_count = line_geo.len();
656 let mut i = 0;
657 while i < line_count {
658 if i == 1 {
659 pbf.write_varint(command_encode(2, (line_count - 1).try_into().unwrap()));
660 }
662
663 let point = &line_geo[i];
664 let dx = point.x - x;
665 let dy = point.y - y;
666 pbf.write_varint(zigzag(dx));
667 pbf.write_varint(zigzag(dy));
668 x += dx;
669 y += dy;
670
671 i += 1;
672 }
673 }
674}
675
676fn write_geometry_polys(
678 polys: &[Vec<VectorLineWithOffset>],
679 pbf: &mut Protobuf,
680 mapbox_support: bool,
681) {
682 let mut x = 0;
683 let mut y = 0;
684
685 for poly in polys {
686 for ring in poly {
687 let ring_geo = &ring.geometry;
688 pbf.write_varint(command_encode(1, 1)); let line_count = ring_geo.len() - 1;
690 let mut i = 0;
691 while i < line_count {
692 if i == 1 {
693 pbf.write_varint(command_encode(2, (line_count - 1).try_into().unwrap()));
694 }
696
697 let point = &ring_geo[i];
698 let dx = point.x - x;
699 let dy = point.y - y;
700 pbf.write_varint(zigzag(dx));
701 pbf.write_varint(zigzag(dy));
702 x += dx;
703 y += dy;
704
705 i += 1;
706 }
707 pbf.write_varint(command_encode(7, 1)); }
709 pbf.write_varint(command_encode(if mapbox_support { 7 } else { 4 }, 1));
711 }
712}