proj_core/crs.rs
1use crate::datum::Datum;
2
3/// A Coordinate Reference System definition.
4#[derive(Debug, Clone, Copy)]
5pub enum CrsDef {
6 /// Geographic CRS (lon/lat in degrees).
7 Geographic(GeographicCrsDef),
8 /// Projected CRS (easting/northing in meters).
9 Projected(ProjectedCrsDef),
10}
11
12impl CrsDef {
13 /// Get the datum for this CRS.
14 pub fn datum(&self) -> &Datum {
15 match self {
16 CrsDef::Geographic(g) => &g.datum,
17 CrsDef::Projected(p) => &p.datum,
18 }
19 }
20
21 /// Get the EPSG code for this CRS.
22 pub fn epsg(&self) -> u32 {
23 match self {
24 CrsDef::Geographic(g) => g.epsg,
25 CrsDef::Projected(p) => p.epsg,
26 }
27 }
28
29 /// Get the CRS name.
30 pub fn name(&self) -> &str {
31 match self {
32 CrsDef::Geographic(g) => g.name,
33 CrsDef::Projected(p) => p.name,
34 }
35 }
36
37 /// Returns true if this is a geographic CRS.
38 pub fn is_geographic(&self) -> bool {
39 matches!(self, CrsDef::Geographic(_))
40 }
41
42 /// Returns true if this is a projected CRS.
43 pub fn is_projected(&self) -> bool {
44 matches!(self, CrsDef::Projected(_))
45 }
46}
47
48/// Definition of a geographic CRS (longitude, latitude in degrees).
49#[derive(Debug, Clone, Copy)]
50pub struct GeographicCrsDef {
51 /// EPSG code.
52 pub epsg: u32,
53 /// Geodetic datum.
54 pub datum: Datum,
55 /// Human-readable name.
56 pub name: &'static str,
57}
58
59/// Definition of a projected CRS (easting, northing in meters).
60#[derive(Debug, Clone, Copy)]
61pub struct ProjectedCrsDef {
62 /// EPSG code.
63 pub epsg: u32,
64 /// Geodetic datum.
65 pub datum: Datum,
66 /// Projection method and parameters.
67 pub method: ProjectionMethod,
68 /// Human-readable name.
69 pub name: &'static str,
70}
71
72/// All supported projection methods with their parameters.
73///
74/// Angle parameters are stored in **degrees**. Conversion to radians happens
75/// at projection construction time (once), not per-transform.
76#[derive(Debug, Clone, Copy)]
77pub enum ProjectionMethod {
78 /// Web Mercator (EPSG:3857) — spherical Mercator on WGS84 semi-major axis.
79 WebMercator,
80
81 /// Transverse Mercator (includes UTM zones).
82 TransverseMercator {
83 /// Central meridian (degrees).
84 lon0: f64,
85 /// Latitude of origin (degrees).
86 lat0: f64,
87 /// Scale factor on central meridian.
88 k0: f64,
89 /// False easting (meters).
90 false_easting: f64,
91 /// False northing (meters).
92 false_northing: f64,
93 },
94
95 /// Polar Stereographic.
96 PolarStereographic {
97 /// Central meridian / straight vertical longitude (degrees).
98 lon0: f64,
99 /// Latitude of true scale (degrees). Determines the hemisphere.
100 lat_ts: f64,
101 /// Scale factor (used when lat_ts = ±90°, otherwise derived from lat_ts).
102 k0: f64,
103 /// False easting (meters).
104 false_easting: f64,
105 /// False northing (meters).
106 false_northing: f64,
107 },
108
109 /// Lambert Conformal Conic (1SP or 2SP).
110 LambertConformalConic {
111 /// Central meridian (degrees).
112 lon0: f64,
113 /// Latitude of origin (degrees).
114 lat0: f64,
115 /// First standard parallel (degrees).
116 lat1: f64,
117 /// Second standard parallel (degrees). Set equal to lat1 for 1SP variant.
118 lat2: f64,
119 /// False easting (meters).
120 false_easting: f64,
121 /// False northing (meters).
122 false_northing: f64,
123 },
124
125 /// Albers Equal Area Conic.
126 AlbersEqualArea {
127 /// Central meridian (degrees).
128 lon0: f64,
129 /// Latitude of origin (degrees).
130 lat0: f64,
131 /// First standard parallel (degrees).
132 lat1: f64,
133 /// Second standard parallel (degrees).
134 lat2: f64,
135 /// False easting (meters).
136 false_easting: f64,
137 /// False northing (meters).
138 false_northing: f64,
139 },
140
141 /// Standard Mercator (ellipsoidal, distinct from Web Mercator).
142 Mercator {
143 /// Central meridian (degrees).
144 lon0: f64,
145 /// Latitude of true scale (degrees). 0 for 1SP variant.
146 lat_ts: f64,
147 /// Scale factor (for 1SP when lat_ts = 0).
148 k0: f64,
149 /// False easting (meters).
150 false_easting: f64,
151 /// False northing (meters).
152 false_northing: f64,
153 },
154
155 /// Equidistant Cylindrical / Plate Carrée.
156 EquidistantCylindrical {
157 /// Central meridian (degrees).
158 lon0: f64,
159 /// Latitude of true scale (degrees).
160 lat_ts: f64,
161 /// False easting (meters).
162 false_easting: f64,
163 /// False northing (meters).
164 false_northing: f64,
165 },
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171 use crate::datum;
172
173 #[test]
174 fn geographic_crs_is_geographic() {
175 let crs = CrsDef::Geographic(GeographicCrsDef {
176 epsg: 4326,
177 datum: datum::WGS84,
178 name: "WGS 84",
179 });
180 assert!(crs.is_geographic());
181 assert!(!crs.is_projected());
182 assert_eq!(crs.epsg(), 4326);
183 }
184
185 #[test]
186 fn projected_crs_is_projected() {
187 let crs = CrsDef::Projected(ProjectedCrsDef {
188 epsg: 3857,
189 datum: datum::WGS84,
190 method: ProjectionMethod::WebMercator,
191 name: "WGS 84 / Pseudo-Mercator",
192 });
193 assert!(crs.is_projected());
194 assert!(!crs.is_geographic());
195 assert_eq!(crs.epsg(), 3857);
196 }
197}