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