1use super::{
2 OSMFilterable, OSMReader, OSMTagFilterType,
3 info::{Info, InfoBlock},
4 node::IntermediateNode,
5 primitive::{OSMMetadata, PrimitiveBlock},
6 way::{IntermediateWay, WayNodes},
7};
8use crate::{data_store::kv::KVStore, parsers::Reader};
9use alloc::{string::String, vec, vec::Vec};
10use pbf::{BitCast, ProtoRead, Protobuf};
11use s2json::{
12 BBox3D, MValue, Properties, VectorFeature, VectorFeatureType, VectorGeometry, VectorLineString,
13 VectorMultiLineString, VectorMultiPolygon, VectorPoint, VectorPolygon,
14};
15use serde::{Deserialize, Serialize};
16
17#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
19pub enum IntermediateMember {
20 Node(IntermediateNodeMember),
22 Way(IntermediateWayMember),
24}
25#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
27pub struct IntermediateNodeMember {
28 pub role: String,
30 pub node_id: u64,
32}
33#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
35pub struct IntermediateWayMember {
36 pub role: String,
38 pub way_id: u64,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
44pub struct IntermediateRelation {
45 pub id: u64,
47 pub properties: Properties,
49 pub members: Vec<IntermediateMember>,
51 pub info: Option<InfoBlock>,
53}
54impl IntermediateRelation {
55 pub fn to_vector_feature<_N: KVStore<u64, VectorPoint<MValue>>, _W: KVStore<u64, WayNodes>>(
57 &self,
58 node_geometry: &_N,
59 way_geometry: &_W,
60 add_bbox: bool,
61 ) -> Option<VectorFeature<OSMMetadata, Properties, MValue>> {
62 let mut bbox = BBox3D::default();
63 let IntermediateRelation { id, members, properties, info } = &self;
64 let i_nodes: Vec<IntermediateNodeMember> = members
65 .iter()
66 .filter_map(|m| {
67 if let IntermediateMember::Node(node) = m { Some(node.clone()) } else { None }
68 })
69 .collect();
70 let mut nodes: Vec<NodeMember> = vec![];
71 for IntermediateNodeMember { role, node_id, .. } in &i_nodes {
72 let n = node_geometry.get(*node_id);
73 if let Some(n) = n {
74 nodes.push(NodeMember { id: *node_id, role: role.into(), node: n.clone() });
75 }
76 }
77 let i_ways: Vec<IntermediateWayMember> = members
78 .iter()
79 .filter_map(
80 |m| if let IntermediateMember::Way(way) = m { Some(way.clone()) } else { None },
81 )
82 .collect();
83 let mut ways: Vec<WayMember> = vec![];
84 for IntermediateWayMember { role, way_id } in &i_ways {
85 let w = way_geometry.get(*way_id);
86 if let Some(w) = w {
87 let mut mapped_w: VectorLineString<MValue> = vec![];
88 for node_id in w {
89 let n = node_geometry.get(*node_id);
90 if let Some(n) = n {
91 if add_bbox {
92 bbox.extend_from_point(n);
93 }
94 mapped_w.push(n.clone());
95 }
96 }
97 ways.push(WayMember { id: *way_id, role: role.into(), way: mapped_w });
98 }
99 }
100 let geo = build_geometry(&mut ways);
101 geo.as_ref()?;
102
103 let mut relation_geo = geo.unwrap();
104 let bbox = if add_bbox { Some(bbox) } else { None };
105 let geometry: VectorGeometry<MValue> = match &mut relation_geo {
106 RelationGeometry::Lines(lines) => {
107 if lines.len() == 1 {
108 VectorGeometry::new_linestring(core::mem::take(&mut lines[0]), bbox)
109 } else {
110 VectorGeometry::new_multilinestring(core::mem::take(lines), bbox)
111 }
112 }
113 RelationGeometry::Area(area) => {
114 if area.len() == 1 {
115 VectorGeometry::new_polygon(core::mem::take(&mut area[0]), bbox)
116 } else {
117 VectorGeometry::new_multipolygon(core::mem::take(area), bbox)
118 }
119 }
120 };
121 Some(VectorFeature {
122 id: Some(*id),
123 face: 0.into(),
124 _type: VectorFeatureType::VectorFeature,
125 properties: properties.clone(),
126 geometry,
127 metadata: Some(OSMMetadata {
128 osm_type: MemberType::Relation,
129 info: info.clone(),
130 nodes: Some(i_nodes),
131 relation: None,
132 }),
133 })
134 }
135}
136
137#[derive(Debug)]
139pub enum Member {
140 Node(NodeMember),
142 Way(WayMember),
144}
145#[derive(Debug)]
147pub struct NodeMember {
148 pub id: u64,
150 pub role: String,
152 pub node: VectorPoint<MValue>,
154}
155#[derive(Debug)]
157pub struct WayMember {
158 pub id: u64,
160 pub role: String,
162 pub way: VectorLineString<MValue>,
164}
165
166#[derive(Debug)]
168pub enum RelationGeometry {
169 Lines(VectorMultiLineString<MValue>),
171 Area(VectorMultiPolygon<MValue>),
173}
174
175#[derive(Debug, Default, Copy, Clone, PartialEq, BitCast)]
177pub enum MemberType {
178 #[default]
180 Node = 0,
181 Way = 1,
183 Relation = 2,
185}
186
187#[derive(Debug, Default, PartialEq)]
189pub struct Relation {
190 pub id: u64,
192 info: Option<Info>,
193 keys: Vec<u32>,
195 vals: Vec<u32>,
196 roles_sid: Vec<i32>, memids: Vec<i64>, types: Vec<MemberType>,
199}
200impl Relation {
201 pub fn properties(&self, pb: &PrimitiveBlock) -> Properties {
203 pb.tags(&self.keys, &self.vals)
204 }
205
206 pub fn members(&self, pb: &PrimitiveBlock) -> Vec<IntermediateMember> {
208 let mut res = vec![];
209 let mut memid = 0;
210 for i in 0..self.memids.len() {
211 memid += self.memids[i];
212 let role = pb.get_string(self.roles_sid[i] as usize);
213 let cur_type = self.types[i];
214 if cur_type == MemberType::Node {
215 res.push(IntermediateMember::Node(IntermediateNodeMember {
216 role: role.into(),
217 node_id: memid as u64,
218 }));
219 } else if cur_type == MemberType::Way {
220 res.push(IntermediateMember::Way(IntermediateWayMember {
221 role: role.into(),
222 way_id: memid as u64,
223 }));
224 } else {
225 }
227 }
228 res
229 }
230
231 pub fn to_intermediate_feature(&self, pb: &PrimitiveBlock) -> Option<IntermediateRelation> {
233 let members = self.members(pb);
234 if members.is_empty() {
235 None
236 } else {
237 Some(IntermediateRelation {
238 id: self.id,
239 properties: self.properties(pb),
240 members,
241 info: self.info.as_ref().map(|info| info.to_block(pb)),
242 })
243 }
244 }
245
246 pub fn get_node_relation_pairs(members: &[IntermediateMember]) -> Vec<IntermediateNodeMember> {
248 let mut res = vec![];
249 for member in members {
250 if let IntermediateMember::Node(member) = member
251 && (member.role == "label" || member.role == "admin_centre")
252 {
253 res.push(member.clone());
254 }
255 }
256 res
257 }
258}
259impl OSMFilterable for Relation {
260 fn is_filterable<
261 T: Reader,
262 _N: KVStore<u64, VectorPoint<MValue>>,
263 N: KVStore<u64, IntermediateNode>,
264 _W: KVStore<u64, WayNodes>,
265 W: KVStore<u64, IntermediateWay>,
266 R: KVStore<u64, IntermediateRelation>,
267 >(
268 &self,
269 pb: &PrimitiveBlock,
270 reader: &mut OSMReader<T, _N, N, _W, W, R>,
271 ) -> bool {
272 if reader.skip_relations {
273 return true;
274 }
275 if let Some(tag_filter) = &mut reader.tag_filter {
276 for i in 0..self.keys.len() {
277 let key_str = pb.get_string(self.keys[i] as usize);
278 let val_str = pb.get_string(self.vals[i] as usize);
279 if tag_filter.match_found(OSMTagFilterType::Relation, key_str, val_str) {
280 return false;
281 }
282 }
283 return true;
285 }
286 false
287 }
288}
289impl ProtoRead for Relation {
291 fn read(&mut self, tag: u64, pb: &mut Protobuf) {
292 match tag {
293 1 => self.id = pb.read_varint(),
294 2 => self.keys = pb.read_packed(),
295 3 => self.vals = pb.read_packed(),
296 4 => {
297 let mut info = Info::default();
298 pb.read_message(&mut info);
299 self.info = Some(info);
300 }
301 8 => self.roles_sid = pb.read_packed(),
302 9 => self.memids = pb.read_s_packed(),
303 10 => self.types = pb.read_packed(),
304 _ => panic!("unknown tag {}", tag),
305 }
306 }
307}
308
309fn build_geometry(ways: &mut [WayMember]) -> Option<RelationGeometry> {
318 let mut polygons: VectorMultiPolygon<MValue> = vec![];
320 let mut current_polygon: VectorPolygon<MValue> = vec![];
321 let mut current_ring: VectorLineString<MValue> = vec![];
322 let is_area = ways.iter().any(|m| m.role == "outer" || m.role == "inner");
323
324 sort_members(ways);
326
327 for member in ways {
328 if current_ring.is_empty() {
338 current_ring.extend_from_slice(&member.way);
339 } else {
340 current_ring.extend_from_slice(&member.way[1..]);
341 }
342
343 if current_ring.first() == current_ring.last() {
345 if member.role == "outer" && !current_polygon.is_empty() {
351 polygons.push(current_polygon);
352 current_polygon = vec![];
353 }
354 current_polygon.push(current_ring);
355 current_ring = vec![];
356 }
357 }
358
359 if !current_ring.is_empty() {
362 current_polygon.push(current_ring);
363 }
364 if !is_area {
366 return Some(RelationGeometry::Lines(current_polygon));
367 }
368 if !current_polygon.is_empty() {
370 polygons.push(current_polygon);
371 }
372 Some(RelationGeometry::Area(polygons))
374}
375
376fn sort_members(members: &mut [WayMember]) {
382 let len = members.len();
383 if len < 3 {
384 return;
385 }
386 for i in 0..len - 1 {
387 let cur_first_point = &members[i].way[0];
388 let cur_last_point = &members[i].way[members[i].way.len() - 1];
389 if cur_first_point == cur_last_point {
391 break;
392 }
393 for j in i + 1..len {
394 let next_first_point = &members[j].way[0];
395 let next_last_point = &members[j].way[members[j].way.len() - 1];
396 let equal_first = cur_first_point == next_first_point;
400 let equal_last = cur_last_point == next_last_point;
401 let equal_first_last = cur_first_point == next_last_point;
402 let equal_last_first = cur_last_point == next_first_point;
403 if equal_first || equal_last || equal_first_last || equal_last_first {
404 if equal_first {
405 members[i].way.reverse();
406 } else if equal_last {
407 members[j].way.reverse();
408 } else if equal_first_last {
409 members[i].way.reverse();
410 members[j].way.reverse();
411 }
412 if i + 1 != j {
414 members.swap(i + 1, j);
415 }
416 break;
417 }
418 }
419 }
420}