surrealdb_core/sql/
geometry.rs

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	// Add new variants here
35}
36
37impl Geometry {
38	/// Check if this is a Point
39	pub fn is_point(&self) -> bool {
40		matches!(self, Self::Point(_))
41	}
42	/// Check if this is a Line
43	pub fn is_line(&self) -> bool {
44		matches!(self, Self::Line(_))
45	}
46	/// Check if this is a Polygon
47	pub fn is_polygon(&self) -> bool {
48		matches!(self, Self::Polygon(_))
49	}
50	/// Check if this is a MultiPoint
51	pub fn is_multipoint(&self) -> bool {
52		matches!(self, Self::MultiPoint(_))
53	}
54	/// Check if this is a MultiLine
55	pub fn is_multiline(&self) -> bool {
56		matches!(self, Self::MultiLine(_))
57	}
58	/// Check if this is a MultiPolygon
59	pub fn is_multipolygon(&self) -> bool {
60		matches!(self, Self::MultiPolygon(_))
61	}
62	/// Check if this is not a Collection
63	pub fn is_geometry(&self) -> bool {
64		!matches!(self, Self::Collection(_))
65	}
66	/// Check if this is a Collection
67	pub fn is_collection(&self) -> bool {
68		matches!(self, Self::Collection(_))
69	}
70	/// Check if this has valid latitude and longitude points:
71	/// * -90 <= lat <= 90
72	/// * -180 <= lng <= 180
73	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	/// Get the type of this Geometry as text
113	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	/// Get the raw coordinates of this Geometry as an Array
125	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	/// Get the GeoJSON object representation for this geometry
166	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	/// Converts a surreal value to a MultiPolygon if the array matches to a MultiPolygon.
182	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	/// Converts a surreal value to a MultiLine if the array matches to a MultiLine.
194	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	/// Converts a surreal value to a MultiPoint if the array matches to a MultiPoint.
206	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	/// Converts a surreal value to a Polygon if the array matches to a Polygon.
218	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	/// Converts a surreal value to a LineString if the array matches to a LineString.
234	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	/// Converts a surreal value to a Point if the array matches to a point.
246	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		// FIXME: This truncates decimals and large integers into a f64.
254		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			//
297			(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			//
304			(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			//
311			(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			//
318			(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			//
325			(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			//
332			(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			//
339			(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			//
346			(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	// -----------------------------------
455	// Value operations
456	// -----------------------------------
457
458	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}