1use geo_types::{self, CoordFloat};
2
3use crate::{geometry, Feature, FeatureCollection};
4
5use crate::{LineStringType, PointType, PolygonType};
6use std::convert::From;
7
8#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
9impl<T> From<&geo_types::Point<T>> for geometry::Value
10where
11 T: CoordFloat,
12{
13 fn from(point: &geo_types::Point<T>) -> Self {
14 let coords = create_point_type(point);
15
16 geometry::Value::Point(coords)
17 }
18}
19
20#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
21impl<T> From<&geo_types::MultiPoint<T>> for geometry::Value
22where
23 T: CoordFloat,
24{
25 fn from(multi_point: &geo_types::MultiPoint<T>) -> Self {
26 let coords = multi_point
27 .0
28 .iter()
29 .map(|point| create_point_type(point))
30 .collect();
31
32 geometry::Value::MultiPoint(coords)
33 }
34}
35
36#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
37impl<T> From<&geo_types::LineString<T>> for geometry::Value
38where
39 T: CoordFloat,
40{
41 fn from(line_string: &geo_types::LineString<T>) -> Self {
42 let coords = create_line_string_type(line_string);
43
44 geometry::Value::LineString(coords)
45 }
46}
47
48#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
49impl<T> From<&geo_types::Line<T>> for geometry::Value
50where
51 T: CoordFloat,
52{
53 fn from(line: &geo_types::Line<T>) -> Self {
54 let coords = create_from_line_type(line);
55
56 geometry::Value::LineString(coords)
57 }
58}
59
60#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
61impl<T> From<&geo_types::Triangle<T>> for geometry::Value
62where
63 T: CoordFloat,
64{
65 fn from(triangle: &geo_types::Triangle<T>) -> Self {
66 let coords = create_from_triangle_type(triangle);
67
68 geometry::Value::Polygon(coords)
69 }
70}
71
72#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
73impl<T> From<&geo_types::Rect<T>> for geometry::Value
74where
75 T: CoordFloat,
76{
77 fn from(rect: &geo_types::Rect<T>) -> Self {
78 let coords = create_from_rect_type(rect);
79
80 geometry::Value::Polygon(coords)
81 }
82}
83
84#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
85impl<T> From<&geo_types::MultiLineString<T>> for geometry::Value
86where
87 T: CoordFloat,
88{
89 fn from(multi_line_string: &geo_types::MultiLineString<T>) -> Self {
90 let coords = create_multi_line_string_type(multi_line_string);
91
92 geometry::Value::MultiLineString(coords)
93 }
94}
95
96#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
97impl<T> From<&geo_types::Polygon<T>> for geometry::Value
98where
99 T: CoordFloat,
100{
101 fn from(polygon: &geo_types::Polygon<T>) -> Self {
102 let coords = create_polygon_type(polygon);
103
104 geometry::Value::Polygon(coords)
105 }
106}
107
108#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
109impl<T> From<&geo_types::MultiPolygon<T>> for geometry::Value
110where
111 T: CoordFloat,
112{
113 fn from(multi_polygon: &geo_types::MultiPolygon<T>) -> Self {
114 let coords = create_multi_polygon_type(multi_polygon);
115
116 geometry::Value::MultiPolygon(coords)
117 }
118}
119
120#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
121impl<T> From<&geo_types::GeometryCollection<T>> for geometry::Value
122where
123 T: CoordFloat,
124{
125 fn from(geometry_collection: &geo_types::GeometryCollection<T>) -> Self {
126 let values = geometry_collection
127 .0
128 .iter()
129 .map(|geometry| geometry::Geometry::new(geometry::Value::from(geometry)))
130 .collect();
131
132 geometry::Value::GeometryCollection(values)
133 }
134}
135
136#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
137impl<T> From<&geo_types::GeometryCollection<T>> for FeatureCollection
138where
139 T: CoordFloat,
140{
141 fn from(geometry_collection: &geo_types::GeometryCollection<T>) -> Self {
142 let values: Vec<Feature> = geometry_collection
143 .0
144 .iter()
145 .map(|geometry| geometry::Geometry::new(geometry::Value::from(geometry)).into())
146 .collect();
147
148 FeatureCollection {
149 bbox: None,
150 features: values,
151 foreign_members: None,
152 }
153 }
154}
155
156#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
157impl<'a, T> From<&'a geo_types::Geometry<T>> for geometry::Value
158where
159 T: CoordFloat,
160{
161 fn from(geometry: &'a geo_types::Geometry<T>) -> Self {
163 match *geometry {
164 geo_types::Geometry::Point(ref point) => geometry::Value::from(point),
165 geo_types::Geometry::MultiPoint(ref multi_point) => geometry::Value::from(multi_point),
166 geo_types::Geometry::LineString(ref line_string) => geometry::Value::from(line_string),
167 geo_types::Geometry::Line(ref line) => geometry::Value::from(line),
168 geo_types::Geometry::Triangle(ref triangle) => geometry::Value::from(triangle),
169 geo_types::Geometry::Rect(ref rect) => geometry::Value::from(rect),
170 geo_types::Geometry::GeometryCollection(ref gc) => geometry::Value::from(gc),
171 geo_types::Geometry::MultiLineString(ref multi_line_string) => {
172 geometry::Value::from(multi_line_string)
173 }
174 geo_types::Geometry::Polygon(ref polygon) => geometry::Value::from(polygon),
175 geo_types::Geometry::MultiPolygon(ref multi_polygon) => {
176 geometry::Value::from(multi_polygon)
177 }
178 }
179 }
180}
181
182fn create_point_type<T>(point: &geo_types::Point<T>) -> PointType
183where
184 T: CoordFloat,
185{
186 let x: f64 = point.x().to_f64().unwrap();
187 let y: f64 = point.y().to_f64().unwrap();
188
189 vec![x, y]
190}
191
192fn create_line_string_type<T>(line_string: &geo_types::LineString<T>) -> LineStringType
193where
194 T: CoordFloat,
195{
196 line_string
197 .points()
198 .map(|point| create_point_type(&point))
199 .collect()
200}
201
202fn create_from_line_type<T>(line_string: &geo_types::Line<T>) -> LineStringType
203where
204 T: CoordFloat,
205{
206 vec![
207 create_point_type(&line_string.start_point()),
208 create_point_type(&line_string.end_point()),
209 ]
210}
211
212fn create_from_triangle_type<T>(triangle: &geo_types::Triangle<T>) -> PolygonType
213where
214 T: CoordFloat,
215{
216 create_polygon_type(&triangle.to_polygon())
217}
218
219fn create_from_rect_type<T>(rect: &geo_types::Rect<T>) -> PolygonType
220where
221 T: CoordFloat,
222{
223 create_polygon_type(&rect.to_polygon())
224}
225
226fn create_multi_line_string_type<T>(
227 multi_line_string: &geo_types::MultiLineString<T>,
228) -> Vec<LineStringType>
229where
230 T: CoordFloat,
231{
232 multi_line_string
233 .0
234 .iter()
235 .map(|line_string| create_line_string_type(line_string))
236 .collect()
237}
238
239fn create_polygon_type<T>(polygon: &geo_types::Polygon<T>) -> PolygonType
240where
241 T: CoordFloat,
242{
243 let mut coords = vec![polygon
244 .exterior()
245 .points()
246 .map(|point| create_point_type(&point))
247 .collect()];
248
249 coords.extend(
250 polygon
251 .interiors()
252 .iter()
253 .map(|line_string| create_line_string_type(line_string)),
254 );
255
256 coords
257}
258
259fn create_multi_polygon_type<T>(multi_polygon: &geo_types::MultiPolygon<T>) -> Vec<PolygonType>
260where
261 T: CoordFloat,
262{
263 multi_polygon
264 .0
265 .iter()
266 .map(|polygon| create_polygon_type(polygon))
267 .collect()
268}
269
270#[cfg(test)]
271mod tests {
272 use crate::{GeoJson, Geometry, Value};
273 use geo_types::{
274 Coord, GeometryCollection, Line, LineString, MultiLineString, MultiPoint, MultiPolygon,
275 Point, Polygon, Rect, Triangle,
276 };
277
278 #[test]
279 fn geo_point_conversion_test() {
280 let geo_point = Point::new(40.02f32, 116.34f32);
282 let geojson_point = Value::from(&geo_point);
283
284 if let Value::Point(c) = geojson_point {
285 assert_almost_eq!(geo_point.x(), c[0] as f32, 1e-6);
286 assert_almost_eq!(geo_point.y(), c[1] as f32, 1e-6);
287 } else {
288 panic!("Not valid geometry {:?}", geojson_point);
289 }
290
291 let geo_point = Point::new(40.02f64, 116.34f64);
293 let geojson_point = Value::from(&geo_point);
294
295 if let Value::Point(c) = geojson_point {
296 assert_almost_eq!(geo_point.x(), c[0], 1e-6);
297 assert_almost_eq!(geo_point.y(), c[1], 1e-6);
298 } else {
299 panic!("Not valid geometry {:?}", geojson_point);
300 }
301 }
302
303 #[test]
304 fn geo_multi_point_conversion_test() {
305 let p1 = Point::new(40.02f64, 116.34f64);
306 let p2 = Point::new(13.02f64, 24.34f64);
307
308 let geo_multi_point = MultiPoint(vec![p1, p2]);
309 let geojson_multi_point = Value::from(&geo_multi_point);
310
311 if let Value::MultiPoint(c) = geojson_multi_point {
312 assert_almost_eq!(p1.x(), c[0][0], 1e-6);
313 assert_almost_eq!(p1.y(), c[0][1], 1e-6);
314 assert_almost_eq!(p2.x(), c[1][0], 1e-6);
315 assert_almost_eq!(p2.y(), c[1][1], 1e-6);
316 } else {
317 panic!("Not valid geometry {:?}", geojson_multi_point);
318 }
319 }
320
321 #[test]
322 fn geo_line_string_conversion_test() {
323 let p1 = Point::new(40.02f64, 116.34f64);
324 let p2 = Point::new(13.02f64, 24.34f64);
325
326 let geo_line_string = LineString::from(vec![p1, p2]);
327 let geojson_line_point = Value::from(&geo_line_string);
328
329 if let Value::LineString(c) = geojson_line_point {
330 assert_almost_eq!(p1.x(), c[0][0], 1e-6);
331 assert_almost_eq!(p1.y(), c[0][1], 1e-6);
332 assert_almost_eq!(p2.x(), c[1][0], 1e-6);
333 assert_almost_eq!(p2.y(), c[1][1], 1e-6);
334 } else {
335 panic!("Not valid geometry {:?}", geojson_line_point);
336 }
337 }
338
339 #[test]
340 fn geo_line_conversion_test() {
341 let p1 = Point::new(40.02f64, 116.34f64);
342 let p2 = Point::new(13.02f64, 24.34f64);
343
344 let geo_line = Line::new(p1, p2);
345 let geojson_line_point = Value::from(&geo_line);
346
347 if let Value::LineString(c) = geojson_line_point {
348 assert_almost_eq!(p1.x(), c[0][0], 1e-6);
349 assert_almost_eq!(p1.y(), c[0][1], 1e-6);
350 assert_almost_eq!(p2.x(), c[1][0], 1e-6);
351 assert_almost_eq!(p2.y(), c[1][1], 1e-6);
352 } else {
353 panic!("Not valid geometry {:?}", geojson_line_point);
354 }
355 }
356
357 #[test]
358 fn geo_triangle_conversion_test() {
359 let c1: Coord<f64> = Coord { x: 0., y: 0. };
360 let c2: Coord<f64> = Coord { x: 10., y: 20. };
361 let c3: Coord<f64> = Coord { x: 20., y: -10. };
362
363 let triangle = Triangle(c1, c2, c3);
364
365 let geojson_polygon = Value::from(&triangle);
366
367 if let Value::Polygon(c) = geojson_polygon {
369 assert_almost_eq!(c1.x, c[0][0][0], 1e-6);
370 assert_almost_eq!(c1.y, c[0][0][1], 1e-6);
371 assert_almost_eq!(c2.x, c[0][1][0], 1e-6);
372 assert_almost_eq!(c2.y, c[0][1][1], 1e-6);
373 assert_almost_eq!(c3.x, c[0][2][0], 1e-6);
374 assert_almost_eq!(c3.y, c[0][2][1], 1e-6);
375 assert_almost_eq!(c1.x, c[0][3][0], 1e-6);
376 assert_almost_eq!(c1.y, c[0][3][1], 1e-6);
377 } else {
378 panic!("Not valid geometry {:?}", geojson_polygon);
379 }
380 }
381
382 #[test]
383 fn geo_rect_conversion_test() {
384 let c1: Coord<f64> = Coord { x: 0., y: 0. };
385 let c2: Coord<f64> = Coord { x: 10., y: 20. };
386
387 let rect = Rect::new(c1, c2);
388
389 let geojson_polygon = Value::from(&rect);
390
391 if let Value::Polygon(c) = geojson_polygon {
393 assert_almost_eq!(c1.x, c[0][0][0], 1e-6);
394 assert_almost_eq!(c1.y, c[0][0][1], 1e-6);
395 assert_almost_eq!(c1.x, c[0][1][0], 1e-6);
396 assert_almost_eq!(c2.y, c[0][1][1], 1e-6);
397 assert_almost_eq!(c2.x, c[0][2][0], 1e-6);
398 assert_almost_eq!(c2.y, c[0][2][1], 1e-6);
399 assert_almost_eq!(c2.x, c[0][3][0], 1e-6);
400 assert_almost_eq!(c1.y, c[0][3][1], 1e-6);
401 assert_almost_eq!(c1.x, c[0][4][0], 1e-6);
402 assert_almost_eq!(c1.y, c[0][4][1], 1e-6);
403 } else {
404 panic!("Not valid geometry {:?}", geojson_polygon);
405 }
406 }
407
408 #[test]
409 fn geo_multi_line_string_conversion_test() {
410 let p1 = Point::new(40.02f64, 116.34f64);
411 let p2 = Point::new(13.02f64, 24.34f64);
412 let p3 = Point::new(46.84f64, 160.95f64);
413 let p4 = Point::new(42.02f64, 96.34f64);
414
415 let geo_line_string1 = LineString::from(vec![p1, p2]);
416 let geo_line_string2 = LineString::from(vec![p3, p4]);
417
418 let geo_multi_line_string = MultiLineString(vec![geo_line_string1, geo_line_string2]);
419 let geojson_multi_line_point = Value::from(&geo_multi_line_string);
420
421 if let Value::MultiLineString(c) = geojson_multi_line_point {
422 assert_almost_eq!(p1.x(), c[0][0][0], 1e-6);
423 assert_almost_eq!(p1.y(), c[0][0][1], 1e-6);
424 assert_almost_eq!(p2.x(), c[0][1][0], 1e-6);
425 assert_almost_eq!(p2.y(), c[0][1][1], 1e-6);
426 assert_almost_eq!(p3.x(), c[1][0][0], 1e-6);
427 assert_almost_eq!(p3.y(), c[1][0][1], 1e-6);
428 assert_almost_eq!(p4.x(), c[1][1][0], 1e-6);
429 assert_almost_eq!(p4.y(), c[1][1][1], 1e-6);
430 } else {
431 panic!("Not valid geometry {:?}", geojson_multi_line_point);
432 }
433 }
434
435 #[test]
436 fn geo_polygon_conversion_test() {
437 let p1 = Point::new(100.0f64, 0.0f64);
438 let p2 = Point::new(101.0f64, 0.0f64);
439 let p3 = Point::new(101.0f64, 1.0f64);
440 let p4 = Point::new(104.0f64, 0.2f64);
441 let p5 = Point::new(100.9f64, 0.2f64);
442 let p6 = Point::new(100.9f64, 0.7f64);
443
444 let geo_line_string1 = LineString::from(vec![p1, p2, p3, p1]);
445 let geo_line_string2 = LineString::from(vec![p4, p5, p6, p4]);
446
447 let geo_polygon = Polygon::new(geo_line_string1, vec![geo_line_string2]);
448 let geojson_polygon = Value::from(&geo_polygon);
449
450 if let Value::Polygon(c) = geojson_polygon {
451 assert_almost_eq!(p1.x(), c[0][0][0], 1e-6);
452 assert_almost_eq!(p1.y(), c[0][0][1], 1e-6);
453 assert_almost_eq!(p2.x(), c[0][1][0], 1e-6);
454 assert_almost_eq!(p2.y(), c[0][1][1], 1e-6);
455 assert_almost_eq!(p3.x(), c[0][2][0], 1e-6);
456 assert_almost_eq!(p3.y(), c[0][2][1], 1e-6);
457 assert_almost_eq!(p4.x(), c[1][0][0], 1e-6);
458 assert_almost_eq!(p4.y(), c[1][0][1], 1e-6);
459 assert_almost_eq!(p5.x(), c[1][1][0], 1e-6);
460 assert_almost_eq!(p5.y(), c[1][1][1], 1e-6);
461 assert_almost_eq!(p6.x(), c[1][2][0], 1e-6);
462 assert_almost_eq!(p6.y(), c[1][2][1], 1e-6);
463 } else {
464 panic!("Not valid geometry {:?}", geojson_polygon);
465 }
466 }
467
468 #[test]
469 fn geo_multi_polygon_conversion_test() {
470 let p1 = Point::new(102.0f64, 2.0f64);
471 let p2 = Point::new(103.0f64, 2.0f64);
472 let p3 = Point::new(103.0f64, 3.0f64);
473 let p4 = Point::new(100.0f64, 0.0f64);
474 let p5 = Point::new(101.0f64, 0.0f64);
475 let p6 = Point::new(101.0f64, 1.0f64);
476
477 let geo_line_string1 = LineString::from(vec![p1, p2, p3, p1]);
478 let geo_line_string2 = LineString::from(vec![p4, p5, p6, p4]);
479
480 let geo_polygon1 = Polygon::new(geo_line_string1, vec![]);
481 let geo_polygon2 = Polygon::new(geo_line_string2, vec![]);
482 let geo_multi_polygon = MultiPolygon(vec![geo_polygon1, geo_polygon2]);
483 let geojson_multi_polygon = Value::from(&geo_multi_polygon);
484
485 if let Value::MultiPolygon(c) = geojson_multi_polygon {
486 assert_almost_eq!(p1.x(), c[0][0][0][0], 1e-6);
487 assert_almost_eq!(p1.y(), c[0][0][0][1], 1e-6);
488 assert_almost_eq!(p2.x(), c[0][0][1][0], 1e-6);
489 assert_almost_eq!(p2.y(), c[0][0][1][1], 1e-6);
490 assert_almost_eq!(p3.x(), c[0][0][2][0], 1e-6);
491 assert_almost_eq!(p3.y(), c[0][0][2][1], 1e-6);
492 assert_almost_eq!(p4.x(), c[1][0][0][0], 1e-6);
493 assert_almost_eq!(p4.y(), c[1][0][0][1], 1e-6);
494 assert_almost_eq!(p5.x(), c[1][0][1][0], 1e-6);
495 assert_almost_eq!(p5.y(), c[1][0][1][1], 1e-6);
496 assert_almost_eq!(p6.x(), c[1][0][2][0], 1e-6);
497 assert_almost_eq!(p6.y(), c[1][0][2][1], 1e-6);
498 } else {
499 panic!("Not valid geometry {:?}", geojson_multi_polygon);
500 }
501 }
502
503 #[test]
504 fn geo_geometry_collection_conversion_test() {
505 let p1 = Point::new(100.0f64, 0.0f64);
506 let p2 = Point::new(100.0f64, 1.0f64);
507 let p3 = Point::new(101.0f64, 1.0f64);
508 let p4 = Point::new(102.0f64, 0.0f64);
509 let p5 = Point::new(101.0f64, 0.0f64);
510 let geo_multi_point = MultiPoint(vec![p1, p2]);
511 let geo_multi_line_string = MultiLineString(vec![
512 LineString::from(vec![p1, p2]),
513 LineString::from(vec![p2, p3]),
514 ]);
515 let geo_multi_polygon = MultiPolygon(vec![
516 Polygon::new(LineString::from(vec![p3, p4, p5, p3]), vec![]),
517 Polygon::new(LineString::from(vec![p1, p5, p3, p1]), vec![]),
518 ]);
519 let geo_geometry_collection = GeometryCollection(vec![
520 geo_types::Geometry::MultiPoint(geo_multi_point),
521 geo_types::Geometry::MultiLineString(geo_multi_line_string),
522 geo_types::Geometry::MultiPolygon(geo_multi_polygon),
523 ]);
524
525 let geojson_geometry_collection = Value::from(&geo_geometry_collection);
526
527 if let Value::GeometryCollection(geometries) = geojson_geometry_collection {
528 let geometry_type = |geometry: &Geometry| match geometry.value {
529 Value::Point(..) => "Point",
530 Value::MultiPoint(..) => "MultiPoint",
531 Value::LineString(..) => "LineString",
532 Value::MultiLineString(..) => "MultiLineString",
533 Value::Polygon(..) => "Polygon",
534 Value::MultiPolygon(..) => "MultiPolygon",
535 Value::GeometryCollection(..) => "GeometryCollection",
536 };
537
538 assert_eq!(3, geometries.len());
539 assert_eq!(geometry_type(&geometries[0]), "MultiPoint");
540 assert_eq!(geometry_type(&geometries[1]), "MultiLineString");
541 assert_eq!(geometry_type(&geometries[2]), "MultiPolygon");
542 } else {
543 panic!("Not valid geometry {:?}", geojson_geometry_collection);
544 }
545 }
546
547 #[test]
548 fn test_from_geo_type_to_geojson() {
549 let p1 = geo_types::Point::new(100.0f64, 0.0f64);
550 let actual = serde_json::Value::from(GeoJson::from(&p1));
551 let expected: serde_json::Value =
552 serde_json::json!({"coordinates": [100.0, 0.0], "type": "Point"});
553 assert_eq!(expected, actual);
554 }
555
556 #[test]
557 fn test_from_iter_geo_type_to_geojson() {
558 let p1 = geo_types::Point::new(100.0f64, 0.0f64);
559 let p2 = geo_types::Point::new(200.0f64, 0.0f64);
560 let points: Vec<_> = vec![p1, p2];
561
562 use std::iter::FromIterator;
563
564 let actual = GeoJson::from_iter(points.iter());
565 let actual2 = points.iter().collect::<GeoJson>();
566 assert_eq!(actual, actual2);
567
568 let expected: serde_json::Value = serde_json::json!({
569 "type": "GeometryCollection",
570 "geometries": [
571 {"coordinates": [100.0, 0.0], "type": "Point"},
572 {"coordinates": [200.0, 0.0], "type": "Point"},
573 ]
574 });
575 assert_eq!(expected, serde_json::Value::from(actual));
576 }
577}