1use std::fmt::{self, Display, Formatter, Write};
7
8use crate::crs::*;
9
10fn write_comma_items<T: Display>(f: &mut Formatter<'_>, items: &[T]) -> fmt::Result {
16 for item in items {
17 write!(f, ",{item}")?;
18 }
19 Ok(())
20}
21
22fn write_quoted(f: &mut Formatter<'_>, s: &str) -> fmt::Result {
24 write!(f, "\"{s}\"")
25}
26
27impl Display for Crs {
32 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
33 match self {
34 Crs::ProjectedCrs(crs) => crs.fmt(f),
35 Crs::GeogCrs(crs) => crs.fmt(f),
36 Crs::GeodCrs(crs) => crs.fmt(f),
37 Crs::VertCrs(crs) => crs.fmt(f),
38 Crs::CompoundCrs(crs) => crs.fmt(f),
39 }
40 }
41}
42
43impl Display for GeogCrs {
44 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
45 f.write_str("GEOGCRS[")?;
46 write_quoted(f, &self.name)?;
47
48 if let Some(ref dynamic) = self.dynamic {
49 write!(f, ",{dynamic}")?;
50 }
51
52 match &self.datum {
53 Datum::ReferenceFrame(rf) => {
54 write!(f, ",{rf}")?;
55 if let Some(ref pm) = rf.prime_meridian {
56 write!(f, ",{pm}")?;
57 }
58 }
59 Datum::Ensemble(ens) => {
60 write!(f, ",{ens}")?;
61 if let Some(ref pm) = ens.prime_meridian {
62 write!(f, ",{pm}")?;
63 }
64 }
65 }
66
67 write!(f, ",{}", self.coordinate_system)?;
68 write_comma_items(f, &self.usages)?;
69 write_comma_items(f, &self.identifiers)?;
70 if let Some(ref remark) = self.remark {
71 f.write_str(",REMARK[")?;
72 write_quoted(f, remark)?;
73 f.write_char(']')?;
74 }
75 f.write_char(']')
76 }
77}
78
79impl Display for GeodCrs {
80 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
81 f.write_str("GEODCRS[")?;
82 write_quoted(f, &self.name)?;
83
84 if let Some(ref dynamic) = self.dynamic {
85 write!(f, ",{dynamic}")?;
86 }
87
88 match &self.datum {
89 Datum::ReferenceFrame(rf) => {
90 write!(f, ",{rf}")?;
91 if let Some(ref pm) = rf.prime_meridian {
92 write!(f, ",{pm}")?;
93 }
94 }
95 Datum::Ensemble(ens) => {
96 write!(f, ",{ens}")?;
97 if let Some(ref pm) = ens.prime_meridian {
98 write!(f, ",{pm}")?;
99 }
100 }
101 }
102
103 write!(f, ",{}", self.coordinate_system)?;
104 write_comma_items(f, &self.usages)?;
105 write_comma_items(f, &self.identifiers)?;
106 if let Some(ref remark) = self.remark {
107 f.write_str(",REMARK[")?;
108 write_quoted(f, remark)?;
109 f.write_char(']')?;
110 }
111 f.write_char(']')
112 }
113}
114
115impl Display for VertCrs {
116 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
117 f.write_str("VERTCRS[")?;
118 write_quoted(f, &self.name)?;
119
120 match &self.source {
121 VertCrsSource::Datum { dynamic, datum } => {
122 if let Some(dynamic) = dynamic {
123 write!(f, ",{dynamic}")?;
124 }
125 match datum {
126 VerticalDatum::ReferenceFrame(rf) => write!(f, ",{rf}")?,
127 VerticalDatum::Ensemble(ens) => write!(f, ",{ens}")?,
128 }
129 }
130 VertCrsSource::Derived {
131 base_vert_crs,
132 deriving_conversion,
133 } => {
134 write!(f, ",{base_vert_crs}")?;
135 f.write_str(",DERIVINGCONVERSION[")?;
136 write_quoted(f, &deriving_conversion.name)?;
137 write!(f, ",{}", deriving_conversion.method)?;
138 write_comma_items(f, &deriving_conversion.parameters)?;
139 write_comma_items(f, &deriving_conversion.identifiers)?;
140 f.write_char(']')?;
141 }
142 }
143
144 write!(f, ",{}", self.coordinate_system)?;
145 write_comma_items(f, &self.geoid_models)?;
146 write_comma_items(f, &self.usages)?;
147 write_comma_items(f, &self.identifiers)?;
148 if let Some(ref remark) = self.remark {
149 f.write_str(",REMARK[")?;
150 write_quoted(f, remark)?;
151 f.write_char(']')?;
152 }
153 f.write_char(']')
154 }
155}
156
157impl Display for BaseVertCrs {
158 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
159 f.write_str("BASEVERTCRS[")?;
160 write_quoted(f, &self.name)?;
161
162 if let Some(ref dynamic) = self.dynamic {
163 write!(f, ",{dynamic}")?;
164 }
165
166 match &self.datum {
167 VerticalDatum::ReferenceFrame(rf) => write!(f, ",{rf}")?,
168 VerticalDatum::Ensemble(ens) => write!(f, ",{ens}")?,
169 }
170
171 write_comma_items(f, &self.identifiers)?;
172 f.write_char(']')
173 }
174}
175
176impl Display for VerticalReferenceFrame {
177 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
178 f.write_str("VDATUM[")?;
179 write_quoted(f, &self.name)?;
180 if let Some(ref anchor) = self.anchor {
181 f.write_str(",ANCHOR[")?;
182 write_quoted(f, anchor)?;
183 f.write_char(']')?;
184 }
185 if let Some(epoch) = self.anchor_epoch {
186 write!(f, ",ANCHOREPOCH[{epoch}]")?;
187 }
188 write_comma_items(f, &self.identifiers)?;
189 f.write_char(']')
190 }
191}
192
193impl Display for GeoidModel {
194 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
195 f.write_str("GEOIDMODEL[")?;
196 write_quoted(f, &self.name)?;
197 write_comma_items(f, &self.identifiers)?;
198 f.write_char(']')
199 }
200}
201
202impl Display for CompoundCrs {
203 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
204 f.write_str("COMPOUNDCRS[")?;
205 write_quoted(f, &self.name)?;
206 for component in &self.components {
207 write!(f, ",{component}")?;
208 }
209 write_comma_items(f, &self.usages)?;
210 write_comma_items(f, &self.identifiers)?;
211 if let Some(ref remark) = self.remark {
212 f.write_str(",REMARK[")?;
213 write_quoted(f, remark)?;
214 f.write_char(']')?;
215 }
216 f.write_char(']')
217 }
218}
219
220impl Display for SingleCrs {
221 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
222 match self {
223 SingleCrs::ProjectedCrs(crs) => crs.fmt(f),
224 SingleCrs::GeogCrs(crs) => crs.fmt(f),
225 SingleCrs::GeodCrs(crs) => crs.fmt(f),
226 SingleCrs::VertCrs(crs) => crs.fmt(f),
227 SingleCrs::Other(raw) => f.write_str(raw),
228 }
229 }
230}
231
232impl Display for ProjectedCrs {
233 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
234 f.write_str("PROJCRS[")?;
235 write_quoted(f, &self.name)?;
236 write!(f, ",{}", self.base_geodetic_crs)?;
237 write!(f, ",{}", self.map_projection)?;
238 write!(f, ",{}", self.coordinate_system)?;
239 write_comma_items(f, &self.usages)?;
240 write_comma_items(f, &self.identifiers)?;
241 if let Some(ref remark) = self.remark {
242 f.write_str(",REMARK[")?;
243 write_quoted(f, remark)?;
244 f.write_char(']')?;
245 }
246 f.write_char(']')
247 }
248}
249
250impl Display for BaseGeodeticCrsKeyword {
255 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
256 f.write_str(match self {
257 BaseGeodeticCrsKeyword::BaseGeodCrs => "BASEGEODCRS",
258 BaseGeodeticCrsKeyword::BaseGeogCrs => "BASEGEOGCRS",
259 })
260 }
261}
262
263impl Display for BaseGeodeticCrs {
264 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
265 write!(f, "{}[", self.keyword)?;
266 write_quoted(f, &self.name)?;
267
268 if let Some(ref dynamic) = self.dynamic {
269 write!(f, ",{dynamic}")?;
270 }
271
272 match &self.datum {
273 Datum::ReferenceFrame(rf) => {
274 write!(f, ",{rf}")?;
275 if let Some(ref pm) = rf.prime_meridian {
276 write!(f, ",{pm}")?;
277 }
278 }
279 Datum::Ensemble(ens) => {
280 write!(f, ",{ens}")?;
281 if let Some(ref pm) = ens.prime_meridian {
282 write!(f, ",{pm}")?;
283 }
284 }
285 }
286
287 if let Some(ref unit) = self.ellipsoidal_cs_unit {
288 write!(f, ",{unit}")?;
289 }
290 write_comma_items(f, &self.identifiers)?;
291 f.write_char(']')
292 }
293}
294
295impl Display for DynamicCrs {
300 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
301 write!(f, "DYNAMIC[FRAMEEPOCH[{}]", self.frame_reference_epoch)?;
302 if let Some(ref model) = self.deformation_model {
303 write!(f, ",{model}")?;
304 }
305 f.write_char(']')
306 }
307}
308
309impl Display for DeformationModel {
310 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
311 f.write_str("MODEL[")?;
312 write_quoted(f, &self.name)?;
313 write_comma_items(f, &self.identifiers)?;
314 f.write_char(']')
315 }
316}
317
318impl Display for GeodeticReferenceFrame {
323 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
324 f.write_str("DATUM[")?;
325 write_quoted(f, &self.name)?;
326 write!(f, ",{}", self.ellipsoid)?;
327 if let Some(ref anchor) = self.anchor {
328 f.write_str(",ANCHOR[")?;
329 write_quoted(f, anchor)?;
330 f.write_char(']')?;
331 }
332 if let Some(epoch) = self.anchor_epoch {
333 write!(f, ",ANCHOREPOCH[{epoch}]")?;
334 }
335 write_comma_items(f, &self.identifiers)?;
336 f.write_char(']')
338 }
339}
340
341impl Display for DatumEnsemble {
342 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
343 f.write_str("ENSEMBLE[")?;
344 write_quoted(f, &self.name)?;
345 write_comma_items(f, &self.members)?;
346 if let Some(ref ellipsoid) = self.ellipsoid {
347 write!(f, ",{ellipsoid}")?;
348 }
349 write!(f, ",ENSEMBLEACCURACY[{}]", self.accuracy)?;
350 write_comma_items(f, &self.identifiers)?;
351 f.write_char(']')
353 }
354}
355
356impl Display for EnsembleMember {
357 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
358 f.write_str("MEMBER[")?;
359 write_quoted(f, &self.name)?;
360 write_comma_items(f, &self.identifiers)?;
361 f.write_char(']')
362 }
363}
364
365impl Display for Ellipsoid {
370 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
371 f.write_str("ELLIPSOID[")?;
372 write_quoted(f, &self.name)?;
373 write!(f, ",{},{}", self.semi_major_axis, self.inverse_flattening)?;
374 if let Some(ref unit) = self.unit {
375 write!(f, ",{unit}")?;
376 }
377 write_comma_items(f, &self.identifiers)?;
378 f.write_char(']')
379 }
380}
381
382impl Display for PrimeMeridian {
383 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
384 f.write_str("PRIMEM[")?;
385 write_quoted(f, &self.name)?;
386 write!(f, ",{}", self.irm_longitude)?;
387 if let Some(ref unit) = self.unit {
388 write!(f, ",{unit}")?;
389 }
390 write_comma_items(f, &self.identifiers)?;
391 f.write_char(']')
392 }
393}
394
395impl Display for MapProjection {
400 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
401 f.write_str("CONVERSION[")?;
402 write_quoted(f, &self.name)?;
403 write!(f, ",{}", self.method)?;
404 write_comma_items(f, &self.parameters)?;
405 write_comma_items(f, &self.identifiers)?;
406 f.write_char(']')
407 }
408}
409
410impl Display for MapProjectionMethod {
411 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
412 f.write_str("METHOD[")?;
413 write_quoted(f, &self.name)?;
414 write_comma_items(f, &self.identifiers)?;
415 f.write_char(']')
416 }
417}
418
419impl Display for MapProjectionParameter {
420 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
421 f.write_str("PARAMETER[")?;
422 write_quoted(f, &self.name)?;
423 write!(f, ",{}", self.value)?;
424 if let Some(ref unit) = self.unit {
425 write!(f, ",{unit}")?;
426 }
427 write_comma_items(f, &self.identifiers)?;
428 f.write_char(']')
429 }
430}
431
432impl Display for CoordinateSystem {
437 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
438 write!(f, "CS[{},{}", self.cs_type, self.dimension)?;
439 write_comma_items(f, &self.identifiers)?;
440 f.write_char(']')?;
441 write_comma_items(f, &self.axes)?;
443 if let Some(ref unit) = self.cs_unit {
444 write!(f, ",{unit}")?;
445 }
446 Ok(())
447 }
448}
449
450impl Display for CsType {
451 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
452 f.write_str(match self {
453 CsType::Affine => "affine",
454 CsType::Cartesian => "Cartesian",
455 CsType::Cylindrical => "cylindrical",
456 CsType::Ellipsoidal => "ellipsoidal",
457 CsType::Linear => "linear",
458 CsType::Parametric => "parametric",
459 CsType::Polar => "polar",
460 CsType::Spherical => "spherical",
461 CsType::Vertical => "vertical",
462 CsType::TemporalCount => "temporalCount",
463 CsType::TemporalMeasure => "temporalMeasure",
464 CsType::Ordinal => "ordinal",
465 CsType::TemporalDateTime => "temporalDateTime",
466 })
467 }
468}
469
470impl Display for Axis {
471 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
472 f.write_str("AXIS[")?;
473 write_quoted(f, &self.name_abbrev)?;
474 write!(f, ",{}", self.direction)?;
475 if let Some(ref meridian) = self.meridian {
476 write!(f, ",{meridian}")?;
477 }
478 if let Some(bearing) = self.bearing {
479 write!(f, ",BEARING[{bearing}]")?;
480 }
481 if let Some(order) = self.order {
482 write!(f, ",ORDER[{order}]")?;
483 }
484 if let Some(ref unit) = self.unit {
485 write!(f, ",{unit}")?;
486 }
487 if let Some(min) = self.axis_min_value {
488 write!(f, ",AXISMINVALUE[{min}]")?;
489 }
490 if let Some(max) = self.axis_max_value {
491 write!(f, ",AXISMAXVALUE[{max}]")?;
492 }
493 if let Some(rm) = self.range_meaning {
494 write!(f, ",{rm}")?;
495 }
496 write_comma_items(f, &self.identifiers)?;
497 f.write_char(']')
498 }
499}
500
501impl Display for Meridian {
502 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
503 write!(f, "MERIDIAN[{},{}]", self.value, self.unit)
504 }
505}
506
507impl Display for RangeMeaning {
508 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
509 f.write_str(match self {
510 RangeMeaning::Exact => "RANGEMEANING[exact]",
511 RangeMeaning::Wraparound => "RANGEMEANING[wraparound]",
512 })
513 }
514}
515
516impl Display for UnitKeyword {
521 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
522 f.write_str(match self {
523 UnitKeyword::AngleUnit => "ANGLEUNIT",
524 UnitKeyword::LengthUnit => "LENGTHUNIT",
525 UnitKeyword::ParametricUnit => "PARAMETRICUNIT",
526 UnitKeyword::ScaleUnit => "SCALEUNIT",
527 UnitKeyword::TimeUnit => "TIMEUNIT",
528 UnitKeyword::Unit => "UNIT",
529 })
530 }
531}
532
533impl Display for Unit {
534 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
535 write!(f, "{}[", self.keyword)?;
536 write_quoted(f, &self.name)?;
537 if let Some(factor) = self.conversion_factor {
538 write!(f, ",{factor}")?;
539 }
540 write_comma_items(f, &self.identifiers)?;
541 f.write_char(']')
542 }
543}
544
545impl Display for AuthorityId {
550 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
551 match self {
552 AuthorityId::Number(n) => write!(f, "{n}"),
553 AuthorityId::Text(s) => write_quoted(f, s),
554 }
555 }
556}
557
558impl Display for Identifier {
559 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
560 f.write_str("ID[")?;
561 write_quoted(f, &self.authority_name)?;
562 write!(f, ",{}", self.authority_unique_id)?;
563 if let Some(ref version) = self.version {
564 write!(f, ",{version}")?;
565 }
566 if let Some(ref citation) = self.citation {
567 f.write_str(",CITATION[")?;
568 write_quoted(f, citation)?;
569 f.write_char(']')?;
570 }
571 if let Some(ref uri) = self.uri {
572 f.write_str(",URI[")?;
573 write_quoted(f, uri)?;
574 f.write_char(']')?;
575 }
576 f.write_char(']')
577 }
578}
579
580impl Display for Usage {
585 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
586 f.write_str("USAGE[SCOPE[")?;
587 write_quoted(f, &self.scope)?;
588 f.write_char(']')?;
589 if let Some(ref area) = self.area {
590 f.write_str(",AREA[")?;
591 write_quoted(f, area)?;
592 f.write_char(']')?;
593 }
594 if let Some(ref bbox) = self.bbox {
595 write!(f, ",{bbox}")?;
596 }
597 if let Some(ref ve) = self.vertical_extent {
598 write!(f, ",{ve}")?;
599 }
600 if let Some(ref te) = self.temporal_extent {
601 write!(f, ",{te}")?;
602 }
603 f.write_char(']')
604 }
605}
606
607impl Display for BBox {
608 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
609 write!(
610 f,
611 "BBOX[{},{},{},{}]",
612 self.lower_left_latitude,
613 self.lower_left_longitude,
614 self.upper_right_latitude,
615 self.upper_right_longitude
616 )
617 }
618}
619
620impl Display for VerticalExtent {
621 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
622 write!(
623 f,
624 "VERTICALEXTENT[{},{}",
625 self.minimum_height, self.maximum_height
626 )?;
627 if let Some(ref unit) = self.unit {
628 write!(f, ",{unit}")?;
629 }
630 f.write_char(']')
631 }
632}
633
634impl Display for TemporalExtent {
635 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
636 write!(f, "TIMEEXTENT[")?;
639 write_temporal_value(f, &self.start)?;
640 f.write_char(',')?;
641 write_temporal_value(f, &self.end)?;
642 f.write_char(']')
643 }
644}
645
646fn write_temporal_value(f: &mut Formatter<'_>, value: &str) -> fmt::Result {
647 if value.starts_with(|c: char| c.is_ascii_digit()) {
649 f.write_str(value)
650 } else {
651 write_quoted(f, value)
652 }
653}