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_geometry_flat(&mut self) -> (Vec<f64>, Vec<u32>) {
173 let multiplier: f64 = 1.0 / self.extent as f64;
175 let mut geometry: Vec<f64> = match self.load_geometry() {
177 VectorGeometry::VectorPolys(polys) => polys
178 .iter()
179 .flat_map(|p| {
180 p.iter().flat_map(|p| {
181 p.geometry
182 .clone()
183 .into_iter()
184 .flat_map(|p| vec![p.x as f64 * multiplier, p.y as f64 * multiplier])
185 })
186 })
187 .collect(),
188 #[tarpaulin::skip]
189 _ => panic!("unexpected geometry type"),
190 };
191 let indices = self.read_indices();
193 self.add_tessellation(&mut geometry, multiplier);
195
196 (geometry, indices)
197 }
198
199 fn load_geometry(&mut self) -> VectorGeometry {
201 if let Some(geometry) = &self.geometry {
202 return geometry.clone();
203 }
204
205 let mut pbf = self.pbf.borrow_mut();
206 pbf.set_pos(self.geometry_index);
207
208 let end: usize = pbf.read_varint::<usize>() + pbf.get_pos();
209 let mut cmd: usize = 1;
210 let mut length: isize = 0;
211 let mut x: i32 = 0;
212 let mut y: i32 = 0;
213
214 let mut points: VectorPoints = vec![];
215 let mut lines: VectorLinesWithOffset = vec![];
216 let mut polys: Vec<VectorLinesWithOffset> = vec![];
217
218 while pbf.get_pos() < end {
219 if length <= 0 {
220 let cmd_len: usize = pbf.read_varint();
221 cmd = cmd_len & 0x7;
222 length = (cmd_len >> 3) as isize;
223 }
224
225 length -= 1;
226
227 if cmd == 1 || cmd == 2 {
228 x += pbf.read_s_varint::<i32>();
229 y += pbf.read_s_varint::<i32>();
230
231 if cmd == 1 {
232 if !points.is_empty() && self.r#type != FeatureType::Point {
234 lines.push((&points[..]).into());
235 points = vec![];
236 }
237 }
238 points.push(Point::new(x, y));
239 } else if cmd == 4 {
240 if !points.is_empty() {
242 lines.push((&points[..]).into());
243 }
244 polys.push(lines);
245 lines = vec![];
246 points = vec![];
247 } else if cmd == 7 {
248 if !points.is_empty() {
250 points.push(points[0].clone());
251 lines.push((&points[..]).into());
252 points = vec![];
253 }
254 } else {
255 #[tarpaulin::skip]
256 panic!("unknown cmd: {}", cmd);
257 }
258 }
259
260 let geometry = if self.r#type == FeatureType::Point {
261 VectorGeometry::VectorPoints(points)
262 } else {
263 if !points.is_empty() {
264 lines.push(VectorLineWithOffset::new(0.0, points.clone()));
265 }
266 if self.r#type == FeatureType::Line {
267 VectorGeometry::VectorLines(lines)
268 } else if (self.r#type == FeatureType::MultiPolygon
269 || self.r#type == FeatureType::Polygon)
270 && !self.is_s2
271 {
272 VectorGeometry::VectorPolys(classify_rings(&lines))
273 } else {
274 VectorGeometry::VectorPolys(polys)
275 }
276 };
277
278 self.geometry = Some(geometry.clone());
279 geometry
280 }
281
282 fn read_indices(&mut self) -> Vec<u32> {
284 if let Some(indices) = &self.indices {
285 return indices.clone();
286 } else if self.indices_index.is_none() {
287 return vec![];
288 }
289
290 let mut pbf = self.pbf.borrow_mut();
291 pbf.set_pos(self.indices_index.unwrap());
292
293 let mut curr: i32 = 0;
294 let end = pbf.read_varint::<usize>() + pbf.get_pos();
295 let mut indices: Vec<u32> = vec![];
297 while pbf.get_pos() < end {
298 curr += pbf.read_s_varint::<i32>();
299 indices.push(curr as u32);
300 }
301
302 self.indices = Some(indices.clone());
303 indices
304 }
305
306 fn add_tessellation(&mut self, geometry: &mut Vec<f64>, multiplier: f64) {
308 if self.tessellation_index.is_none() {
309 return;
310 }
311
312 let mut pbf = self.pbf.borrow_mut();
313 pbf.set_pos(self.tessellation_index.unwrap());
314
315 let end = pbf.read_varint::<usize>() + pbf.get_pos();
316 let mut x = 0;
317 let mut y = 0;
318 while pbf.get_pos() < end {
319 x += pbf.read_s_varint::<i32>();
320 y += pbf.read_s_varint::<i32>();
321 geometry.push(x as f64 * multiplier);
322 geometry.push(y as f64 * multiplier);
323 }
324 }
325
326 #[tarpaulin::skip]
328 fn add_tessellation_3d(&mut self, _geometry: &mut Vec<f64>, _multiplier: f64) {
329 panic!("unexpected geometry type")
330 }
331}
332impl ProtoRead for MapboxVectorFeature {
333 fn read(&mut self, tag: u64, pb: &mut Protobuf) {
334 if self.is_s2 {
335 match tag {
336 15 => self.id = Some(pb.read_varint::<u64>()),
337 1 => {
338 let end = pb.get_pos() + pb.read_varint::<usize>();
339
340 while pb.get_pos() < end {
341 let key = &self.keys.borrow()[pb.read_varint::<usize>()];
342 let value = &self.values.borrow()[pb.read_varint::<usize>()];
343
344 self.properties.insert(key.clone(), value.clone());
345 }
346 }
347 2 => self.r#type = pb.read_varint::<FeatureType>(),
348 3 => self.geometry_index = pb.get_pos(),
349 4 => self.indices_index = Some(pb.get_pos()),
350 5 => self.tessellation_index = Some(pb.get_pos()),
351 #[tarpaulin::skip]
352 _ => panic!("unknown tag: {}", tag),
353 }
354 } else {
355 match tag {
356 1 => self.id = Some(pb.read_varint::<u64>()),
357 2 => {
358 let end = pb.get_pos() + pb.read_varint::<usize>();
359
360 while pb.get_pos() < end {
361 let key = &self.keys.borrow()[pb.read_varint::<usize>()];
362 let value = &self.values.borrow()[pb.read_varint::<usize>()];
363
364 self.properties.insert(key.clone(), value.clone());
365 }
366 }
367 3 => self.r#type = pb.read_varint::<FeatureType>(),
368 4 => self.geometry_index = pb.get_pos(),
369 5 => self.indices_index = Some(pb.get_pos()),
370 6 => self.tessellation_index = Some(pb.get_pos()),
371 #[tarpaulin::skip]
372 _ => panic!("unknown tag: {}", tag),
373 }
374 }
375 }
376}
377
378fn classify_rings(rings: &VectorLinesWithOffset) -> Vec<VectorLinesWithOffset> {
379 let mut polygons: Vec<VectorLinesWithOffset> = vec![];
380 let mut polygon: VectorLinesWithOffset = vec![];
381 let mut ccw: Option<bool> = None;
382
383 let mut i: usize = 0;
384 while i < rings.len() {
385 let area = signed_area(&rings[i].geometry);
386 if area == 0 {
387 continue;
388 }
389 if ccw.is_none() {
390 ccw = Some(area < 0);
391 }
392
393 if ccw.is_some() && ccw.unwrap() == (area < 0) {
394 if !polygon.is_empty() {
396 polygons.push(polygon.clone());
397 polygon = vec![];
398 }
399 polygon.push(rings[i].clone());
400 } else {
401 polygon.push(rings[i].clone());
403 }
404
405 i += 1
406 }
407 if !polygon.is_empty() {
408 polygons.push(polygon.clone());
409 }
410
411 polygons
412}
413
414fn signed_area(ring: &[Point]) -> i32 {
415 let mut sum: i32 = 0;
416 let mut i: usize = 0;
417 let mut j = ring.len() - 1;
418 while i < ring.len() {
419 let p1 = &ring[i];
420 let p2 = &ring[j];
421 sum += (p2.x - p1.x) * (p1.y + p2.y);
422
423 j = i;
424 i += 1;
425 }
426
427 sum
428}
429
430#[derive(Debug, Clone, PartialEq)]
432pub enum FeatureType {
433 Point = 1,
435 Line = 2,
437 Polygon = 3,
439 MultiPolygon = 4,
441}
442impl From<OpenFeatureType> for FeatureType {
443 fn from(value: OpenFeatureType) -> Self {
444 match value {
445 OpenFeatureType::Points => FeatureType::Point,
446 OpenFeatureType::Lines => FeatureType::Line,
447 OpenFeatureType::Polygons => FeatureType::MultiPolygon,
448 #[tarpaulin::skip]
449 _ => panic!("unknown value: {:?}", value),
450 }
451 }
452}
453impl BitCast for FeatureType {
454 fn to_u64(&self) -> u64 {
455 (*self).clone() as u64
456 }
457 fn from_u64(value: u64) -> Self {
458 match value {
459 1 => FeatureType::Point,
460 2 => FeatureType::Line,
461 3 => FeatureType::Polygon,
462 4 => FeatureType::MultiPolygon,
463 #[tarpaulin::skip]
464 _ => panic!("unknown value: {}", value),
465 }
466 }
467}
468
469pub fn write_feature(
471 feature: &BaseVectorFeature,
472 keys: &mut BTreeMap<String, usize>,
473 values: &mut BTreeMap<PrimitiveValue, usize>,
474 mapbox_support: bool,
475) -> Vec<u8> {
476 let mut pbf = Protobuf::new();
477
478 let properties: MapboxProperties = feature.properties().clone().into();
479 if let Some(id) = feature.id() {
480 pbf.write_varint_field(if mapbox_support { 1 } else { 15 }, id);
481 }
482 pbf.write_bytes_field(
483 if mapbox_support { 2 } else { 1 },
484 &write_properties(&properties, keys, values),
485 );
486 let _type: FeatureType = feature.get_type().into();
487 pbf.write_varint_field(if mapbox_support { 3 } else { 2 }, _type);
488 let written = write_geometry(feature, mapbox_support);
490 pbf.write_bytes_field(if mapbox_support { 4 } else { 3 }, &written);
491 if let Some(indices) = feature.indices() {
493 pbf.write_bytes_field(if mapbox_support { 5 } else { 4 }, &write_indices(&indices));
494 }
495 if let Some(TessellationWrapper::Tessellation(tess)) = feature.tessellation() {
497 pbf.write_bytes_field(if mapbox_support { 6 } else { 5 }, &write_tessellation(&tess));
498 }
499
500 pbf.take()
501}
502
503fn write_properties(
505 properties: &MapboxProperties,
506 keys: &mut BTreeMap<String, usize>,
507 values: &mut BTreeMap<PrimitiveValue, usize>,
508) -> Vec<u8> {
509 let mut pbf = Protobuf::new();
510
511 for (key, value) in properties.iter() {
512 let key_length = keys.len();
513 let key_index = keys.entry(key.clone()).or_insert(key_length);
514 pbf.write_varint(*key_index);
515 let value_length = values.len();
516 let value_index = values.entry(value.clone()).or_insert(value_length);
517 pbf.write_varint(*value_index);
518 }
519
520 pbf.take()
521}
522
523fn write_indices(indices: &[u32]) -> Vec<u8> {
525 let mut pbf = Protobuf::new();
526
527 let mut curr: i32 = 0;
528 for index in indices {
529 let d_curr = (*index as i32) - curr;
530 pbf.write_varint(zigzag(d_curr));
531 curr += d_curr;
532 }
533
534 pbf.take()
535}
536
537fn write_tessellation(geometry: &[Point]) -> Vec<u8> {
539 let mut pbf = Protobuf::new();
540 let mut x = 0;
541 let mut y = 0;
542 for point in geometry {
543 let dx = point.x - x;
544 let dy = point.y - y;
545 pbf.write_varint(zigzag(dx));
546 pbf.write_varint(zigzag(dy));
547 x += dx;
548 y += dy;
549 }
550
551 pbf.take()
552}
553
554fn write_geometry(feature: &BaseVectorFeature, mapbox_support: bool) -> Vec<u8> {
556 use BaseVectorFeature::*;
557 let mut pbf = Protobuf::new();
558 match feature {
559 BaseVectorPointsFeature(points) => write_geometry_points(&points.geometry, &mut pbf),
560 BaseVectorLinesFeature(lines) => write_geometry_lines(&lines.geometry, &mut pbf),
561 BaseVectorPolysFeature(polys) => {
562 write_geometry_polys(&polys.geometry, &mut pbf, mapbox_support)
563 }
564 #[tarpaulin::skip]
565 _ => panic!("unknown feature type: {:?}", feature.get_type()),
566 };
567 pbf.take()
568}
569
570fn write_geometry_points(points: &[Point], pbf: &mut Protobuf) {
572 let mut x = 0;
573 let mut y = 0;
574
575 for point in points {
576 pbf.write_varint(command_encode(1, 1)); let dx = point.x - x;
580 let dy = point.y - y;
581 pbf.write_varint(zigzag(dx));
582 pbf.write_varint(zigzag(dy));
583 x += dx;
585 y += dy;
586 }
587}
588
589fn write_geometry_lines(lines: &[VectorLineWithOffset], pbf: &mut Protobuf) {
591 let mut x = 0;
592 let mut y = 0;
593
594 for line in lines {
595 let line_geo = &line.geometry;
596 pbf.write_varint(command_encode(1, 1)); let line_count = line_geo.len();
599 let mut i = 0;
600 while i < line_count {
601 if i == 1 {
602 pbf.write_varint(command_encode(2, (line_count - 1).try_into().unwrap()));
603 }
605
606 let point = &line_geo[i];
607 let dx = point.x - x;
608 let dy = point.y - y;
609 pbf.write_varint(zigzag(dx));
610 pbf.write_varint(zigzag(dy));
611 x += dx;
612 y += dy;
613
614 i += 1;
615 }
616 }
617}
618
619fn write_geometry_polys(
621 polys: &[Vec<VectorLineWithOffset>],
622 pbf: &mut Protobuf,
623 mapbox_support: bool,
624) {
625 let mut x = 0;
626 let mut y = 0;
627
628 for poly in polys {
629 for ring in poly {
630 let ring_geo = &ring.geometry;
631 pbf.write_varint(command_encode(1, 1)); let line_count = ring_geo.len() - 1;
633 let mut i = 0;
634 while i < line_count {
635 if i == 1 {
636 pbf.write_varint(command_encode(2, (line_count - 1).try_into().unwrap()));
637 }
639
640 let point = &ring_geo[i];
641 let dx = point.x - x;
642 let dy = point.y - y;
643 pbf.write_varint(zigzag(dx));
644 pbf.write_varint(zigzag(dy));
645 x += dx;
646 y += dy;
647
648 i += 1;
649 }
650 pbf.write_varint(command_encode(7, 1)); }
652 pbf.write_varint(command_encode(if mapbox_support { 7 } else { 4 }, 1));
654 }
655}