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