1use crate::geometry::{ClipLineResultWithBBox, LonLat, S2Point, clip_line};
2use alloc::{collections::BTreeSet, vec, vec::Vec};
3use s2json::{
4 BBox3D, Face, MValue, STPoint, VectorGeometry, VectorGeometryType, VectorLineString,
5 VectorLineStringGeometry, VectorMultiLineStringGeometry, VectorMultiPointGeometry,
6 VectorMultiPolygonGeometry, VectorPoint, VectorPointGeometry, VectorPolygon,
7 VectorPolygonGeometry,
8};
9
10#[derive(Debug)]
12pub struct ConvertedGeometry<M: Clone + Default = MValue> {
13 pub geometry: VectorGeometry<M>,
15 pub face: Face,
17}
18pub type ConvertedGeometryList<M> = Vec<ConvertedGeometry<M>>;
20
21pub fn convert_geometry_wm_to_s2<M: Clone + Default>(
25 geometry: &VectorGeometry<M>,
26) -> ConvertedGeometryList<M> {
27 let mut res: ConvertedGeometryList<M> = vec![];
28
29 match geometry {
30 VectorGeometry::Point(geo) => {
31 res.extend(convert_geometry_point(geo));
32 }
33 VectorGeometry::MultiPoint(geo) => {
34 res.extend(convert_geometry_multipoint(geo));
35 }
36 VectorGeometry::LineString(geo) => {
37 res.extend(convert_geometry_linestring(geo));
38 }
39 VectorGeometry::MultiLineString(geo) => {
40 res.extend(convert_geometry_multilinestring(geo));
41 }
42 VectorGeometry::Polygon(geo) => {
43 res.extend(convert_geometry_polygon(geo));
44 }
45 VectorGeometry::MultiPolygon(geo) => {
46 res.extend(convert_geometry_multipolygon(geo));
47 }
48 }
49
50 res
51}
52
53fn convert_geometry_point<M: Clone + Default>(
55 geometry: &VectorPointGeometry<M>,
56) -> ConvertedGeometryList<M> {
57 let VectorPointGeometry::<M> { _type, is_3d, coordinates, bbox, .. } = geometry;
58 let mut new_point = coordinates.clone();
59 let ll: S2Point = (&LonLat::<M>::new(new_point.x, new_point.y, None)).into();
60 let (face, s, t) = ll.to_face_st();
61 new_point.x = s;
62 new_point.y = t;
63 let vec_bbox = Some(BBox3D::from_point(&new_point));
64 vec![ConvertedGeometry {
65 face: face.into(),
66 geometry: VectorGeometry::Point(VectorPointGeometry {
67 _type: VectorGeometryType::Point,
68 coordinates: new_point,
69 is_3d: *is_3d,
70 bbox: *bbox,
71 vec_bbox,
72 ..Default::default()
73 }),
74 }]
75}
76
77fn convert_geometry_multipoint<M: Clone + Default>(
79 geometry: &VectorMultiPointGeometry<M>,
80) -> ConvertedGeometryList<M> {
81 let VectorMultiPointGeometry { is_3d, coordinates, bbox, .. } = geometry;
82 coordinates
83 .iter()
84 .flat_map(|coordinates| {
85 convert_geometry_point(&VectorPointGeometry {
86 _type: VectorGeometryType::Point,
87 is_3d: *is_3d,
88 coordinates: coordinates.clone(),
89 bbox: *bbox,
90 ..Default::default()
91 })
92 })
93 .collect()
94}
95
96fn convert_geometry_linestring<M: Clone + Default>(
98 geometry: &VectorLineStringGeometry<M>,
99) -> ConvertedGeometryList<M> {
100 let VectorLineStringGeometry { _type, is_3d, coordinates, bbox, .. } = geometry;
101
102 convert_line_string(coordinates, false)
103 .into_iter()
104 .map(|cline| {
105 let ConvertedLineString { face, mut line, offset, vec_bbox } = cline;
106 ConvertedGeometry {
107 face,
108 geometry: VectorGeometry::LineString(VectorLineStringGeometry {
109 _type: VectorGeometryType::LineString,
110 is_3d: *is_3d,
111 coordinates: core::mem::take(&mut line),
112 bbox: *bbox,
113 offset: Some(offset),
114 vec_bbox: Some(vec_bbox),
115 ..Default::default()
116 }),
117 }
118 })
119 .collect()
120}
121
122fn convert_geometry_multilinestring<M: Clone + Default>(
124 geometry: &VectorMultiLineStringGeometry<M>,
125) -> ConvertedGeometryList<M> {
126 let VectorMultiLineStringGeometry { is_3d, coordinates, bbox, .. } = geometry;
127
128 coordinates
129 .iter()
130 .flat_map(|line| convert_line_string(line, false))
131 .map(|ConvertedLineString { face, line, offset, vec_bbox }| ConvertedGeometry {
132 face,
133 geometry: VectorGeometry::LineString(VectorLineStringGeometry {
134 _type: VectorGeometryType::LineString,
135 is_3d: *is_3d,
136 coordinates: line,
137 bbox: *bbox,
138 offset: Some(offset),
139 vec_bbox: Some(vec_bbox),
140 ..Default::default()
141 }),
142 })
143 .collect()
144}
145
146fn convert_geometry_polygon<M: Clone + Default>(
148 geometry: &VectorPolygonGeometry<M>,
149) -> ConvertedGeometryList<M> {
150 let VectorPolygonGeometry { _type, is_3d, coordinates, bbox, .. } = geometry;
151 let mut res: ConvertedGeometryList<M> = vec![];
152
153 let mut outer_ring = convert_line_string(&coordinates[0], true);
155 let mut inner_rings = coordinates[1..].iter().flat_map(|line| convert_line_string(line, true));
156
157 for ConvertedLineString { face, line, offset, vec_bbox: poly_bbox } in &mut outer_ring {
159 let mut polygon: VectorPolygon<M> = vec![core::mem::take(line)];
160 let mut polygon_offsets = vec![*offset];
161 let mut poly_bbox = *poly_bbox;
162 for ConvertedLineString {
163 face: inner_face,
164 line: inner_line,
165 offset: inner_offset,
166 vec_bbox,
167 } in &mut inner_rings
168 {
169 if inner_face == *face {
170 polygon.push(inner_line);
171 polygon_offsets.push(inner_offset);
172 poly_bbox.merge_in_place(&vec_bbox);
173 }
174 }
175
176 res.push(ConvertedGeometry {
177 face: *face,
178 geometry: VectorGeometry::Polygon(VectorPolygonGeometry {
179 _type: VectorGeometryType::Polygon,
180 is_3d: *is_3d,
181 coordinates: polygon,
182 bbox: *bbox,
183 offset: Some(polygon_offsets),
184 vec_bbox: Some(poly_bbox),
185 ..Default::default()
186 }),
187 });
188 }
189
190 res
191}
192
193fn convert_geometry_multipolygon<M: Clone + Default>(
195 geometry: &VectorMultiPolygonGeometry<M>,
196) -> ConvertedGeometryList<M> {
197 let VectorMultiPolygonGeometry { is_3d, coordinates, bbox, offset, .. } = geometry;
198 coordinates
199 .iter()
200 .enumerate()
201 .flat_map(|(i, polygon)| {
202 let offset: Option<Vec<f64>> = offset.as_ref().map(|offset| offset[i].clone());
203 convert_geometry_polygon(&VectorPolygonGeometry {
204 _type: VectorGeometryType::Polygon,
205 is_3d: *is_3d,
206 coordinates: polygon.to_vec(),
207 bbox: *bbox,
208 offset,
209 ..Default::default()
210 })
211 })
212 .collect()
213}
214
215pub struct ConvertedLineString<M: Clone + Default = MValue> {
217 face: Face,
218 line: VectorLineString<M>,
219 offset: f64,
220 vec_bbox: BBox3D,
221}
222
223fn convert_line_string<M: Clone + Default>(
225 line: &VectorLineString<M>,
226 is_polygon: bool,
227) -> Vec<ConvertedLineString<M>> {
228 let mut res: Vec<ConvertedLineString<M>> = vec![];
229 let mut faces = BTreeSet::<Face>::new();
231 let mut new_geometry: Vec<STPoint<M>> = vec![];
233 for VectorPoint { x: lon, y: lat, z, m, .. } in line {
234 let ll: S2Point = (&LonLat::<M>::new(*lon, *lat, None)).into();
235 let (face, s, t) = ll.to_face_st();
236 let stpoint = STPoint { face: face.into(), s, t, z: *z, m: m.clone() };
237 faces.insert(stpoint.face);
238 new_geometry.push(stpoint);
239 }
240 for face in faces {
242 let mut line: VectorLineString<M> = vec![];
243 for st_point in &mut new_geometry {
244 line.push(st_point_to_face(face, st_point));
245 }
246 let clipped_lines =
247 clip_line(&line, BBox3D::new(0., 0., 1., 1., 0., 1.), is_polygon, None, None);
248 for ClipLineResultWithBBox { line, offset, vec_bbox } in clipped_lines {
249 res.push(ConvertedLineString { face, line, offset, vec_bbox });
250 }
251 }
252
253 res
254}
255
256fn st_point_to_face<M: Clone + Default>(target_face: Face, stp: &mut STPoint<M>) -> VectorPoint<M> {
258 let cur_face = stp.face;
259 if target_face == cur_face {
260 return VectorPoint {
261 x: stp.s,
262 y: stp.t,
263 z: stp.z,
264 m: core::mem::take(&mut stp.m),
265 t: None,
266 };
267 }
268
269 let (rot, x, y) = &FACE_RULE_SET[target_face as usize][cur_face as usize];
270 let (new_s, new_t) = rotate(*rot, stp.s, stp.t);
271
272 VectorPoint {
273 x: new_s + *x as f64,
274 y: new_t + *y as f64,
275 z: stp.z,
276 m: core::mem::take(&mut stp.m),
277 t: None,
278 }
279}
280
281fn rotate(rot: Rotation, s: f64, t: f64) -> (f64, f64) {
291 match rot {
292 Rotation::_0 => (s, t),
293 Rotation::_90 => (t, 1. - s),
294 Rotation::_Neg90 => (1. - t, s),
295 }
296}
297
298#[derive(Debug, PartialEq, Copy, Clone)]
299pub enum Rotation {
301 _0,
303 _90,
305 _Neg90,
307}
308
309pub const FACE_RULE_SET: [[(Rotation, i8, i8); 6]; 6] = [
315 [
317 (Rotation::_0, 0, 0), (Rotation::_0, 1, 0), (Rotation::_90, 0, 1), (Rotation::_Neg90, 2, 0), (Rotation::_Neg90, -1, 0), (Rotation::_0, 0, -1), ],
324 [
326 (Rotation::_0, -1, 0), (Rotation::_0, 0, 0), (Rotation::_0, 0, 1), (Rotation::_Neg90, 1, 0), (Rotation::_Neg90, 2, 0), (Rotation::_90, 0, -1), ],
333 [
335 (Rotation::_Neg90, -1, 0), (Rotation::_0, 0, -1), (Rotation::_0, 0, 0), (Rotation::_0, 1, 0), (Rotation::_90, 0, 1), (Rotation::_Neg90, 2, 0), ],
342 [
344 (Rotation::_Neg90, 2, 0), (Rotation::_90, 0, -1), (Rotation::_0, -1, 0), (Rotation::_0, 0, 0), (Rotation::_0, 0, 1), (Rotation::_Neg90, 1, 0), ],
351 [
353 (Rotation::_90, 0, 1), (Rotation::_Neg90, 2, 0), (Rotation::_Neg90, -1, 0), (Rotation::_0, 0, -1), (Rotation::_0, 0, 0), (Rotation::_0, 1, 0), ],
360 [
362 (Rotation::_0, 0, 1), (Rotation::_Neg90, 1, 0), (Rotation::_Neg90, 2, 0), (Rotation::_90, 0, -1), (Rotation::_0, -1, 0), (Rotation::_0, 0, 0), ],
369];