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 }
31
32impl Geometry {
33 pub fn is_point(&self) -> bool {
35 matches!(self, Self::Point(_))
36 }
37 pub fn is_line(&self) -> bool {
39 matches!(self, Self::Line(_))
40 }
41 pub fn is_polygon(&self) -> bool {
43 matches!(self, Self::Polygon(_))
44 }
45 pub fn is_multipoint(&self) -> bool {
47 matches!(self, Self::MultiPoint(_))
48 }
49 pub fn is_multiline(&self) -> bool {
51 matches!(self, Self::MultiLine(_))
52 }
53 pub fn is_multipolygon(&self) -> bool {
55 matches!(self, Self::MultiPolygon(_))
56 }
57 pub fn is_geometry(&self) -> bool {
59 !matches!(self, Self::Collection(_))
60 }
61 pub fn is_collection(&self) -> bool {
63 matches!(self, Self::Collection(_))
64 }
65 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 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 (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 (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 (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 (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 (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 (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 (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 (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 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}