1use crate::{
2 conversion::coords::{CoordType, FromSFCGALGeom, ToSFCGALGeom},
3 CoordSeq, Point2d, Point3d, Result, SFCGeometry, ToCoordinates, ToSFCGAL,
4};
5use anyhow::Error;
6use geojson::Value as GeometryValue;
7
8pub trait TryIntoCoords<T> {
12 type Err;
13 fn try_into(&self) -> Result<T>;
14}
15
16pub trait FromSlice {
18 fn from_slice(pt: &[f64]) -> Result<Self>
19 where
20 Self: std::marker::Sized;
21}
22
23pub trait ToVec {
25 fn to_vec(&self) -> Vec<f64>;
26}
27
28impl ToVec for Point2d {
29 fn to_vec(&self) -> Vec<f64> {
30 vec![self.0, self.1]
31 }
32}
33
34impl ToVec for Point3d {
35 fn to_vec(&self) -> Vec<f64> {
36 vec![self.0, self.1, self.2]
37 }
38}
39
40impl FromSlice for Point2d {
41 fn from_slice(pt: &[f64]) -> Result<Point2d> {
42 let mut it = pt.iter();
43 Ok((*it.next().unwrap(), *it.next().unwrap()))
44 }
45}
46
47impl FromSlice for Point3d {
48 fn from_slice(pt: &[f64]) -> Result<Point3d> {
49 let mut it = pt.iter();
50 Ok((
51 *it.next().unwrap(),
52 *it.next().unwrap(),
53 *it.next().unwrap_or(&(0.0f64)),
54 ))
55 }
56}
57
58impl<T> TryIntoCoords<CoordSeq<T>> for GeometryValue
62where
63 T: FromSlice + CoordType,
64{
65 type Err = Error;
66 fn try_into(&self) -> Result<CoordSeq<T>>
67 where
68 T: FromSlice + CoordType,
69 {
70 match *self {
71 GeometryValue::Point(ref pt) => Ok(CoordSeq::Point(T::from_slice(pt)?)),
72 GeometryValue::MultiPoint(ref pts) => {
73 let _pts = pts
74 .iter()
75 .map(|p| T::from_slice(p))
76 .collect::<Result<Vec<T>>>();
77 Ok(CoordSeq::Multipoint(_pts?))
78 }
79 GeometryValue::LineString(ref pts) => {
80 let _pts = pts
81 .iter()
82 .map(|p| T::from_slice(p))
83 .collect::<Result<Vec<T>>>();
84 Ok(CoordSeq::Linestring(_pts?))
85 }
86 GeometryValue::MultiLineString(ref lines) => {
87 let _pts = lines
88 .iter()
89 .map(|pts| pts.iter().map(|p| T::from_slice(p)).collect())
90 .collect::<Result<Vec<Vec<T>>>>();
91 Ok(CoordSeq::Multilinestring(_pts?))
92 }
93 GeometryValue::Polygon(ref rings) => {
94 let _pts = rings
95 .iter()
96 .map(|pts| pts.iter().map(|p| T::from_slice(p)).collect())
97 .collect::<Result<Vec<Vec<T>>>>();
98 Ok(CoordSeq::Polygon(_pts?))
99 }
100 GeometryValue::MultiPolygon(ref polygons) => {
101 let _pts = polygons
102 .iter()
103 .map(|rings| {
104 rings
105 .iter()
106 .map(|pts| pts.iter().map(|p| T::from_slice(p)).collect())
107 .collect()
108 })
109 .collect::<Result<Vec<Vec<Vec<T>>>>>();
110 Ok(CoordSeq::Multipolygon(_pts?))
111 }
112 GeometryValue::GeometryCollection(ref geoms) => {
113 let _geoms = geoms
114 .iter()
115 .map(|geom| TryIntoCoords::try_into(&geom.value))
116 .collect::<Result<Vec<CoordSeq<T>>>>();
117 Ok(CoordSeq::Geometrycollection(_geoms?))
118 }
119 }
120 }
121}
122
123pub trait FromGeoJSON {
125 type Err;
126 fn from_geojson<T: FromSlice + CoordType + ToSFCGALGeom>(
127 geom: &GeometryValue,
128 ) -> Result<SFCGeometry>;
129}
130
131pub trait ToGeoJSON {
133 type Err;
134 fn to_geojson<T: FromSlice + CoordType + ToVec + FromSFCGALGeom>(
135 &self,
136 ) -> Result<GeometryValue>;
137}
138
139impl ToGeoJSON for SFCGeometry {
151 type Err = Error;
152 fn to_geojson<T: FromSlice + CoordType + ToVec + FromSFCGALGeom>(
153 &self,
154 ) -> Result<GeometryValue> {
155 let cs: CoordSeq<T> = self.to_coordinates()?;
156 cs.to_geojson::<T>()
157 }
158}
159
160impl<U> ToGeoJSON for CoordSeq<U>
161where
162 U: FromSlice + CoordType + ToVec + FromSFCGALGeom,
163{
164 type Err = Error;
165 fn to_geojson<T: FromSlice + CoordType + ToVec + FromSFCGALGeom>(
166 &self,
167 ) -> Result<GeometryValue> {
168 match self {
169 CoordSeq::Point(pt) => Ok(GeometryValue::Point(pt.to_vec())),
170 CoordSeq::Multipoint(pts) => Ok(GeometryValue::MultiPoint(
171 pts.iter().map(|p| p.to_vec()).collect(),
172 )),
173 CoordSeq::Linestring(pts) => Ok(GeometryValue::LineString(
174 pts.iter().map(|p| p.to_vec()).collect(),
175 )),
176 CoordSeq::Multilinestring(lines) => Ok(GeometryValue::MultiLineString(
177 lines
178 .iter()
179 .map(|pts| pts.iter().map(|p| p.to_vec()).collect())
180 .collect(),
181 )),
182 CoordSeq::Polygon(rings) => Ok(GeometryValue::Polygon(
183 rings
184 .iter()
185 .map(|pts| pts.iter().map(|p| p.to_vec()).collect())
186 .collect(),
187 )),
188 CoordSeq::Multipolygon(polygons) => Ok(GeometryValue::MultiPolygon(
189 polygons
190 .iter()
191 .map(|rings| {
192 rings
193 .iter()
194 .map(|pts| pts.iter().map(|p| p.to_vec()).collect())
195 .collect()
196 })
197 .collect(),
198 )),
199 CoordSeq::Geometrycollection(geoms) => Ok(GeometryValue::GeometryCollection(
200 geoms
201 .iter()
202 .map(|geom| {
203 Ok(geojson::Geometry {
204 bbox: None,
205 value: geom.to_geojson::<T>()?,
206 foreign_members: None,
207 })
208 })
209 .collect::<Result<Vec<_>>>()?,
210 )),
211 _ => unimplemented!(),
212 }
213 }
214}
215
216impl FromGeoJSON for SFCGeometry {
231 type Err = Error;
232 fn from_geojson<T: FromSlice + CoordType + ToSFCGALGeom>(
233 geom: &GeometryValue,
234 ) -> Result<SFCGeometry> {
235 let coords: CoordSeq<T> = TryIntoCoords::try_into(geom)?;
236 coords.to_sfcgal()
237 }
238}
239
240#[cfg(test)]
241mod tests {
242 use super::{Point2d, Point3d, ToGeoJSON, TryIntoCoords};
243 use crate::*;
244
245 #[test]
246 fn point_2d_sfcgal_to_geojson_to_sfcgal() {
247 let input_wkt = "POINT (0.1 0.9)";
248 let pt_sfcgal = SFCGeometry::new(input_wkt).unwrap();
249 let pt_geojson = pt_sfcgal.to_geojson::<Point2d>().unwrap();
250 let pt_sfcgal_new = SFCGeometry::from_geojson::<Point2d>(&pt_geojson).unwrap();
251 assert_eq!(
252 pt_sfcgal.to_wkt_decim(1).unwrap(),
253 pt_sfcgal_new.to_wkt_decim(1).unwrap()
254 );
255 let a: CoordSeq<Point2d> = TryIntoCoords::try_into(&pt_geojson).unwrap();
256 let b = a.to_sfcgal().unwrap();
257 assert_eq!(
258 pt_sfcgal.to_wkt_decim(1).unwrap(),
259 b.to_wkt_decim(1).unwrap()
260 );
261 }
262
263 #[test]
264 fn point_3d_sfcgal_to_geojson_to_sfcgal() {
265 let input_wkt = "POINT (0.1 0.9 1.0)";
266 let pt_sfcgal = SFCGeometry::new(input_wkt).unwrap();
267 let pt_geojson = pt_sfcgal.to_geojson::<Point3d>().unwrap();
268 let pt_sfcgal_new = SFCGeometry::from_geojson::<Point3d>(&pt_geojson).unwrap();
269 assert_eq!(
270 pt_sfcgal.to_wkt_decim(1).unwrap(),
271 pt_sfcgal_new.to_wkt_decim(1).unwrap()
272 );
273 let a: CoordSeq<Point3d> = TryIntoCoords::try_into(&pt_geojson).unwrap();
274 let b = a.to_sfcgal().unwrap();
275 assert_eq!(
276 pt_sfcgal.to_wkt_decim(1).unwrap(),
277 b.to_wkt_decim(1).unwrap()
278 );
279 }
280 #[test]
281 fn multipoint_2d_sfcgal_to_geojson_to_sfcgal() {
282 let input_wkt = "MULTIPOINT ((0.1 0.9),(2.3 3.4))";
283 let multipt_sfcgal = SFCGeometry::new(input_wkt).unwrap();
284 let multipt_geojson = multipt_sfcgal.to_geojson::<Point2d>().unwrap();
285 let multipt_sfcgal_new = SFCGeometry::from_geojson::<Point2d>(&multipt_geojson).unwrap();
286 assert_eq!(
287 multipt_sfcgal.to_wkt_decim(1).unwrap(),
288 multipt_sfcgal_new.to_wkt_decim(1).unwrap()
289 );
290 }
291
292 #[test]
293 fn multipoint_3d_sfcgal_to_geojson_to_sfcgal() {
294 let input_wkt = "MULTIPOINT ((0.1 0.9 1.1),(2.3 3.4 1.1))";
295 let multipt_sfcgal = SFCGeometry::new(input_wkt).unwrap();
296 let multipt_geojson = multipt_sfcgal.to_geojson::<Point3d>().unwrap();
297 let multipt_sfcgal_new = SFCGeometry::from_geojson::<Point3d>(&multipt_geojson).unwrap();
298 assert_eq!(
299 multipt_sfcgal.to_wkt_decim(1).unwrap(),
300 multipt_sfcgal_new.to_wkt_decim(1).unwrap()
301 );
302 }
303 #[test]
304 fn line_2d_sfcgal_to_geojson_to_sfcgal() {
305 let input_wkt = "LINESTRING (10.0 1.0, 1.0 2.0)";
306 let line_sfcgal = SFCGeometry::new(input_wkt).unwrap();
307 let line_geojson = line_sfcgal.to_geojson::<Point2d>().unwrap();
308 let line_sfcgal_new = SFCGeometry::from_geojson::<Point2d>(&line_geojson).unwrap();
309 assert_eq!(
310 line_sfcgal.to_wkt_decim(1).unwrap(),
311 line_sfcgal_new.to_wkt_decim(1).unwrap()
312 );
313 let a: CoordSeq<Point2d> = TryIntoCoords::try_into(&line_geojson).unwrap();
314 let b = a.to_sfcgal().unwrap();
315 assert_eq!(
316 line_sfcgal.to_wkt_decim(1).unwrap(),
317 b.to_wkt_decim(1).unwrap()
318 );
319 }
320 #[test]
321 fn line_3d_sfcgal_to_geojson_to_sfcgal() {
322 let input_wkt = "LINESTRING (10.0 1.0 2.0, 1.0 2.0 1.7)";
323 let line_sfcgal = SFCGeometry::new(input_wkt).unwrap();
324 let line_geojson = line_sfcgal.to_geojson::<Point3d>().unwrap();
325 let line_sfcgal_new = SFCGeometry::from_geojson::<Point3d>(&line_geojson).unwrap();
326 assert_eq!(
327 line_sfcgal.to_wkt_decim(1).unwrap(),
328 line_sfcgal_new.to_wkt_decim(1).unwrap()
329 );
330 let a: CoordSeq<Point3d> = TryIntoCoords::try_into(&line_geojson).unwrap();
331 let b = a.to_sfcgal().unwrap();
332 assert_eq!(
333 line_sfcgal.to_wkt_decim(1).unwrap(),
334 b.to_wkt_decim(1).unwrap()
335 );
336 }
337 #[test]
338 fn multiline_2d_sfcgal_to_geojson_to_sfcgal() {
339 let input_wkt = "MULTILINESTRING (\
340 (-0.0 -0.0,0.5 0.5),\
341 (1.0 -0.0,0.5 0.5),\
342 (1.0 1.0,0.5 0.5),\
343 (-0.0 1.0,0.5 0.5))";
344 let multiline_sfcgal = SFCGeometry::new(input_wkt).unwrap();
345 let multiline_geojson = multiline_sfcgal.to_geojson::<Point2d>().unwrap();
346 let multiline_sfcgal_new =
347 SFCGeometry::from_geojson::<Point2d>(&multiline_geojson).unwrap();
348 assert_eq!(
349 multiline_sfcgal.to_wkt_decim(1).unwrap(),
350 multiline_sfcgal_new.to_wkt_decim(1).unwrap()
351 );
352 let a: CoordSeq<Point2d> = TryIntoCoords::try_into(&multiline_geojson).unwrap();
353 let b = a.to_sfcgal().unwrap();
354 assert_eq!(
355 multiline_sfcgal.to_wkt_decim(1).unwrap(),
356 b.to_wkt_decim(1).unwrap()
357 );
358 }
359 #[test]
360 fn multiline_3d_sfcgal_to_geojson_to_sfcgal() {
361 let input_wkt = "MULTILINESTRING (\
362 (-0.0 -0.0 1.3,0.5 0.5 1.3),\
363 (1.0 -0.0 1.3,0.5 0.5 1.3),\
364 (1.0 1.0 1.3,0.5 0.5 1.3),\
365 (-0.0 1.0 1.3,0.5 0.5 1.3))";
366 let multiline_sfcgal = SFCGeometry::new(input_wkt).unwrap();
367 let multiline_geojson = multiline_sfcgal.to_geojson::<Point3d>().unwrap();
368 let multiline_sfcgal_new =
369 SFCGeometry::from_geojson::<Point3d>(&multiline_geojson).unwrap();
370 assert_eq!(
371 multiline_sfcgal.to_wkt_decim(1).unwrap(),
372 multiline_sfcgal_new.to_wkt_decim(1).unwrap()
373 );
374 let a: CoordSeq<Point3d> = TryIntoCoords::try_into(&multiline_geojson).unwrap();
375 let b = a.to_sfcgal().unwrap();
376 assert_eq!(
377 multiline_sfcgal.to_wkt_decim(1).unwrap(),
378 b.to_wkt_decim(1).unwrap()
379 );
380 }
381 #[test]
382 fn polyg_2d_sfcgal_to_geojson_to_sfcgal() {
383 let input_wkt = "POLYGON ((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0))";
384 let polyg_sfcgal = SFCGeometry::new(input_wkt).unwrap();
385 let polyg_geojson = polyg_sfcgal.to_geojson::<Point2d>().unwrap();
386 let polyg_sfcgal_new = SFCGeometry::from_geojson::<Point2d>(&polyg_geojson).unwrap();
387 assert_eq!(
388 polyg_sfcgal.to_wkt_decim(1).unwrap(),
389 polyg_sfcgal_new.to_wkt_decim(1).unwrap()
390 );
391 let a: CoordSeq<Point2d> = TryIntoCoords::try_into(&polyg_geojson).unwrap();
392 let b = a.to_sfcgal().unwrap();
393 assert_eq!(
394 polyg_sfcgal.to_wkt_decim(1).unwrap(),
395 b.to_wkt_decim(1).unwrap()
396 );
397 }
398 #[test]
399 fn polyg_3d_sfcgal_to_geojson_to_sfcgal() {
400 let input_wkt = "POLYGON ((0.0 0.0 2.0, 1.0 0.0 2.0, 1.0 1.0 2.0, 0.0 0.0 2.0))";
401 let polyg_sfcgal = SFCGeometry::new(input_wkt).unwrap();
402 let polyg_geojson = polyg_sfcgal.to_geojson::<Point3d>().unwrap();
403 let polyg_sfcgal_new = SFCGeometry::from_geojson::<Point3d>(&polyg_geojson).unwrap();
404 assert_eq!(
405 polyg_sfcgal.to_wkt_decim(1).unwrap(),
406 polyg_sfcgal_new.to_wkt_decim(1).unwrap()
407 );
408 let a: CoordSeq<Point3d> = TryIntoCoords::try_into(&polyg_geojson).unwrap();
409 let b = a.to_sfcgal().unwrap();
410 assert_eq!(
411 polyg_sfcgal.to_wkt_decim(1).unwrap(),
412 b.to_wkt_decim(1).unwrap()
413 );
414 }
415 #[test]
416 fn multipolyg_2d_sfcgal_to_geojson_to_sfcgal() {
417 let input_wkt = "MULTIPOLYGON (((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0)))";
418 let multipolyg_sfcgal = SFCGeometry::new(input_wkt).unwrap();
419 let multipolyg_geojson = multipolyg_sfcgal.to_geojson::<Point2d>().unwrap();
420 let multipolyg_sfcgal_new =
421 SFCGeometry::from_geojson::<Point2d>(&multipolyg_geojson).unwrap();
422 assert_eq!(
423 multipolyg_sfcgal.to_wkt_decim(1).unwrap(),
424 multipolyg_sfcgal_new.to_wkt_decim(1).unwrap()
425 );
426 }
427 #[test]
428 fn multipolyg_3d_sfcgal_to_geojson_to_sfcgal() {
429 let input_wkt = "MULTIPOLYGON (((0.0 0.0 2.0, 1.0 0.0 2.0, 1.0 1.0 2.0, 0.0 0.0 2.0)))";
430 let multipolyg_sfcgal = SFCGeometry::new(input_wkt).unwrap();
431 let multipolyg_geojson = multipolyg_sfcgal.to_geojson::<Point3d>().unwrap();
432 let multipolyg_sfcgal_new =
433 SFCGeometry::from_geojson::<Point3d>(&multipolyg_geojson).unwrap();
434 assert_eq!(
435 multipolyg_sfcgal.to_wkt_decim(1).unwrap(),
436 multipolyg_sfcgal_new.to_wkt_decim(1).unwrap()
437 );
438 let a: CoordSeq<Point3d> = TryIntoCoords::try_into(&multipolyg_geojson).unwrap();
439 let b = a.to_sfcgal().unwrap();
440 assert_eq!(
441 multipolyg_sfcgal.to_wkt_decim(1).unwrap(),
442 b.to_wkt_decim(1).unwrap()
443 );
444 }
445 #[test]
446 fn geomcollection_2d_sfcgal_to_geojson_to_sfcgal() {
447 let input_wkt = "GEOMETRYCOLLECTION (POINT (1.0 1.0),LINESTRING (10.0 1.0,1.0 2.0))";
448 let multipolyg_sfcgal = SFCGeometry::new(input_wkt).unwrap();
449 let multipolyg_geojson = multipolyg_sfcgal.to_geojson::<Point2d>().unwrap();
450 let multipolyg_sfcgal_new =
451 SFCGeometry::from_geojson::<Point2d>(&multipolyg_geojson).unwrap();
452 assert_eq!(
453 multipolyg_sfcgal.to_wkt_decim(1).unwrap(),
454 multipolyg_sfcgal_new.to_wkt_decim(1).unwrap()
455 );
456 }
457 #[test]
458 fn geomcollection_3d_sfcgal_to_geojson_to_sfcgal() {
459 let input_wkt =
460 "GEOMETRYCOLLECTION (POINT (1.0 1.0 4.0),LINESTRING (10.0 1.0 4.0,1.0 2.0 4.0))";
461 let multipolyg_sfcgal = SFCGeometry::new(input_wkt).unwrap();
462 let multipolyg_geojson = multipolyg_sfcgal.to_geojson::<Point3d>().unwrap();
463 let multipolyg_sfcgal_new =
464 SFCGeometry::from_geojson::<Point3d>(&multipolyg_geojson).unwrap();
465 assert_eq!(
466 multipolyg_sfcgal.to_wkt_decim(1).unwrap(),
467 multipolyg_sfcgal_new.to_wkt_decim(1).unwrap()
468 );
469 let a: CoordSeq<Point3d> = TryIntoCoords::try_into(&multipolyg_geojson).unwrap();
470 let c = a.to_geojson::<Point3d>().unwrap();
471 let b = a.to_sfcgal().unwrap();
472 let d = SFCGeometry::from_geojson::<Point3d>(&c).unwrap();
473 assert_eq!(
474 multipolyg_sfcgal.to_wkt_decim(1).unwrap(),
475 b.to_wkt_decim(1).unwrap()
476 );
477 assert_eq!(
478 multipolyg_sfcgal.to_wkt_decim(1).unwrap(),
479 d.to_wkt_decim(1).unwrap()
480 );
481 }
482}