use alloc::vec::Vec;
use geo_types::{Coord, CoordNum, Geometry as GtGeometry, LineString};
use geometry_coords::CoordinateScalar;
use geometry_cs::Cartesian;
use geometry_model::{
DynGeometry, Linestring, MultiLinestring, MultiPoint, MultiPolygon, Point2D, Polygon, Ring,
};
type KernelPoint<T> = Point2D<T, Cartesian>;
#[inline]
fn coord_to_point<T: CoordinateScalar + CoordNum>(c: Coord<T>) -> KernelPoint<T> {
Point2D::new(c.x, c.y)
}
#[inline]
fn point_to_coord<T: CoordinateScalar + CoordNum>(p: &KernelPoint<T>) -> Coord<T> {
use geometry_trait::Point as _;
Coord {
x: p.get::<0>(),
y: p.get::<1>(),
}
}
#[inline]
fn line_string_to_kernel<T: CoordinateScalar + CoordNum>(
ls: LineString<T>,
) -> Linestring<KernelPoint<T>> {
Linestring::from_vec(ls.0.into_iter().map(coord_to_point).collect())
}
#[inline]
fn line_string_to_ring<T: CoordinateScalar + CoordNum>(ls: LineString<T>) -> Ring<KernelPoint<T>> {
Ring::from_vec(ls.0.into_iter().map(coord_to_point).collect())
}
#[inline]
fn kernel_to_line_string<T: CoordinateScalar + CoordNum>(
ls: &Linestring<KernelPoint<T>>,
) -> LineString<T> {
LineString(ls.0.iter().map(point_to_coord).collect())
}
#[inline]
fn ring_to_line_string<T: CoordinateScalar + CoordNum>(r: &Ring<KernelPoint<T>>) -> LineString<T> {
LineString(r.0.iter().map(point_to_coord).collect())
}
#[inline]
fn polygon_to_kernel<T: CoordinateScalar + CoordNum>(
p: geo_types::Polygon<T>,
) -> Polygon<KernelPoint<T>> {
let (exterior, interiors) = p.into_inner();
let inners: Vec<_> = interiors.into_iter().map(line_string_to_ring).collect();
Polygon::with_inners(line_string_to_ring(exterior), inners)
}
#[inline]
fn kernel_to_polygon<T: CoordinateScalar + CoordNum>(
p: &Polygon<KernelPoint<T>>,
) -> geo_types::Polygon<T> {
let exterior = ring_to_line_string(&p.outer);
let interiors: Vec<_> = p.inners.iter().map(ring_to_line_string).collect();
geo_types::Polygon::new(exterior, interiors)
}
#[must_use]
pub fn to_dyn_geometry<T: CoordinateScalar + CoordNum>(
g: GtGeometry<T>,
) -> DynGeometry<T, Cartesian> {
match g {
GtGeometry::Point(p) => DynGeometry::Point(coord_to_point(p.0)),
GtGeometry::Line(l) => DynGeometry::LineString(Linestring::from_vec(vec![
coord_to_point(l.start),
coord_to_point(l.end),
])),
GtGeometry::LineString(ls) => DynGeometry::LineString(line_string_to_kernel(ls)),
GtGeometry::Polygon(p) => DynGeometry::Polygon(polygon_to_kernel(p)),
GtGeometry::MultiPoint(mp) => DynGeometry::MultiPoint(MultiPoint::from_vec(
mp.0.into_iter().map(|p| coord_to_point(p.0)).collect(),
)),
GtGeometry::MultiLineString(mls) => DynGeometry::MultiLineString(
MultiLinestring::from_vec(mls.0.into_iter().map(line_string_to_kernel).collect()),
),
GtGeometry::MultiPolygon(mpg) => DynGeometry::MultiPolygon(MultiPolygon::from_vec(
mpg.0.into_iter().map(polygon_to_kernel).collect(),
)),
GtGeometry::GeometryCollection(gc) => {
DynGeometry::GeometryCollection(gc.0.into_iter().map(to_dyn_geometry).collect())
}
GtGeometry::Rect(r) => DynGeometry::Polygon(polygon_to_kernel(r.to_polygon())),
GtGeometry::Triangle(t) => DynGeometry::Polygon(polygon_to_kernel(t.to_polygon())),
}
}
#[must_use]
pub fn from_dyn_geometry<T: CoordinateScalar + CoordNum>(
g: DynGeometry<T, Cartesian>,
) -> GtGeometry<T> {
match g {
DynGeometry::Point(p) => GtGeometry::Point(geo_types::Point(point_to_coord(&p))),
DynGeometry::LineString(ls) => GtGeometry::LineString(kernel_to_line_string(&ls)),
DynGeometry::Polygon(p) => GtGeometry::Polygon(kernel_to_polygon(&p)),
DynGeometry::MultiPoint(mp) => GtGeometry::MultiPoint(geo_types::MultiPoint(
mp.0.iter()
.map(|p| geo_types::Point(point_to_coord(p)))
.collect(),
)),
DynGeometry::MultiLineString(mls) => GtGeometry::MultiLineString(
geo_types::MultiLineString::new(mls.0.iter().map(kernel_to_line_string).collect()),
),
DynGeometry::MultiPolygon(mpg) => GtGeometry::MultiPolygon(geo_types::MultiPolygon::new(
mpg.0.iter().map(kernel_to_polygon).collect(),
)),
DynGeometry::GeometryCollection(gc) => GtGeometry::GeometryCollection(
geo_types::GeometryCollection(gc.into_iter().map(from_dyn_geometry).collect()),
),
}
}