surrealdb_sql/
geometry.rs

1#![allow(clippy::derived_hash_with_manual_eq)]
2
3use crate::array::Array;
4use crate::fmt::Fmt;
5use crate::value::Value;
6use geo::algorithm::contains::Contains;
7use geo::algorithm::intersects::Intersects;
8use geo::{Coord, LineString, Point, Polygon};
9use geo::{MultiLineString, MultiPoint, MultiPolygon};
10use revision::revisioned;
11use serde::{Deserialize, Serialize};
12use std::cmp::Ordering;
13use std::iter::{once, FromIterator};
14use std::{fmt, hash};
15
16pub(crate) const TOKEN: &str = "$surrealdb::private::crate::Geometry";
17
18#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
19#[serde(rename = "$surrealdb::private::crate::Geometry")]
20#[revisioned(revision = 1)]
21pub enum Geometry {
22	Point(Point<f64>),
23	Line(LineString<f64>),
24	Polygon(Polygon<f64>),
25	MultiPoint(MultiPoint<f64>),
26	MultiLine(MultiLineString<f64>),
27	MultiPolygon(MultiPolygon<f64>),
28	Collection(Vec<Geometry>),
29	// Add new variants here
30}
31
32impl Geometry {
33	/// Check if this is a Point
34	pub fn is_point(&self) -> bool {
35		matches!(self, Self::Point(_))
36	}
37	/// Check if this is a Line
38	pub fn is_line(&self) -> bool {
39		matches!(self, Self::Line(_))
40	}
41	/// Check if this is a Polygon
42	pub fn is_polygon(&self) -> bool {
43		matches!(self, Self::Polygon(_))
44	}
45	/// Check if this is a MultiPoint
46	pub fn is_multipoint(&self) -> bool {
47		matches!(self, Self::MultiPoint(_))
48	}
49	/// Check if this is a MultiLine
50	pub fn is_multiline(&self) -> bool {
51		matches!(self, Self::MultiLine(_))
52	}
53	/// Check if this is a MultiPolygon
54	pub fn is_multipolygon(&self) -> bool {
55		matches!(self, Self::MultiPolygon(_))
56	}
57	/// Check if this is not a Collection
58	pub fn is_geometry(&self) -> bool {
59		!matches!(self, Self::Collection(_))
60	}
61	/// Check if this is a Collection
62	pub fn is_collection(&self) -> bool {
63		matches!(self, Self::Collection(_))
64	}
65	/// Get the type of this Geometry as text
66	pub fn as_type(&self) -> &'static str {
67		match self {
68			Self::Point(_) => "Point",
69			Self::Line(_) => "LineString",
70			Self::Polygon(_) => "Polygon",
71			Self::MultiPoint(_) => "MultiPoint",
72			Self::MultiLine(_) => "MultiLineString",
73			Self::MultiPolygon(_) => "MultiPolygon",
74			Self::Collection(_) => "GeometryCollection",
75		}
76	}
77	/// Get the raw coordinates of this Geometry as an Array
78	pub fn as_coordinates(&self) -> Value {
79		fn point(v: &Point) -> Value {
80			Array::from(vec![v.x(), v.y()]).into()
81		}
82
83		fn line(v: &LineString) -> Value {
84			v.points().map(|v| point(&v)).collect::<Vec<Value>>().into()
85		}
86
87		fn polygon(v: &Polygon) -> Value {
88			once(v.exterior()).chain(v.interiors()).map(line).collect::<Vec<Value>>().into()
89		}
90
91		fn multipoint(v: &MultiPoint) -> Value {
92			v.iter().map(point).collect::<Vec<Value>>().into()
93		}
94
95		fn multiline(v: &MultiLineString) -> Value {
96			v.iter().map(line).collect::<Vec<Value>>().into()
97		}
98
99		fn multipolygon(v: &MultiPolygon) -> Value {
100			v.iter().map(polygon).collect::<Vec<Value>>().into()
101		}
102
103		fn collection(v: &[Geometry]) -> Value {
104			v.iter().map(Geometry::as_coordinates).collect::<Vec<Value>>().into()
105		}
106
107		match self {
108			Self::Point(v) => point(v),
109			Self::Line(v) => line(v),
110			Self::Polygon(v) => polygon(v),
111			Self::MultiPoint(v) => multipoint(v),
112			Self::MultiLine(v) => multiline(v),
113			Self::MultiPolygon(v) => multipolygon(v),
114			Self::Collection(v) => collection(v),
115		}
116	}
117}
118
119impl PartialOrd for Geometry {
120	#[rustfmt::skip]
121	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
122		fn coord(v: &Coord) -> (f64, f64) {
123			v.x_y()
124		}
125
126		fn point(v: &Point) -> (f64, f64) {
127			coord(&v.0)
128		}
129
130		fn line(v: &LineString) -> impl Iterator<Item = (f64, f64)> + '_ {
131			v.into_iter().map(coord)
132		}
133
134		fn polygon(v: &Polygon) -> impl Iterator<Item = (f64, f64)> + '_ {
135			v.interiors().iter().chain(once(v.exterior())).flat_map(line)
136		}
137
138		fn multipoint(v: &MultiPoint) -> impl Iterator<Item = (f64, f64)> + '_ {
139			v.iter().map(point)
140		}
141
142		fn multiline(v: &MultiLineString) -> impl Iterator<Item = (f64, f64)> + '_ {
143			v.iter().flat_map(line)
144		}
145
146		fn multipolygon(v: &MultiPolygon) -> impl Iterator<Item = (f64, f64)> + '_ {
147			v.iter().flat_map(polygon)
148		}
149
150		match (self, other) {
151			//
152			(Self::Point(_), Self::Line(_)) => Some(Ordering::Less),
153			(Self::Point(_), Self::Polygon(_)) => Some(Ordering::Less),
154			(Self::Point(_), Self::MultiPoint(_)) => Some(Ordering::Less),
155			(Self::Point(_), Self::MultiLine(_)) => Some(Ordering::Less),
156			(Self::Point(_), Self::MultiPolygon(_)) => Some(Ordering::Less),
157			(Self::Point(_), Self::Collection(_)) => Some(Ordering::Less),
158			//
159			(Self::Line(_), Self::Point(_)) => Some(Ordering::Greater),
160			(Self::Line(_), Self::Polygon(_)) => Some(Ordering::Less),
161			(Self::Line(_), Self::MultiPoint(_)) => Some(Ordering::Less),
162			(Self::Line(_), Self::MultiLine(_)) => Some(Ordering::Less),
163			(Self::Line(_), Self::MultiPolygon(_)) => Some(Ordering::Less),
164			(Self::Line(_), Self::Collection(_)) => Some(Ordering::Less),
165			//
166			(Self::Polygon(_), Self::Point(_)) => Some(Ordering::Greater),
167			(Self::Polygon(_), Self::Line(_)) => Some(Ordering::Greater),
168			(Self::Polygon(_), Self::MultiPoint(_)) => Some(Ordering::Less),
169			(Self::Polygon(_), Self::MultiLine(_)) => Some(Ordering::Less),
170			(Self::Polygon(_), Self::MultiPolygon(_)) => Some(Ordering::Less),
171			(Self::Polygon(_), Self::Collection(_)) => Some(Ordering::Less),
172			//
173			(Self::MultiPoint(_), Self::Point(_)) => Some(Ordering::Greater),
174			(Self::MultiPoint(_), Self::Line(_)) => Some(Ordering::Greater),
175			(Self::MultiPoint(_), Self::Polygon(_)) => Some(Ordering::Greater),
176			(Self::MultiPoint(_), Self::MultiLine(_)) => Some(Ordering::Less),
177			(Self::MultiPoint(_), Self::MultiPolygon(_)) => Some(Ordering::Less),
178			(Self::MultiPoint(_), Self::Collection(_)) => Some(Ordering::Less),
179			//
180			(Self::MultiLine(_), Self::Point(_)) => Some(Ordering::Greater),
181			(Self::MultiLine(_), Self::Line(_)) => Some(Ordering::Greater),
182			(Self::MultiLine(_), Self::Polygon(_)) => Some(Ordering::Greater),
183			(Self::MultiLine(_), Self::MultiPoint(_)) => Some(Ordering::Greater),
184			(Self::MultiLine(_), Self::MultiPolygon(_)) => Some(Ordering::Less),
185			(Self::MultiLine(_), Self::Collection(_)) => Some(Ordering::Less),
186			//
187			(Self::MultiPolygon(_), Self::Point(_)) => Some(Ordering::Greater),
188			(Self::MultiPolygon(_), Self::Line(_)) => Some(Ordering::Greater),
189			(Self::MultiPolygon(_), Self::Polygon(_)) => Some(Ordering::Greater),
190			(Self::MultiPolygon(_), Self::MultiPoint(_)) => Some(Ordering::Greater),
191			(Self::MultiPolygon(_), Self::MultiLine(_)) => Some(Ordering::Greater),
192			(Self::MultiPolygon(_), Self::Collection(_)) => Some(Ordering::Less),
193			//
194			(Self::Collection(_), Self::Point(_)) => Some(Ordering::Greater),
195			(Self::Collection(_), Self::Line(_)) => Some(Ordering::Greater),
196			(Self::Collection(_), Self::Polygon(_)) => Some(Ordering::Greater),
197			(Self::Collection(_), Self::MultiPoint(_)) => Some(Ordering::Greater),
198			(Self::Collection(_), Self::MultiLine(_)) => Some(Ordering::Greater),
199			(Self::Collection(_), Self::MultiPolygon(_)) => Some(Ordering::Greater),
200			//
201			(Self::Point(a), Self::Point(b)) => point(a).partial_cmp(&point(b)),
202			(Self::Line(a), Self::Line(b)) => line(a).partial_cmp(line(b)),
203			(Self::Polygon(a), Self::Polygon(b)) => polygon(a).partial_cmp(polygon(b)),
204			(Self::MultiPoint(a), Self::MultiPoint(b)) => multipoint(a).partial_cmp(multipoint(b)),
205			(Self::MultiLine(a), Self::MultiLine(b)) => multiline(a).partial_cmp(multiline(b)),
206			(Self::MultiPolygon(a), Self::MultiPolygon(b)) => multipolygon(a).partial_cmp(multipolygon(b)),
207			(Self::Collection(a), Self::Collection(b)) => a.partial_cmp(b),
208		}
209	}
210}
211
212impl From<(f64, f64)> for Geometry {
213	fn from(v: (f64, f64)) -> Self {
214		Self::Point(v.into())
215	}
216}
217
218impl From<[f64; 2]> for Geometry {
219	fn from(v: [f64; 2]) -> Self {
220		Self::Point(v.into())
221	}
222}
223
224impl From<Point<f64>> for Geometry {
225	fn from(v: Point<f64>) -> Self {
226		Self::Point(v)
227	}
228}
229
230impl From<LineString<f64>> for Geometry {
231	fn from(v: LineString<f64>) -> Self {
232		Self::Line(v)
233	}
234}
235
236impl From<Polygon<f64>> for Geometry {
237	fn from(v: Polygon<f64>) -> Self {
238		Self::Polygon(v)
239	}
240}
241
242impl From<MultiPoint<f64>> for Geometry {
243	fn from(v: MultiPoint<f64>) -> Self {
244		Self::MultiPoint(v)
245	}
246}
247
248impl From<MultiLineString<f64>> for Geometry {
249	fn from(v: MultiLineString<f64>) -> Self {
250		Self::MultiLine(v)
251	}
252}
253
254impl From<MultiPolygon<f64>> for Geometry {
255	fn from(v: MultiPolygon<f64>) -> Self {
256		Self::MultiPolygon(v)
257	}
258}
259
260impl From<Vec<Geometry>> for Geometry {
261	fn from(v: Vec<Geometry>) -> Self {
262		Self::Collection(v)
263	}
264}
265
266impl From<Vec<Point<f64>>> for Geometry {
267	fn from(v: Vec<Point<f64>>) -> Self {
268		Self::MultiPoint(MultiPoint(v))
269	}
270}
271
272impl From<Vec<LineString<f64>>> for Geometry {
273	fn from(v: Vec<LineString<f64>>) -> Self {
274		Self::MultiLine(MultiLineString(v))
275	}
276}
277
278impl From<Vec<Polygon<f64>>> for Geometry {
279	fn from(v: Vec<Polygon<f64>>) -> Self {
280		Self::MultiPolygon(MultiPolygon(v))
281	}
282}
283
284impl From<Geometry> for geo::Geometry<f64> {
285	fn from(v: Geometry) -> Self {
286		match v {
287			Geometry::Point(v) => v.into(),
288			Geometry::Line(v) => v.into(),
289			Geometry::Polygon(v) => v.into(),
290			Geometry::MultiPoint(v) => v.into(),
291			Geometry::MultiLine(v) => v.into(),
292			Geometry::MultiPolygon(v) => v.into(),
293			Geometry::Collection(v) => v.into_iter().collect::<geo::Geometry<f64>>(),
294		}
295	}
296}
297
298impl FromIterator<Geometry> for geo::Geometry<f64> {
299	fn from_iter<I: IntoIterator<Item = Geometry>>(iter: I) -> Self {
300		let mut c: Vec<geo::Geometry<f64>> = vec![];
301		for i in iter {
302			c.push(i.into())
303		}
304		geo::Geometry::GeometryCollection(geo::GeometryCollection(c))
305	}
306}
307
308impl Geometry {
309	// -----------------------------------
310	// Value operations
311	// -----------------------------------
312
313	pub fn contains(&self, other: &Self) -> bool {
314		match self {
315			Self::Point(v) => match other {
316				Self::Point(w) => v.contains(w),
317				Self::MultiPoint(w) => w.iter().all(|x| v.contains(x)),
318				Self::Collection(w) => w.iter().all(|x| self.contains(x)),
319				_ => false,
320			},
321			Self::Line(v) => match other {
322				Self::Point(w) => v.contains(w),
323				Self::Line(w) => v.contains(w),
324				Self::MultiLine(w) => w.iter().all(|x| w.contains(x)),
325				Self::Collection(w) => w.iter().all(|x| self.contains(x)),
326				_ => false,
327			},
328			Self::Polygon(v) => match other {
329				Self::Point(w) => v.contains(w),
330				Self::Line(w) => v.contains(w),
331				Self::Polygon(w) => v.contains(w),
332				Self::MultiPolygon(w) => w.iter().all(|x| w.contains(x)),
333				Self::Collection(w) => w.iter().all(|x| self.contains(x)),
334				_ => false,
335			},
336			Self::MultiPoint(v) => match other {
337				Self::Point(w) => v.contains(w),
338				Self::MultiPoint(w) => w.iter().all(|x| w.contains(x)),
339				Self::Collection(w) => w.iter().all(|x| self.contains(x)),
340				_ => false,
341			},
342			Self::MultiLine(v) => match other {
343				Self::Point(w) => v.contains(w),
344				Self::Line(w) => v.contains(w),
345				Self::MultiLine(w) => w.iter().all(|x| w.contains(x)),
346				Self::Collection(w) => w.iter().all(|x| self.contains(x)),
347				_ => false,
348			},
349			Self::MultiPolygon(v) => match other {
350				Self::Point(w) => v.contains(w),
351				Self::Line(w) => v.contains(w),
352				Self::Polygon(w) => v.contains(w),
353				Self::MultiPoint(w) => v.contains(w),
354				Self::MultiLine(w) => v.contains(w),
355				Self::MultiPolygon(w) => v.contains(w),
356				Self::Collection(w) => w.iter().all(|x| self.contains(x)),
357			},
358			Self::Collection(v) => v.iter().all(|x| x.contains(other)),
359		}
360	}
361
362	pub fn intersects(&self, other: &Self) -> bool {
363		match self {
364			Self::Point(v) => match other {
365				Self::Point(w) => v.intersects(w),
366				Self::Line(w) => v.intersects(w),
367				Self::Polygon(w) => v.intersects(w),
368				Self::MultiPoint(w) => v.intersects(w),
369				Self::MultiLine(w) => w.iter().any(|x| v.intersects(x)),
370				Self::MultiPolygon(w) => v.intersects(w),
371				Self::Collection(w) => w.iter().all(|x| self.intersects(x)),
372			},
373			Self::Line(v) => match other {
374				Self::Point(w) => v.intersects(w),
375				Self::Line(w) => v.intersects(w),
376				Self::Polygon(w) => v.intersects(w),
377				Self::MultiPoint(w) => v.intersects(w),
378				Self::MultiLine(w) => w.iter().any(|x| v.intersects(x)),
379				Self::MultiPolygon(w) => v.intersects(w),
380				Self::Collection(w) => w.iter().all(|x| self.intersects(x)),
381			},
382			Self::Polygon(v) => match other {
383				Self::Point(w) => v.intersects(w),
384				Self::Line(w) => v.intersects(w),
385				Self::Polygon(w) => v.intersects(w),
386				Self::MultiPoint(w) => v.intersects(w),
387				Self::MultiLine(w) => v.intersects(w),
388				Self::MultiPolygon(w) => v.intersects(w),
389				Self::Collection(w) => w.iter().all(|x| self.intersects(x)),
390			},
391			Self::MultiPoint(v) => match other {
392				Self::Point(w) => v.intersects(w),
393				Self::Line(w) => v.intersects(w),
394				Self::Polygon(w) => v.intersects(w),
395				Self::MultiPoint(w) => v.intersects(w),
396				Self::MultiLine(w) => w.iter().any(|x| v.intersects(x)),
397				Self::MultiPolygon(w) => v.intersects(w),
398				Self::Collection(w) => w.iter().all(|x| self.intersects(x)),
399			},
400			Self::MultiLine(v) => match other {
401				Self::Point(w) => v.intersects(w),
402				Self::Line(w) => v.intersects(w),
403				Self::Polygon(w) => v.intersects(w),
404				Self::MultiPoint(w) => v.intersects(w),
405				Self::MultiLine(w) => w.iter().any(|x| v.intersects(x)),
406				Self::MultiPolygon(w) => v.intersects(w),
407				Self::Collection(w) => w.iter().all(|x| self.intersects(x)),
408			},
409			Self::MultiPolygon(v) => match other {
410				Self::Point(w) => v.intersects(w),
411				Self::Line(w) => v.intersects(w),
412				Self::Polygon(w) => v.intersects(w),
413				Self::MultiPoint(w) => v.intersects(w),
414				Self::MultiLine(w) => v.intersects(w),
415				Self::MultiPolygon(w) => v.intersects(w),
416				Self::Collection(w) => w.iter().all(|x| self.intersects(x)),
417			},
418			Self::Collection(v) => v.iter().all(|x| x.intersects(other)),
419		}
420	}
421}
422
423impl fmt::Display for Geometry {
424	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
425		match self {
426			Self::Point(v) => {
427				write!(f, "({}, {})", v.x(), v.y())
428			}
429			Self::Line(v) => write!(
430				f,
431				"{{ type: 'LineString', coordinates: [{}] }}",
432				Fmt::comma_separated(v.points().map(|v| Fmt::new(v, |v, f| write!(
433					f,
434					"[{}, {}]",
435					v.x(),
436					v.y()
437				))))
438			),
439			Self::Polygon(v) => write!(
440				f,
441				"{{ type: 'Polygon', coordinates: [[{}]{}] }}",
442				Fmt::comma_separated(v.exterior().points().map(|v| Fmt::new(v, |v, f| write!(
443					f,
444					"[{}, {}]",
445					v.x(),
446					v.y()
447				)))),
448				Fmt::new(v.interiors(), |interiors, f| {
449					match interiors.len() {
450						0 => Ok(()),
451						_ => write!(
452							f,
453							", [{}]",
454							Fmt::comma_separated(interiors.iter().map(|i| Fmt::new(i, |i, f| {
455								write!(
456									f,
457									"[{}]",
458									Fmt::comma_separated(i.points().map(|v| Fmt::new(
459										v,
460										|v, f| write!(f, "[{}, {}]", v.x(), v.y())
461									)))
462								)
463							})))
464						),
465					}
466				})
467			),
468			Self::MultiPoint(v) => {
469				write!(
470					f,
471					"{{ type: 'MultiPoint', coordinates: [{}] }}",
472					Fmt::comma_separated(v.iter().map(|v| Fmt::new(v, |v, f| write!(
473						f,
474						"[{}, {}]",
475						v.x(),
476						v.y()
477					))))
478				)
479			}
480			Self::MultiLine(v) => write!(
481				f,
482				"{{ type: 'MultiLineString', coordinates: [{}] }}",
483				Fmt::comma_separated(v.iter().map(|v| Fmt::new(v, |v, f| write!(
484					f,
485					"[{}]",
486					Fmt::comma_separated(v.points().map(|v| Fmt::new(v, |v, f| write!(
487						f,
488						"[{}, {}]",
489						v.x(),
490						v.y()
491					))))
492				))))
493			),
494			Self::MultiPolygon(v) => write!(
495				f,
496				"{{ type: 'MultiPolygon', coordinates: [{}] }}",
497				Fmt::comma_separated(v.iter().map(|v| Fmt::new(v, |v, f| {
498					write!(
499						f,
500						"[[{}]{}]",
501						Fmt::comma_separated(
502							v.exterior().points().map(|v| Fmt::new(v, |v, f| write!(
503								f,
504								"[{}, {}]",
505								v.x(),
506								v.y()
507							)))
508						),
509						Fmt::new(v.interiors(), |interiors, f| {
510							match interiors.len() {
511								0 => Ok(()),
512								_ => write!(
513									f,
514									", [{}]",
515									Fmt::comma_separated(interiors.iter().map(|i| Fmt::new(
516										i,
517										|i, f| {
518											write!(
519												f,
520												"[{}]",
521												Fmt::comma_separated(i.points().map(|v| Fmt::new(
522													v,
523													|v, f| write!(f, "[{}, {}]", v.x(), v.y())
524												)))
525											)
526										}
527									)))
528								),
529							}
530						})
531					)
532				}))),
533			),
534			Self::Collection(v) => {
535				write!(
536					f,
537					"{{ type: 'GeometryCollection', geometries: [{}] }}",
538					Fmt::comma_separated(v)
539				)
540			}
541		}
542	}
543}
544
545impl hash::Hash for Geometry {
546	fn hash<H: hash::Hasher>(&self, state: &mut H) {
547		match self {
548			Geometry::Point(p) => {
549				"Point".hash(state);
550				p.x().to_bits().hash(state);
551				p.y().to_bits().hash(state);
552			}
553			Geometry::Line(l) => {
554				"Line".hash(state);
555				l.points().for_each(|v| {
556					v.x().to_bits().hash(state);
557					v.y().to_bits().hash(state);
558				});
559			}
560			Geometry::Polygon(p) => {
561				"Polygon".hash(state);
562				p.exterior().points().for_each(|ext| {
563					ext.x().to_bits().hash(state);
564					ext.y().to_bits().hash(state);
565				});
566				p.interiors().iter().for_each(|int| {
567					int.points().for_each(|v| {
568						v.x().to_bits().hash(state);
569						v.y().to_bits().hash(state);
570					});
571				});
572			}
573			Geometry::MultiPoint(v) => {
574				"MultiPoint".hash(state);
575				v.0.iter().for_each(|v| {
576					v.x().to_bits().hash(state);
577					v.y().to_bits().hash(state);
578				});
579			}
580			Geometry::MultiLine(ml) => {
581				"MultiLine".hash(state);
582				ml.0.iter().for_each(|ls| {
583					ls.points().for_each(|p| {
584						p.x().to_bits().hash(state);
585						p.y().to_bits().hash(state);
586					});
587				});
588			}
589			Geometry::MultiPolygon(mp) => {
590				"MultiPolygon".hash(state);
591				mp.0.iter().for_each(|p| {
592					p.exterior().points().for_each(|ext| {
593						ext.x().to_bits().hash(state);
594						ext.y().to_bits().hash(state);
595					});
596					p.interiors().iter().for_each(|int| {
597						int.points().for_each(|v| {
598							v.x().to_bits().hash(state);
599							v.y().to_bits().hash(state);
600						});
601					});
602				});
603			}
604			Geometry::Collection(v) => {
605				"GeometryCollection".hash(state);
606				v.iter().for_each(|v| v.hash(state));
607			}
608		}
609	}
610}