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