galileo_types/geo/
crs.rs

1use serde::{Deserialize, Serialize};
2
3use crate::cartesian::NewCartesianPoint2d;
4use crate::geo::datum::Datum;
5use crate::geo::impls::projection::{GeodesyProjection, WebMercator};
6use crate::geo::traits::point::NewGeoPoint;
7use crate::geo::traits::projection::Projection;
8
9/// Coordinate reference system.
10#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
11pub struct Crs {
12    datum: Datum,
13    projection_type: ProjectionType,
14}
15
16/// Method used for projecting coordinates.
17#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
18#[non_exhaustive]
19pub enum ProjectionType {
20    /// Some method.
21    Unknown,
22    /// No projection is used. The coordinates used by the CRS are *latitude* and *longitude*.
23    None,
24    /// Web Mercator projection.
25    WebMercator,
26    /// `proj` or `geodesy` definition of the projection.
27    Other(String),
28}
29
30impl Crs {
31    /// Standard Web Mercator coordinate system used by most web GIS applications.
32    pub const EPSG3857: Crs = Crs {
33        datum: Datum::WGS84,
34        projection_type: ProjectionType::WebMercator,
35    };
36
37    /// Coordinate system in geographic coordinates with WGS84 datum.
38    pub const WGS84: Crs = Crs {
39        datum: Datum::WGS84,
40        projection_type: ProjectionType::None,
41    };
42
43    /// Creates a new CRS.
44    pub fn new(datum: Datum, projection_type: ProjectionType) -> Self {
45        Self {
46            datum,
47            projection_type,
48        }
49    }
50
51    /// Returns a projection that converts geographic coordinates into the coordinates of this CRS.
52    ///
53    /// Returns `None` if the CRS coordinates cannot be projected from geographic coordinates.
54    pub fn get_projection<In, Out>(
55        &self,
56    ) -> Option<Box<dyn Projection<InPoint = In, OutPoint = Out>>>
57    where
58        In: NewGeoPoint + 'static,
59        Out: NewCartesianPoint2d + 'static,
60    {
61        match &self.projection_type {
62            ProjectionType::WebMercator => Some(Box::new(WebMercator::new(self.datum))),
63            ProjectionType::Other(definition) => {
64                Some(Box::new(GeodesyProjection::new(definition)?))
65            }
66            _ => None,
67        }
68    }
69}