// Ported from georust/geo-types
// https://github.com/georust/geo/blob/main/geo-types/src/geometry/mod.rs (the
// `Geometry` enum) and adapted to MoonBit's enum syntax.
///|
/// An enumeration of all geometry types except `Coord` (which is not itself a
/// "geometry" in the OGC sense).
pub(all) enum Geometry {
Point(Point)
Line(Line)
LineString(LineString)
Polygon(Polygon)
MultiPoint(MultiPoint)
MultiLineString(MultiLineString)
MultiPolygon(MultiPolygon)
GeometryCollection(GeometryCollection)
Rect(Rect)
Triangle(Triangle)
} derive(Eq, Debug)
///|
/// Raised by `Geometry::try_into_*` when the variant does not match the
/// expected one. Carries both the expected variant name and the actual
/// variant name observed, matching the upstream Rust `MismatchedGeometry`
/// error.
pub suberror MismatchedGeometry {
MismatchedGeometry(expected~ : String, found~ : String)
} derive(Eq, Debug)
///|
/// Returns the variant name of the given geometry, used in error messages.
fn Geometry::variant_name(self : Geometry) -> String {
match self {
Point(_) => "Point"
Line(_) => "Line"
LineString(_) => "LineString"
Polygon(_) => "Polygon"
MultiPoint(_) => "MultiPoint"
MultiLineString(_) => "MultiLineString"
MultiPolygon(_) => "MultiPolygon"
GeometryCollection(_) => "GeometryCollection"
Rect(_) => "Rect"
Triangle(_) => "Triangle"
}
}
///|
/// If `self` is the `Point` variant, returns the inner `Point`. Otherwise
/// raises `MismatchedGeometry` with the expected / actual variant names.
/// Mirrors Rust upstream `TryFrom for Point` (`g.try_into()`).
pub fn Geometry::try_into_point(
self : Geometry,
) -> Point raise MismatchedGeometry {
match self {
Point(p) => p
other =>
raise MismatchedGeometry(expected="Point", found=other.variant_name())
}
}
///|
pub fn Geometry::try_into_line(
self : Geometry,
) -> Line raise MismatchedGeometry {
match self {
Line(l) => l
other =>
raise MismatchedGeometry(expected="Line", found=other.variant_name())
}
}
///|
pub fn Geometry::try_into_line_string(
self : Geometry,
) -> LineString raise MismatchedGeometry {
match self {
LineString(ls) => ls
other =>
raise MismatchedGeometry(
expected="LineString",
found=other.variant_name(),
)
}
}
///|
pub fn Geometry::try_into_polygon(
self : Geometry,
) -> Polygon raise MismatchedGeometry {
match self {
Polygon(p) => p
other =>
raise MismatchedGeometry(expected="Polygon", found=other.variant_name())
}
}
///|
pub fn Geometry::try_into_multi_point(
self : Geometry,
) -> MultiPoint raise MismatchedGeometry {
match self {
MultiPoint(mp) => mp
other =>
raise MismatchedGeometry(
expected="MultiPoint",
found=other.variant_name(),
)
}
}
///|
pub fn Geometry::try_into_multi_line_string(
self : Geometry,
) -> MultiLineString raise MismatchedGeometry {
match self {
MultiLineString(mls) => mls
other =>
raise MismatchedGeometry(
expected="MultiLineString",
found=other.variant_name(),
)
}
}
///|
pub fn Geometry::try_into_multi_polygon(
self : Geometry,
) -> MultiPolygon raise MismatchedGeometry {
match self {
MultiPolygon(mp) => mp
other =>
raise MismatchedGeometry(
expected="MultiPolygon",
found=other.variant_name(),
)
}
}
///|
/// Unlike the Rust upstream — which excludes `GeometryCollection` from its
/// `try_from_geometry_impl!` macro to avoid clashing with a deprecated
/// `From for GeometryCollection` impl — the port has no such
/// deprecated conversion, so the symmetry is preserved here.
pub fn Geometry::try_into_geometry_collection(
self : Geometry,
) -> GeometryCollection raise MismatchedGeometry {
match self {
GeometryCollection(gc) => gc
other =>
raise MismatchedGeometry(
expected="GeometryCollection",
found=other.variant_name(),
)
}
}
///|
pub fn Geometry::try_into_rect(
self : Geometry,
) -> Rect raise MismatchedGeometry {
match self {
Rect(r) => r
other =>
raise MismatchedGeometry(expected="Rect", found=other.variant_name())
}
}
///|
pub fn Geometry::try_into_triangle(
self : Geometry,
) -> Triangle raise MismatchedGeometry {
match self {
Triangle(t) => t
other =>
raise MismatchedGeometry(expected="Triangle", found=other.variant_name())
}
}
///|
/// Returns whether this geometry has no coordinates. Single-point and
/// single-segment geometries (Point, Line, Rect, Triangle) are never empty.
/// Collections are empty when **all** of their components are empty.
pub impl IsEmpty for Geometry with fn is_empty(self) {
match self {
Point(_) | Line(_) | Rect(_) | Triangle(_) => false
LineString(ls) => ls.is_empty()
MultiPoint(mp) => mp.is_empty()
MultiLineString(mls) => mls.line_strings().iter().all(IsEmpty::is_empty)
Polygon(p) => p.exterior().is_empty()
MultiPolygon(mp) =>
mp.polygons().iter().all(fn(p) { p.exterior().is_empty() })
GeometryCollection(gc) => gc.geometries().iter().all(IsEmpty::is_empty)
}
}
///|
pub extend Geometry with IsEmpty::{is_empty}