1use super::{
2 OSMFilterable, OSMReader, OSMTagFilterType,
3 info::{DenseInfo, Info, InfoBlock},
4 primitive::{OSMMetadata, PrimitiveBlock},
5 relation::{IntermediateRelation, MemberType},
6 way::{IntermediateWay, WayNodes},
7};
8use crate::{data_store::kv::KVStore, parsers::Reader};
9use alloc::{string::String, vec, vec::Vec};
10use pbf::{ProtoRead, Protobuf};
11use s2json::{
12 BBox3D, MValue, Properties, VectorFeature, VectorFeatureType, VectorGeometry, VectorPoint,
13};
14use serde::{Deserialize, Serialize};
15
16#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
18pub struct IntermediateNode {
19 pub id: u64,
21 pub point: VectorPoint<MValue>,
23 pub properties: Properties,
25 pub info: Option<InfoBlock>,
27}
28impl IntermediateNode {
29 pub fn to_vector_feature(
31 &self,
32 add_bbox: bool,
33 ) -> VectorFeature<OSMMetadata, Properties, MValue> {
34 let coordinates = self.point.clone();
35 let bbox = if add_bbox { Some(BBox3D::from_point(&coordinates)) } else { None };
36 VectorFeature {
37 id: Some(self.id),
38 face: 0.into(),
39 _type: VectorFeatureType::VectorFeature,
40 properties: self.properties.clone(),
41 geometry: VectorGeometry::new_point(coordinates, bbox),
42 metadata: Some(OSMMetadata {
43 osm_type: MemberType::Node,
44 info: self.info.clone(),
45 nodes: None,
46 relation: None,
47 }),
48 }
49 }
50}
51
52#[derive(Debug, Default, PartialEq)]
55pub struct Node {
56 pub id: u64,
58 info: Option<Info>,
60 lat: i64,
62 lon: i64,
64 keys: Vec<u32>,
66 vals: Vec<u32>,
68}
69impl OSMFilterable for Node {
70 fn is_filterable<
71 T: Reader,
72 _N: KVStore<u64, VectorPoint<MValue>>,
73 N: KVStore<u64, IntermediateNode>,
74 _W: KVStore<u64, WayNodes>,
75 W: KVStore<u64, IntermediateWay>,
76 R: KVStore<u64, IntermediateRelation>,
77 >(
78 &self,
79 pb: &PrimitiveBlock,
80 reader: &mut OSMReader<T, _N, N, _W, W, R>,
81 ) -> bool {
82 if reader.skip_nodes || (reader.skip_empty_nodes && self.keys.is_empty()) {
83 return true;
84 }
85 if let Some(tag_filter) = &mut reader.tag_filter {
86 for i in 0..self.keys.len() {
87 let key_str = pb.get_string(self.keys[i] as usize);
88 let val_str = pb.get_string(self.vals[i] as usize);
89 if tag_filter.match_found(OSMTagFilterType::Node, key_str, val_str) {
90 return false;
91 }
92 }
93 return true;
95 }
96
97 false
98 }
99}
100impl Node {
101 pub fn get_lon_lat(&self, pb: &PrimitiveBlock) -> (f64, f64) {
103 let lon_offset = pb.lon_offset as f64;
104 let lat_offset = pb.lat_offset as f64;
105 let granularity = pb.granularity as f64;
106 (
107 0.000000001 * (lon_offset + granularity * self.lon as f64),
108 0.000000001 * (lat_offset + granularity * self.lat as f64),
109 )
110 }
111
112 pub fn properties(&self, pb: &PrimitiveBlock) -> Properties {
114 pb.tags(&self.keys, &self.vals)
115 }
116
117 pub fn to_vector_geometry(&self, pb: &PrimitiveBlock) -> VectorPoint<MValue> {
119 let (lon, lat) = self.get_lon_lat(pb);
120 let z = get_elevation(&self.properties(pb));
121 VectorPoint::new(lon, lat, z, None)
122 }
123
124 pub fn to_intermediate_feature(&self, pb: &PrimitiveBlock) -> IntermediateNode {
129 let point = self.to_vector_geometry(pb);
130 IntermediateNode {
131 id: self.id,
132 point,
133 properties: self.properties(pb),
134 info: self.info.as_ref().map(|info| info.to_block(pb)),
135 }
136 }
137}
138impl ProtoRead for Node {
140 fn read(&mut self, tag: u64, pb: &mut Protobuf) {
141 match tag {
142 1 => self.id = pb.read_varint(),
143 2 => self.keys = pb.read_packed(),
144 3 => self.vals = pb.read_packed(),
145 4 => {
146 let mut info = Info::default();
147 pb.read_message(&mut info);
148 self.info = Some(info);
149 }
150 8 => self.lat = pb.read_s_varint(),
151 9 => self.lon = pb.read_s_varint(),
152 _ => panic!("unknown tag {}", tag),
153 }
154 }
155}
156
157#[derive(Debug, Default, PartialEq)]
166pub struct DenseNodes {
167 ids: Vec<i64>, denseinfo: Option<DenseInfo>,
169 lats: Vec<i64>, lons: Vec<i64>, keys_vals: Vec<i64>,
173}
174impl DenseNodes {
175 pub fn nodes(&self) -> Vec<Node> {
177 let mut res: Vec<Node> = vec![];
178 let info_map = self.denseinfo.as_ref().map(|info| info.infos()).unwrap_or_default();
179 let mut j = 0;
180 let mut cur_id = 0;
181 let mut cur_lat = 0;
182 let mut cur_lon = 0;
183 for i in 0..self.ids.len() {
184 let cur_info = info_map.get(i);
185 cur_id += self.ids[i];
186 cur_lat += self.lats[i];
187 cur_lon += self.lons[i];
188 let mut keys: Vec<u32> = vec![];
189 let mut vals: Vec<u32> = vec![];
190 if !self.keys_vals.is_empty() {
191 while self.keys_vals[j] != 0 {
192 keys.push(self.keys_vals[j] as u32);
193 vals.push(self.keys_vals[j + 1] as u32);
194 j += 2;
195 }
196 j += 1;
197 }
198
199 res.push(Node {
200 id: cur_id as u64,
201 keys,
202 vals,
203 info: cur_info.cloned(),
204 lat: cur_lat,
205 lon: cur_lon,
206 });
207 }
208
209 res
210 }
211}
212impl ProtoRead for DenseNodes {
214 fn read(&mut self, tag: u64, pb: &mut Protobuf) {
215 match tag {
216 1 => self.ids = pb.read_s_packed(),
217 5 => {
218 let mut info = DenseInfo::default();
219 pb.read_message(&mut info);
220 self.denseinfo = Some(info);
221 }
222 8 => self.lats = pb.read_s_packed(),
223 9 => self.lons = pb.read_s_packed(),
224 10 => self.keys_vals = pb.read_packed(),
225 _ => panic!("unknown tag {}", tag),
226 }
227 }
228}
229
230fn get_elevation(props: &Properties) -> Option<f64> {
232 for s in ["altitude", "ele", "elevation", "height", "depth"] {
233 if let Some(elevation) = props.get(s) {
234 let val = parse_altitude(&elevation.to_prim().unwrap().to_string().unwrap());
235 if let Some(val) = val {
236 if s == "depth" {
237 return Some(-val);
238 }
239 return Some(val);
240 }
241 }
242 }
243 None
244}
245
246fn parse_altitude(alt: &str) -> Option<f64> {
248 let digits: String = alt.chars().filter(|c| c.is_ascii_digit()).collect();
249 if digits.is_empty() { None } else { digits.parse().ok() }
250}