geotiff_reader/
geokeys.rs1pub const GT_MODEL_TYPE: u16 = 1024;
12pub const GT_RASTER_TYPE: u16 = 1025;
13pub const GEOGRAPHIC_TYPE: u16 = 2048;
14pub const GEOG_CITATION: u16 = 2049;
15pub const GEOG_GEODETIC_DATUM: u16 = 2050;
16pub const GEOG_ANGULAR_UNITS: u16 = 2054;
17pub const PROJECTED_CS_TYPE: u16 = 3072;
18pub const PROJ_CITATION: u16 = 3073;
19pub const PROJECTION: u16 = 3074;
20pub const PROJ_COORD_TRANS: u16 = 3075;
21pub const PROJ_LINEAR_UNITS: u16 = 3076;
22pub const VERTICAL_CS_TYPE: u16 = 4096;
23pub const VERTICAL_DATUM: u16 = 4098;
24pub const VERTICAL_UNITS: u16 = 4099;
25
26#[derive(Debug, Clone)]
28pub struct GeoKey {
29 pub id: u16,
30 pub value: GeoKeyValue,
31}
32
33#[derive(Debug, Clone)]
35pub enum GeoKeyValue {
36 Short(u16),
38 Double(Vec<f64>),
40 Ascii(String),
42}
43
44#[derive(Debug, Clone)]
46pub struct GeoKeyDirectory {
47 pub version: u16,
48 pub major_revision: u16,
49 pub minor_revision: u16,
50 pub keys: Vec<GeoKey>,
51}
52
53impl GeoKeyDirectory {
54 pub fn parse(directory: &[u16], double_params: &[f64], ascii_params: &str) -> Option<Self> {
60 if directory.len() < 4 {
61 return None;
62 }
63
64 let version = directory[0];
65 let major_revision = directory[1];
66 let minor_revision = directory[2];
67 let num_keys = directory[3] as usize;
68
69 if directory.len() < 4 + num_keys * 4 {
70 return None;
71 }
72
73 let mut keys = Vec::with_capacity(num_keys);
74 for i in 0..num_keys {
75 let base = 4 + i * 4;
76 let key_id = directory[base];
77 let location = directory[base + 1];
78 let count = directory[base + 2] as usize;
79 let value_offset = directory[base + 3];
80
81 let value = match location {
82 0 => {
83 GeoKeyValue::Short(value_offset)
85 }
86 34736 => {
87 let start = value_offset as usize;
89 let end = start + count;
90 if end <= double_params.len() {
91 GeoKeyValue::Double(double_params[start..end].to_vec())
92 } else {
93 continue;
94 }
95 }
96 34737 => {
97 let start = value_offset as usize;
99 let end = start + count;
100 if end <= ascii_params.len() {
101 let s = ascii_params[start..end]
102 .trim_end_matches('|')
103 .trim_end_matches('\0')
104 .to_string();
105 GeoKeyValue::Ascii(s)
106 } else {
107 continue;
108 }
109 }
110 _ => continue,
111 };
112
113 keys.push(GeoKey { id: key_id, value });
114 }
115
116 Some(Self {
117 version,
118 major_revision,
119 minor_revision,
120 keys,
121 })
122 }
123
124 pub fn get(&self, id: u16) -> Option<&GeoKey> {
126 self.keys.iter().find(|k| k.id == id)
127 }
128
129 pub fn get_short(&self, id: u16) -> Option<u16> {
131 self.get(id).and_then(|k| match &k.value {
132 GeoKeyValue::Short(v) => Some(*v),
133 _ => None,
134 })
135 }
136
137 pub fn get_ascii(&self, id: u16) -> Option<&str> {
139 self.get(id).and_then(|k| match &k.value {
140 GeoKeyValue::Ascii(s) => Some(s.as_str()),
141 _ => None,
142 })
143 }
144
145 pub fn get_double(&self, id: u16) -> Option<&[f64]> {
147 self.get(id).and_then(|k| match &k.value {
148 GeoKeyValue::Double(v) => Some(v.as_slice()),
149 _ => None,
150 })
151 }
152}