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