use super::TransformCoordinates;
use crate::proj::{
ALBERS_EQUAL_AREA, AZIMUTHAL_EQUIDISTANT, AiryProjection, AlbersConicEqualAreaProjection,
AxisSwapConverter, AzimuthalEquidistantProjection, BONNE, BaseProjection, BonneProjection,
CASSINI, CartesianConverter, CassiniProjection, EQUAL_EARTH, EQUIDISTANT_CONIC,
EQUIDISTANT_CYLINDRICAL, EckertVIProjection, EqualAreaCylindricalProjection,
EqualEarthProjection, EquidistantConicProjection, EquidistantCylindricalProjection,
ExtendedTransverseMercatorProjection, GaussSchreiberTransverseMercatorProjection,
GeneralSinusoidalSeriesProjection, GeocentricConverter, GeocentricLatitudeConverter,
GnomonicProjection, GoodeHomolosineProjection, HOTINE_OBLIQUE_MERCATOR_VARIANT_A,
HOTINE_OBLIQUE_MERCATOR_VARIANT_B, HotineObliqueMercatorVariantAProjection,
HotineObliqueMercatorVariantBProjection, KROVAK, KROVAK_MODIFIED,
KROVAK_MODIFIED_NORTH_ORIENTED, KROVAK_NORTH_ORIENTED, KrovakModifiedNorthOrientedProjection,
KrovakModifiedProjection, KrovakNorthOrientedProjection, KrovakProjection, LABORDE,
LAMBERT_AZIMUTHAL_EQUAL_AREA, LAMBERT_AZIMUTHAL_EQUAL_AREA_SPHERICAL,
LAMBERT_CONFORMAL_CONIC_1SP, LAMBERT_CONFORMAL_CONIC_2SP, LabordeProjection,
LambertAzimuthalEqualAreaProjection, LambertAzimuthalEqualAreaSphericalProjection,
LambertConformalConic1SPProjection, LambertConformalConic2SPProjection,
LambertConformalConicAlternativeProjection, LambertEqualAreaConicProjection, MERCATOR,
McBrydeThomasFlatPolarSinusoidalProjection, MercatorProjection, Method,
MillerCylindricalProjection, MollweideProjection, NewZealandMapGridProjection,
OBLIQUE_STEREOGRAPHIC, ORTHOGRAPHIC, OblatedEqualAreaProjection,
ObliqueCylindricalEqualAreaProjection, ObliqueStereographicAlternativeProjection,
OrthographicProjection, POLAR_STEREOGRAPHIC_VARIANT_A, POLAR_STEREOGRAPHIC_VARIANT_B,
POLAR_STEREOGRAPHIC_VARIANT_C, POLYCONIC, PolarStereographicVariantAProjection,
PolarStereographicVariantBProjection, PolarStereographicVariantCProjection,
PolyconicProjection, Proj, ProjectCoordinates, RobinsonProjection, SOMERC,
SinusoidalProjection, StereographicProjection, SwissOblMercatorProjection, TRANSVERSE_MERCATOR,
TRANSVERSE_MERCATOR_SOUTH_ORIENTATED, TransverseCentralCylindricalProjection,
TransverseCylindricalEqualArealProjection, TransverseMercatorProjection,
TransverseMercatorSouthOrientedProjection, UniversalTransverseMercatorProjection,
VanDerGrintenIProjection, WEB_MERCATOR, WagnerIVProjection, WagnerVProjection,
WebMercatorProjection,
};
use alloc::{boxed::Box, rc::Rc};
use core::cell::RefCell;
macro_rules! dispatch_step {
($self:ident, $point:ident, $method:ident, [ $($variant:ident),* ]) => {
match $self {
$(
Step::$variant(inner) => inner.$method($point),
)*
}
};
}
macro_rules! match_projections {
($name:expr, $proj:expr, [
$( ($variant:ident, $projection:ty) ),* $(,)?
]) => {{
$(
if <$projection>::names().contains(&$name) {
return Some(Step::$variant(Box::new(<$projection>::new($proj))));
}
)*
None
}};
}
macro_rules! match_ids {
($id:expr, $proj:expr, [
$( ($const_id:ident, $variant:ident, $projection:ty) ),* $(,)?
]) => {{
match $id {
$(
$const_id => Some(Step::$variant(Box::new(<$projection>::new($proj)))),
)*
_ => None,
}
}};
}
macro_rules! dispatch_name {
($self:ident, [ $($variant:ident),* ]) => {
match $self {
$(
Step::$variant(inner) => inner.name(),
)*
}
};
}
#[derive(Debug, Clone, PartialEq)]
pub enum Step {
AxisSwap(Box<AxisSwapConverter>),
Cartesian(Box<CartesianConverter>),
GeoLat(Box<GeocentricLatitudeConverter>),
Geocentric(Box<GeocentricConverter>),
Aea(Box<AlbersConicEqualAreaProjection>),
Aeqd(Box<AzimuthalEquidistantProjection>),
Airy(Box<AiryProjection>),
Base(Box<BaseProjection>),
Bonne(Box<BonneProjection>),
Cass(Box<CassiniProjection>),
Cea(Box<EqualAreaCylindricalProjection>),
Eck6(Box<EckertVIProjection>),
Eqc(Box<EquidistantCylindricalProjection>),
Eqdc(Box<EquidistantConicProjection>),
Eqearth(Box<EqualEarthProjection>),
Etmerc(Box<ExtendedTransverseMercatorProjection>),
GnSinu(Box<GeneralSinusoidalSeriesProjection>),
Gnom(Box<GnomonicProjection>),
Goode(Box<GoodeHomolosineProjection>),
Gstmerc(Box<GaussSchreiberTransverseMercatorProjection>),
HotineA(Box<HotineObliqueMercatorVariantAProjection>),
HotineB(Box<HotineObliqueMercatorVariantBProjection>),
Krovak(Box<KrovakProjection>),
KrovakNO(Box<KrovakNorthOrientedProjection>),
KrovakM(Box<KrovakModifiedProjection>),
KrovakMNO(Box<KrovakModifiedNorthOrientedProjection>),
Labrd(Box<LabordeProjection>),
Laea(Box<LambertAzimuthalEqualAreaProjection>),
LaeaS(Box<LambertAzimuthalEqualAreaSphericalProjection>),
Leac(Box<LambertEqualAreaConicProjection>),
Lcc1SP(Box<LambertConformalConic1SPProjection>),
Lcc2SP(Box<LambertConformalConic2SPProjection>),
LccA(Box<LambertConformalConicAlternativeProjection>),
MBTfps(Box<McBrydeThomasFlatPolarSinusoidalProjection>),
Merc(Box<MercatorProjection>),
Mill(Box<MillerCylindricalProjection>),
Moll(Box<MollweideProjection>),
Nzmg(Box<NewZealandMapGridProjection>),
Ocea(Box<ObliqueCylindricalEqualAreaProjection>),
Oea(Box<OblatedEqualAreaProjection>),
Ortho(Box<OrthographicProjection>),
PSterA(Box<PolarStereographicVariantAProjection>),
PSterB(Box<PolarStereographicVariantBProjection>),
PSterC(Box<PolarStereographicVariantCProjection>),
Poly(Box<PolyconicProjection>),
Robin(Box<RobinsonProjection>),
Sinu(Box<SinusoidalProjection>),
Somerc(Box<SwissOblMercatorProjection>),
Stere(Box<StereographicProjection>),
Sterea(Box<ObliqueStereographicAlternativeProjection>),
Tcc(Box<TransverseCentralCylindricalProjection>),
Tcea(Box<TransverseCylindricalEqualArealProjection>),
Tmerc(Box<TransverseMercatorProjection>),
TmercSO(Box<TransverseMercatorSouthOrientedProjection>),
Utm(Box<UniversalTransverseMercatorProjection>),
Vandg(Box<VanDerGrintenIProjection>),
WagIV(Box<WagnerIVProjection>),
WagV(Box<WagnerVProjection>),
WebMerc(Box<WebMercatorProjection>),
}
impl Step {
pub fn same_step(&self, other: &Step) -> bool {
self.name() == other.name()
}
pub fn name(&self) -> &str {
dispatch_name!(
self,
[
AxisSwap, Cartesian, GeoLat, Geocentric, Aea, Aeqd, Airy, Base, Bonne, Cass, Cea,
Eck6, Eqc, Eqdc, Eqearth, Etmerc, Gnom, GnSinu, Goode, Gstmerc, HotineA, HotineB,
Krovak, KrovakNO, KrovakM, KrovakMNO, Labrd, Laea, LaeaS, Leac, Lcc1SP, Lcc2SP,
LccA, MBTfps, Merc, Mill, Moll, Nzmg, Ocea, Oea, Ortho, PSterA, PSterB, PSterC,
Poly, Robin, Sinu, Somerc, Stere, Sterea, Tcc, Tcea, Tmerc, TmercSO, Utm, Vandg,
WagIV, WagV, WebMerc
]
)
}
pub fn forward<P: TransformCoordinates>(&self, point: &mut P) {
dispatch_step!(
self,
point,
forward,
[
AxisSwap, Cartesian, GeoLat, Geocentric, Aea, Aeqd, Airy, Base, Bonne, Cass, Cea,
Eck6, Eqc, Eqdc, Eqearth, Etmerc, Gnom, GnSinu, Goode, Gstmerc, HotineA, HotineB,
Krovak, KrovakNO, KrovakM, KrovakMNO, Labrd, Laea, LaeaS, Leac, Lcc1SP, Lcc2SP,
LccA, MBTfps, Merc, Mill, Moll, Nzmg, Ocea, Oea, Ortho, PSterA, PSterB, PSterC,
Poly, Robin, Sinu, Somerc, Stere, Sterea, Tcc, Tcea, Tmerc, TmercSO, Utm, Vandg,
WagIV, WagV, WebMerc
]
);
}
pub fn inverse<P: TransformCoordinates>(&self, point: &mut P) {
dispatch_step!(
self,
point,
inverse,
[
AxisSwap, Cartesian, GeoLat, Geocentric, Aea, Aeqd, Airy, Base, Bonne, Cass, Cea,
Eck6, Eqc, Eqdc, Eqearth, Etmerc, Gnom, GnSinu, Goode, Gstmerc, HotineA, HotineB,
Krovak, KrovakNO, KrovakM, KrovakMNO, Labrd, Laea, LaeaS, Leac, Lcc1SP, Lcc2SP,
LccA, MBTfps, Merc, Mill, Moll, Nzmg, Ocea, Oea, Ortho, PSterA, PSterB, PSterC,
Poly, Robin, Sinu, Somerc, Stere, Sterea, Tcc, Tcea, Tmerc, TmercSO, Utm, Vandg,
WagIV, WagV, WebMerc
]
);
}
pub fn from_method(method: &Method, proj: Rc<RefCell<Proj>>) -> Option<Step> {
if let Some(id) = method.id.as_ref()
&& let Some(step) = Step::from_id(id.code.i64(), proj.clone())
{
return Some(step);
}
for id in method.ids.iter() {
if let Some(step) = Step::from_id(id.code.i64(), proj.clone()) {
return Some(step);
}
}
Step::from_name(&method.name, proj)
}
pub fn from_id(id: i64, proj: Rc<RefCell<Proj>>) -> Option<Step> {
if id == 0 {
return Some(Step::Base(BaseProjection::new(proj).into()));
}
match_ids!(
id,
proj,
[
(ALBERS_EQUAL_AREA, Aea, AlbersConicEqualAreaProjection),
(AZIMUTHAL_EQUIDISTANT, Aeqd, AzimuthalEquidistantProjection),
(BONNE, Bonne, BonneProjection),
(CASSINI, Cass, CassiniProjection),
(EQUIDISTANT_CYLINDRICAL, Eqc, EquidistantCylindricalProjection),
(EQUIDISTANT_CONIC, Eqdc, EquidistantConicProjection),
(EQUAL_EARTH, Eqearth, EqualEarthProjection),
(
HOTINE_OBLIQUE_MERCATOR_VARIANT_A,
HotineA,
HotineObliqueMercatorVariantAProjection
),
(
HOTINE_OBLIQUE_MERCATOR_VARIANT_B,
HotineB,
HotineObliqueMercatorVariantBProjection
),
(KROVAK, Krovak, KrovakProjection),
(KROVAK_NORTH_ORIENTED, KrovakNO, KrovakNorthOrientedProjection),
(KROVAK_MODIFIED, KrovakM, KrovakModifiedProjection),
(KROVAK_MODIFIED_NORTH_ORIENTED, KrovakMNO, KrovakModifiedNorthOrientedProjection),
(LABORDE, Labrd, LabordeProjection),
(LAMBERT_AZIMUTHAL_EQUAL_AREA, Laea, LambertAzimuthalEqualAreaProjection),
(
LAMBERT_AZIMUTHAL_EQUAL_AREA_SPHERICAL,
LaeaS,
LambertAzimuthalEqualAreaSphericalProjection
),
(LAMBERT_CONFORMAL_CONIC_1SP, Lcc1SP, LambertConformalConic1SPProjection),
(LAMBERT_CONFORMAL_CONIC_2SP, Lcc2SP, LambertConformalConic2SPProjection),
(MERCATOR, Merc, MercatorProjection),
(OBLIQUE_STEREOGRAPHIC, Sterea, ObliqueStereographicAlternativeProjection),
(ORTHOGRAPHIC, Ortho, OrthographicProjection),
(POLAR_STEREOGRAPHIC_VARIANT_A, PSterA, PolarStereographicVariantAProjection),
(POLAR_STEREOGRAPHIC_VARIANT_B, PSterB, PolarStereographicVariantBProjection),
(POLAR_STEREOGRAPHIC_VARIANT_C, PSterC, PolarStereographicVariantCProjection),
(POLYCONIC, Poly, PolyconicProjection),
(SOMERC, Somerc, SwissOblMercatorProjection),
(TRANSVERSE_MERCATOR, Tmerc, TransverseMercatorProjection),
(
TRANSVERSE_MERCATOR_SOUTH_ORIENTATED,
TmercSO,
TransverseMercatorSouthOrientedProjection
),
(WEB_MERCATOR, WebMerc, WebMercatorProjection)
]
)
}
pub fn from_name(name: &str, proj: Rc<RefCell<Proj>>) -> Option<Step> {
match_projections!(
name,
proj,
[
(Aea, AlbersConicEqualAreaProjection),
(Aeqd, AzimuthalEquidistantProjection),
(Airy, AiryProjection),
(Base, BaseProjection),
(Bonne, BonneProjection),
(Cass, CassiniProjection),
(Cea, EqualAreaCylindricalProjection),
(Eck6, EckertVIProjection),
(Eqc, EquidistantCylindricalProjection),
(Eqdc, EquidistantConicProjection),
(Eqearth, EqualEarthProjection),
(Etmerc, ExtendedTransverseMercatorProjection),
(Gnom, GnomonicProjection),
(GnSinu, GeneralSinusoidalSeriesProjection),
(Goode, GoodeHomolosineProjection),
(Gstmerc, GaussSchreiberTransverseMercatorProjection),
(HotineA, HotineObliqueMercatorVariantAProjection),
(HotineB, HotineObliqueMercatorVariantBProjection),
(Krovak, KrovakProjection),
(KrovakNO, KrovakNorthOrientedProjection),
(KrovakM, KrovakModifiedProjection),
(KrovakMNO, KrovakModifiedNorthOrientedProjection),
(Labrd, LabordeProjection),
(Laea, LambertAzimuthalEqualAreaProjection),
(LaeaS, LambertAzimuthalEqualAreaSphericalProjection),
(Leac, LambertEqualAreaConicProjection),
(Lcc1SP, LambertConformalConic1SPProjection),
(Lcc2SP, LambertConformalConic2SPProjection),
(LccA, LambertConformalConicAlternativeProjection),
(MBTfps, McBrydeThomasFlatPolarSinusoidalProjection),
(Merc, MercatorProjection),
(Mill, MillerCylindricalProjection),
(Moll, MollweideProjection),
(Nzmg, NewZealandMapGridProjection),
(Ocea, ObliqueCylindricalEqualAreaProjection),
(Oea, OblatedEqualAreaProjection),
(Ortho, OrthographicProjection),
(PSterA, PolarStereographicVariantAProjection),
(PSterB, PolarStereographicVariantBProjection),
(PSterC, PolarStereographicVariantCProjection),
(Poly, PolyconicProjection),
(Robin, RobinsonProjection),
(Sinu, SinusoidalProjection),
(Somerc, SwissOblMercatorProjection),
(Stere, StereographicProjection),
(Sterea, ObliqueStereographicAlternativeProjection),
(Tcc, TransverseCentralCylindricalProjection),
(Tcea, TransverseCylindricalEqualArealProjection),
(Tmerc, TransverseMercatorProjection),
(TmercSO, TransverseMercatorSouthOrientedProjection),
(Utm, UniversalTransverseMercatorProjection),
(Vandg, VanDerGrintenIProjection),
(WagIV, WagnerIVProjection),
(WagV, WagnerVProjection),
(WebMerc, WebMercatorProjection),
]
)
}
}
pub trait CoordinateStep {
fn new(proj: Rc<RefCell<Proj>>) -> Self;
fn forward<P: TransformCoordinates>(&self, point: &mut P);
fn inverse<P: TransformCoordinates>(&self, point: &mut P);
}