1#![allow(clippy::derived_hash_with_manual_eq)]
2
3use crate::sql::array::Array;
4use crate::sql::fmt::Fmt;
5use crate::sql::value::Value;
6use geo::algorithm::contains::Contains;
7use geo::algorithm::intersects::Intersects;
8use geo::{Coord, LineString, LinesIter, Point, Polygon};
9use geo_types::{MultiLineString, MultiPoint, MultiPolygon};
10use revision::revisioned;
11use serde::{Deserialize, Serialize};
12use std::cmp::Ordering;
13use std::collections::BTreeMap;
14use std::iter::once;
15use std::{fmt, hash};
16
17use super::Object;
18
19pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Geometry";
20
21#[revisioned(revision = 1)]
22#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
23#[serde(rename = "$surrealdb::private::sql::Geometry")]
24#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
25#[non_exhaustive]
26pub enum Geometry {
27 Point(Point<f64>),
28 Line(LineString<f64>),
29 Polygon(Polygon<f64>),
30 MultiPoint(MultiPoint<f64>),
31 MultiLine(MultiLineString<f64>),
32 MultiPolygon(MultiPolygon<f64>),
33 Collection(Vec<Geometry>),
34 }
36
37impl Geometry {
38 pub fn is_point(&self) -> bool {
40 matches!(self, Self::Point(_))
41 }
42 pub fn is_line(&self) -> bool {
44 matches!(self, Self::Line(_))
45 }
46 pub fn is_polygon(&self) -> bool {
48 matches!(self, Self::Polygon(_))
49 }
50 pub fn is_multipoint(&self) -> bool {
52 matches!(self, Self::MultiPoint(_))
53 }
54 pub fn is_multiline(&self) -> bool {
56 matches!(self, Self::MultiLine(_))
57 }
58 pub fn is_multipolygon(&self) -> bool {
60 matches!(self, Self::MultiPolygon(_))
61 }
62 pub fn is_geometry(&self) -> bool {
64 !matches!(self, Self::Collection(_))
65 }
66 pub fn is_collection(&self) -> bool {
68 matches!(self, Self::Collection(_))
69 }
70 pub fn is_valid(&self) -> bool {
74 match self {
75 Geometry::Point(p) => {
76 (-90.0..=90.0).contains(&p.0.y) && (-180.0..=180.0).contains(&p.0.x)
77 }
78 Geometry::MultiPoint(v) => v
79 .iter()
80 .all(|p| (-90.0..=90.0).contains(&p.0.y) && (-180.0..=180.0).contains(&p.0.x)),
81 Geometry::Line(v) => v.lines_iter().all(|l| {
82 (-90.0..=90.0).contains(&l.start.y)
83 && (-180.0..=180.0).contains(&l.start.x)
84 && (-90.0..=90.0).contains(&l.end.y)
85 && (-180.0..=180.0).contains(&l.end.x)
86 }),
87 Geometry::Polygon(v) => v.lines_iter().all(|l| {
88 (-90.0..=90.0).contains(&l.start.y)
89 && (-180.0..=180.0).contains(&l.start.x)
90 && (-90.0..=90.0).contains(&l.end.y)
91 && (-180.0..=180.0).contains(&l.end.x)
92 }),
93 Geometry::MultiLine(v) => v.iter().all(|l| {
94 l.lines_iter().all(|l| {
95 (-90.0..=90.0).contains(&l.start.y)
96 && (-180.0..=180.0).contains(&l.start.x)
97 && (-90.0..=90.0).contains(&l.end.y)
98 && (-180.0..=180.0).contains(&l.end.x)
99 })
100 }),
101 Geometry::MultiPolygon(v) => v.iter().all(|p| {
102 p.lines_iter().all(|l| {
103 (-90.0..=90.0).contains(&l.start.y)
104 && (-180.0..=180.0).contains(&l.start.x)
105 && (-90.0..=90.0).contains(&l.end.y)
106 && (-180.0..=180.0).contains(&l.end.x)
107 })
108 }),
109 Geometry::Collection(v) => v.iter().all(Geometry::is_valid),
110 }
111 }
112 pub fn as_type(&self) -> &'static str {
114 match self {
115 Self::Point(_) => "Point",
116 Self::Line(_) => "LineString",
117 Self::Polygon(_) => "Polygon",
118 Self::MultiPoint(_) => "MultiPoint",
119 Self::MultiLine(_) => "MultiLineString",
120 Self::MultiPolygon(_) => "MultiPolygon",
121 Self::Collection(_) => "GeometryCollection",
122 }
123 }
124 pub fn as_coordinates(&self) -> Value {
126 fn point(v: &Point) -> Value {
127 Array::from(vec![v.x(), v.y()]).into()
128 }
129
130 fn line(v: &LineString) -> Value {
131 v.points().map(|v| point(&v)).collect::<Vec<Value>>().into()
132 }
133
134 fn polygon(v: &Polygon) -> Value {
135 once(v.exterior()).chain(v.interiors()).map(line).collect::<Vec<Value>>().into()
136 }
137
138 fn multipoint(v: &MultiPoint) -> Value {
139 v.iter().map(point).collect::<Vec<Value>>().into()
140 }
141
142 fn multiline(v: &MultiLineString) -> Value {
143 v.iter().map(line).collect::<Vec<Value>>().into()
144 }
145
146 fn multipolygon(v: &MultiPolygon) -> Value {
147 v.iter().map(polygon).collect::<Vec<Value>>().into()
148 }
149
150 fn collection(v: &[Geometry]) -> Value {
151 v.iter().map(Geometry::as_coordinates).collect::<Vec<Value>>().into()
152 }
153
154 match self {
155 Self::Point(v) => point(v),
156 Self::Line(v) => line(v),
157 Self::Polygon(v) => polygon(v),
158 Self::MultiPoint(v) => multipoint(v),
159 Self::MultiLine(v) => multiline(v),
160 Self::MultiPolygon(v) => multipolygon(v),
161 Self::Collection(v) => collection(v),
162 }
163 }
164
165 pub fn as_object(&self) -> Object {
167 let mut obj = BTreeMap::<String, Value>::new();
168 obj.insert("type".into(), self.as_type().into());
169 obj.insert(
170 match self {
171 Self::Collection(_) => "geometries",
172 _ => "coordinates",
173 }
174 .into(),
175 self.as_coordinates(),
176 );
177
178 obj.into()
179 }
180
181 pub(crate) fn array_to_multipolygon(v: &Value) -> Option<MultiPolygon<f64>> {
183 let mut res = Vec::new();
184 let Value::Array(v) = v else {
185 return None;
186 };
187 for x in v.iter() {
188 res.push(Self::array_to_polygon(x)?);
189 }
190 Some(MultiPolygon::new(res))
191 }
192
193 pub(crate) fn array_to_multiline(v: &Value) -> Option<MultiLineString<f64>> {
195 let mut res = Vec::new();
196 let Value::Array(v) = v else {
197 return None;
198 };
199 for x in v.iter() {
200 res.push(Self::array_to_line(x)?);
201 }
202 Some(MultiLineString::new(res))
203 }
204
205 pub(crate) fn array_to_multipoint(v: &Value) -> Option<MultiPoint<f64>> {
207 let mut res = Vec::new();
208 let Value::Array(v) = v else {
209 return None;
210 };
211 for x in v.iter() {
212 res.push(Self::array_to_point(x)?);
213 }
214 Some(MultiPoint::new(res))
215 }
216
217 pub(crate) fn array_to_polygon(v: &Value) -> Option<Polygon<f64>> {
219 let mut res = Vec::new();
220 let Value::Array(v) = v else {
221 return None;
222 };
223 if v.is_empty() {
224 return None;
225 }
226 let first = Self::array_to_line(&v[0])?;
227 for x in &v[1..] {
228 res.push(Self::array_to_line(x)?);
229 }
230 Some(Polygon::new(first, res))
231 }
232
233 pub(crate) fn array_to_line(v: &Value) -> Option<LineString<f64>> {
235 let mut res = Vec::new();
236 let Value::Array(v) = v else {
237 return None;
238 };
239 for x in v.iter() {
240 res.push(Self::array_to_point(x)?);
241 }
242 Some(LineString::from(res))
243 }
244
245 pub(crate) fn array_to_point(v: &Value) -> Option<Point<f64>> {
247 let Value::Array(v) = v else {
248 return None;
249 };
250 if v.len() != 2 {
251 return None;
252 }
253 let Value::Number(ref a) = v.0[0] else {
255 return None;
256 };
257 let Value::Number(ref b) = v.0[1] else {
258 return None;
259 };
260 Some(Point::from(((*a).try_into().ok()?, (*b).try_into().ok()?)))
261 }
262}
263
264impl PartialOrd for Geometry {
265 #[rustfmt::skip]
266 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
267 fn coord(v: &Coord) -> (f64, f64) {
268 v.x_y()
269 }
270
271 fn point(v: &Point) -> (f64, f64) {
272 coord(&v.0)
273 }
274
275 fn line(v: &LineString) -> impl Iterator<Item = (f64, f64)> + '_ {
276 v.into_iter().map(coord)
277 }
278
279 fn polygon(v: &Polygon) -> impl Iterator<Item = (f64, f64)> + '_ {
280 v.interiors().iter().chain(once(v.exterior())).flat_map(line)
281 }
282
283 fn multipoint(v: &MultiPoint) -> impl Iterator<Item = (f64, f64)> + '_ {
284 v.iter().map(point)
285 }
286
287 fn multiline(v: &MultiLineString) -> impl Iterator<Item = (f64, f64)> + '_ {
288 v.iter().flat_map(line)
289 }
290
291 fn multipolygon(v: &MultiPolygon) -> impl Iterator<Item = (f64, f64)> + '_ {
292 v.iter().flat_map(polygon)
293 }
294
295 match (self, other) {
296 (Self::Point(_), Self::Line(_)) => Some(Ordering::Less),
298 (Self::Point(_), Self::Polygon(_)) => Some(Ordering::Less),
299 (Self::Point(_), Self::MultiPoint(_)) => Some(Ordering::Less),
300 (Self::Point(_), Self::MultiLine(_)) => Some(Ordering::Less),
301 (Self::Point(_), Self::MultiPolygon(_)) => Some(Ordering::Less),
302 (Self::Point(_), Self::Collection(_)) => Some(Ordering::Less),
303 (Self::Line(_), Self::Point(_)) => Some(Ordering::Greater),
305 (Self::Line(_), Self::Polygon(_)) => Some(Ordering::Less),
306 (Self::Line(_), Self::MultiPoint(_)) => Some(Ordering::Less),
307 (Self::Line(_), Self::MultiLine(_)) => Some(Ordering::Less),
308 (Self::Line(_), Self::MultiPolygon(_)) => Some(Ordering::Less),
309 (Self::Line(_), Self::Collection(_)) => Some(Ordering::Less),
310 (Self::Polygon(_), Self::Point(_)) => Some(Ordering::Greater),
312 (Self::Polygon(_), Self::Line(_)) => Some(Ordering::Greater),
313 (Self::Polygon(_), Self::MultiPoint(_)) => Some(Ordering::Less),
314 (Self::Polygon(_), Self::MultiLine(_)) => Some(Ordering::Less),
315 (Self::Polygon(_), Self::MultiPolygon(_)) => Some(Ordering::Less),
316 (Self::Polygon(_), Self::Collection(_)) => Some(Ordering::Less),
317 (Self::MultiPoint(_), Self::Point(_)) => Some(Ordering::Greater),
319 (Self::MultiPoint(_), Self::Line(_)) => Some(Ordering::Greater),
320 (Self::MultiPoint(_), Self::Polygon(_)) => Some(Ordering::Greater),
321 (Self::MultiPoint(_), Self::MultiLine(_)) => Some(Ordering::Less),
322 (Self::MultiPoint(_), Self::MultiPolygon(_)) => Some(Ordering::Less),
323 (Self::MultiPoint(_), Self::Collection(_)) => Some(Ordering::Less),
324 (Self::MultiLine(_), Self::Point(_)) => Some(Ordering::Greater),
326 (Self::MultiLine(_), Self::Line(_)) => Some(Ordering::Greater),
327 (Self::MultiLine(_), Self::Polygon(_)) => Some(Ordering::Greater),
328 (Self::MultiLine(_), Self::MultiPoint(_)) => Some(Ordering::Greater),
329 (Self::MultiLine(_), Self::MultiPolygon(_)) => Some(Ordering::Less),
330 (Self::MultiLine(_), Self::Collection(_)) => Some(Ordering::Less),
331 (Self::MultiPolygon(_), Self::Point(_)) => Some(Ordering::Greater),
333 (Self::MultiPolygon(_), Self::Line(_)) => Some(Ordering::Greater),
334 (Self::MultiPolygon(_), Self::Polygon(_)) => Some(Ordering::Greater),
335 (Self::MultiPolygon(_), Self::MultiPoint(_)) => Some(Ordering::Greater),
336 (Self::MultiPolygon(_), Self::MultiLine(_)) => Some(Ordering::Greater),
337 (Self::MultiPolygon(_), Self::Collection(_)) => Some(Ordering::Less),
338 (Self::Collection(_), Self::Point(_)) => Some(Ordering::Greater),
340 (Self::Collection(_), Self::Line(_)) => Some(Ordering::Greater),
341 (Self::Collection(_), Self::Polygon(_)) => Some(Ordering::Greater),
342 (Self::Collection(_), Self::MultiPoint(_)) => Some(Ordering::Greater),
343 (Self::Collection(_), Self::MultiLine(_)) => Some(Ordering::Greater),
344 (Self::Collection(_), Self::MultiPolygon(_)) => Some(Ordering::Greater),
345 (Self::Point(a), Self::Point(b)) => point(a).partial_cmp(&point(b)),
347 (Self::Line(a), Self::Line(b)) => line(a).partial_cmp(line(b)),
348 (Self::Polygon(a), Self::Polygon(b)) => polygon(a).partial_cmp(polygon(b)),
349 (Self::MultiPoint(a), Self::MultiPoint(b)) => multipoint(a).partial_cmp(multipoint(b)),
350 (Self::MultiLine(a), Self::MultiLine(b)) => multiline(a).partial_cmp(multiline(b)),
351 (Self::MultiPolygon(a), Self::MultiPolygon(b)) => multipolygon(a).partial_cmp(multipolygon(b)),
352 (Self::Collection(a), Self::Collection(b)) => a.partial_cmp(b),
353 }
354 }
355}
356
357impl From<(f64, f64)> for Geometry {
358 fn from(v: (f64, f64)) -> Self {
359 Self::Point(v.into())
360 }
361}
362
363impl From<[f64; 2]> for Geometry {
364 fn from(v: [f64; 2]) -> Self {
365 Self::Point(v.into())
366 }
367}
368
369impl From<Point<f64>> for Geometry {
370 fn from(v: Point<f64>) -> Self {
371 Self::Point(v)
372 }
373}
374
375impl From<LineString<f64>> for Geometry {
376 fn from(v: LineString<f64>) -> Self {
377 Self::Line(v)
378 }
379}
380
381impl From<Polygon<f64>> for Geometry {
382 fn from(v: Polygon<f64>) -> Self {
383 Self::Polygon(v)
384 }
385}
386
387impl From<MultiPoint<f64>> for Geometry {
388 fn from(v: MultiPoint<f64>) -> Self {
389 Self::MultiPoint(v)
390 }
391}
392
393impl From<MultiLineString<f64>> for Geometry {
394 fn from(v: MultiLineString<f64>) -> Self {
395 Self::MultiLine(v)
396 }
397}
398
399impl From<MultiPolygon<f64>> for Geometry {
400 fn from(v: MultiPolygon<f64>) -> Self {
401 Self::MultiPolygon(v)
402 }
403}
404
405impl From<Vec<Geometry>> for Geometry {
406 fn from(v: Vec<Geometry>) -> Self {
407 Self::Collection(v)
408 }
409}
410
411impl From<Vec<Point<f64>>> for Geometry {
412 fn from(v: Vec<Point<f64>>) -> Self {
413 Self::MultiPoint(MultiPoint(v))
414 }
415}
416
417impl From<Vec<LineString<f64>>> for Geometry {
418 fn from(v: Vec<LineString<f64>>) -> Self {
419 Self::MultiLine(MultiLineString(v))
420 }
421}
422
423impl From<Vec<Polygon<f64>>> for Geometry {
424 fn from(v: Vec<Polygon<f64>>) -> Self {
425 Self::MultiPolygon(MultiPolygon(v))
426 }
427}
428
429impl From<Geometry> for geo::Geometry<f64> {
430 fn from(v: Geometry) -> Self {
431 match v {
432 Geometry::Point(v) => v.into(),
433 Geometry::Line(v) => v.into(),
434 Geometry::Polygon(v) => v.into(),
435 Geometry::MultiPoint(v) => v.into(),
436 Geometry::MultiLine(v) => v.into(),
437 Geometry::MultiPolygon(v) => v.into(),
438 Geometry::Collection(v) => v.into_iter().collect::<geo::Geometry<f64>>(),
439 }
440 }
441}
442
443impl FromIterator<Geometry> for geo::Geometry<f64> {
444 fn from_iter<I: IntoIterator<Item = Geometry>>(iter: I) -> Self {
445 let mut c: Vec<geo::Geometry<f64>> = vec![];
446 for i in iter {
447 c.push(i.into())
448 }
449 geo::Geometry::GeometryCollection(geo::GeometryCollection(c))
450 }
451}
452
453impl Geometry {
454 pub fn contains(&self, other: &Self) -> bool {
459 match self {
460 Self::Point(v) => match other {
461 Self::Point(w) => v.contains(w),
462 Self::MultiPoint(w) => w.iter().all(|x| v.contains(x)),
463 Self::Collection(w) => w.iter().all(|x| self.contains(x)),
464 _ => false,
465 },
466 Self::Line(v) => match other {
467 Self::Point(w) => v.contains(w),
468 Self::Line(w) => v.contains(w),
469 Self::MultiLine(w) => w.iter().all(|x| w.contains(x)),
470 Self::Collection(w) => w.iter().all(|x| self.contains(x)),
471 _ => false,
472 },
473 Self::Polygon(v) => match other {
474 Self::Point(w) => v.contains(w),
475 Self::Line(w) => v.contains(w),
476 Self::Polygon(w) => v.contains(w),
477 Self::MultiPolygon(w) => w.iter().all(|x| w.contains(x)),
478 Self::Collection(w) => w.iter().all(|x| self.contains(x)),
479 _ => false,
480 },
481 Self::MultiPoint(v) => match other {
482 Self::Point(w) => v.contains(w),
483 Self::MultiPoint(w) => w.iter().all(|x| w.contains(x)),
484 Self::Collection(w) => w.iter().all(|x| self.contains(x)),
485 _ => false,
486 },
487 Self::MultiLine(v) => match other {
488 Self::Point(w) => v.contains(w),
489 Self::Line(w) => v.contains(w),
490 Self::MultiLine(w) => w.iter().all(|x| w.contains(x)),
491 Self::Collection(w) => w.iter().all(|x| self.contains(x)),
492 _ => false,
493 },
494 Self::MultiPolygon(v) => match other {
495 Self::Point(w) => v.contains(w),
496 Self::Line(w) => v.contains(w),
497 Self::Polygon(w) => v.contains(w),
498 Self::MultiPoint(w) => v.contains(w),
499 Self::MultiLine(w) => v.contains(w),
500 Self::MultiPolygon(w) => v.contains(w),
501 Self::Collection(w) => w.iter().all(|x| self.contains(x)),
502 },
503 Self::Collection(v) => v.iter().all(|x| x.contains(other)),
504 }
505 }
506
507 pub fn intersects(&self, other: &Self) -> bool {
508 match self {
509 Self::Point(v) => match other {
510 Self::Point(w) => v.intersects(w),
511 Self::Line(w) => v.intersects(w),
512 Self::Polygon(w) => v.intersects(w),
513 Self::MultiPoint(w) => v.intersects(w),
514 Self::MultiLine(w) => w.iter().any(|x| v.intersects(x)),
515 Self::MultiPolygon(w) => v.intersects(w),
516 Self::Collection(w) => w.iter().all(|x| self.intersects(x)),
517 },
518 Self::Line(v) => match other {
519 Self::Point(w) => v.intersects(w),
520 Self::Line(w) => v.intersects(w),
521 Self::Polygon(w) => v.intersects(w),
522 Self::MultiPoint(w) => v.intersects(w),
523 Self::MultiLine(w) => w.iter().any(|x| v.intersects(x)),
524 Self::MultiPolygon(w) => v.intersects(w),
525 Self::Collection(w) => w.iter().all(|x| self.intersects(x)),
526 },
527 Self::Polygon(v) => match other {
528 Self::Point(w) => v.intersects(w),
529 Self::Line(w) => v.intersects(w),
530 Self::Polygon(w) => v.intersects(w),
531 Self::MultiPoint(w) => v.intersects(w),
532 Self::MultiLine(w) => v.intersects(w),
533 Self::MultiPolygon(w) => v.intersects(w),
534 Self::Collection(w) => w.iter().all(|x| self.intersects(x)),
535 },
536 Self::MultiPoint(v) => match other {
537 Self::Point(w) => v.intersects(w),
538 Self::Line(w) => v.intersects(w),
539 Self::Polygon(w) => v.intersects(w),
540 Self::MultiPoint(w) => v.intersects(w),
541 Self::MultiLine(w) => w.iter().any(|x| v.intersects(x)),
542 Self::MultiPolygon(w) => v.intersects(w),
543 Self::Collection(w) => w.iter().all(|x| self.intersects(x)),
544 },
545 Self::MultiLine(v) => match other {
546 Self::Point(w) => v.intersects(w),
547 Self::Line(w) => v.intersects(w),
548 Self::Polygon(w) => v.intersects(w),
549 Self::MultiPoint(w) => v.intersects(w),
550 Self::MultiLine(w) => w.iter().any(|x| v.intersects(x)),
551 Self::MultiPolygon(w) => v.intersects(w),
552 Self::Collection(w) => w.iter().all(|x| self.intersects(x)),
553 },
554 Self::MultiPolygon(v) => match other {
555 Self::Point(w) => v.intersects(w),
556 Self::Line(w) => v.intersects(w),
557 Self::Polygon(w) => v.intersects(w),
558 Self::MultiPoint(w) => v.intersects(w),
559 Self::MultiLine(w) => v.intersects(w),
560 Self::MultiPolygon(w) => v.intersects(w),
561 Self::Collection(w) => w.iter().all(|x| self.intersects(x)),
562 },
563 Self::Collection(v) => v.iter().all(|x| x.intersects(other)),
564 }
565 }
566}
567
568impl fmt::Display for Geometry {
569 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
570 match self {
571 Self::Point(v) => {
572 write!(f, "({}, {})", v.x(), v.y())
573 }
574 Self::Line(v) => write!(
575 f,
576 "{{ type: 'LineString', coordinates: [{}] }}",
577 Fmt::comma_separated(v.points().map(|v| Fmt::new(v, |v, f| write!(
578 f,
579 "[{}, {}]",
580 v.x(),
581 v.y()
582 ))))
583 ),
584 Self::Polygon(v) => write!(
585 f,
586 "{{ type: 'Polygon', coordinates: [{}] }}",
587 Fmt::comma_separated(once(v.exterior()).chain(v.interiors()).map(|v| Fmt::new(
588 v,
589 |v, f| write!(
590 f,
591 "[{}]",
592 Fmt::comma_separated(v.points().map(|v| Fmt::new(v, |v, f| write!(
593 f,
594 "[{}, {}]",
595 v.x(),
596 v.y()
597 ))))
598 )
599 )))
600 ),
601 Self::MultiPoint(v) => {
602 write!(
603 f,
604 "{{ type: 'MultiPoint', coordinates: [{}] }}",
605 Fmt::comma_separated(v.iter().map(|v| Fmt::new(v, |v, f| write!(
606 f,
607 "[{}, {}]",
608 v.x(),
609 v.y()
610 ))))
611 )
612 }
613 Self::MultiLine(v) => write!(
614 f,
615 "{{ type: 'MultiLineString', coordinates: [{}] }}",
616 Fmt::comma_separated(v.iter().map(|v| Fmt::new(v, |v, f| write!(
617 f,
618 "[{}]",
619 Fmt::comma_separated(v.points().map(|v| Fmt::new(v, |v, f| write!(
620 f,
621 "[{}, {}]",
622 v.x(),
623 v.y()
624 ))))
625 ))))
626 ),
627 Self::MultiPolygon(v) => {
628 write!(
629 f,
630 "{{ type: 'MultiPolygon', coordinates: [{}] }}",
631 Fmt::comma_separated(v.iter().map(|v| Fmt::new(v, |v, f| {
632 write!(
633 f,
634 "[{}]",
635 Fmt::comma_separated(once(v.exterior()).chain(v.interiors()).map(
636 |v| Fmt::new(v, |v, f| write!(
637 f,
638 "[{}]",
639 Fmt::comma_separated(v.points().map(|v| Fmt::new(
640 v,
641 |v, f| write!(f, "[{}, {}]", v.x(), v.y())
642 )))
643 ))
644 ))
645 )
646 }))),
647 )
648 }
649 Self::Collection(v) => {
650 write!(
651 f,
652 "{{ type: 'GeometryCollection', geometries: [{}] }}",
653 Fmt::comma_separated(v)
654 )
655 }
656 }
657 }
658}
659
660impl hash::Hash for Geometry {
661 fn hash<H: hash::Hasher>(&self, state: &mut H) {
662 match self {
663 Geometry::Point(p) => {
664 "Point".hash(state);
665 p.x().to_bits().hash(state);
666 p.y().to_bits().hash(state);
667 }
668 Geometry::Line(l) => {
669 "Line".hash(state);
670 l.points().for_each(|v| {
671 v.x().to_bits().hash(state);
672 v.y().to_bits().hash(state);
673 });
674 }
675 Geometry::Polygon(p) => {
676 "Polygon".hash(state);
677 p.exterior().points().for_each(|ext| {
678 ext.x().to_bits().hash(state);
679 ext.y().to_bits().hash(state);
680 });
681 p.interiors().iter().for_each(|int| {
682 int.points().for_each(|v| {
683 v.x().to_bits().hash(state);
684 v.y().to_bits().hash(state);
685 });
686 });
687 }
688 Geometry::MultiPoint(v) => {
689 "MultiPoint".hash(state);
690 v.0.iter().for_each(|v| {
691 v.x().to_bits().hash(state);
692 v.y().to_bits().hash(state);
693 });
694 }
695 Geometry::MultiLine(ml) => {
696 "MultiLine".hash(state);
697 ml.0.iter().for_each(|ls| {
698 ls.points().for_each(|p| {
699 p.x().to_bits().hash(state);
700 p.y().to_bits().hash(state);
701 });
702 });
703 }
704 Geometry::MultiPolygon(mp) => {
705 "MultiPolygon".hash(state);
706 mp.0.iter().for_each(|p| {
707 p.exterior().points().for_each(|ext| {
708 ext.x().to_bits().hash(state);
709 ext.y().to_bits().hash(state);
710 });
711 p.interiors().iter().for_each(|int| {
712 int.points().for_each(|v| {
713 v.x().to_bits().hash(state);
714 v.y().to_bits().hash(state);
715 });
716 });
717 });
718 }
719 Geometry::Collection(v) => {
720 "GeometryCollection".hash(state);
721 v.iter().for_each(|v| v.hash(state));
722 }
723 }
724 }
725}