1use super::{
2 OSMFilterable, OSMReader, OSMTagFilterType,
3 info::{Info, InfoBlock},
4 node::IntermediateNode,
5 primitive::{OSMMetadata, PrimitiveBlock},
6 relation::{IntermediateRelation, MemberType},
7};
8use crate::{data_store::kv::KVStore, parsers::Reader};
9use alloc::{vec, vec::Vec};
10use pbf::{ProtoRead, Protobuf};
11use s2json::{
12 BBox3D, MValue, Properties, VectorFeature, VectorFeatureType, VectorGeometry, VectorLineString,
13 VectorPoint,
14};
15use serde::{Deserialize, Serialize};
16
17pub type WayNodes = Vec<u64>;
19
20#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
22pub struct IntermediateWay {
23 pub id: u64,
25 pub properties: Properties,
27 pub info: Option<InfoBlock>,
29 pub way_nodes: WayNodes,
31 pub is_area: bool,
33}
34impl IntermediateWay {
35 pub fn to_vector_feature<_N: KVStore<u64, VectorPoint<MValue>>>(
37 &self,
38 node_geometry: &_N,
39 add_bbox: bool,
40 ) -> VectorFeature<OSMMetadata, Properties, MValue> {
41 let IntermediateWay { id, is_area, way_nodes, properties, info } = &self;
42 let mut bbox = BBox3D::default();
43 let mut vector_line: VectorLineString<MValue> = vec![];
45 for way_node in way_nodes {
46 let node = node_geometry.get(*way_node);
47 if let Some(node) = node {
48 if add_bbox {
49 bbox.extend_from_point(node)
50 }
51 vector_line.push(node.clone());
52 }
53 }
54 let bbox = if add_bbox { Some(bbox) } else { None };
56 let geometry = match is_area {
57 true => VectorGeometry::new_polygon(vec![vector_line], bbox),
58 false => VectorGeometry::new_linestring(vector_line, bbox),
59 };
60
61 VectorFeature {
62 id: Some(*id),
63 face: 0.into(),
64 _type: VectorFeatureType::VectorFeature,
65 properties: properties.clone(),
66 geometry,
67 metadata: Some(OSMMetadata {
68 osm_type: MemberType::Way,
69 info: info.clone(),
70 nodes: None,
71 relation: None,
72 }),
73 }
74 }
75}
76
77#[derive(Debug, Default, PartialEq)]
79pub struct Way {
80 pub id: u64,
82 info: Option<Info>,
83 keys: Vec<u32>,
85 vals: Vec<u32>,
86 refs: Vec<i64>,
88 }
93impl Way {
94 pub fn properties(&self, pb: &PrimitiveBlock) -> Properties {
96 pb.tags(&self.keys, &self.vals)
97 }
98
99 pub fn is_area<
101 T: Reader,
102 _N: KVStore<u64, VectorPoint<MValue>>,
103 N: KVStore<u64, IntermediateNode>,
104 _W: KVStore<u64, WayNodes>,
105 W: KVStore<u64, IntermediateWay>,
106 R: KVStore<u64, IntermediateRelation>,
107 >(
108 &self,
109 pb: &PrimitiveBlock,
110 reader: &mut OSMReader<T, _N, N, _W, W, R>,
111 ) -> bool {
112 if (reader.upgrade_ways_to_areas
113 && self.refs.len() >= 4
114 && self.refs[0] == self.refs[self.refs.len() - 1])
115 || self.has_key_value(pb, "area", Some("yes"))
116 {
117 return true;
118 }
119 false
120 }
121
122 pub fn has_key_value(&self, pb: &PrimitiveBlock, key: &str, val: Option<&str>) -> bool {
124 for i in 0..self.keys.len() {
125 if pb.get_string(self.keys[i] as usize) == key {
126 match val {
127 None => return true,
128 Some(v) => {
129 if pb.get_string(self.vals[i] as usize) == v {
130 return true;
131 }
132 }
133 }
134 }
135 }
136 false
137 }
138
139 pub fn node_refs(&self) -> WayNodes {
141 let mut res = vec![];
142 let mut _ref = 0;
143 for i in 0..self.refs.len() {
145 _ref += self.refs[i];
146 res.push(_ref as u64);
147 }
148 res
149 }
150
151 pub fn to_intermediate_feature<
156 T: Reader,
157 _N: KVStore<u64, VectorPoint<MValue>>,
158 N: KVStore<u64, IntermediateNode>,
159 _W: KVStore<u64, WayNodes>,
160 W: KVStore<u64, IntermediateWay>,
161 R: KVStore<u64, IntermediateRelation>,
162 >(
163 &self,
164 pb: &PrimitiveBlock,
165 reader: &mut OSMReader<T, _N, N, _W, W, R>,
166 ) -> Option<IntermediateWay> {
167 let is_area = self.is_area(pb, reader);
168 let way_nodes = self.node_refs();
169 if way_nodes.len() < 2 {
170 None
171 } else {
172 Some(IntermediateWay {
173 id: self.id,
174 is_area,
175 properties: self.properties(pb),
176 way_nodes,
177 info: self.info.as_ref().map(|info| info.to_block(pb)),
178 })
179 }
180 }
181}
182impl OSMFilterable for Way {
183 fn is_filterable<
184 T: Reader,
185 _N: KVStore<u64, VectorPoint<MValue>>,
186 N: KVStore<u64, IntermediateNode>,
187 _W: KVStore<u64, WayNodes>,
188 W: KVStore<u64, IntermediateWay>,
189 R: KVStore<u64, IntermediateRelation>,
190 >(
191 &self,
192 pb: &PrimitiveBlock,
193 reader: &mut OSMReader<T, _N, N, _W, W, R>,
194 ) -> bool {
195 if reader.skip_ways {
196 return true;
197 }
198 if let Some(tag_filter) = &mut reader.tag_filter {
199 for i in 0..self.keys.len() {
200 let key_str = pb.get_string(self.keys[i] as usize);
201 let val_str = pb.get_string(self.vals[i] as usize);
202 if tag_filter.match_found(OSMTagFilterType::Way, key_str, val_str) {
203 return false;
204 }
205 }
206 return true;
208 }
209 false
210 }
211}
212impl ProtoRead for Way {
214 fn read(&mut self, tag: u64, pb: &mut Protobuf) {
215 match tag {
216 1 => self.id = pb.read_varint(),
217 2 => self.keys = pb.read_packed(),
218 3 => self.vals = pb.read_packed(),
219 4 => {
220 let mut info = Info::default();
221 pb.read_message(&mut info);
222 self.info = Some(info);
223 }
224 8 => self.refs = pb.read_s_packed(),
225 9 | 10 => (),
227 _ => panic!("unknown tag {}", tag),
228 }
229 }
230}