use crate::geo_types::{self, CoordFloat};
use crate::geo_types::{
Geometry as GtGeometry, GeometryCollection, LineString as GtLineString,
MultiLineString as GtMultiLineString, MultiPoint as GtMultiPoint,
MultiPolygon as GtMultiPolygon, Point as GtPoint, Polygon as GtPolygon,
};
use crate::geojson::GeoJson;
use crate::geojson::GeoJson::{Feature, FeatureCollection, Geometry};
use crate::geometry::Geometry as GjGeometry;
use crate::Error as GJError;
use crate::Value;
use std::convert::TryInto;
#[cfg(test)]
macro_rules! assert_almost_eq {
($x:expr, $y:expr, $epsilon:expr) => {{
use num_traits::Zero;
let a = $x.abs();
let b = $y.abs();
let delta = (a - b).abs();
if a.is_infinite() || a.is_nan() || b.is_infinite() || b.is_nan() {
panic!(
"Assertion failed: Non comparable value ({} = {}, {} = {})",
stringify!($x),
$x,
stringify!($y),
$y
);
} else if a.is_zero() || b.is_zero() {
if delta > $epsilon {
panic!(
"Assertion failed: ({} = {}, {} = {}, delta = {})",
stringify!($x),
$x,
stringify!($y),
$y,
delta / b
);
}
} else {
let normalized_delta = delta / b;
if normalized_delta > $epsilon {
panic!(
"Assertion failed: ({} = {}, {} = {}, delta = {})",
stringify!($x),
$x,
stringify!($y),
$y,
normalized_delta
);
}
}
}};
}
pub(crate) mod from_geo_types;
pub(crate) mod to_geo_types;
fn process_geojson<T>(gj: &GeoJson) -> Result<geo_types::GeometryCollection<T>, GJError>
where
T: CoordFloat,
{
match &*gj {
FeatureCollection(collection) => Ok(GeometryCollection(
collection
.features
.iter()
.filter_map(|feature| feature.geometry.as_ref())
.map(|geometry| process_geometry(&geometry))
.collect::<Result<_, _>>()?,
)),
Feature(feature) => {
if let Some(geometry) = &feature.geometry {
Ok(GeometryCollection(vec![process_geometry(&geometry)?]))
} else {
Ok(GeometryCollection(vec![]))
}
}
Geometry(geometry) => Ok(GeometryCollection(vec![process_geometry(&geometry)?])),
}
}
fn process_geometry<T>(geometry: &GjGeometry) -> Result<geo_types::Geometry<T>, GJError>
where
T: CoordFloat,
{
match &geometry.value {
Value::Point(_) => Ok(TryInto::<GtPoint<_>>::try_into(geometry.value.clone())?.into()),
Value::MultiPoint(_) => {
Ok(TryInto::<GtMultiPoint<_>>::try_into(geometry.value.clone())?.into())
}
Value::LineString(_) => {
Ok(TryInto::<GtLineString<_>>::try_into(geometry.value.clone())?.into())
}
Value::MultiLineString(_) => {
Ok(TryInto::<GtMultiLineString<_>>::try_into(geometry.value.clone())?.into())
}
Value::Polygon(_) => Ok(TryInto::<GtPolygon<_>>::try_into(geometry.value.clone())?.into()),
Value::MultiPolygon(_) => {
Ok(TryInto::<GtMultiPolygon<_>>::try_into(geometry.value.clone())?.into())
}
Value::GeometryCollection(gc) => {
let gc = GtGeometry::GeometryCollection(GeometryCollection(
gc.iter()
.map(|geom| process_geometry(&geom))
.collect::<Result<Vec<geo_types::Geometry<T>>, GJError>>()?,
));
Ok(gc)
}
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
pub fn quick_collection<T>(gj: &GeoJson) -> Result<geo_types::GeometryCollection<T>, GJError>
where
T: CoordFloat,
{
process_geojson(gj)
}