1#![allow(dead_code)]
2#![allow(missing_docs)]
3
4use std::collections::HashMap;
5
6use num_enum::{IntoPrimitive, TryFromPrimitive};
7
8use crate::tiff::Value;
9use crate::tiff::{TiffError, TiffResult};
10
11#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive, Eq, Hash)]
13#[repr(u16)]
14pub(crate) enum GeoKeyTag {
15 ModelType = 1024,
17 RasterType = 1025,
18 Citation = 1026,
19
20 GeographicType = 2048,
22 GeogCitation = 2049,
23 GeogGeodeticDatum = 2050,
24 GeogPrimeMeridian = 2051,
25 GeogLinearUnits = 2052,
26 GeogLinearUnitSize = 2053,
27 GeogAngularUnits = 2054,
28 GeogAngularUnitSize = 2055,
29 GeogEllipsoid = 2056,
30 GeogSemiMajorAxis = 2057,
31 GeogSemiMinorAxis = 2058,
32 GeogInvFlattening = 2059,
33 GeogAzimuthUnits = 2060,
34 GeogPrimeMeridianLong = 2061,
35
36 ProjectedType = 3072,
38 ProjCitation = 3073,
39 Projection = 3074,
40 ProjCoordTrans = 3075,
41 ProjLinearUnits = 3076,
42 ProjLinearUnitSize = 3077,
43 ProjStdParallel1 = 3078,
44 ProjStdParallel2 = 3079,
45 ProjNatOriginLong = 3080,
46 ProjNatOriginLat = 3081,
47 ProjFalseEasting = 3082,
48 ProjFalseNorthing = 3083,
49 ProjFalseOriginLong = 3084,
50 ProjFalseOriginLat = 3085,
51 ProjFalseOriginEasting = 3086,
52 ProjFalseOriginNorthing = 3087,
53 ProjCenterLong = 3088,
54 ProjCenterLat = 3089,
55 ProjCenterEasting = 3090,
56 ProjCenterNorthing = 3091,
57 ProjScaleAtNatOrigin = 3092,
58 ProjScaleAtCenter = 3093,
59 ProjAzimuthAngle = 3094,
60 ProjStraightVertPoleLong = 3095,
61
62 Vertical = 4096,
64 VerticalCitation = 4097,
65 VerticalDatum = 4098,
66 VerticalUnits = 4099,
67}
68
69#[derive(Debug, Clone)]
73pub struct GeoKeyDirectory {
74 pub model_type: Option<u16>,
75 pub raster_type: Option<u16>,
76 pub citation: Option<String>,
77
78 pub geographic_type: Option<u16>,
79 pub geog_citation: Option<String>,
80 pub geog_geodetic_datum: Option<u16>,
81
82 pub geog_prime_meridian: Option<u16>,
86
87 pub geog_linear_units: Option<u16>,
88 pub geog_linear_unit_size: Option<f64>,
89 pub geog_angular_units: Option<u16>,
90 pub geog_angular_unit_size: Option<f64>,
91
92 pub geog_ellipsoid: Option<u16>,
95 pub geog_semi_major_axis: Option<f64>,
96 pub geog_semi_minor_axis: Option<f64>,
97 pub geog_inv_flattening: Option<f64>,
98 pub geog_azimuth_units: Option<u16>,
99
100 pub geog_prime_meridian_long: Option<f64>,
104
105 pub projected_type: Option<u16>,
106 pub proj_citation: Option<String>,
107 pub projection: Option<u16>,
108 pub proj_coord_trans: Option<u16>,
109 pub proj_linear_units: Option<u16>,
110 pub proj_linear_unit_size: Option<f64>,
111 pub proj_std_parallel1: Option<f64>,
112 pub proj_std_parallel2: Option<f64>,
113 pub proj_nat_origin_long: Option<f64>,
114 pub proj_nat_origin_lat: Option<f64>,
115 pub proj_false_easting: Option<f64>,
116 pub proj_false_northing: Option<f64>,
117 pub proj_false_origin_long: Option<f64>,
118 pub proj_false_origin_lat: Option<f64>,
119 pub proj_false_origin_easting: Option<f64>,
120 pub proj_false_origin_northing: Option<f64>,
121 pub proj_center_long: Option<f64>,
122 pub proj_center_lat: Option<f64>,
123 pub proj_center_easting: Option<f64>,
124 pub proj_center_northing: Option<f64>,
125 pub proj_scale_at_nat_origin: Option<f64>,
126 pub proj_scale_at_center: Option<f64>,
127 pub proj_azimuth_angle: Option<f64>,
128 pub proj_straight_vert_pole_long: Option<f64>,
129
130 pub vertical: Option<u16>,
131 pub vertical_citation: Option<String>,
132 pub vertical_datum: Option<u16>,
133 pub vertical_units: Option<u16>,
134}
135
136impl GeoKeyDirectory {
137 pub(crate) fn from_tags(mut tag_data: HashMap<GeoKeyTag, Value>) -> TiffResult<Self> {
139 let mut model_type = None;
140 let mut raster_type = None;
141 let mut citation = None;
142
143 let mut geographic_type = None;
144 let mut geog_citation = None;
145 let mut geog_geodetic_datum = None;
146 let mut geog_prime_meridian = None;
147 let mut geog_linear_units = None;
148 let mut geog_linear_unit_size = None;
149 let mut geog_angular_units = None;
150 let mut geog_angular_unit_size = None;
151 let mut geog_ellipsoid = None;
152 let mut geog_semi_major_axis = None;
153 let mut geog_semi_minor_axis = None;
154 let mut geog_inv_flattening = None;
155 let mut geog_azimuth_units = None;
156 let mut geog_prime_meridian_long = None;
157
158 let mut projected_type = None;
159 let mut proj_citation = None;
160 let mut projection = None;
161 let mut proj_coord_trans = None;
162 let mut proj_linear_units = None;
163 let mut proj_linear_unit_size = None;
164 let mut proj_std_parallel1 = None;
165 let mut proj_std_parallel2 = None;
166 let mut proj_nat_origin_long = None;
167 let mut proj_nat_origin_lat = None;
168 let mut proj_false_easting = None;
169 let mut proj_false_northing = None;
170 let mut proj_false_origin_long = None;
171 let mut proj_false_origin_lat = None;
172 let mut proj_false_origin_easting = None;
173 let mut proj_false_origin_northing = None;
174 let mut proj_center_long = None;
175 let mut proj_center_lat = None;
176 let mut proj_center_easting = None;
177 let mut proj_center_northing = None;
178 let mut proj_scale_at_nat_origin = None;
179 let mut proj_scale_at_center = None;
180 let mut proj_azimuth_angle = None;
181 let mut proj_straight_vert_pole_long = None;
182
183 let mut vertical = None;
184 let mut vertical_citation = None;
185 let mut vertical_datum = None;
186 let mut vertical_units = None;
187
188 tag_data.drain().try_for_each(|(tag, value)| {
189 match tag {
190 GeoKeyTag::ModelType => model_type = Some(value.into_u16()?),
191 GeoKeyTag::RasterType => raster_type = Some(value.into_u16()?),
192 GeoKeyTag::Citation => citation = Some(value.into_string()?),
193 GeoKeyTag::GeographicType => geographic_type = Some(value.into_u16()?),
194 GeoKeyTag::GeogCitation => geog_citation = Some(value.into_string()?),
195 GeoKeyTag::GeogGeodeticDatum => geog_geodetic_datum = Some(value.into_u16()?),
196 GeoKeyTag::GeogPrimeMeridian => geog_prime_meridian = Some(value.into_u16()?),
197 GeoKeyTag::GeogLinearUnits => geog_linear_units = Some(value.into_u16()?),
198 GeoKeyTag::GeogLinearUnitSize => geog_linear_unit_size = Some(value.into_f64()?),
199 GeoKeyTag::GeogAngularUnits => geog_angular_units = Some(value.into_u16()?),
200 GeoKeyTag::GeogAngularUnitSize => geog_angular_unit_size = Some(value.into_f64()?),
201 GeoKeyTag::GeogEllipsoid => geog_ellipsoid = Some(value.into_u16()?),
202 GeoKeyTag::GeogSemiMajorAxis => geog_semi_major_axis = Some(value.into_f64()?),
203 GeoKeyTag::GeogSemiMinorAxis => geog_semi_minor_axis = Some(value.into_f64()?),
204 GeoKeyTag::GeogInvFlattening => geog_inv_flattening = Some(value.into_f64()?),
205 GeoKeyTag::GeogAzimuthUnits => geog_azimuth_units = Some(value.into_u16()?),
206 GeoKeyTag::GeogPrimeMeridianLong => {
207 geog_prime_meridian_long = Some(value.into_f64()?)
208 }
209 GeoKeyTag::ProjectedType => projected_type = Some(value.into_u16()?),
210 GeoKeyTag::ProjCitation => proj_citation = Some(value.into_string()?),
211 GeoKeyTag::Projection => projection = Some(value.into_u16()?),
212 GeoKeyTag::ProjCoordTrans => proj_coord_trans = Some(value.into_u16()?),
213 GeoKeyTag::ProjLinearUnits => proj_linear_units = Some(value.into_u16()?),
214 GeoKeyTag::ProjLinearUnitSize => proj_linear_unit_size = Some(value.into_f64()?),
215 GeoKeyTag::ProjStdParallel1 => proj_std_parallel1 = Some(value.into_f64()?),
216 GeoKeyTag::ProjStdParallel2 => proj_std_parallel2 = Some(value.into_f64()?),
217 GeoKeyTag::ProjNatOriginLong => proj_nat_origin_long = Some(value.into_f64()?),
218 GeoKeyTag::ProjNatOriginLat => proj_nat_origin_lat = Some(value.into_f64()?),
219 GeoKeyTag::ProjFalseEasting => proj_false_easting = Some(value.into_f64()?),
220 GeoKeyTag::ProjFalseNorthing => proj_false_northing = Some(value.into_f64()?),
221 GeoKeyTag::ProjFalseOriginLong => proj_false_origin_long = Some(value.into_f64()?),
222 GeoKeyTag::ProjFalseOriginLat => proj_false_origin_lat = Some(value.into_f64()?),
223 GeoKeyTag::ProjFalseOriginEasting => {
224 proj_false_origin_easting = Some(value.into_f64()?)
225 }
226 GeoKeyTag::ProjFalseOriginNorthing => {
227 proj_false_origin_northing = Some(value.into_f64()?)
228 }
229 GeoKeyTag::ProjCenterLong => proj_center_long = Some(value.into_f64()?),
230 GeoKeyTag::ProjCenterLat => proj_center_lat = Some(value.into_f64()?),
231 GeoKeyTag::ProjCenterEasting => proj_center_easting = Some(value.into_f64()?),
232 GeoKeyTag::ProjCenterNorthing => proj_center_northing = Some(value.into_f64()?),
233 GeoKeyTag::ProjScaleAtNatOrigin => {
234 proj_scale_at_nat_origin = Some(value.into_f64()?)
235 }
236 GeoKeyTag::ProjScaleAtCenter => proj_scale_at_center = Some(value.into_f64()?),
237 GeoKeyTag::ProjAzimuthAngle => proj_azimuth_angle = Some(value.into_f64()?),
238 GeoKeyTag::ProjStraightVertPoleLong => {
239 proj_straight_vert_pole_long = Some(value.into_f64()?)
240 }
241 GeoKeyTag::Vertical => vertical = Some(value.into_u16()?),
242 GeoKeyTag::VerticalCitation => vertical_citation = Some(value.into_string()?),
243 GeoKeyTag::VerticalDatum => vertical_datum = Some(value.into_u16()?),
244 GeoKeyTag::VerticalUnits => vertical_units = Some(value.into_u16()?),
245 };
246 Ok::<_, TiffError>(())
247 })?;
248
249 Ok(Self {
250 model_type,
251 raster_type,
252 citation,
253
254 geographic_type,
255 geog_citation,
256 geog_geodetic_datum,
257 geog_prime_meridian,
258 geog_linear_units,
259 geog_linear_unit_size,
260 geog_angular_units,
261 geog_angular_unit_size,
262 geog_ellipsoid,
263 geog_semi_major_axis,
264 geog_semi_minor_axis,
265 geog_inv_flattening,
266 geog_azimuth_units,
267 geog_prime_meridian_long,
268
269 projected_type,
270 proj_citation,
271 projection,
272 proj_coord_trans,
273 proj_linear_units,
274 proj_linear_unit_size,
275 proj_std_parallel1,
276 proj_std_parallel2,
277 proj_nat_origin_long,
278 proj_nat_origin_lat,
279 proj_false_easting,
280 proj_false_northing,
281 proj_false_origin_long,
282 proj_false_origin_lat,
283 proj_false_origin_easting,
284 proj_false_origin_northing,
285 proj_center_long,
286 proj_center_lat,
287 proj_center_easting,
288 proj_center_northing,
289 proj_scale_at_nat_origin,
290 proj_scale_at_center,
291 proj_azimuth_angle,
292 proj_straight_vert_pole_long,
293
294 vertical,
295 vertical_citation,
296 vertical_datum,
297 vertical_units,
298 })
299 }
300
301 pub fn epsg_code(&self) -> Option<u16> {
306 if let Some(projected_type) = self.projected_type {
307 Some(projected_type)
308 } else {
309 self.geographic_type
310 }
311 }
312}