gistools/proj/parse/
json.rs

1// https://docs.ogc.org/is/18-010r7/18-010r7.html
2use crate::proj::{
3    AxisSwapConverter, CoordinateStep, Proj, ProjectionTransform, Step, derive_sphere,
4    name_to_unit, to_camel_case,
5};
6use alloc::{
7    boxed::Box,
8    format,
9    rc::Rc,
10    string::{String, ToString},
11    vec,
12    vec::Vec,
13};
14use core::cell::RefCell;
15use libm::fabs;
16use serde::{Deserialize, Serialize};
17
18// NOTE: Because the 0.7 spec is not always being followed correctly by generators, serde(default) is applied to everything
19
20/// Helper functions that default to do nothing
21pub trait ToProjJSON {
22    /// Set Usage
23    fn set_usage(&mut self, _usage: ObjectUsage) {}
24    /// Set an Anchor
25    fn set_anchor(&mut self, _anchor: String) {}
26    /// Set a Unit
27    fn set_unit(&mut self, _unit: Unit) {}
28    /// Set an Id
29    fn set_id(&mut self, _id: Id) {}
30    /// Set an Axis
31    fn set_axis(&mut self, _axis: Axis) {}
32    /// Set a CoordinateSystem
33    fn set_coordinate_system(&mut self, _cs: CoordinateSystem) {}
34    /// Set Temporal Extent
35    fn set_temporal_extent(&mut self, _extent: TemporalExtent) {}
36    /// Set Vertical Extent
37    fn set_vertical_extent(&mut self, _extent: VerticalExtent) {}
38    /// Set Bounding Box
39    fn set_bbox(&mut self, _bbox: ProjBBox) {}
40    /// Set Area
41    fn set_area(&mut self, _area: Option<String>) {}
42    /// Set a Method
43    fn set_method(&mut self, _method: Method) {}
44    /// Set a DatumEnsemble
45    fn set_ensemble(&mut self, _ensemble: DatumEnsemble) {}
46    /// Set a Member
47    fn set_member(&mut self, _member: DatumEnsembleMember) {}
48    /// Set an Ellipsoid
49    fn set_ellipsoid(&mut self, _ellipsoid: Ellipsoid) {}
50    /// Set Accuracy
51    fn set_accuracy(&mut self, _accuracy: String) {}
52    /// Set Epoch
53    fn set_epoch(&mut self, _epoch: f64) {}
54    /// Set a frame epoch
55    fn set_frame_epoch(&mut self, _epoch: f64) {}
56    /// Set a datum
57    fn set_datum(&mut self, _datum: Datum) {}
58    /// Set a Parameter
59    fn set_parameter(&mut self, _parameter: ParameterValue) {}
60    /// Set a Meridian
61    fn set_meridian(&mut self, _meridian: Meridian) {}
62    /// Set a PrimeMeridian
63    fn set_prime_meridian(&mut self, _prime_meridian: PrimeMeridian) {}
64    /// Set a Conversion
65    fn set_conversion(&mut self, _conversion: Conversion) {}
66    /// Set a GeodeticCRS
67    fn set_geodetic_crs(&mut self, _geodetic_crs: GeodeticCRS) {}
68    /// Set a ProjectedCRS
69    fn set_projected_crs(&mut self, _projected_crs: ProjectedCRS) {}
70    /// Set the name
71    fn set_projection(&mut self, _name: String) {}
72    /// Set the order
73    fn set_order(&mut self, _order: usize) {}
74}
75
76/// # Schema for PROJJSON (v0.7)
77///
78/// ## References
79/// - `https://proj.org/schemas/v0.7/projjson.schema.json`
80/// - `https://docs.ogc.org/is/18-010r7/18-010r7.html#1`
81#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
82#[serde(untagged)]
83pub enum ProjJSON {
84    /// Coordinate Reference System
85    CRS(Box<CRS>),
86    /// Represents a datum which can be one of several types of reference frames or datums.
87    Datum(Box<Datum>),
88    /// Represents a datum ensemble, which is a collection of datums.
89    DatumEnsemble(Box<DatumEnsemble>),
90    /// Represents an ellipsoid, a geometric figure used in geodetic reference frames.
91    Ellipsoid(Box<Ellipsoid>),
92    /// Represents a prime meridian, which defines the origin of longitude in a geographic coordinate system.
93    PrimeMeridian(Box<PrimeMeridian>),
94    /// Represents a single operation, which can be a conversion, transformation, or point motion operation.
95    SingleOperation(Box<SingleOperation>),
96    /// Represents an operation that is composed of multiple steps, transforming one CRS to another.
97    ConcatenatedOperation(Box<ConcatenatedOperation>),
98    /// Represents metadata associated with a coordinate, including its reference system and epoch.
99    CoordinateMetadata(Box<CoordinateMetadata>),
100}
101impl Default for ProjJSON {
102    fn default() -> Self {
103        ProjJSON::CRS(Box::default())
104    }
105}
106impl ToProjJSON for ProjJSON {
107    fn set_id(&mut self, id: Id) {
108        match self {
109            ProjJSON::CRS(crs) => crs.set_id(id),
110            ProjJSON::Datum(datum) => datum.set_id(id),
111            ProjJSON::DatumEnsemble(ensemble) => ensemble.set_id(id),
112            ProjJSON::PrimeMeridian(prime_meridian) => prime_meridian.set_id(id),
113            ProjJSON::Ellipsoid(ellipsoid) => ellipsoid.set_id(id),
114            ProjJSON::SingleOperation(operation) => operation.set_id(id),
115            ProjJSON::ConcatenatedOperation(operation) => operation.set_id(id),
116            ProjJSON::CoordinateMetadata(metadata) => metadata.set_id(id),
117        }
118    }
119    fn set_datum(&mut self, datum: Datum) {
120        *self = ProjJSON::Datum(Box::new(datum));
121    }
122    fn set_ensemble(&mut self, ensemble: DatumEnsemble) {
123        *self = ProjJSON::DatumEnsemble(Box::new(ensemble));
124    }
125    fn set_prime_meridian(&mut self, prime_meridian: PrimeMeridian) {
126        *self = ProjJSON::PrimeMeridian(Box::new(prime_meridian));
127    }
128    fn set_geodetic_crs(&mut self, geodetic_crs: GeodeticCRS) {
129        *self = ProjJSON::CRS(Box::new(CRS::GeodeticCRS(Box::new(geodetic_crs))));
130    }
131    fn set_projected_crs(&mut self, projected_crs: ProjectedCRS) {
132        *self = ProjJSON::CRS(Box::new(CRS::ProjectedCRS(Box::new(projected_crs))));
133    }
134}
135impl ProjJSON {
136    /// Convert a Proj JSON to a ProjectionTransform (Proj constants with steps)
137    pub fn to_projection_transform(&self) -> ProjectionTransform {
138        let mut proj_transform = ProjectionTransform::default();
139        match self {
140            ProjJSON::CRS(crs) => crs.to_projection_transform(&mut proj_transform),
141            _ => panic!("Unsupported operation"),
142        }
143
144        proj_transform
145    }
146}
147
148/// Coordinate Reference System
149#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
150#[serde(untagged)]
151pub enum CRS {
152    /// Represents a coordinate reference system that is bounded by a source and target CRS with a transformation.
153    BoundCRS(Box<BoundCRS>),
154    /// Represents a compound coordinate reference system, consisting of multiple components.
155    CompoundCRS(Box<CompoundCRS>),
156    /// Represents a derived engineering coordinate reference system.
157    DerivedEngineeringCRS(Box<DerivedEngineeringCRS>),
158    /// Represents a derived geodetic or geographic coordinate reference system.
159    DerivedGeodeticCRS(Box<DerivedGeodeticCRS>),
160    /// Represents a derived parametric coordinate reference system.
161    DerivedParametricCRS(Box<DerivedParametricCRS>),
162    /// Represents a derived projected coordinate reference system.
163    DerivedProjectedCRS(Box<DerivedProjectedCRS>),
164    /// Represents a derived temporal coordinate reference system.
165    DerivedTemporalCRS(Box<DerivedTemporalCRS>),
166    /// Represents a derived vertical coordinate reference system.
167    DerivedVerticalCRS(Box<DerivedVerticalCRS>),
168    /// Represents an engineering coordinate reference system.
169    EngineeringCRS(Box<EngineeringCRS>),
170    /// Represents a geodetic or geographic coordinate reference system.
171    GeodeticCRS(Box<GeodeticCRS>),
172    /// Represents a parametric coordinate reference system.
173    ParametricCRS(Box<ParametricCRS>),
174    /// Represents a projected coordinate reference system, which transforms geodetic or geographic coordinates
175    /// into a flat, two-dimensional plane using a map projection.
176    ProjectedCRS(Box<ProjectedCRS>),
177    /// Represents a temporal coordinate reference system, which defines time-based coordinates.
178    TemporalCRS(Box<TemporalCRS>),
179    /// Represents a vertical coordinate reference system, which is used for height or depth measurements.
180    VerticalCRS(Box<VerticalCRS>),
181}
182impl Default for CRS {
183    fn default() -> Self {
184        CRS::GeodeticCRS(Box::default())
185    }
186}
187impl ToProjJSON for CRS {
188    fn set_id(&mut self, id: Id) {
189        match self {
190            CRS::BoundCRS(crs) => crs.set_id(id),
191            CRS::CompoundCRS(crs) => crs.set_id(id),
192            CRS::DerivedEngineeringCRS(crs) => crs.set_id(id),
193            CRS::DerivedGeodeticCRS(crs) => crs.set_id(id),
194            CRS::DerivedParametricCRS(crs) => crs.set_id(id),
195            CRS::DerivedProjectedCRS(crs) => crs.set_id(id),
196            CRS::DerivedTemporalCRS(crs) => crs.set_id(id),
197            CRS::DerivedVerticalCRS(crs) => crs.set_id(id),
198            CRS::EngineeringCRS(crs) => crs.set_id(id),
199            CRS::GeodeticCRS(crs) => crs.set_id(id),
200            CRS::ParametricCRS(crs) => crs.set_id(id),
201            CRS::ProjectedCRS(crs) => crs.set_id(id),
202            CRS::TemporalCRS(crs) => crs.set_id(id),
203            CRS::VerticalCRS(crs) => crs.set_id(id),
204        }
205    }
206    fn set_geodetic_crs(&mut self, geodetic_crs: GeodeticCRS) {
207        *self = CRS::GeodeticCRS(geodetic_crs.into());
208    }
209    fn set_projected_crs(&mut self, projected_crs: ProjectedCRS) {
210        *self = CRS::ProjectedCRS(projected_crs.into());
211    }
212}
213impl CRS {
214    /// Convert a Proj JSON to a ProjectionTransform (Proj constants with steps)
215    pub fn to_projection_transform(&self, proj_transform: &mut ProjectionTransform) {
216        match self {
217            CRS::GeodeticCRS(crs) => crs.to_projection_transform(proj_transform),
218            CRS::ProjectedCRS(crs) => crs.to_projection_transform(proj_transform),
219            _ => panic!("Unsupported operation"),
220        };
221    }
222}
223
224/// # Datum Interface
225///
226/// Represents a datum which can be one of several types of reference frames or datums.
227#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
228#[serde(untagged)]
229pub enum Datum {
230    /// Represents the geodetic reference frame associated with a geodetic CRS.
231    GeodeticReferenceFrame(GeodeticReferenceFrame),
232    /// Represents the vertical reference frame associated with a vertical CRS.
233    VerticalReferenceFrame(VerticalReferenceFrame),
234    /// Represents a dynamic geodetic reference frame.
235    DynamicGeodeticReferenceFrame(DynamicGeodeticReferenceFrame),
236    /// Represents a dynamic vertical reference frame.
237    DynamicVerticalReferenceFrame(DynamicVerticalReferenceFrame),
238    /// Represents the temporal datum associated with a temporal CRS.
239    TemporalDatum(TemporalDatum),
240    /// Represents the parametric datum associated with a parametric CRS.
241    ParametricDatum(ParametricDatum),
242    /// Represents the datum associated with an engineering CRS.
243    EngineeringDatum(EngineeringDatum),
244}
245impl Datum {
246    /// Convert a GeodeticCRS to a ProjectionTransform
247    pub fn to_projection_transform(&self, proj_transform: &mut ProjectionTransform) {
248        // TODO: Implement for all
249        match self {
250            Datum::GeodeticReferenceFrame(d) => d.to_projection_transform(proj_transform),
251            _ => todo!(),
252            // Datum::VerticalReferenceFrame(d) => d.to_projection_transform(proj_transform),
253            // Datum::DynamicGeodeticReferenceFrame(d) => d.to_projection_transform(proj_transform),
254            // Datum::DynamicVerticalReferenceFrame(d) => d.to_projection_transform(proj_transform),
255            // Datum::TemporalDatum(d) => d.to_projection_transform(proj_transform),
256            // Datum::ParametricDatum(d) => d.to_projection_transform(proj_transform),
257            // Datum::EngineeringDatum(d) => d.to_projection_transform(proj_transform),
258        };
259    }
260}
261impl Default for Datum {
262    fn default() -> Self {
263        Datum::GeodeticReferenceFrame(GeodeticReferenceFrame::default())
264    }
265}
266impl ToProjJSON for Datum {
267    fn set_id(&mut self, id: Id) {
268        match self {
269            Datum::GeodeticReferenceFrame(d) => d.set_id(id),
270            Datum::VerticalReferenceFrame(d) => d.set_id(id),
271            Datum::DynamicGeodeticReferenceFrame(d) => d.set_id(id),
272            Datum::DynamicVerticalReferenceFrame(d) => d.set_id(id),
273            Datum::TemporalDatum(d) => d.set_id(id),
274            Datum::ParametricDatum(d) => d.set_id(id),
275            Datum::EngineeringDatum(d) => d.set_id(id),
276        }
277    }
278    fn set_prime_meridian(&mut self, pm: PrimeMeridian) {
279        match self {
280            Datum::GeodeticReferenceFrame(d) => {
281                d.set_prime_meridian(pm);
282            }
283            Datum::DynamicGeodeticReferenceFrame(d) => {
284                d.set_prime_meridian(pm);
285            }
286            _ => {}
287        }
288    }
289}
290
291/// # Geographic Bounding Box
292///
293/// ## Description
294/// The geographic bounding box is an optional attribute which describes a "north up" area.
295/// Upper right latitude will be greater than the lower left latitude. Generally the upper right
296/// longitude will be greater than the lower left longitude. However when the area crosses the
297/// 180° meridian, the value of the lower left longitude will be greater than the value of the
298/// upper right longitude.
299///
300/// The geographic bounding box is an approximate description of location. For most purposes a
301/// coordinate precision of two decimal places of a degree is sufficient. At this resolution the
302/// identification of the geodetic CRS to which the bounding box coordinates are referenced is not
303/// required.
304///
305/// ## Requirement
306/// Bounding box latitude coordinates shall be given in decimal degrees in the range -90 to +90,
307/// longitude coordinates shall be given in decimal degrees in the range -180 to +180 relative to
308/// the international reference meridian.
309///
310/// ## Examples
311/// - `BBOX[51.43,2.54,55.77,6.40]`
312/// - `BBOX[-55.95,160.60,-25.88,-171.20]`
313#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
314#[serde(default)]
315pub struct ProjBBox {
316    /// The southernmost latitude of the bounding box.
317    pub south_latitude: f64,
318    /// The westernmost longitude of the bounding box.
319    pub west_longitude: f64,
320    /// The northernmost latitude of the bounding box.
321    pub north_latitude: f64,
322    /// The easternmost longitude of the bounding box.
323    pub east_longitude: f64,
324}
325
326/// # VerticalExtent
327///
328/// ## Description
329/// Vertical extent is an optional attribute which describes a height range over which a CRS or
330/// coordinate operation is applicable. Depths have negative height values. Vertical extent is an
331/// approximate description of location; heights are relative to an unspecified mean sea level.
332///
333/// ## Requirement
334/// If vertical extent units are not stated they shall be assumed to be metres.
335///
336/// ## Examples
337/// - `VERTICALEXTENT[-1000,0,LENGTHUNIT["metre",1.0]]`
338/// - `VERTICALEXTENT[-1000,0]` (where the heights are implicitly in metres).
339#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
340#[serde(default)]
341pub struct VerticalExtent {
342    /// Minimum height
343    pub minimum: f64,
344    /// Maximum height
345    pub maximum: f64,
346    /// Unit of measurement
347    pub unit: Unit,
348}
349
350/// # Temporal Extent
351///
352/// ## Description
353/// Temporal extent is an optional attribute which describes a date or time range over which a CRS
354/// or coordinate operation is applicable. The format for date and time values is defined in
355/// ISO/IEC 9075-2. Start time is earlier than end time.
356///
357/// ## Requirement
358/// `<temporal extent end>` should have the same data type (dateTime or quoted Latin text) as
359/// `<temporal extent start>`.
360///
361/// ## Examples
362/// - `TIMEEXTENT[2013-01-01,2013-12-31]`
363/// - `TIMEEXTENT["Jurassic","Quaternary"]`
364#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
365#[serde(default)]
366pub struct TemporalExtent {
367    /// Start time (ISO 8601 format)
368    pub start: String,
369    /// End time (ISO 8601 format)
370    pub end: String,
371}
372
373/// String or Number
374#[derive(Debug, Clone, Serialize, Deserialize)]
375#[serde(untagged)]
376pub enum ProjValue {
377    /// Boolean case
378    Bool(bool),
379    /// Float case
380    F64(f64),
381    /// Integer case
382    I64(i64),
383    /// String case
384    String(String),
385}
386impl Default for ProjValue {
387    fn default() -> Self {
388        ProjValue::String("".into())
389    }
390}
391impl PartialEq for ProjValue {
392    fn eq(&self, other: &Self) -> bool {
393        match (self, other) {
394            (ProjValue::Bool(a), ProjValue::Bool(b)) => a == b,
395            (ProjValue::F64(a), ProjValue::F64(b)) => fabs(*a - *b) < f64::EPSILON,
396            (ProjValue::I64(a), ProjValue::I64(b)) => a == b,
397            (ProjValue::String(a), ProjValue::String(b)) => a == b,
398            _ => false,
399        }
400    }
401}
402impl ProjValue {
403    /// Get the boolean representation
404    pub fn bool(&self) -> bool {
405        match self {
406            ProjValue::Bool(b) => *b,
407            ProjValue::F64(f) => *f != 0.0,
408            ProjValue::I64(i) => *i != 0,
409            ProjValue::String(s) => s.to_lowercase() == "true" || self.i64() != 0,
410        }
411    }
412    /// Get the float representation
413    pub fn f64(&self) -> f64 {
414        match self {
415            ProjValue::Bool(b) => {
416                if *b {
417                    1.0
418                } else {
419                    0.0
420                }
421            }
422            ProjValue::F64(f) => *f,
423            ProjValue::I64(i) => *i as f64,
424            ProjValue::String(s) => s.parse().unwrap_or(0.0),
425        }
426    }
427    /// Get the integer representation
428    pub fn i64(&self) -> i64 {
429        match self {
430            ProjValue::Bool(b) => {
431                if *b {
432                    1
433                } else {
434                    0
435                }
436            }
437            ProjValue::F64(f) => *f as i64,
438            ProjValue::I64(i) => *i,
439            ProjValue::String(s) => s.parse().unwrap_or(0),
440        }
441    }
442    /// Get the string representation
443    pub fn string(&self) -> String {
444        match self {
445            ProjValue::Bool(b) => b.to_string(),
446            ProjValue::F64(f) => f.to_string(),
447            ProjValue::I64(i) => i.to_string(),
448            ProjValue::String(s) => s.clone(),
449        }
450    }
451}
452impl From<&str> for ProjValue {
453    fn from(v: &str) -> ProjValue {
454        ProjValue::String(v.into())
455    }
456}
457impl From<String> for ProjValue {
458    fn from(v: String) -> ProjValue {
459        ProjValue::String(v)
460    }
461}
462impl From<ProjValue> for String {
463    fn from(v: ProjValue) -> String {
464        match v {
465            ProjValue::String(s) => s,
466            _ => "".into(),
467        }
468    }
469}
470impl From<f64> for ProjValue {
471    fn from(v: f64) -> ProjValue {
472        ProjValue::F64(v)
473    }
474}
475
476/// # Identifier
477///
478/// ## Description
479/// Identifier is an optional attribute which references an external description of the object and
480/// which may be applied to a coordinate reference system, a coordinate operation or a bound CRS.
481/// Multiple identifiers may be given for any object.
482///
483/// ## Examples
484/// - `ID["Authority name","Abcd_Ef",7.1]`
485/// - `ID["EPSG",4326]`
486/// - `ID["EPSG",4326,URI["urn:ogc:def:crs:EPSG::4326"]]`
487/// - `ID["EuroGeographics","ES_ED50 (BAL99) to ETRS89","2001-04-20"]`
488#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
489#[serde(default)]
490pub struct Id {
491    /// Authority issuing the identifier
492    pub authority: String,
493    /// Code associated with the identifier
494    pub code: ProjValue,
495    /// Version of the identifier
496    /// NOTE: This is not supposed to be optional, but it rarely shows up
497    pub version: Option<ProjValue>,
498    /// Citation of the authority
499    #[serde(skip_serializing_if = "Option::is_none")]
500    pub authority_citation: Option<String>,
501    /// URI reference
502    #[serde(skip_serializing_if = "Option::is_none")]
503    pub uri: Option<String>,
504}
505
506/// Identifiers list
507pub type Ids = Vec<Id>;
508
509/// # Parameter
510///
511/// ## Description
512/// Parameter name is for human readability. For interoperability it is the method formula and its parameters that are critical in determining the equivalence of methods. See Annex F. Identifiers for commonly encountered map projection methods are given in F.2; their parameters are listed in F.3.
513///
514/// The map projection parameters required are specific to the map projection method and will be listed sequentially. The order within the sequence is not significant but should be logical.
515///
516/// `<map projection parameter unit>` is an optional attribute, for reasons of backward compatibility. Best practice is that it is included explicitly in WKT strings.
517///
518/// ## Requirements
519/// If `<map projection parameter unit>` is omitted from `<map projection parameter>` then:
520/// - Map parameter values that are lengths shall be given in metres.
521/// - Map projection parameter values that are angles shall be given in decimal degrees.
522/// - Map projection parameters that are unitless (for example scale factor) shall be given as a number which is close to or is unity (1.0).
523///
524/// ## Examples
525/// - `PARAMETER["semi_major",6378137.0]` - Defines a parameter named "semi_major" with a numeric value.
526/// - `PARAMETER["towgs84","8,-183,-105,0,0,0,0"]` - Defines a parameter named "towgs84" with a string value.
527/// - `PARAMETER["central_meridian",0.0,UNIT["degree",0.0174532925199433]]` - Defines a parameter with a name, numeric value, and a unit.
528/// - `PARAMETER["standard_parallel_1",30.0,ID["EPSG",8831]]` - Defines a parameter with a name, numeric value, and an identifier.
529/// - `PARAMETER["latitude_of_origin",0.0,UNIT["degree",0.0174532925199433],ID["EPSG",8821]]` - Defines a parameter with a name, numeric value, unit, and identifier.
530/// - `PARAMETER["is_sphere",TRUE]` - Defines a boolean parameter.
531#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
532#[serde(default)]
533pub struct ParameterValue {
534    /// Schema reference
535    #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")]
536    pub schema: Option<String>,
537    /// Type identifier - always 'ParameterValue'
538    #[serde(rename = "type")]
539    pub r#type: Option<String>, // 'ParameterValue';
540    /// Name of the parameter
541    pub name: String,
542    /// Parameter value, which can be a string or number
543    pub value: ProjValue,
544    /// Optional unit of measurement
545    #[serde(skip_serializing_if = "Option::is_none")]
546    pub unit: Option<Unit>,
547    /// Identifier
548    #[serde(skip_serializing_if = "Option::is_none")]
549    pub id: Option<Id>,
550    /// Alternative identifiers
551    #[serde(skip_serializing_if = "Vec::is_empty")]
552    pub ids: Ids,
553    /// NOT PART OF SPEC
554    pub is_file: bool,
555}
556impl ParameterValue {
557    /// Get the radians of the value
558    pub fn rad(&self) -> f64 {
559        // If no unit, build from name_to_unit, if angle, it's degree, otherwise metre
560        let unit = self.unit.clone().unwrap_or_else(|| name_to_unit(&self.name));
561        self.value.f64() * unit.rad()
562    }
563}
564impl From<&ParameterValue> for ProjValue {
565    fn from(p_value: &ParameterValue) -> Self {
566        ProjValue::F64(p_value.rad())
567    }
568}
569impl ToProjJSON for ParameterValue {
570    fn set_id(&mut self, id: Id) {
571        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
572        if !self.ids.is_empty() {
573            self.ids.push(id);
574        } else if let Some(i) = self.id.clone() {
575            self.ids.extend(vec![i, id]);
576            self.id = None;
577        } else {
578            self.id = Some(id);
579        }
580    }
581    fn set_unit(&mut self, unit: Unit) {
582        self.unit = Some(unit);
583    }
584}
585
586/// # Parametric CRS
587///
588/// Represents a parametric coordinate reference system.
589#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
590#[serde(default)]
591pub struct ParametricCRS {
592    /// Type identifier - always 'ParametricCRS'
593    #[serde(rename = "type")]
594    pub r#type: Option<String>, // 'ParametricCRS';
595    /// Name of the CRS
596    pub name: String,
597    /// Parametric datum
598    pub datum: ParametricDatum,
599    /// Coordinate system
600    pub coordinate_system: Option<CoordinateSystem>,
601    /// Usage Information
602    #[serde(flatten, skip_serializing_if = "Option::is_none")]
603    pub usage: Option<ObjectUsage>,
604    /// Usages
605    #[serde(skip_serializing_if = "Vec::is_empty")]
606    pub usages: Vec<ObjectUsage>,
607}
608impl ToProjJSON for ParametricCRS {
609    fn set_id(&mut self, id: Id) {
610        if self.usage.is_none() && self.usages.is_empty() {
611            self.usage = Some(ObjectUsage::default());
612        }
613        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
614            u.set_id(id);
615        }
616    }
617    fn set_usage(&mut self, usage: ObjectUsage) {
618        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
619        if self.usages.is_empty() {
620            if let Some(u) = self.usage.clone() {
621                self.usages.extend(vec![u, usage]);
622                self.usage = None;
623            } else {
624                self.usage = Some(usage);
625            }
626        } else {
627            self.usages.push(usage);
628        }
629    }
630    fn set_coordinate_system(&mut self, cs: CoordinateSystem) {
631        self.coordinate_system = Some(cs);
632    }
633    // Pass down to the coordinate system
634    fn set_axis(&mut self, axis: Axis) {
635        if let Some(ref mut cs) = self.coordinate_system {
636            cs.axis.push(axis);
637        }
638    }
639    fn set_unit(&mut self, unit: Unit) {
640        if let Some(ref mut cs) = self.coordinate_system {
641            for axis in cs.axis.iter_mut() {
642                axis.unit = Some(unit.clone());
643            }
644        }
645    }
646}
647
648/// # Parametric Datum
649///
650/// Represents the parametric datum associated with a parametric CRS.
651#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
652#[serde(default)]
653pub struct ParametricDatum {
654    /// Type identifier - always 'ParametricDatum'
655    #[serde(rename = "type")]
656    pub r#type: Option<String>, // 'ParametricDatum';
657    /// Name of the datum
658    pub name: String,
659    /// Anchor point
660    pub anchor: String,
661    /// Usage Information
662    #[serde(flatten, skip_serializing_if = "Option::is_none")]
663    pub usage: Option<ObjectUsage>,
664    /// Usages
665    #[serde(skip_serializing_if = "Vec::is_empty")]
666    pub usages: Vec<ObjectUsage>,
667}
668impl ToProjJSON for ParametricDatum {
669    fn set_id(&mut self, id: Id) {
670        if self.usage.is_none() && self.usages.is_empty() {
671            self.usage = Some(ObjectUsage::default());
672        }
673        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
674            u.set_id(id);
675        }
676    }
677    fn set_usage(&mut self, usage: ObjectUsage) {
678        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
679        if self.usages.is_empty() {
680            if let Some(u) = self.usage.clone() {
681                self.usages.extend(vec![u, usage]);
682                self.usage = None;
683            } else {
684                self.usage = Some(usage);
685            }
686        } else {
687            self.usages.push(usage);
688        }
689    }
690    fn set_anchor(&mut self, anchor: String) {
691        self.anchor = anchor;
692    }
693}
694
695/// # Point Motion Operation
696///
697/// Represents a point motion operation
698#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
699#[serde(default)]
700pub struct PointMotionOperation {
701    /// Type identifier
702    #[serde(rename = "type")]
703    pub r#type: Option<String>, // 'PointMotionOperation';
704    /// Name of the operation
705    pub name: String,
706    /// Source coordinate reference system
707    pub source_crs: CRS,
708    /// Method used for point motion
709    pub method: Method,
710    /// Parameters used in the operation
711    #[serde(skip_serializing_if = "Vec::is_empty")]
712    pub parameters: Vec<ParameterValue>,
713    /// Accuracy of the operation
714    #[serde(skip_serializing_if = "Option::is_none")]
715    pub accuracy: Option<String>,
716    /// Usage Information
717    #[serde(flatten, skip_serializing_if = "Option::is_none")]
718    pub usage: Option<ObjectUsage>,
719    /// Usages
720    #[serde(skip_serializing_if = "Vec::is_empty")]
721    pub usages: Vec<ObjectUsage>,
722}
723impl ToProjJSON for PointMotionOperation {
724    fn set_id(&mut self, id: Id) {
725        if self.usage.is_none() && self.usages.is_empty() {
726            self.usage = Some(ObjectUsage::default());
727        }
728        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
729            u.set_id(id);
730        }
731    }
732    fn set_usage(&mut self, usage: ObjectUsage) {
733        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
734        if self.usages.is_empty() {
735            if let Some(u) = self.usage.clone() {
736                self.usages.extend(vec![u, usage]);
737                self.usage = None;
738            } else {
739                self.usage = Some(usage);
740            }
741        } else {
742            self.usages.push(usage);
743        }
744    }
745    fn set_accuracy(&mut self, accuracy: String) {
746        self.accuracy = Some(accuracy);
747    }
748    fn set_projection(&mut self, name: String) {
749        self.method = Method { name, ..Default::default() };
750    }
751    fn set_method(&mut self, method: Method) {
752        self.method = method;
753    }
754    fn set_parameter(&mut self, parameter: ParameterValue) {
755        self.parameters.push(parameter);
756    }
757}
758
759/// # Method Object
760///
761/// Defines an operation method with a name and identifier
762#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
763#[serde(default)]
764pub struct Method {
765    /// Schema reference
766    #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")]
767    pub schema: Option<String>,
768    /// Type identifier - always 'OperationMethod'
769    #[serde(rename = "type")]
770    pub r#type: Option<String>, // 'OperationMethod';
771    /// Name of the method
772    pub name: String,
773    /// Identifier
774    #[serde(skip_serializing_if = "Option::is_none")]
775    pub id: Option<Id>,
776    /// Alternative identifiers
777    #[serde(skip_serializing_if = "Vec::is_empty")]
778    pub ids: Ids,
779}
780impl Method {
781    /// Convert a Method to a ProjectionTransform
782    pub fn to_projection_transform(&self, proj_transform: &mut ProjectionTransform) {
783        // add projection from method
784        proj_transform.method = Step::from_method(self, proj_transform.proj.clone()).unwrap();
785    }
786}
787impl ToProjJSON for Method {
788    fn set_id(&mut self, id: Id) {
789        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
790        if !self.ids.is_empty() {
791            self.ids.push(id);
792        } else if let Some(i) = self.id.clone() {
793            self.ids.extend(vec![i, id]);
794            self.id = None;
795        } else {
796            self.id = Some(id);
797        }
798    }
799}
800
801/// Base Unit - common units as string input
802#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
803pub enum BaseUnit {
804    /// Metre
805    #[serde(rename = "metre")]
806    #[default]
807    Metre,
808    /// Degree
809    #[serde(rename = "degree")]
810    Degree,
811    /// Unity
812    #[serde(rename = "unity")]
813    Unity,
814}
815
816/// Unit Type - String input
817#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
818#[serde(rename_all = "PascalCase")]
819pub enum UnitType {
820    /// Linear
821    LinearUnit,
822    /// Angular
823    AngularUnit,
824    /// Scale
825    ScaleUnit,
826    /// Time
827    TimeUnit,
828    /// Parametric
829    ParametricUnit,
830    /// Unit
831    #[default]
832    Unit,
833}
834impl From<&str> for UnitType {
835    fn from(s: &str) -> Self {
836        match s {
837            "LENGTHUNIT" => UnitType::LinearUnit,
838            "ANGLEUNIT" => UnitType::AngularUnit,
839            "SCALEUNIT" => UnitType::ScaleUnit,
840            "TIMEUNIT" => UnitType::TimeUnit,
841            "PARAMETRICUNIT" => UnitType::ParametricUnit,
842            _ => UnitType::Unit, // UNIT
843        }
844    }
845}
846
847/// Unit Object
848#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
849#[serde(default)]
850pub struct UnitObject {
851    /// Type of unit
852    #[serde(rename = "type")]
853    pub r#type: UnitType,
854    /// Name of the unit
855    pub name: String,
856    /// Conversion factor
857    #[serde(skip_serializing_if = "Option::is_none")]
858    pub conversion_factor: Option<f64>,
859    /// Schema reference
860    #[serde(skip_serializing_if = "Option::is_none")]
861    pub id: Option<Id>,
862    /// Alternative identifiers
863    #[serde(skip_serializing_if = "Vec::is_empty")]
864    pub ids: Ids,
865}
866impl UnitObject {
867    /// Set the unit type
868    pub fn set_unit_type(&mut self, unit_type: UnitType) {
869        self.r#type = unit_type;
870    }
871    /// Convert to Radian
872    pub fn rad(&self) -> f64 {
873        match self.r#type {
874            UnitType::AngularUnit => self.conversion_factor.unwrap_or(1.0),
875            _ => 1.0,
876        }
877    }
878    /// Convert to Meters
879    pub fn meters(&self) -> f64 {
880        match self.r#type {
881            UnitType::LinearUnit => self.conversion_factor.unwrap_or(1.0),
882            _ => 1.0,
883        }
884    }
885}
886impl ToProjJSON for UnitObject {
887    fn set_id(&mut self, id: Id) {
888        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
889        if !self.ids.is_empty() {
890            self.ids.push(id);
891        } else if let Some(i) = self.id.clone() {
892            self.ids.extend(vec![i, id]);
893            self.id = None;
894        } else {
895            self.id = Some(id);
896        }
897    }
898}
899
900/// # Unit
901///
902/// ## Description
903/// Defines the unit of measure for lengths or distances, typically used within other spatial
904/// extent definitions like `VerticalExtent`. It consists of a unit name (e.g., "metre", "foot")
905/// and a corresponding numeric value, often representing the conversion factor to a base unit.
906///
907/// ## Common naming convention
908/// - LENGTHUNIT
909/// - ANGLEUNIT
910/// - SCALEUNIT
911/// - TIMEUNIT
912/// - PARAMETRICUNIT
913///
914/// ## Requirement
915/// The WKT representation of a `<length unit>` shall be:
916/// ```bnf
917/// <length unit> ::= <length unit keyword> <left delimiter> <quoted text> <wkt separator> <number> <right delimiter>
918/// <length unit keyword> ::= LENGTHUNIT
919/// ```
920///
921/// Unprovided defaults to BaseUnit->Metre
922///
923/// ## Examples
924/// - `LENGTHUNIT["metre",1.0]`
925/// - `LENGTHUNIT["foot",0.3048]`
926#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
927#[serde(untagged)]
928pub enum Unit {
929    /// Base case
930    BaseUnit(BaseUnit),
931    /// Object with complex units
932    UnitObject(UnitObject),
933}
934impl Default for Unit {
935    fn default() -> Self {
936        Unit::BaseUnit(BaseUnit::default())
937    }
938}
939impl Unit {
940    /// Create a degree unit
941    pub fn new_deg() -> Self {
942        Unit::BaseUnit(BaseUnit::Degree)
943    }
944    /// Set the unit type assuming the unit is a UnitObject
945    pub fn set_unit_type(&mut self, unit_type: UnitType) {
946        match self {
947            Unit::BaseUnit(_) => {}
948            Unit::UnitObject(unit) => unit.set_unit_type(unit_type),
949        };
950    }
951    /// Get the multiplier for the unit to convert to radians
952    pub fn rad(&self) -> f64 {
953        match self {
954            Unit::BaseUnit(unit) => match unit {
955                BaseUnit::Metre => 1.0,
956                BaseUnit::Degree => core::f64::consts::PI / 180.0,
957                BaseUnit::Unity => 1.0,
958            },
959            Unit::UnitObject(unit) => unit.rad(),
960        }
961    }
962    /// Get the multiplier for the unit to convert to meters
963    pub fn meters(&self) -> f64 {
964        match self {
965            Unit::BaseUnit(unit) => match unit {
966                BaseUnit::Metre => 1.0,
967                BaseUnit::Degree => core::f64::consts::PI / 180.0,
968                BaseUnit::Unity => 1.0,
969            },
970            Unit::UnitObject(unit) => unit.meters(),
971        }
972    }
973}
974impl ToProjJSON for Unit {
975    fn set_unit(&mut self, unit: Unit) {
976        *self = unit
977    }
978}
979
980/// # BoundCRS Interface
981///
982/// Represents a coordinate reference system that is bounded by a source and target CRS with a transformation.
983#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
984#[serde(default)]
985pub struct BoundCRS {
986    /// Indicates the type of object. Always "BoundCRS" for this interface.
987    #[serde(rename = "type")]
988    pub r#type: Option<String>,
989    /// The name of the bound CRS.
990    pub name: Option<String>,
991    /// The source coordinate reference system.
992    pub source_crs: Box<CRS>,
993    /// The target coordinate reference system.
994    pub target_crs: Box<CRS>,
995    /// The transformation applied to convert between the source and target CRS.
996    pub transformation: AbridgedTransformation,
997    /// Usage Information
998    #[serde(flatten, skip_serializing_if = "Option::is_none")]
999    pub usage: Option<ObjectUsage>,
1000    /// Usages
1001    #[serde(skip_serializing_if = "Vec::is_empty")]
1002    pub usages: Vec<ObjectUsage>,
1003}
1004impl ToProjJSON for BoundCRS {
1005    fn set_id(&mut self, id: Id) {
1006        if self.usage.is_none() && self.usages.is_empty() {
1007            self.usage = Some(ObjectUsage::default());
1008        }
1009        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
1010            u.set_id(id);
1011        }
1012    }
1013    fn set_usage(&mut self, usage: ObjectUsage) {
1014        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
1015        if self.usages.is_empty() {
1016            if let Some(u) = self.usage.clone() {
1017                self.usages.extend(vec![u, usage]);
1018                self.usage = None;
1019            } else {
1020                self.usage = Some(usage);
1021            }
1022        } else {
1023            self.usages.push(usage);
1024        }
1025    }
1026}
1027
1028/// # ConcatenatedOperation Interface
1029///
1030/// Represents an operation that is composed of multiple steps, transforming one CRS to another.
1031#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1032#[serde(default)]
1033pub struct ConcatenatedOperation {
1034    /// Indicates the type of object. Always "ConcatenatedOperation" for this interface.
1035    #[serde(rename = "type")]
1036    pub r#type: Option<String>, // 'ConcatenatedOperation';
1037    /// The name of the concatenated operation.
1038    pub name: String,
1039    /// The source coordinate reference system.
1040    pub source_crs: CRS,
1041    /// The target coordinate reference system.
1042    pub target_crs: CRS,
1043    /// An array of individual steps in the concatenated operation.
1044    #[serde(skip_serializing_if = "Vec::is_empty")]
1045    pub steps: Vec<SingleOperation>,
1046    /// The accuracy of the concatenated operation.
1047    #[serde(skip_serializing_if = "Option::is_none")]
1048    pub accuracy: Option<String>,
1049    /// Usage Information
1050    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1051    pub usage: Option<ObjectUsage>,
1052    /// Usages
1053    #[serde(skip_serializing_if = "Vec::is_empty")]
1054    pub usages: Vec<ObjectUsage>,
1055}
1056impl ToProjJSON for ConcatenatedOperation {
1057    fn set_id(&mut self, id: Id) {
1058        if self.usage.is_none() && self.usages.is_empty() {
1059            self.usage = Some(ObjectUsage::default());
1060        }
1061        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
1062            u.set_id(id);
1063        }
1064    }
1065    fn set_usage(&mut self, usage: ObjectUsage) {
1066        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
1067        if self.usages.is_empty() {
1068            if let Some(u) = self.usage.clone() {
1069                self.usages.extend(vec![u, usage]);
1070                self.usage = None;
1071            } else {
1072                self.usage = Some(usage);
1073            }
1074        } else {
1075            self.usages.push(usage);
1076        }
1077    }
1078    fn set_accuracy(&mut self, accuracy: String) {
1079        self.accuracy = Some(accuracy);
1080    }
1081}
1082
1083/// # AbridgedTransformation Interface
1084///
1085/// Represents an abridged transformation used for converting between different coordinate reference systems.
1086#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1087#[serde(default)]
1088pub struct AbridgedTransformation {
1089    /// The schema URL or identifier.
1090    #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")]
1091    pub schema: Option<String>,
1092    /// Indicates the type of object. Always "AbridgedTransformation" for this interface.
1093    #[serde(rename = "type")]
1094    pub r#type: Option<String>, // 'AbridgedTransformation';
1095    /// The name of the transformation.
1096    pub name: String,
1097    /// The source coordinate reference system, only present if it differs from the source CRS of the bound CRS.
1098    #[serde(skip_serializing_if = "Option::is_none")]
1099    pub source_crs: Option<Box<CRS>>,
1100    /// The method used for the transformation.
1101    pub method: Method,
1102    /// The parameters used in the transformation.
1103    #[serde(skip_serializing_if = "Vec::is_empty")]
1104    pub parameters: Vec<ParameterValue>,
1105    /// An identifier for the axis.
1106    #[serde(skip_serializing_if = "Option::is_none")]
1107    pub id: Option<Id>,
1108    /// An array of identifiers for the axis.
1109    #[serde(skip_serializing_if = "Vec::is_empty")]
1110    pub ids: Ids,
1111}
1112impl ToProjJSON for AbridgedTransformation {
1113    fn set_projection(&mut self, name: String) {
1114        self.method = Method { name, ..Default::default() };
1115    }
1116    fn set_method(&mut self, method: Method) {
1117        self.method = method;
1118    }
1119    fn set_parameter(&mut self, parameter: ParameterValue) {
1120        self.parameters.push(parameter);
1121    }
1122    fn set_id(&mut self, id: Id) {
1123        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
1124        if !self.ids.is_empty() {
1125            self.ids.push(id);
1126        } else if let Some(i) = self.id.clone() {
1127            self.ids.extend(vec![i, id]);
1128            self.id = None;
1129        } else {
1130            self.id = Some(id);
1131        }
1132    }
1133}
1134
1135/// # CompoundCRS Interface
1136///
1137/// Represents a compound coordinate reference system, consisting of multiple components.
1138#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1139#[serde(default)]
1140pub struct CompoundCRS {
1141    /// Indicates the type of object. Always "CompoundCRS" for this interface.
1142    #[serde(rename = "type")]
1143    pub r#type: Option<String>, // 'CompoundCRS';
1144    /// The name of the compound CRS.
1145    pub name: String,
1146    /// An array of coordinate reference systems that make up the compound CRS.
1147    #[serde(skip_serializing_if = "Vec::is_empty")]
1148    pub components: Vec<CRS>,
1149    /// Usage Information
1150    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1151    pub usage: Option<ObjectUsage>,
1152    /// Usages
1153    #[serde(skip_serializing_if = "Vec::is_empty")]
1154    pub usages: Vec<ObjectUsage>,
1155}
1156impl ToProjJSON for CompoundCRS {
1157    fn set_id(&mut self, id: Id) {
1158        if self.usage.is_none() && self.usages.is_empty() {
1159            self.usage = Some(ObjectUsage::default());
1160        }
1161        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
1162            u.set_id(id);
1163        }
1164    }
1165    fn set_usage(&mut self, usage: ObjectUsage) {
1166        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
1167        if self.usages.is_empty() {
1168            if let Some(u) = self.usage.clone() {
1169                self.usages.extend(vec![u, usage]);
1170                self.usage = None;
1171            } else {
1172                self.usage = Some(usage);
1173            }
1174        } else {
1175            self.usages.push(usage);
1176        }
1177    }
1178}
1179
1180/// # EngineeringCRS Interface
1181///
1182/// Represents an engineering coordinate reference system.
1183#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1184#[serde(default)]
1185pub struct EngineeringCRS {
1186    /// Indicates the type of CRS. Always "EngineeringCRS" for this interface.
1187    #[serde(rename = "type")]
1188    pub r#type: Option<String>, // 'EngineeringCRS';
1189    /// The name of the engineering CRS.
1190    pub name: String,
1191    /// The engineering datum associated with this CRS.
1192    pub datum: EngineeringDatum,
1193    /// The coordinate system used in this CRS.
1194    pub coordinate_system: Option<CoordinateSystem>,
1195    /// Usage Information
1196    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1197    pub usage: Option<ObjectUsage>,
1198    /// Usages
1199    #[serde(skip_serializing_if = "Vec::is_empty")]
1200    pub usages: Vec<ObjectUsage>,
1201}
1202impl ToProjJSON for EngineeringCRS {
1203    fn set_id(&mut self, id: Id) {
1204        if self.usage.is_none() && self.usages.is_empty() {
1205            self.usage = Some(ObjectUsage::default());
1206        }
1207        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
1208            u.set_id(id);
1209        }
1210    }
1211    fn set_usage(&mut self, usage: ObjectUsage) {
1212        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
1213        if self.usages.is_empty() {
1214            if let Some(u) = self.usage.clone() {
1215                self.usages.extend(vec![u, usage]);
1216                self.usage = None;
1217            } else {
1218                self.usage = Some(usage);
1219            }
1220        } else {
1221            self.usages.push(usage);
1222        }
1223    }
1224    fn set_coordinate_system(&mut self, cs: CoordinateSystem) {
1225        self.coordinate_system = Some(cs);
1226    }
1227    // Pass down to the coordinate system
1228    fn set_axis(&mut self, axis: Axis) {
1229        if let Some(ref mut cs) = self.coordinate_system {
1230            cs.axis.push(axis);
1231        }
1232    }
1233    fn set_unit(&mut self, unit: Unit) {
1234        if let Some(ref mut cs) = self.coordinate_system {
1235            for axis in cs.axis.iter_mut() {
1236                axis.unit = Some(unit.clone());
1237            }
1238        }
1239    }
1240}
1241
1242/// # EngineeringDatum Interface
1243///
1244/// Represents the datum associated with an engineering CRS.
1245#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1246#[serde(default)]
1247pub struct EngineeringDatum {
1248    /// Indicates the type of datum. Always "EngineeringDatum" for this interface.
1249    #[serde(rename = "type")]
1250    pub r#type: Option<String>, // 'EngineeringDatum';
1251    /// The name of the datum.
1252    pub name: String,
1253    /// Anchor point of the datum.
1254    #[serde(skip_serializing_if = "Option::is_none")]
1255    pub anchor: Option<String>,
1256    /// Usage Information
1257    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1258    pub usage: Option<ObjectUsage>,
1259    /// Usages
1260    #[serde(skip_serializing_if = "Vec::is_empty")]
1261    pub usages: Vec<ObjectUsage>,
1262}
1263impl ToProjJSON for EngineeringDatum {
1264    fn set_id(&mut self, id: Id) {
1265        if self.usage.is_none() && self.usages.is_empty() {
1266            self.usage = Some(ObjectUsage::default());
1267        }
1268        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
1269            u.set_id(id);
1270        }
1271    }
1272    fn set_usage(&mut self, usage: ObjectUsage) {
1273        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
1274        if self.usages.is_empty() {
1275            if let Some(u) = self.usage.clone() {
1276                self.usages.extend(vec![u, usage]);
1277                self.usage = None;
1278            } else {
1279                self.usage = Some(usage);
1280            }
1281        } else {
1282            self.usages.push(usage);
1283        }
1284    }
1285    fn set_anchor(&mut self, anchor: String) {
1286        self.anchor = Some(anchor);
1287    }
1288}
1289
1290/// Axis Direction defines an axis direction
1291#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, PartialEq)]
1292#[serde(rename_all = "camelCase")]
1293pub enum AxisDirection {
1294    /// North
1295    North,
1296    /// North by North East
1297    NorthNorthEast,
1298    /// North East
1299    NorthEast,
1300    /// East by North East
1301    EastNorthEast,
1302    /// East
1303    East,
1304    /// East by South East
1305    EastSouthEast,
1306    /// South East
1307    SouthEast,
1308    /// South by South East
1309    SouthSouthEast,
1310    /// South
1311    South,
1312    /// South by South West
1313    SouthSouthWest,
1314    /// South West
1315    SouthWest,
1316    /// West by South West
1317    WestSouthWest,
1318    /// West
1319    West,
1320    /// West by North West
1321    WestNorthWest,
1322    /// North West
1323    NorthWest,
1324    /// North by North West
1325    NorthNorthWest,
1326    /// Up
1327    Up,
1328    /// Down
1329    Down,
1330    /// Geocentric X
1331    GeocentricX,
1332    /// Geocentric Y
1333    GeocentricY,
1334    /// Geocentric Z
1335    GeocentricZ,
1336    /// Column Positive
1337    ColumnPositive,
1338    /// Column Negative
1339    ColumnNegative,
1340    /// Row Positive
1341    RowPositive,
1342    /// Row Negative
1343    RowNegative,
1344    /// Display Right
1345    DisplayRight,
1346    /// Display Left
1347    DisplayLeft,
1348    /// Display Up
1349    DisplayUp,
1350    /// Display Down
1351    DisplayDown,
1352    /// Forward
1353    Forward,
1354    /// Aft
1355    Aft,
1356    /// Port
1357    Port,
1358    /// Starboard
1359    Starboard,
1360    /// Clockwise
1361    Clockwise,
1362    /// Counter Clockwise
1363    CounterClockwise,
1364    /// Towards
1365    Towards,
1366    /// Away From
1367    AwayFrom,
1368    /// Future
1369    Future,
1370    /// Past
1371    Past,
1372    /// Unspecified
1373    #[default]
1374    Unspecified,
1375}
1376impl From<String> for AxisDirection {
1377    fn from(s: String) -> Self {
1378        serde_json::from_str(&format!("\"{}\"", &s))
1379            .or_else(|_| serde_json::from_str(&format!("\"{}\"", to_camel_case(&s))))
1380            .unwrap_or_else(|_| {
1381                // try a few cases otherwise default
1382                match s.to_lowercase().as_str() {
1383                    "n" => AxisDirection::North,
1384                    "ne" | "northeast" => AxisDirection::NorthEast,
1385                    "e" => AxisDirection::East,
1386                    "se" | "southeast" => AxisDirection::SouthEast,
1387                    "s" => AxisDirection::South,
1388                    "sw" | "southwest" => AxisDirection::SouthWest,
1389                    "w" => AxisDirection::West,
1390                    "nw" | "northwest" => AxisDirection::NorthWest,
1391                    _ => AxisDirection::Unspecified,
1392                }
1393            })
1394    }
1395}
1396
1397/// Axis Range Meaning
1398#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1399#[serde(rename_all = "lowercase")]
1400pub enum AxisRangeMeaning {
1401    /// Exact
1402    #[default]
1403    Exact,
1404    /// Wraparound
1405    Wraparound,
1406}
1407
1408/// # Axis Interface
1409///
1410/// Represents an individual axis in a coordinate system.
1411#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1412#[serde(default)]
1413pub struct Axis {
1414    /// Indicates the type of axis. Always "Axis" for this interface.
1415    #[serde(rename = "type")]
1416    pub r#type: Option<String>, // 'Axis';
1417    /// The name of the axis.
1418    pub name: String,
1419    /// Abbreviation for the axis name.
1420    pub abbreviation: String,
1421    /// The direction of the axis.
1422    /// Examples include north, east, up, down, geocentricX, geocentricY, geocentricZ, etc.
1423    pub direction: AxisDirection,
1424    /// The order of the axis.
1425    /// Not part of the specification, added for convenience.
1426    pub order: usize,
1427    /// The meridian for the axis, if applicable.
1428    #[serde(skip_serializing_if = "Option::is_none")]
1429    pub meridian: Option<Meridian>,
1430    /// The unit of measurement for the axis.
1431    #[serde(skip_serializing_if = "Option::is_none")]
1432    pub unit: Option<Unit>,
1433    /// The minimum value allowed for the axis.
1434    #[serde(skip_serializing_if = "Option::is_none")]
1435    pub minimum_value: Option<f64>,
1436    /// The maximum value allowed for the axis.
1437    #[serde(skip_serializing_if = "Option::is_none")]
1438    pub maximum_value: Option<f64>,
1439    /// The range meaning for the axis.
1440    /// Can be either "exact" or "wraparound".
1441    #[serde(skip_serializing_if = "Option::is_none")]
1442    pub range_meaning: Option<AxisRangeMeaning>,
1443    /// An identifier for the axis.
1444    #[serde(skip_serializing_if = "Option::is_none")]
1445    pub id: Option<Id>,
1446    /// An array of identifiers for the axis.
1447    #[serde(skip_serializing_if = "Vec::is_empty")]
1448    pub ids: Ids,
1449}
1450impl Axis {
1451    /// Adjust the order if needed
1452    pub fn adjust_if_needed(&mut self) {
1453        if self.order != 0 {
1454            return;
1455        }
1456        let name = self.name.to_lowercase();
1457        self.order = if name.contains("longitude")
1458            || name.contains("northing")
1459            || name.contains("(lon)")
1460            || name.contains("(Y)")
1461            || name.contains("(N)")
1462        {
1463            2
1464        } else if name.contains("z") {
1465            3
1466        } else {
1467            0
1468        };
1469    }
1470}
1471impl ToProjJSON for Axis {
1472    fn set_id(&mut self, id: Id) {
1473        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
1474        if !self.ids.is_empty() {
1475            self.ids.push(id);
1476        } else if let Some(i) = self.id.clone() {
1477            self.ids.extend(vec![i, id]);
1478            self.id = None;
1479        } else {
1480            self.id = Some(id);
1481        }
1482    }
1483    fn set_unit(&mut self, unit: Unit) {
1484        self.unit = Some(unit);
1485    }
1486    fn set_meridian(&mut self, meridian: Meridian) {
1487        self.meridian = Some(meridian);
1488    }
1489    fn set_order(&mut self, order: usize) {
1490        self.order = order;
1491    }
1492}
1493
1494/// # Meridian Interface
1495///
1496/// Represents a meridian, which defines the longitude for an axis.
1497#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1498#[serde(default)]
1499pub struct Meridian {
1500    /// The schema URL or identifier.
1501    #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")]
1502    pub schema: Option<String>,
1503    /// Indicates the type of meridian. Always "Meridian" for this interface.
1504    #[serde(rename = "type")]
1505    pub r#type: Option<String>, // 'Meridian';
1506    /// The longitude of the meridian.
1507    pub longitude: ValueInDegreeOrValueAndUnit,
1508    /// An identifier for the meridian.
1509    #[serde(skip_serializing_if = "Option::is_none")]
1510    pub id: Option<Id>,
1511    /// An array of identifiers for the meridian.
1512    #[serde(skip_serializing_if = "Vec::is_empty")]
1513    pub ids: Ids,
1514}
1515impl ToProjJSON for Meridian {
1516    fn set_id(&mut self, id: Id) {
1517        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
1518        if !self.ids.is_empty() {
1519            self.ids.push(id);
1520        } else if let Some(i) = self.id.clone() {
1521            self.ids.extend(vec![i, id]);
1522            self.id = None;
1523        } else {
1524            self.id = Some(id);
1525        }
1526    }
1527}
1528
1529/// # ValueAndUnit Interface
1530///
1531/// Represents a value paired with a unit of measurement.
1532#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1533#[serde(default)]
1534pub struct ValueAndUnit {
1535    /// The numeric degree value.
1536    pub value: f64,
1537    /// The unit of measurement.
1538    pub unit: Unit,
1539}
1540impl ValueAndUnit {
1541    /// Get the radians of the value
1542    pub fn rad(&self) -> f64 {
1543        self.value * self.unit.rad()
1544    }
1545}
1546
1547/// Value in Degrees or Value and Unit
1548#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1549#[serde(untagged)]
1550pub enum ValueInDegreeOrValueAndUnit {
1551    /// Float value (degrees)
1552    F64(f64),
1553    /// Value and Unit Object
1554    ValueAndUnit(ValueAndUnit),
1555}
1556impl ValueInDegreeOrValueAndUnit {
1557    /// Create a new `ValueInDegreeOrValueAndUnit` from a unit and value
1558    pub fn from_unit(unit: Unit, value: f64) -> Self {
1559        ValueInDegreeOrValueAndUnit::ValueAndUnit(ValueAndUnit { value, unit })
1560    }
1561    /// Get the radians of the value
1562    pub fn rad(&self) -> f64 {
1563        match self {
1564            ValueInDegreeOrValueAndUnit::F64(value) => (*value).to_radians(),
1565            ValueInDegreeOrValueAndUnit::ValueAndUnit(value) => value.rad(),
1566        }
1567    }
1568}
1569impl Default for ValueInDegreeOrValueAndUnit {
1570    fn default() -> Self {
1571        ValueInDegreeOrValueAndUnit::F64(0.0)
1572    }
1573}
1574impl ToProjJSON for ValueInDegreeOrValueAndUnit {
1575    fn set_unit(&mut self, unit: Unit) {
1576        match self {
1577            ValueInDegreeOrValueAndUnit::F64(val) => {
1578                *self =
1579                    ValueInDegreeOrValueAndUnit::ValueAndUnit(ValueAndUnit { value: *val, unit });
1580            }
1581            ValueInDegreeOrValueAndUnit::ValueAndUnit(value) => value.unit = unit,
1582        }
1583    }
1584}
1585
1586/// Value in Metres or Value and Unit
1587#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1588#[serde(untagged)]
1589pub enum ValueInMetreOrValueAndUnit {
1590    /// Float
1591    F64(f64),
1592    /// Value and Unit
1593    ValueAndUnit(ValueAndUnit),
1594}
1595impl ValueInMetreOrValueAndUnit {
1596    /// Create a new `ValueInMetreOrValueAndUnit` from a unit and value
1597    pub fn from_unit(unit: Unit, value: f64) -> Self {
1598        ValueInMetreOrValueAndUnit::ValueAndUnit(ValueAndUnit { value, unit })
1599    }
1600    /// Get the meters of the value
1601    pub fn meters(&self) -> f64 {
1602        match self {
1603            ValueInMetreOrValueAndUnit::F64(value) => *value,
1604            ValueInMetreOrValueAndUnit::ValueAndUnit(value) => value.unit.meters() * value.value,
1605        }
1606    }
1607}
1608impl Default for ValueInMetreOrValueAndUnit {
1609    fn default() -> Self {
1610        ValueInMetreOrValueAndUnit::F64(0.0)
1611    }
1612}
1613impl From<f64> for ValueInMetreOrValueAndUnit {
1614    fn from(value: f64) -> Self {
1615        ValueInMetreOrValueAndUnit::F64(value)
1616    }
1617}
1618
1619/// # Single Operation
1620///
1621/// Represents a single operation, which can be a conversion, transformation, or point motion operation.
1622#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1623#[serde(untagged)]
1624pub enum SingleOperation {
1625    /// Conversion Operation
1626    Conversion(Box<Conversion>),
1627    /// Transformation Operation
1628    Transformation(Box<Transformation>),
1629    /// Point & Motion Operation
1630    PointMotionOperation(Box<PointMotionOperation>),
1631}
1632impl ToProjJSON for SingleOperation {
1633    fn set_id(&mut self, id: Id) {
1634        match self {
1635            SingleOperation::Conversion(c) => c.set_id(id),
1636            SingleOperation::Transformation(t) => t.set_id(id),
1637            SingleOperation::PointMotionOperation(p) => p.set_id(id),
1638        }
1639    }
1640    fn set_conversion(&mut self, conversion: Conversion) {
1641        *self = SingleOperation::Conversion(Box::new(conversion));
1642    }
1643}
1644
1645/// # DeformationModel Interface
1646///
1647/// Represents a deformation model associated with a point motion operation.
1648#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1649#[serde(default)]
1650pub struct DeformationModel {
1651    /// The name of the deformation model.
1652    pub name: String,
1653    /// An identifier for the deformation model.
1654    #[serde(skip_serializing_if = "Option::is_none")]
1655    pub id: Option<Id>,
1656}
1657
1658/// # DerivedEngineeringCRS Interface
1659///
1660/// Represents a derived engineering coordinate reference system.
1661#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1662#[serde(default)]
1663pub struct DerivedEngineeringCRS {
1664    /// Indicates the type of coordinate reference system. Always "DerivedEngineeringCRS" for this interface.
1665    #[serde(rename = "type")]
1666    pub r#type: Option<String>, // 'DerivedEngineeringCRS';
1667    /// The name of the derived engineering CRS.
1668    pub name: String,
1669    /// The base CRS from which this derived CRS is created.
1670    pub base_crs: EngineeringCRS,
1671    /// The conversion method applied to the base CRS.
1672    pub conversion: Conversion,
1673    /// The coordinate system used in the CRS.
1674    pub coordinate_system: CoordinateSystem,
1675    /// Usage Information
1676    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1677    pub usage: Option<ObjectUsage>,
1678    /// Usages
1679    #[serde(skip_serializing_if = "Vec::is_empty")]
1680    pub usages: Vec<ObjectUsage>,
1681}
1682impl ToProjJSON for DerivedEngineeringCRS {
1683    fn set_id(&mut self, id: Id) {
1684        if self.usage.is_none() && self.usages.is_empty() {
1685            self.usage = Some(ObjectUsage::default());
1686        }
1687        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
1688            u.set_id(id);
1689        }
1690    }
1691    fn set_usage(&mut self, usage: ObjectUsage) {
1692        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
1693        if self.usages.is_empty() {
1694            if let Some(u) = self.usage.clone() {
1695                self.usages.extend(vec![u, usage]);
1696                self.usage = None;
1697            } else {
1698                self.usage = Some(usage);
1699            }
1700        } else {
1701            self.usages.push(usage);
1702        }
1703    }
1704    fn set_coordinate_system(&mut self, cs: CoordinateSystem) {
1705        self.coordinate_system = cs;
1706    }
1707    fn set_conversion(&mut self, conversion: Conversion) {
1708        self.conversion = conversion;
1709    }
1710    // Pass down to the coordinate system
1711    fn set_axis(&mut self, axis: Axis) {
1712        self.coordinate_system.axis.push(axis);
1713    }
1714    fn set_unit(&mut self, unit: Unit) {
1715        for axis in self.coordinate_system.axis.iter_mut() {
1716            axis.unit = Some(unit.clone());
1717        }
1718    }
1719}
1720
1721/// # DerivedGeodeticCRS Interface
1722///
1723/// Represents a derived geodetic or geographic coordinate reference system.
1724#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1725#[serde(default)]
1726pub struct DerivedGeodeticCRS {
1727    /// Indicates the type of coordinate reference system. Can be either "DerivedGeodeticCRS" or "DerivedGeographicCRS".
1728    #[serde(rename = "type")]
1729    pub r#type: Option<String>, // 'DerivedGeodeticCRS' | 'DerivedGeographicCRS';
1730    /// The name of the derived geodetic CRS.
1731    pub name: String,
1732    /// The base CRS from which this derived CRS is created.
1733    pub base_crs: GeodeticCRS,
1734    /// The conversion method applied to the base CRS.
1735    pub conversion: Conversion,
1736    /// The coordinate system used in the CRS.
1737    pub coordinate_system: CoordinateSystem,
1738    /// Usage Information
1739    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1740    pub usage: Option<ObjectUsage>,
1741    /// Usages
1742    #[serde(skip_serializing_if = "Vec::is_empty")]
1743    pub usages: Vec<ObjectUsage>,
1744}
1745impl ToProjJSON for DerivedGeodeticCRS {
1746    fn set_id(&mut self, id: Id) {
1747        if self.usage.is_none() && self.usages.is_empty() {
1748            self.usage = Some(ObjectUsage::default());
1749        }
1750        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
1751            u.set_id(id);
1752        }
1753    }
1754    fn set_usage(&mut self, usage: ObjectUsage) {
1755        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
1756        if self.usages.is_empty() {
1757            if let Some(u) = self.usage.clone() {
1758                self.usages.extend(vec![u, usage]);
1759                self.usage = None;
1760            } else {
1761                self.usage = Some(usage);
1762            }
1763        } else {
1764            self.usages.push(usage);
1765        }
1766    }
1767    fn set_coordinate_system(&mut self, cs: CoordinateSystem) {
1768        self.coordinate_system = cs;
1769    }
1770    fn set_conversion(&mut self, conversion: Conversion) {
1771        self.conversion = conversion;
1772    }
1773    fn set_geodetic_crs(&mut self, geodetic_crs: GeodeticCRS) {
1774        self.base_crs = geodetic_crs;
1775    }
1776    // Pass down to the coordinate system
1777    fn set_axis(&mut self, axis: Axis) {
1778        self.coordinate_system.axis.push(axis);
1779    }
1780    fn set_unit(&mut self, unit: Unit) {
1781        for axis in self.coordinate_system.axis.iter_mut() {
1782            axis.unit = Some(unit.clone());
1783        }
1784    }
1785}
1786
1787/// # GeodeticCRS Interface
1788///
1789/// Represents a geodetic or geographic coordinate reference system.
1790#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1791#[serde(default)]
1792pub struct GeodeticCRS {
1793    /// Indicates the type of CRS. Can be "GeodeticCRS" or "GeographicCRS".
1794    #[serde(rename = "type")]
1795    pub r#type: Option<String>, // 'GeodeticCRS' | 'GeographicCRS';
1796    /// The name of the geodetic CRS.
1797    pub name: String,
1798    /// The datum associated with the geodetic CRS.
1799    /// One and only one of `datum` or `datum_ensemble` must be provided.
1800    /// Can only be `GeodeticReferenceFrame` or `DynamicGeodeticReferenceFrame`.
1801    #[serde(skip_serializing_if = "Option::is_none")]
1802    pub datum: Option<Datum>,
1803    /// The datum ensemble associated with the geodetic CRS.
1804    #[serde(skip_serializing_if = "Option::is_none")]
1805    pub datum_ensemble: Option<DatumEnsemble>,
1806    /// The coordinate system used in the geodetic CRS.
1807    #[serde(skip_serializing_if = "Option::is_none")]
1808    pub coordinate_system: Option<CoordinateSystem>,
1809    /// An array of deformation models associated with the geodetic CRS.
1810    /// DYNAMIC[FRAMEEPOCH[2010.0],MODEL["NAD83(CSRS)v6 velocity grid"]] (referenced by MODEL)
1811    #[serde(skip_serializing_if = "Option::is_none")]
1812    pub deformation_models: Option<Vec<DeformationModel>>,
1813    /// Usage Information
1814    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1815    pub usage: Option<ObjectUsage>,
1816    /// Usages
1817    #[serde(skip_serializing_if = "Vec::is_empty")]
1818    pub usages: Vec<ObjectUsage>,
1819}
1820impl ToProjJSON for GeodeticCRS {
1821    fn set_id(&mut self, id: Id) {
1822        if self.usage.is_none() && self.usages.is_empty() {
1823            self.usage = Some(ObjectUsage::default());
1824        }
1825        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
1826            u.set_id(id);
1827        }
1828    }
1829    fn set_usage(&mut self, usage: ObjectUsage) {
1830        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
1831        if self.usages.is_empty() {
1832            if let Some(u) = self.usage.clone() {
1833                self.usages.extend(vec![u, usage]);
1834                self.usage = None;
1835            } else {
1836                self.usage = Some(usage);
1837            }
1838        } else {
1839            self.usages.push(usage);
1840        }
1841    }
1842    fn set_coordinate_system(&mut self, cs: CoordinateSystem) {
1843        self.coordinate_system = Some(cs);
1844    }
1845    fn set_datum(&mut self, datum: Datum) {
1846        self.datum = Some(datum);
1847    }
1848    fn set_ensemble(&mut self, ensemble: DatumEnsemble) {
1849        self.datum_ensemble = Some(ensemble);
1850    }
1851    // Pass down to the datum
1852    fn set_prime_meridian(&mut self, prime_meridian: PrimeMeridian) {
1853        if let Some(ref mut datum) = self.datum {
1854            datum.set_prime_meridian(prime_meridian);
1855        }
1856    }
1857    // Pass down to the coordinate system
1858    fn set_axis(&mut self, axis: Axis) {
1859        if let Some(ref mut cs) = self.coordinate_system {
1860            cs.axis.push(axis);
1861        }
1862    }
1863    fn set_unit(&mut self, unit: Unit) {
1864        if let Some(ref mut cs) = self.coordinate_system {
1865            for axis in cs.axis.iter_mut() {
1866                axis.unit = Some(unit.clone());
1867            }
1868        }
1869    }
1870}
1871impl GeodeticCRS {
1872    /// Convert a GeodeticCRS to a ProjectionTransform
1873    pub fn to_projection_transform(&self, proj_transform: &mut ProjectionTransform) {
1874        proj_transform.proj.borrow_mut().name = self.name.clone();
1875        // TODO: DeformationModel
1876        // TODO: Datum -> build_datum
1877        if let Some(datum_ensemble) = &self.datum_ensemble {
1878            datum_ensemble.to_projection_transform(proj_transform);
1879        }
1880        if let Some(datum) = &self.datum {
1881            datum.to_projection_transform(proj_transform);
1882        }
1883        if let Some(coordinate_system) = &self.coordinate_system {
1884            coordinate_system.to_projection_transform(proj_transform);
1885        }
1886    }
1887}
1888
1889/// # Geodetic reference frame (geodetic datum)
1890///
1891/// Represented with the `DATUM` keyword
1892#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1893#[serde(default)]
1894pub struct GeodeticReferenceFrame {
1895    /// Indicates the type of reference frame. Always "GeodeticReferenceFrame" for this interface.
1896    #[serde(rename = "type")]
1897    pub r#type: Option<String>, // 'GeodeticReferenceFrame';
1898    /// The name of the reference frame.
1899    pub name: String,
1900    /// The ellipsoid used in the reference frame.
1901    pub ellipsoid: Ellipsoid,
1902    /// The anchor point of the reference frame.
1903    #[serde(skip_serializing_if = "Option::is_none")]
1904    pub anchor: Option<String>,
1905    /// The epoch of the anchor point.
1906    #[serde(skip_serializing_if = "Option::is_none")]
1907    pub anchor_epoch: Option<f64>,
1908    /// The prime meridian associated with the reference frame.
1909    #[serde(skip_serializing_if = "Option::is_none")]
1910    pub prime_meridian: Option<PrimeMeridian>,
1911    /// Usage Information
1912    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1913    pub usage: Option<ObjectUsage>,
1914    /// Usages
1915    #[serde(skip_serializing_if = "Vec::is_empty")]
1916    pub usages: Vec<ObjectUsage>,
1917}
1918impl GeodeticReferenceFrame {
1919    /// Convert a GeodeticReferenceFrame to a ProjectionTransform
1920    pub fn to_projection_transform(&self, proj_transform: &mut ProjectionTransform) {
1921        self.ellipsoid.to_projection_transform(proj_transform);
1922        if let Some(pm) = &self.prime_meridian {
1923            pm.to_projection_transform(proj_transform);
1924        }
1925    }
1926}
1927impl ToProjJSON for GeodeticReferenceFrame {
1928    fn set_id(&mut self, id: Id) {
1929        if self.usage.is_none() && self.usages.is_empty() {
1930            self.usage = Some(ObjectUsage::default());
1931        }
1932        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
1933            u.set_id(id);
1934        }
1935    }
1936    fn set_usage(&mut self, usage: ObjectUsage) {
1937        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
1938        if self.usages.is_empty() {
1939            if let Some(u) = self.usage.clone() {
1940                self.usages.extend(vec![u, usage]);
1941                self.usage = None;
1942            } else {
1943                self.usage = Some(usage);
1944            }
1945        } else {
1946            self.usages.push(usage);
1947        }
1948    }
1949    fn set_anchor(&mut self, anchor: String) {
1950        self.anchor = Some(anchor);
1951    }
1952    fn set_ellipsoid(&mut self, ellipsoid: Ellipsoid) {
1953        self.ellipsoid = ellipsoid;
1954    }
1955    fn set_epoch(&mut self, epoch: f64) {
1956        self.anchor_epoch = Some(epoch);
1957    }
1958    fn set_prime_meridian(&mut self, prime_meridian: PrimeMeridian) {
1959        self.prime_meridian = Some(prime_meridian);
1960    }
1961}
1962
1963/// # DerivedParametricCRS Interface
1964///
1965/// Represents a derived parametric coordinate reference system.
1966#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
1967#[serde(default)]
1968pub struct DerivedParametricCRS {
1969    /// Indicates the type of coordinate reference system. Always "DerivedParametricCRS" for this interface.
1970    #[serde(rename = "type")]
1971    pub r#type: Option<String>, // 'DerivedParametricCRS';
1972    /// The name of the derived parametric CRS.
1973    pub name: String,
1974    /// The base parametric CRS from which this CRS is derived.
1975    pub base_crs: ParametricCRS,
1976    /// The conversion method applied to the base CRS.
1977    pub conversion: Conversion,
1978    /// The coordinate system used in the CRS.
1979    pub coordinate_system: CoordinateSystem,
1980    /// Usage Information
1981    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1982    pub usage: Option<ObjectUsage>,
1983    /// Usages
1984    #[serde(skip_serializing_if = "Vec::is_empty")]
1985    pub usages: Vec<ObjectUsage>,
1986}
1987impl ToProjJSON for DerivedParametricCRS {
1988    fn set_id(&mut self, id: Id) {
1989        if self.usage.is_none() && self.usages.is_empty() {
1990            self.usage = Some(ObjectUsage::default());
1991        }
1992        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
1993            u.set_id(id);
1994        }
1995    }
1996    fn set_usage(&mut self, usage: ObjectUsage) {
1997        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
1998        if self.usages.is_empty() {
1999            if let Some(u) = self.usage.clone() {
2000                self.usages.extend(vec![u, usage]);
2001                self.usage = None;
2002            } else {
2003                self.usage = Some(usage);
2004            }
2005        } else {
2006            self.usages.push(usage);
2007        }
2008    }
2009    fn set_coordinate_system(&mut self, cs: CoordinateSystem) {
2010        self.coordinate_system = cs;
2011    }
2012    fn set_conversion(&mut self, conversion: Conversion) {
2013        self.conversion = conversion;
2014    }
2015    // Pass down to the coordinate system
2016    fn set_axis(&mut self, axis: Axis) {
2017        self.coordinate_system.axis.push(axis);
2018    }
2019    fn set_unit(&mut self, unit: Unit) {
2020        for axis in self.coordinate_system.axis.iter_mut() {
2021            axis.unit = Some(unit.clone());
2022        }
2023    }
2024}
2025
2026/// # DerivedProjectedCRS Interface
2027///
2028/// Represents a derived projected coordinate reference system.
2029#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2030#[serde(default)]
2031pub struct DerivedProjectedCRS {
2032    /// Indicates the type of coordinate reference system. Always "DerivedProjectedCRS" for this interface.
2033    #[serde(rename = "type")]
2034    pub r#type: Option<String>, // 'DerivedProjectedCRS';
2035    /// The name of the derived projected CRS.
2036    pub name: String,
2037    /// The base projected CRS from which this CRS is derived.
2038    pub base_crs: ProjectedCRS,
2039    /// The conversion method applied to the base CRS.
2040    pub conversion: Conversion,
2041    /// The coordinate system used in the CRS.
2042    pub coordinate_system: CoordinateSystem,
2043    /// Usage Information
2044    #[serde(flatten, skip_serializing_if = "Option::is_none")]
2045    pub usage: Option<ObjectUsage>,
2046    /// Usages
2047    #[serde(skip_serializing_if = "Vec::is_empty")]
2048    pub usages: Vec<ObjectUsage>,
2049}
2050impl ToProjJSON for DerivedProjectedCRS {
2051    fn set_id(&mut self, id: Id) {
2052        if self.usage.is_none() && self.usages.is_empty() {
2053            self.usage = Some(ObjectUsage::default());
2054        }
2055        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
2056            u.set_id(id);
2057        }
2058    }
2059    fn set_usage(&mut self, usage: ObjectUsage) {
2060        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
2061        if self.usages.is_empty() {
2062            if let Some(u) = self.usage.clone() {
2063                self.usages.extend(vec![u, usage]);
2064                self.usage = None;
2065            } else {
2066                self.usage = Some(usage);
2067            }
2068        } else {
2069            self.usages.push(usage);
2070        }
2071    }
2072    fn set_coordinate_system(&mut self, cs: CoordinateSystem) {
2073        self.coordinate_system = cs;
2074    }
2075    fn set_conversion(&mut self, conversion: Conversion) {
2076        self.conversion = conversion;
2077    }
2078    fn set_projected_crs(&mut self, projected_crs: ProjectedCRS) {
2079        self.base_crs = projected_crs;
2080    }
2081    // Pass down to the coordinate system
2082    fn set_axis(&mut self, axis: Axis) {
2083        self.coordinate_system.axis.push(axis);
2084    }
2085    fn set_unit(&mut self, unit: Unit) {
2086        for axis in self.coordinate_system.axis.iter_mut() {
2087            axis.unit = Some(unit.clone());
2088        }
2089    }
2090}
2091
2092/// # DerivedTemporalCRS Interface
2093///
2094/// Represents a derived temporal coordinate reference system.
2095#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2096#[serde(default)]
2097pub struct DerivedTemporalCRS {
2098    /// Indicates the type of coordinate reference system. Always "DerivedTemporalCRS" for this interface.
2099    #[serde(rename = "type")]
2100    pub r#type: Option<String>, // 'DerivedTemporalCRS';
2101    /// The name of the derived temporal CRS.
2102    pub name: String,
2103    /// The base temporal CRS from which this CRS is derived.
2104    pub base_crs: TemporalCRS,
2105    /// The conversion method applied to the base CRS.
2106    pub conversion: Conversion,
2107    /// The coordinate system used in the CRS.
2108    pub coordinate_system: CoordinateSystem,
2109    /// Usage Information
2110    #[serde(flatten, skip_serializing_if = "Option::is_none")]
2111    pub usage: Option<ObjectUsage>,
2112    /// Usages
2113    #[serde(skip_serializing_if = "Vec::is_empty")]
2114    pub usages: Vec<ObjectUsage>,
2115}
2116impl ToProjJSON for DerivedTemporalCRS {
2117    fn set_id(&mut self, id: Id) {
2118        if self.usage.is_none() && self.usages.is_empty() {
2119            self.usage = Some(ObjectUsage::default());
2120        }
2121        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
2122            u.set_id(id);
2123        }
2124    }
2125    fn set_usage(&mut self, usage: ObjectUsage) {
2126        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
2127        if self.usages.is_empty() {
2128            if let Some(u) = self.usage.clone() {
2129                self.usages.extend(vec![u, usage]);
2130                self.usage = None;
2131            } else {
2132                self.usage = Some(usage);
2133            }
2134        } else {
2135            self.usages.push(usage);
2136        }
2137    }
2138    fn set_coordinate_system(&mut self, cs: CoordinateSystem) {
2139        self.coordinate_system = cs;
2140    }
2141    fn set_conversion(&mut self, conversion: Conversion) {
2142        self.conversion = conversion;
2143    }
2144    // Pass down to the coordinate system
2145    fn set_axis(&mut self, axis: Axis) {
2146        self.coordinate_system.axis.push(axis);
2147    }
2148    fn set_unit(&mut self, unit: Unit) {
2149        for axis in self.coordinate_system.axis.iter_mut() {
2150            axis.unit = Some(unit.clone());
2151        }
2152    }
2153}
2154
2155/// # DerivedVerticalCRS Interface
2156///
2157/// Represents a derived vertical coordinate reference system.
2158#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2159#[serde(default)]
2160pub struct DerivedVerticalCRS {
2161    /// Indicates the type of coordinate reference system. Always "DerivedVerticalCRS" for this interface.
2162    #[serde(rename = "type")]
2163    pub r#type: Option<String>, // 'DerivedVerticalCRS';
2164    /// The name of the derived vertical CRS.
2165    pub name: String,
2166    /// The base vertical CRS from which this CRS is derived.
2167    pub base_crs: VerticalCRS,
2168    /// The conversion method applied to the base CRS.
2169    pub conversion: Conversion,
2170    /// The coordinate system used in the CRS.
2171    pub coordinate_system: CoordinateSystem,
2172    /// Usage Information
2173    #[serde(flatten, skip_serializing_if = "Option::is_none")]
2174    pub usage: Option<ObjectUsage>,
2175    /// Usages
2176    #[serde(skip_serializing_if = "Vec::is_empty")]
2177    pub usages: Vec<ObjectUsage>,
2178}
2179impl ToProjJSON for DerivedVerticalCRS {
2180    fn set_id(&mut self, id: Id) {
2181        if self.usage.is_none() && self.usages.is_empty() {
2182            self.usage = Some(ObjectUsage::default());
2183        }
2184        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
2185            u.set_id(id);
2186        }
2187    }
2188    fn set_usage(&mut self, usage: ObjectUsage) {
2189        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
2190        if self.usages.is_empty() {
2191            if let Some(u) = self.usage.clone() {
2192                self.usages.extend(vec![u, usage]);
2193                self.usage = None;
2194            } else {
2195                self.usage = Some(usage);
2196            }
2197        } else {
2198            self.usages.push(usage);
2199        }
2200    }
2201    fn set_coordinate_system(&mut self, cs: CoordinateSystem) {
2202        self.coordinate_system = cs;
2203    }
2204    fn set_conversion(&mut self, conversion: Conversion) {
2205        self.conversion = conversion;
2206    }
2207    // Pass down to the coordinate system
2208    fn set_axis(&mut self, axis: Axis) {
2209        self.coordinate_system.axis.push(axis);
2210    }
2211    fn set_unit(&mut self, unit: Unit) {
2212        for axis in self.coordinate_system.axis.iter_mut() {
2213            axis.unit = Some(unit.clone());
2214        }
2215    }
2216}
2217
2218/// # DynamicGeodeticReferenceFrame Interface
2219///
2220/// Represents a dynamic geodetic reference frame.
2221#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2222#[serde(default)]
2223pub struct DynamicGeodeticReferenceFrame {
2224    /// Indicates the type of reference frame. Always "DynamicGeodeticReferenceFrame" for this interface.
2225    #[serde(rename = "type")]
2226    pub r#type: Option<String>, // 'DynamicGeodeticReferenceFrame';
2227    /// The name of the reference frame.
2228    pub name: String,
2229    /// The ellipsoid used in the reference frame.
2230    pub ellipsoid: Ellipsoid,
2231    /// The frame reference epoch.
2232    pub frame_reference_epoch: f64,
2233    /// The anchor point of the reference frame.
2234    #[serde(skip_serializing_if = "Option::is_none")]
2235    pub anchor: Option<String>,
2236    /// The epoch of the anchor point.
2237    pub anchor_epoch: Option<f64>,
2238    /// The prime meridian associated with the reference frame.
2239    #[serde(skip_serializing_if = "Option::is_none")]
2240    pub prime_meridian: Option<PrimeMeridian>,
2241    /// Usage Information
2242    #[serde(flatten, skip_serializing_if = "Option::is_none")]
2243    pub usage: Option<ObjectUsage>,
2244    /// Usages
2245    #[serde(skip_serializing_if = "Vec::is_empty")]
2246    pub usages: Vec<ObjectUsage>,
2247}
2248impl ToProjJSON for DynamicGeodeticReferenceFrame {
2249    fn set_id(&mut self, id: Id) {
2250        if self.usage.is_none() && self.usages.is_empty() {
2251            self.usage = Some(ObjectUsage::default());
2252        }
2253        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
2254            u.set_id(id);
2255        }
2256    }
2257    fn set_usage(&mut self, usage: ObjectUsage) {
2258        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
2259        if self.usages.is_empty() {
2260            if let Some(u) = self.usage.clone() {
2261                self.usages.extend(vec![u, usage]);
2262                self.usage = None;
2263            } else {
2264                self.usage = Some(usage);
2265            }
2266        } else {
2267            self.usages.push(usage);
2268        }
2269    }
2270    fn set_anchor(&mut self, anchor: String) {
2271        self.anchor = Some(anchor);
2272    }
2273    fn set_epoch(&mut self, epoch: f64) {
2274        self.anchor_epoch = Some(epoch);
2275    }
2276    fn set_frame_epoch(&mut self, epoch: f64) {
2277        self.frame_reference_epoch = epoch;
2278    }
2279    fn set_ellipsoid(&mut self, ellipsoid: Ellipsoid) {
2280        self.ellipsoid = ellipsoid;
2281    }
2282    fn set_prime_meridian(&mut self, prime_meridian: PrimeMeridian) {
2283        self.prime_meridian = Some(prime_meridian);
2284    }
2285}
2286
2287/// members in the datum ensemble
2288#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2289#[serde(default)]
2290pub struct DatumEnsembleMember {
2291    /// The name of the datum.
2292    pub name: String,
2293    /// An identifier for the datum.
2294    #[serde(skip_serializing_if = "Option::is_none")]
2295    pub id: Option<Id>,
2296    /// An array of identifiers for the datum.
2297    #[serde(skip_serializing_if = "Vec::is_empty")]
2298    pub ids: Ids,
2299}
2300impl ToProjJSON for DatumEnsembleMember {
2301    fn set_id(&mut self, id: Id) {
2302        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
2303        if !self.ids.is_empty() {
2304            self.ids.push(id);
2305        } else if let Some(i) = self.id.clone() {
2306            self.ids.extend(vec![i, id]);
2307            self.id = None;
2308        } else {
2309            self.id = Some(id);
2310        }
2311    }
2312}
2313
2314/// # DatumEnsemble Interface
2315///
2316/// Represents a datum ensemble, which is a collection of datums.
2317///
2318/// Geodetic and vertical CRSs are associated with either a reference frame (datum) or a datum ensemble. The members of a datum ensemble are given as a list of reference frames. The list may contain reference frame name and/or identifier. All members of a datum ensemble are realizations of one shared terrestrial or vertical reference system.
2319///
2320/// For an ensemble of geodetic reference frames (datums), the WKT string includes the description of the ellipsoid used by the members. This information is available from any and all of the definitions of each member. It is included in the ensemble WKT to facilitate direct access to the information. The WKT string for a datum ensemble may also include the description of the prime meridian applying to all members of the ensemble.
2321///
2322/// For both geodetic and vertical datum ensembles, the ensemble description includes its 'accuracy', an indication of the difference in coordinate values of a point between different members of the datum ensemble. It may be regarded as a measure of the inaccuracy introduced through the assumption that ensemble members are approximately equivalent.
2323///
2324/// Use of the datum ensemble concept comes with a health warning. If data is associated with a CRS having a datum ensemble, it will not be possible to identify which of the datum ensemble members the data might more accurately be referenced to. In high accuracy applications, datum ensembles should not be used; individual reference frames should be identified.
2325#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2326#[serde(default)]
2327pub struct DatumEnsemble {
2328    /// Indicates the type of datum ensemble. Always "DatumEnsemble" for this interface.
2329    #[serde(rename = "type")]
2330    pub r#type: Option<String>, // 'DatumEnsemble';
2331    /// The name of the datum ensemble.
2332    pub name: String,
2333    /// An array of members in the datum ensemble.
2334    #[serde(skip_serializing_if = "Vec::is_empty")]
2335    pub members: Vec<DatumEnsembleMember>,
2336    /// The accuracy of the datum ensemble.
2337    pub accuracy: String,
2338    /// The ellipsoid associated with the datum ensemble.
2339    #[serde(skip_serializing_if = "Option::is_none")]
2340    pub ellipsoid: Option<Ellipsoid>,
2341    /// An identifier for the datum ensemble.
2342    #[serde(skip_serializing_if = "Option::is_none")]
2343    pub id: Option<Id>,
2344    /// An array of identifiers for the datum ensemble.
2345    #[serde(skip_serializing_if = "Vec::is_empty")]
2346    pub ids: Ids,
2347}
2348impl ToProjJSON for DatumEnsemble {
2349    fn set_accuracy(&mut self, accuracy: String) {
2350        self.accuracy = accuracy;
2351    }
2352    fn set_ellipsoid(&mut self, ellipsoid: Ellipsoid) {
2353        self.ellipsoid = Some(ellipsoid);
2354    }
2355    fn set_member(&mut self, member: DatumEnsembleMember) {
2356        self.members.push(member);
2357    }
2358    fn set_id(&mut self, id: Id) {
2359        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
2360        if !self.ids.is_empty() {
2361            self.ids.push(id);
2362        } else if let Some(i) = self.id.clone() {
2363            self.ids.extend(vec![i, id]);
2364            self.id = None;
2365        } else {
2366            self.id = Some(id);
2367        }
2368    }
2369}
2370impl DatumEnsemble {
2371    /// Convert a DatumEnsemble to a ProjectionTransform
2372    pub fn to_projection_transform(&self, proj_transform: &mut ProjectionTransform) {
2373        if let Some(ellipsoid) = &self.ellipsoid {
2374            ellipsoid.to_projection_transform(proj_transform);
2375        }
2376    }
2377}
2378
2379/// # Ellipsoid
2380///
2381/// ## Description
2382/// The `<ellipsoid>` object is an attribute of `<geodetic reference frame>`. It is not used with other types of datum.
2383///
2384/// ISO 19111 allows an oblate ellipsoid to be defined through semi-major axis (a) and either
2385/// semi-minor axis (b) or inverse flattening (1/f). If semi-minor axis is used as the second
2386/// defining parameter the value for inverse flattening to be shown in the WKT string should be
2387/// calculated from $1/f  =  a / (a – b)$.
2388///
2389/// ISO 19111 also allows for the earth model to be a sphere, for which 1/f is infinite.
2390/// In this document if the earth model is a sphere `<inverse flattening>` shall be given an
2391/// artificial value of zero.
2392///
2393/// ## Requirements:
2394/// a) The WKT representation of a sphere shall have an `<inverse flattening>` value of 0.
2395/// b) `<length unit>` is an optional attribute, optional for reasons of backward compatibility,
2396/// but it is recommended that it is explicitly included in WKT strings. Its `<conversion factor>`
2397/// shall be to metres and is the number of metres per unit. `<length unit>` is described in 7.4.
2398/// If it is omitted then the value for the length of the semi-axis or -axes shall be given in metres.
2399/// Conversely, if it is omitted then the value for the semi-major axis shall be assumed to be in
2400/// metres.
2401///
2402/// ## Note:
2403/// - In the WKT for a geodetic, geographic or projected CRS, the length unit for the ellipsoid may
2404///   differ from the length unit for the coordinate system. The units in which coordinates are expressed
2405///   are given by the CS element.
2406/// - In this document the preferred keyword is ELLIPSOID. SPHEROID is permitted for backward compatibility.
2407///   Implementations should be prepared to read both forms.
2408///
2409/// ## Examples of WKT describing an ellipsoid:
2410/// - `ELLIPSOID["GRS 1980",6378137,298.257222101,LENGTHUNIT["metre",1.0]]`
2411/// - `SPHEROID["GRS 1980",6378137.0,298.257222101]` (unit = metre is implied)
2412/// - `ELLIPSOID["Clark 1866",20925832.164,294.97869821, LENGTHUNIT["US survey foot",0.304800609601219]]`
2413/// - `ELLIPSOID["Sphere",6371000,0,LENGTHUNIT["metre",1.0]]`
2414///
2415/// The definition of WKT for a triaxial ellipsoid required for planetary mapping is given in Annex E.
2416#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2417#[serde(default)]
2418pub struct Ellipsoid {
2419    /// Indicates the type of ellipsoid. Always "Ellipsoid" for this interface.
2420    #[serde(rename = "type")]
2421    pub r#type: Option<String>, // 'Ellipsoid';
2422    /// The name of the ellipsoid.
2423    pub name: String,
2424    /// The semi-major axis of the ellipsoid.
2425    /// Represented as a number or a value with a unit.
2426    pub semi_major_axis: Option<ValueInMetreOrValueAndUnit>,
2427    /// The semi-minor axis of the ellipsoid.
2428    /// Represented as a number or a value with a unit.
2429    /// Required when `inverse_flattening` is not provided.
2430    pub semi_minor_axis: Option<ValueInMetreOrValueAndUnit>,
2431    /// The inverse flattening of the ellipsoid.
2432    /// Required when `semi_minor_axis` is not provided.
2433    pub inverse_flattening: Option<ValueInMetreOrValueAndUnit>,
2434    /// The radius of the ellipsoid, used for spherical representations.
2435    /// Required when neither `semi_minor_axis` nor `inverse_flattening` are provided.
2436    pub radius: Option<ValueInMetreOrValueAndUnit>,
2437    /// An identifier for the datum ensemble.
2438    #[serde(skip_serializing_if = "Option::is_none")]
2439    pub id: Option<Id>,
2440    /// An array of identifiers for the datum ensemble.
2441    #[serde(skip_serializing_if = "Vec::is_empty")]
2442    pub ids: Ids,
2443}
2444impl ToProjJSON for Ellipsoid {
2445    fn set_id(&mut self, id: Id) {
2446        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
2447        if !self.ids.is_empty() {
2448            self.ids.push(id);
2449        } else if let Some(i) = self.id.clone() {
2450            self.ids.extend(vec![i, id]);
2451            self.id = None;
2452        } else {
2453            self.id = Some(id);
2454        }
2455    }
2456}
2457impl Ellipsoid {
2458    /// Convert a Ellipsoid to a ProjectionTransform
2459    pub fn to_projection_transform(&self, proj_transform: &mut ProjectionTransform) {
2460        let proj = &mut proj_transform.proj.borrow_mut();
2461        proj.ellps = self.name.clone();
2462        if let Some(semi_major_axis) = &self.semi_major_axis {
2463            proj.a = semi_major_axis.meters();
2464        }
2465        if let Some(semi_minor_axis) = &self.semi_minor_axis {
2466            proj.b = semi_minor_axis.meters();
2467        }
2468        if let Some(inverse_flattening) = &self.inverse_flattening {
2469            proj.rf = inverse_flattening.meters();
2470        }
2471        if let Some(radius) = &self.radius {
2472            proj.a = radius.meters();
2473            proj.b = radius.meters();
2474            proj.rf = 0.0;
2475        }
2476        derive_sphere(proj);
2477    }
2478}
2479
2480/// # Prime meridian
2481/// The WKT for prime meridian is defined in 8.2.2.
2482/// In this document the following definition from both ISO 19125-1:2004 and OGC 01-009 has been deprecated but is included here for the purposes of documenting backward compatibility:
2483/// - `<irm longitude>` is the longitude of the prime meridian measured from the international reference meridian, positive eastward.
2484/// - `<angle unit>` is an optional attribute, optional for reasons of backward compatibility, but best practice is that it is included in WKT strings. If it is omitted then the value for `<irm longitude>` shall be given in the CRS's `<cs unit>` where this is angular, else in decimal degrees. If the subtype of the geodetic CRS to which the prime meridian is an attribute is geographic, the prime meridian's `<irm longitude>` value shall be given in the same angular units as those for the horizontal axes of the geographic CRS; if the geodetic CRS subtype is geocentric the prime meridian's `<irm longitude>` value shall be given in degrees. Its `<conversion factor>` shall be to radians and is the number of radians per unit. `<angle unit>` is described in 7.4.
2485///
2486/// Examples of WKT describing a prime meridian:
2487/// - `PRIMEM["Paris",2.5969213,ANGLEUNIT["grad",0.015707963267949]]`
2488/// - `PRIMEM["Greenwich",0.0]`
2489#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2490#[serde(default)]
2491pub struct PrimeMeridian {
2492    /// Indicates the type of prime meridian. Always "PrimeMeridian" for this interface.
2493    #[serde(rename = "type")]
2494    pub r#type: Option<String>, // 'PrimeMeridian';
2495    /// The name of the prime meridian.
2496    pub name: String,
2497    /// The longitude of the prime meridian.
2498    /// Represented as a number or a value with a unit.
2499    pub longitude: ValueInDegreeOrValueAndUnit,
2500    /// An identifier for the datum ensemble.
2501    #[serde(skip_serializing_if = "Option::is_none")]
2502    pub id: Option<Id>,
2503    /// An array of identifiers for the datum ensemble.
2504    #[serde(skip_serializing_if = "Vec::is_empty")]
2505    pub ids: Ids,
2506}
2507impl PrimeMeridian {
2508    /// Convert a PrimeMeridian to a ProjectionTransform
2509    pub fn to_projection_transform(&self, proj_transform: &mut ProjectionTransform) {
2510        proj_transform.proj.borrow_mut().from_greenwich = self.longitude.rad();
2511    }
2512}
2513impl ToProjJSON for PrimeMeridian {
2514    fn set_id(&mut self, id: Id) {
2515        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
2516        if !self.ids.is_empty() {
2517            self.ids.push(id);
2518        } else if let Some(i) = self.id.clone() {
2519            self.ids.extend(vec![i, id]);
2520            self.id = None;
2521        } else {
2522            self.id = Some(id);
2523        }
2524    }
2525    fn set_unit(&mut self, unit: Unit) {
2526        self.longitude.set_unit(unit);
2527    }
2528}
2529
2530/// # ProjectedCRS Interface
2531///
2532/// Represents a projected coordinate reference system, which transforms geodetic or geographic
2533/// coordinates into a flat, two-dimensional plane using a map projection.
2534#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2535#[serde(default)]
2536pub struct ProjectedCRS {
2537    /// Indicates the type of CRS. Always "ProjectedCRS" for this interface.
2538    #[serde(rename = "type")]
2539    pub r#type: Option<String>, // 'ProjectedCRS';
2540    /// The name of the projected CRS.
2541    pub name: String,
2542    /// The base CRS upon which the projection is defined.
2543    /// Typically a geodetic CRS.
2544    pub base_crs: GeodeticCRS,
2545    /// The conversion defining the map projection.
2546    pub conversion: Conversion,
2547    /// The coordinate system used in the projected CRS.
2548    pub coordinate_system: CoordinateSystem,
2549    /// Usage Information
2550    #[serde(flatten, skip_serializing_if = "Option::is_none")]
2551    pub usage: Option<ObjectUsage>,
2552    /// Usages
2553    #[serde(skip_serializing_if = "Vec::is_empty")]
2554    pub usages: Vec<ObjectUsage>,
2555}
2556impl ToProjJSON for ProjectedCRS {
2557    fn set_id(&mut self, id: Id) {
2558        if self.usage.is_none() && self.usages.is_empty() {
2559            self.usage = Some(ObjectUsage::default());
2560        }
2561        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
2562            u.set_id(id);
2563        }
2564    }
2565    fn set_usage(&mut self, usage: ObjectUsage) {
2566        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
2567        if self.usages.is_empty() {
2568            if let Some(u) = self.usage.clone() {
2569                self.usages.extend(vec![u, usage]);
2570                self.usage = None;
2571            } else {
2572                self.usage = Some(usage);
2573            }
2574        } else {
2575            self.usages.push(usage);
2576        }
2577    }
2578    fn set_coordinate_system(&mut self, cs: CoordinateSystem) {
2579        self.coordinate_system = cs;
2580    }
2581    fn set_conversion(&mut self, conversion: Conversion) {
2582        self.conversion = conversion;
2583    }
2584    fn set_geodetic_crs(&mut self, geodetic_crs: GeodeticCRS) {
2585        self.base_crs = geodetic_crs;
2586    }
2587    // Pass down to the coordinate system
2588    fn set_axis(&mut self, axis: Axis) {
2589        self.coordinate_system.set_axis(axis);
2590    }
2591    fn set_unit(&mut self, unit: Unit) {
2592        self.coordinate_system.set_unit(unit);
2593    }
2594    // NOTE: Conversion also needs variables passed down
2595    fn set_projection(&mut self, name: String) {
2596        self.conversion.set_projection(name);
2597    }
2598    fn set_method(&mut self, method: Method) {
2599        self.conversion.set_method(method);
2600    }
2601    fn set_parameter(&mut self, parameter: ParameterValue) {
2602        self.conversion.set_parameter(parameter);
2603    }
2604}
2605impl ProjectedCRS {
2606    /// Convert a ProjectedCRS to a ProjectionTransform
2607    pub fn to_projection_transform(&self, proj_transform: &mut ProjectionTransform) {
2608        // First update the conversion type with "coordinate_system" (set axis step at least)
2609        self.coordinate_system.to_projection_transform(proj_transform);
2610        // set base_crs as first step
2611        self.base_crs.to_projection_transform(proj_transform);
2612        // set conversion
2613        self.conversion.to_projection_transform(proj_transform);
2614    }
2615}
2616
2617/// # Conversion Interface
2618///
2619/// Represents the map projection or transformation used in a projected CRS.
2620#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2621#[serde(default)]
2622pub struct Conversion {
2623    /// The schema URL or identifier.
2624    #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")]
2625    pub schema: Option<String>,
2626    /// Indicates the type of conversion. Always "Conversion" for this interface.
2627    #[serde(rename = "type")]
2628    pub r#type: Option<String>, // 'Conversion';
2629    /// The name of the conversion (map projection or transformation).
2630    pub name: String,
2631    /// The method used for the conversion.
2632    pub method: Method,
2633    /// An array of parameter values defining the conversion.
2634    #[serde(skip_serializing_if = "Vec::is_empty")]
2635    pub parameters: Vec<ParameterValue>,
2636    /// An identifier for the datum ensemble.
2637    #[serde(skip_serializing_if = "Option::is_none")]
2638    pub id: Option<Id>,
2639    /// An array of identifiers for the datum ensemble.
2640    #[serde(skip_serializing_if = "Vec::is_empty")]
2641    pub ids: Ids,
2642}
2643impl ToProjJSON for Conversion {
2644    fn set_id(&mut self, id: Id) {
2645        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
2646        if !self.ids.is_empty() {
2647            self.ids.push(id);
2648        } else if let Some(i) = self.id.clone() {
2649            self.ids.extend(vec![i, id]);
2650            self.id = None;
2651        } else {
2652            self.id = Some(id);
2653        }
2654    }
2655    fn set_projection(&mut self, name: String) {
2656        self.method = Method { name, ..Default::default() };
2657    }
2658    fn set_method(&mut self, method: Method) {
2659        self.method = method;
2660    }
2661    fn set_parameter(&mut self, parameter: ParameterValue) {
2662        self.parameters.push(parameter);
2663    }
2664}
2665impl Conversion {
2666    /// Convert a ProjectedCRS to a ProjectionTransform
2667    pub fn to_projection_transform(&self, proj_transform: &mut ProjectionTransform) {
2668        // add Params
2669        for param in self.parameters.iter() {
2670            proj_transform.proj.borrow_mut().add_param(param);
2671        }
2672        self.method.to_projection_transform(proj_transform);
2673    }
2674}
2675
2676/// # CoordinateMetadata Interface
2677///
2678/// Represents metadata associated with a coordinate, including its reference system and epoch.
2679#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2680#[serde(default)]
2681pub struct CoordinateMetadata {
2682    /// The schema URL or identifier.
2683    #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")]
2684    pub schema: Option<String>,
2685    /// Indicates the type of object. Always "CoordinateMetadata" for this interface.
2686    #[serde(rename = "type")]
2687    pub r#type: Option<String>, // 'CoordinateMetadata';
2688    /// The coordinate reference system associated with the coordinate.
2689    pub crs: CRS,
2690    /// The epoch of the coordinate.
2691    #[serde(rename = "coordinateEpoch", skip_serializing_if = "Option::is_none")]
2692    pub coordinate_epoch: Option<f64>,
2693}
2694impl ToProjJSON for CoordinateMetadata {
2695    fn set_epoch(&mut self, epoch: f64) {
2696        self.coordinate_epoch = Some(epoch);
2697    }
2698}
2699
2700/// # Coordinate system type
2701///
2702/// For various types of CRS the type of coordinate system that may be used is constrained, as is
2703/// the permissible number of axes. Additionally the data type for coordinates in an ordinal
2704/// coordinate system and in a temporal coordinate system is constrained.
2705///
2706/// ## Examples of WKT describing an CoordinateSystem with the specified subtype as the first element:
2707/// - `CS[ordinal,2],AXIS["inline (I)",southeast,ORDER[1]],AXIS["crossline (J)",northeast,ORDER[2]]`
2708/// - `CS[Cartesian,3],AXIS["(X)",geocentricX],AXIS["(Y)",geocentricY],AXIS["(Z)",geocentricZ],LENGTHUNIT["metre",1.0]`
2709#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2710pub enum CoordinateSystemSubtype {
2711    /// Cartesian
2712    #[serde(rename = "Cartesian")]
2713    #[default]
2714    Cartesian,
2715    /// Spherical
2716    #[serde(rename = "spherical")]
2717    Spherical,
2718    /// Ellipsoidal
2719    #[serde(rename = "ellipsoidal")]
2720    Ellipsoidal,
2721    /// Vertical
2722    #[serde(rename = "vertical")]
2723    Vertical,
2724    /// Ordinal
2725    #[serde(rename = "ordinal")]
2726    Ordinal,
2727    /// Parametric
2728    #[serde(rename = "parametric")]
2729    Parametric,
2730    /// Affine
2731    #[serde(rename = "affine")]
2732    Affine,
2733    /// TemporalDateTime
2734    #[serde(rename = "TemporalDateTime")]
2735    TemporalDateTime,
2736    /// TemporalCount
2737    #[serde(rename = "TemporalCount")]
2738    TemporalCount,
2739    /// TemporalMeasure
2740    #[serde(rename = "TemporalMeasure")]
2741    TemporalMeasure,
2742}
2743impl CoordinateSystemSubtype {
2744    /// Convert a CoordinateSystem to a ProjectionTransform
2745    pub fn to_projection_transform(&self, _proj_transform: &mut ProjectionTransform) {
2746        // TODO: ALL of them. I don't know the best way to add cart, but it needs to be a step
2747        match self {
2748            CoordinateSystemSubtype::Cartesian => {
2749                // let cart = CartesianConverter::new(Rc::new(RefCell::new(Proj::default())));
2750                // proj_transform.cart = Some(Box::new(cart.into()));
2751            }
2752            _ => todo!(), /* CoordinateSystemSubtype::Spherical => {}
2753                           * CoordinateSystemSubtype::Ellipsoidal => {}
2754                           * CoordinateSystemSubtype::Vertical => {}
2755                           * CoordinateSystemSubtype::Ordinal => {}
2756                           * CoordinateSystemSubtype::Parametric => {}
2757                           * CoordinateSystemSubtype::Affine => {}
2758                           * CoordinateSystemSubtype::TemporalDateTime => {}
2759                           * CoordinateSystemSubtype::TemporalCount => {}
2760                           * CoordinateSystemSubtype::TemporalMeasure => {} */
2761        }
2762    }
2763}
2764
2765/// # Coordinate System
2766///
2767/// Represents a coordinate system, including its subtype and axes.
2768///
2769/// Most coordinate system attributes are common to all subtypes of spatial and temporal coordinate systems. Exceptions are associated with the coordinate system axis unit attribute and its qualifier, the conversion factor to an SI base unit:
2770/// - When the coordinate system type is 'temporalCount' or 'temporalMeasure', the inclusion of the axis unit conversion factor in WKT is conditional, see 7.4.3.
2771/// - When the coordinate system type is 'ordinal' or 'temporalDateTime', the axis unit attribute and its conversion factor are not required in WKT, see 7.5.6 and 13.3.
2772///
2773/// ## Examples of WKT describing an CoordinateSystem:
2774/// - `CS[ordinal,2],AXIS["inline (I)",southeast,ORDER[1]],AXIS["crossline (J)",northeast,ORDER[2]]`
2775/// - `CS[Cartesian,3],AXIS["(X)",geocentricX],AXIS["(Y)",geocentricY],AXIS["(Z)",geocentricZ],LENGTHUNIT["metre",1.0]`
2776#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2777#[serde(default)]
2778pub struct CoordinateSystem {
2779    /// The schema URL or identifier.
2780    #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")]
2781    pub schema: Option<String>,
2782    /// Indicates the type of object. Always "CoordinateSystem" for this interface.
2783    #[serde(rename = "type")]
2784    pub r#type: Option<String>, // 'CoordinateSystem';
2785    /// The name of the coordinate system.
2786    pub name: Option<String>,
2787    /// The subtype of the coordinate system.
2788    pub subtype: CoordinateSystemSubtype,
2789    /// The axes of the coordinate system.
2790    #[serde(skip_serializing_if = "Vec::is_empty")]
2791    pub axis: Vec<Axis>,
2792    /// An identifier for the datum ensemble.
2793    #[serde(skip_serializing_if = "Option::is_none")]
2794    pub id: Option<Id>,
2795    /// An array of identifiers for the datum ensemble.
2796    #[serde(skip_serializing_if = "Vec::is_empty")]
2797    pub ids: Ids,
2798}
2799impl ToProjJSON for CoordinateSystem {
2800    fn set_id(&mut self, id: Id) {
2801        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
2802        if !self.ids.is_empty() {
2803            self.ids.push(id);
2804        } else if let Some(i) = self.id.clone() {
2805            self.ids.extend(vec![i, id]);
2806            self.id = None;
2807        } else {
2808            self.id = Some(id);
2809        }
2810    }
2811    fn set_axis(&mut self, axis: Axis) {
2812        self.axis.push(axis);
2813    }
2814    fn set_unit(&mut self, unit: Unit) {
2815        for axis in self.axis.iter_mut() {
2816            axis.unit = Some(unit.clone());
2817        }
2818    }
2819}
2820impl CoordinateSystem {
2821    /// Convert a CoordinateSystem to a ProjectionTransform
2822    pub fn to_projection_transform(&self, proj_transform: &mut ProjectionTransform) {
2823        self.subtype.to_projection_transform(proj_transform);
2824        if !self.axis.is_empty() {
2825            let mut axiss = self.axis.clone();
2826            axiss.sort_by(|a, b| a.order.cmp(&b.order));
2827            let axis: Vec<AxisDirection> = axiss.iter().map(|a| a.direction).collect();
2828            let mut axis_converter = AxisSwapConverter::new(Rc::new(RefCell::new(Proj::default())));
2829            axis_converter.swap = axis.into();
2830            proj_transform.axisswap = Some(Box::new(axis_converter.into()));
2831        }
2832    }
2833}
2834
2835/// # Transformation Interface
2836///
2837/// Represents a transformation between two coordinate reference systems.
2838#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2839#[serde(default)]
2840pub struct Transformation {
2841    /// Type identifier
2842    #[serde(rename = "type")]
2843    pub r#type: Option<String>, // 'Transformation';
2844    /// Name of the transformation
2845    pub name: String,
2846    /// Source CRS
2847    pub source_crs: CRS,
2848    /// Target CRS
2849    pub target_crs: CRS,
2850    /// Transformation method
2851    pub method: Method,
2852    /// Transformation parameters
2853    #[serde(skip_serializing_if = "Vec::is_empty")]
2854    pub parameters: Vec<ParameterValue>,
2855    /// Interpolation CRS
2856    #[serde(skip_serializing_if = "Option::is_none")]
2857    pub interpolation_crs: Option<CRS>,
2858    /// Transformation accuracy
2859    #[serde(skip_serializing_if = "Option::is_none")]
2860    pub accuracy: Option<String>,
2861    /// Usage Information
2862    #[serde(flatten, skip_serializing_if = "Option::is_none")]
2863    pub usage: Option<ObjectUsage>,
2864    /// Usages
2865    #[serde(skip_serializing_if = "Vec::is_empty")]
2866    pub usages: Vec<ObjectUsage>,
2867}
2868impl ToProjJSON for Transformation {
2869    fn set_id(&mut self, id: Id) {
2870        if self.usage.is_none() && self.usages.is_empty() {
2871            self.usage = Some(ObjectUsage::default());
2872        }
2873        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
2874            u.set_id(id);
2875        }
2876    }
2877    fn set_usage(&mut self, usage: ObjectUsage) {
2878        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
2879        if self.usages.is_empty() {
2880            if let Some(u) = self.usage.clone() {
2881                self.usages.extend(vec![u, usage]);
2882                self.usage = None;
2883            } else {
2884                self.usage = Some(usage);
2885            }
2886        } else {
2887            self.usages.push(usage);
2888        }
2889    }
2890    fn set_accuracy(&mut self, accuracy: String) {
2891        self.accuracy = Some(accuracy);
2892    }
2893    fn set_parameter(&mut self, parameter: ParameterValue) {
2894        self.parameters.push(parameter);
2895    }
2896    fn set_projection(&mut self, name: String) {
2897        self.method = Method { name, ..Default::default() };
2898    }
2899    fn set_method(&mut self, method: Method) {
2900        self.method = method;
2901    }
2902}
2903
2904/// # TemporalCRS Interface
2905///
2906/// Represents a temporal coordinate reference system, which defines time-based coordinates.
2907#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2908#[serde(default)]
2909pub struct TemporalCRS {
2910    /// Indicates the type of CRS. Always "TemporalCRS" for this interface.
2911    #[serde(rename = "type")]
2912    pub r#type: Option<String>, // 'TemporalCRS';
2913    /// The name of the temporal CRS.
2914    pub name: String,
2915    /// The temporal datum associated with the CRS.
2916    pub datum: TemporalDatum,
2917    /// The coordinate system used in the temporal CRS.
2918    #[serde(skip_serializing_if = "Option::is_none")]
2919    pub coordinate_system: Option<CoordinateSystem>,
2920    /// Usage Information
2921    #[serde(flatten, skip_serializing_if = "Option::is_none")]
2922    pub usage: Option<ObjectUsage>,
2923    /// Usages
2924    #[serde(skip_serializing_if = "Vec::is_empty")]
2925    pub usages: Vec<ObjectUsage>,
2926}
2927impl ToProjJSON for TemporalCRS {
2928    fn set_id(&mut self, id: Id) {
2929        if self.usage.is_none() && self.usages.is_empty() {
2930            self.usage = Some(ObjectUsage::default());
2931        }
2932        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
2933            u.set_id(id);
2934        }
2935    }
2936    fn set_usage(&mut self, usage: ObjectUsage) {
2937        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
2938        if self.usages.is_empty() {
2939            if let Some(u) = self.usage.clone() {
2940                self.usages.extend(vec![u, usage]);
2941                self.usage = None;
2942            } else {
2943                self.usage = Some(usage);
2944            }
2945        } else {
2946            self.usages.push(usage);
2947        }
2948    }
2949    fn set_coordinate_system(&mut self, cs: CoordinateSystem) {
2950        self.coordinate_system = Some(cs);
2951    }
2952    // Pass down to the coordinate system
2953    fn set_axis(&mut self, axis: Axis) {
2954        if let Some(ref mut cs) = self.coordinate_system {
2955            cs.axis.push(axis);
2956        }
2957    }
2958    fn set_unit(&mut self, unit: Unit) {
2959        if let Some(ref mut cs) = self.coordinate_system {
2960            for axis in cs.axis.iter_mut() {
2961                axis.unit = Some(unit.clone());
2962            }
2963        }
2964    }
2965}
2966
2967/// # TemporalDatum Interface
2968///
2969/// Represents the temporal datum associated with a temporal CRS.
2970#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
2971#[serde(default)]
2972pub struct TemporalDatum {
2973    /// Indicates the type of datum. Always "TemporalDatum" for this interface.
2974    #[serde(rename = "type")]
2975    pub r#type: Option<String>, // 'TemporalDatum';
2976    /// The name of the temporal datum.
2977    pub name: String,
2978    /// The calendar system used for the datum.
2979    pub calendar: String,
2980    /// The time origin of the temporal datum, typically an ISO 8601 date/time string.
2981    pub time_origin: Option<String>,
2982    /// Usage Information
2983    #[serde(flatten, skip_serializing_if = "Option::is_none")]
2984    pub usage: Option<ObjectUsage>,
2985    /// Usages
2986    #[serde(skip_serializing_if = "Vec::is_empty")]
2987    pub usages: Vec<ObjectUsage>,
2988}
2989impl ToProjJSON for TemporalDatum {
2990    fn set_id(&mut self, id: Id) {
2991        if self.usage.is_none() && self.usages.is_empty() {
2992            self.usage = Some(ObjectUsage::default());
2993        }
2994        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
2995            u.set_id(id);
2996        }
2997    }
2998    fn set_usage(&mut self, usage: ObjectUsage) {
2999        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
3000        if self.usages.is_empty() {
3001            if let Some(u) = self.usage.clone() {
3002                self.usages.extend(vec![u, usage]);
3003                self.usage = None;
3004            } else {
3005                self.usage = Some(usage);
3006            }
3007        } else {
3008            self.usages.push(usage);
3009        }
3010    }
3011}
3012
3013/// # VerticalCRS Interface
3014///
3015/// Represents a vertical coordinate reference system, which is used for height or depth measurements.
3016#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
3017#[serde(default)]
3018pub struct VerticalCRS {
3019    /// Indicates the type of CRS. Always "VerticalCRS" for this interface.
3020    #[serde(rename = "type")]
3021    pub r#type: Option<String>, // 'VerticalCRS';
3022    /// The name of the vertical CRS.
3023    pub name: String,
3024    /// The vertical datum associated with the CRS.
3025    /// One and only one of `datum` or `datum_ensemble` must be provided.
3026    /// Can only be a `VerticalReferenceFrame` or a `DynamicVerticalReferenceFrame`.
3027    #[serde(skip_serializing_if = "Option::is_none")]
3028    pub datum: Option<Datum>,
3029    /// The datum ensemble associated with the CRS.
3030    #[serde(skip_serializing_if = "Option::is_none")]
3031    pub datum_ensemble: Option<DatumEnsemble>,
3032    /// The coordinate system used in the vertical CRS.
3033    #[serde(skip_serializing_if = "Option::is_none")]
3034    pub coordinate_system: Option<CoordinateSystem>,
3035    /// The geoid model associated with the vertical CRS.
3036    #[serde(skip_serializing_if = "Option::is_none")]
3037    pub geoid_model: Option<GeoidModel>,
3038    /// An array of geoid models associated with the vertical CRS.
3039    #[serde(skip_serializing_if = "Option::is_none")]
3040    pub geoid_models: Option<Vec<GeoidModel>>,
3041    /// An array of deformation models associated with the vertical CRS.
3042    #[serde(skip_serializing_if = "Option::is_none")]
3043    pub deformation_models: Option<Vec<DeformationModel>>,
3044    /// Usage Information
3045    #[serde(flatten, skip_serializing_if = "Option::is_none")]
3046    pub usage: Option<ObjectUsage>,
3047    /// Usages
3048    #[serde(skip_serializing_if = "Vec::is_empty")]
3049    pub usages: Vec<ObjectUsage>,
3050}
3051impl ToProjJSON for VerticalCRS {
3052    fn set_id(&mut self, id: Id) {
3053        if self.usage.is_none() && self.usages.is_empty() {
3054            self.usage = Some(ObjectUsage::default());
3055        }
3056        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
3057            u.set_id(id);
3058        }
3059    }
3060    fn set_usage(&mut self, usage: ObjectUsage) {
3061        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
3062        if self.usages.is_empty() {
3063            if let Some(u) = self.usage.clone() {
3064                self.usages.extend(vec![u, usage]);
3065                self.usage = None;
3066            } else {
3067                self.usage = Some(usage);
3068            }
3069        } else {
3070            self.usages.push(usage);
3071        }
3072    }
3073    fn set_coordinate_system(&mut self, cs: CoordinateSystem) {
3074        self.coordinate_system = Some(cs);
3075    }
3076    fn set_datum(&mut self, datum: Datum) {
3077        self.datum = Some(datum);
3078    }
3079    fn set_ensemble(&mut self, ensemble: DatumEnsemble) {
3080        self.datum_ensemble = Some(ensemble);
3081    }
3082    // Pass down to the datum
3083    fn set_prime_meridian(&mut self, prime_meridian: PrimeMeridian) {
3084        if let Some(ref mut datum) = self.datum {
3085            datum.set_prime_meridian(prime_meridian);
3086        }
3087    }
3088    // Pass down to the coordinate system
3089    fn set_axis(&mut self, axis: Axis) {
3090        if let Some(ref mut cs) = self.coordinate_system {
3091            cs.axis.push(axis);
3092        }
3093    }
3094    fn set_unit(&mut self, unit: Unit) {
3095        if let Some(ref mut cs) = self.coordinate_system {
3096            for axis in cs.axis.iter_mut() {
3097                axis.unit = Some(unit.clone());
3098            }
3099        }
3100    }
3101}
3102
3103/// # VerticalReferenceFrame Interface
3104///
3105/// Represents the vertical reference frame associated with a vertical CRS.
3106#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
3107#[serde(default)]
3108pub struct VerticalReferenceFrame {
3109    /// Indicates the type of reference frame. Always "VerticalReferenceFrame" for this interface.
3110    #[serde(rename = "type")]
3111    pub r#type: Option<String>, // 'VerticalReferenceFrame';
3112    /// The name of the vertical reference frame.
3113    pub name: String,
3114    /// The anchor point of the reference frame.
3115    #[serde(skip_serializing_if = "Option::is_none")]
3116    pub anchor: Option<String>,
3117    /// The epoch of the anchor point.
3118    #[serde(skip_serializing_if = "Option::is_none")]
3119    pub anchor_epoch: Option<f64>,
3120    /// Usage Information
3121    #[serde(flatten, skip_serializing_if = "Option::is_none")]
3122    pub usage: Option<ObjectUsage>,
3123    /// Usages
3124    #[serde(skip_serializing_if = "Vec::is_empty")]
3125    pub usages: Vec<ObjectUsage>,
3126}
3127impl ToProjJSON for VerticalReferenceFrame {
3128    fn set_anchor(&mut self, anchor: String) {
3129        self.anchor = Some(anchor);
3130    }
3131    fn set_id(&mut self, id: Id) {
3132        if self.usage.is_none() && self.usages.is_empty() {
3133            self.usage = Some(ObjectUsage::default());
3134        }
3135        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
3136            u.set_id(id);
3137        }
3138    }
3139    fn set_usage(&mut self, usage: ObjectUsage) {
3140        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
3141        if self.usages.is_empty() {
3142            if let Some(u) = self.usage.clone() {
3143                self.usages.extend(vec![u, usage]);
3144                self.usage = None;
3145            } else {
3146                self.usage = Some(usage);
3147            }
3148        } else {
3149            self.usages.push(usage);
3150        }
3151    }
3152    fn set_epoch(&mut self, epoch: f64) {
3153        self.anchor_epoch = Some(epoch);
3154    }
3155}
3156
3157/// # DynamicVerticalReferenceFrame Interface
3158///
3159/// Represents a dynamic vertical reference frame.
3160#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
3161#[serde(default)]
3162pub struct DynamicVerticalReferenceFrame {
3163    /// Indicates the type of reference frame. Always "DynamicVerticalReferenceFrame" for this interface.
3164    #[serde(rename = "type")]
3165    pub r#type: Option<String>, // 'DynamicVerticalReferenceFrame';
3166    /// The name of the reference frame.
3167    pub name: String,
3168    /// The anchor point of the reference frame.
3169    #[serde(skip_serializing_if = "Option::is_none")]
3170    pub anchor: Option<String>,
3171    /// The epoch of the anchor point.
3172    #[serde(skip_serializing_if = "Option::is_none")]
3173    pub anchor_epoch: Option<f64>,
3174    /// The frame reference epoch for the dynamic reference frame.
3175    pub frame_reference_epoch: f64,
3176    /// Usage Information
3177    #[serde(flatten, skip_serializing_if = "Option::is_none")]
3178    pub usage: Option<ObjectUsage>,
3179    /// Usages
3180    #[serde(skip_serializing_if = "Vec::is_empty")]
3181    pub usages: Vec<ObjectUsage>,
3182}
3183impl ToProjJSON for DynamicVerticalReferenceFrame {
3184    fn set_id(&mut self, id: Id) {
3185        if self.usage.is_none() && self.usages.is_empty() {
3186            self.usage = Some(ObjectUsage::default());
3187        }
3188        if let Some(u) = self.usage.as_mut().or_else(|| self.usages.last_mut()) {
3189            u.set_id(id);
3190        }
3191    }
3192    fn set_usage(&mut self, usage: ObjectUsage) {
3193        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
3194        if self.usages.is_empty() {
3195            if let Some(u) = self.usage.clone() {
3196                self.usages.extend(vec![u, usage]);
3197                self.usage = None;
3198            } else {
3199                self.usage = Some(usage);
3200            }
3201        } else {
3202            self.usages.push(usage);
3203        }
3204    }
3205    fn set_anchor(&mut self, anchor: String) {
3206        self.anchor = Some(anchor);
3207    }
3208    fn set_epoch(&mut self, epoch: f64) {
3209        self.anchor_epoch = Some(epoch);
3210    }
3211    fn set_frame_epoch(&mut self, epoch: f64) {
3212        self.frame_reference_epoch = epoch;
3213    }
3214}
3215
3216/// # GeoidModel Interface
3217///
3218/// Represents a geoid model associated with a vertical CRS.
3219#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
3220#[serde(default)]
3221pub struct GeoidModel {
3222    /// The name of the geoid model.
3223    pub name: String,
3224    /// The interpolation CRS for the geoid model.
3225    pub interpolation_crs: Option<Box<CRS>>,
3226    /// An identifier for the geoid model.
3227    pub id: Option<Id>,
3228}
3229
3230/// # Usage
3231///
3232/// ## Description
3233/// Usage is an optional attribute which if included in a WKT string shall include both
3234/// `<scope>` and `<extent>`. Multiple pairs of scope/extent may be used to describe the usage for
3235/// different purposes over different extents. In this document the `<scope>` and `<extent>` elements
3236/// may not be given alone but only as a pairing. Within each pairing, extent may consist of one or
3237/// more of area textual description, area bounding box, vertical extent and/or temporal extent,
3238/// see 7.3.2.3.
3239///
3240/// ## Examples
3241/// - `USAGE[<scope>,<extent>]`
3242/// - `USAGE[scope1,extent1],USAGE[scope2,extent2]`
3243#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
3244#[serde(default)]
3245pub struct ObjectUsage {
3246    /// The schema URL or identifier.
3247    #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")]
3248    pub schema: Option<String>,
3249    /// The scope of the CRS.
3250    #[serde(skip_serializing_if = "String::is_empty")]
3251    pub scope: String,
3252    /// The extent if applicable.
3253    #[serde(skip_serializing_if = "Option::is_none")]
3254    pub area: Option<String>,
3255    /// bbox
3256    #[serde(skip_serializing_if = "Option::is_none")]
3257    pub bbox: Option<ProjBBox>,
3258    /// vertical_extent
3259    #[serde(skip_serializing_if = "Option::is_none")]
3260    pub vertical_extent: Option<VerticalExtent>,
3261    /// temporal_extent
3262    #[serde(skip_serializing_if = "Option::is_none")]
3263    pub temporal_extent: Option<TemporalExtent>,
3264    /// Remarks or additional information about the CRS.
3265    #[serde(skip_serializing_if = "Option::is_none")]
3266    pub remarks: Option<String>,
3267    /// An identifier for the CRS.
3268    #[serde(skip_serializing_if = "Option::is_none")]
3269    pub id: Option<Id>,
3270    /// An array of identifiers for the CRS.
3271    #[serde(skip_serializing_if = "Vec::is_empty")]
3272    pub ids: Ids,
3273}
3274impl ToProjJSON for ObjectUsage {
3275    fn set_id(&mut self, id: Id) {
3276        // If array is active, add to array; if id is already set, migrate to array; otherwise set id
3277        if !self.ids.is_empty() {
3278            self.ids.push(id);
3279        } else if let Some(i) = self.id.clone() {
3280            self.ids.extend(vec![i, id]);
3281            self.id = None;
3282        } else {
3283            self.id = Some(id);
3284        }
3285    }
3286    fn set_temporal_extent(&mut self, extent: TemporalExtent) {
3287        self.temporal_extent = Some(extent);
3288    }
3289    fn set_vertical_extent(&mut self, extent: VerticalExtent) {
3290        self.vertical_extent = Some(extent);
3291    }
3292    fn set_bbox(&mut self, bbox: ProjBBox) {
3293        self.bbox = Some(bbox);
3294    }
3295    fn set_area(&mut self, area: Option<String>) {
3296        self.area = area;
3297    }
3298}