1 #include <cstdlib>
2 #include <iostream>
3 #include "vil_geotiff_header.h"
4 //:
5 // \file
6 #include <cassert>
7 #ifdef _MSC_VER
8 # include "vcl_msvc_warnings.h"
9 #endif
10 #include <geo_tiffp.h>
11 #include <geotiffio.h>
12 #include <geovalues.h>
13
vil_geotiff_header(TIFF * tif)14 vil_geotiff_header::vil_geotiff_header(TIFF * tif)
15 : tif_(tif)
16 {
17 if (tif)
18 {
19 gtif_ = GTIFNew(tif);
20 if (gtif_)
21 {
22 // GTIFPrint(gtif_, nullptr, nullptr);
23
24 // read the header of the GeoDirectoryKey Tag
25 int version[3];
26 GTIFDirectoryInfo(gtif_, version, &number_of_geokeys_);
27 key_directory_version_ = (unsigned short)version[0];
28 key_revision_ = (unsigned short)version[1];
29 minor_revision_ = (unsigned short)version[2];
30 }
31 }
32 }
33
34 bool
gtif_tiepoints(std::vector<std::vector<double>> & tiepoints)35 vil_geotiff_header::gtif_tiepoints(std::vector<std::vector<double>> & tiepoints)
36 {
37 double * points = nullptr;
38 short count;
39 if (TIFFGetField(tif_, GTIFF_TIEPOINTS, &count, &points) < 0)
40 return false;
41
42 // tiepoints are stored as 3d points (I,J,K)->(X,Y,Z)
43 // where the point at location (I,J) at raster space with pixel value K
44 // and (X,Y,Z) is a vector in model space
45
46 // the number of values should be K*6
47 assert((count % 6) == 0);
48 for (unsigned short i = 0; i < count;)
49 {
50 std::vector<double> tiepoint(6);
51 tiepoint[0] = points[i++];
52 tiepoint[1] = points[i++];
53 tiepoint[2] = points[i++];
54 tiepoint[3] = points[i++];
55 tiepoint[4] = points[i++];
56 tiepoint[5] = points[i++];
57 tiepoints.push_back(tiepoint);
58 }
59 return true;
60 }
61
62 bool
gtif_pixelscale(double & scale_x,double & scale_y,double & scale_z)63 vil_geotiff_header::gtif_pixelscale(double & scale_x, double & scale_y, double & scale_z)
64 {
65 double * data;
66 short count;
67 if (TIFFGetField(tif_, GTIFF_PIXELSCALE, &count, &data))
68 {
69 assert(count == 3);
70 scale_x = data[0];
71 scale_y = data[1];
72 scale_z = data[2];
73 return true;
74 }
75 else
76 return false;
77 }
78
79 bool
gtif_trans_matrix(double * & trans_matrix)80 vil_geotiff_header::gtif_trans_matrix(double *& trans_matrix)
81 {
82 short count;
83 if (TIFFGetField(tif_, GTIFF_TRANSMATRIX, &count, &trans_matrix))
84 {
85 assert(count == 16);
86 return true;
87 }
88 else
89 return false;
90 }
91
92 bool
gtif_modeltype(modeltype_t & type)93 vil_geotiff_header::gtif_modeltype(modeltype_t & type)
94 {
95 geocode_t model;
96 if (!GTIFKeyGet(gtif_, GTModelTypeGeoKey, &model, 0, 1))
97 {
98 std::cerr << "NO Model Type defined!!!!\n";
99 return false;
100 }
101 else
102 {
103 type = static_cast<modeltype_t>(model);
104 return true;
105 }
106 }
107
108 bool
gtif_rastertype(rastertype_t & type)109 vil_geotiff_header::gtif_rastertype(rastertype_t & type)
110 {
111 geocode_t raster;
112 if (!GTIFKeyGet(gtif_, GTRasterTypeGeoKey, &raster, 0, 1))
113 {
114 std::cerr << "NO Raster Type, failure!!!!\n";
115 return false;
116 }
117 else
118 {
119 type = static_cast<rastertype_t>(raster);
120 return true;
121 }
122 }
123
124 bool
geounits(geounits_t & units)125 vil_geotiff_header::geounits(geounits_t & units)
126 {
127 short nGeogUOMLinear;
128 if (!GTIFKeyGet(gtif_, GeogLinearUnitsGeoKey, &nGeogUOMLinear, 0, 1))
129 {
130 std::cerr << "NO GEOUNITS, failure!!!!\n";
131 return false;
132 }
133 else
134 {
135 units = static_cast<geounits_t>(nGeogUOMLinear);
136 return true;
137 }
138 }
139
140 bool
PCS_WGS84_UTM_zone(int & zone,GTIF_HEMISPH & hemisph)141 vil_geotiff_header::PCS_WGS84_UTM_zone(int & zone, GTIF_HEMISPH & hemisph) // hemisph is O for N, 1 for S
142 {
143 modeltype_t type;
144 if (gtif_modeltype(type) && type == ModelTypeProjected)
145 {
146 void * value;
147 int size;
148 int length;
149 tagtype_t ttype;
150 bool status = get_key_value(ProjectedCSTypeGeoKey, &value, size, length, ttype);
151 if (!status)
152 {
153 std::cerr << "Missing ProjectedCSTypeGeoKey (" << ProjectedCSTypeGeoKey << ") key!\n";
154 return false;
155 }
156
157 // WGS84 / UTM northern hemisphere: 326zz where zz is UTM zone number
158 // WGS84 / UTM southern hemisphere: 327zz where zz is UTM zone number
159 // we are looking for a short value, only one
160 if (length != 1 || ttype != TYPE_SHORT)
161 {
162 std::cerr << "Expected a single value with type int16 (short)!\n";
163 return false;
164 }
165
166 auto * val = static_cast<short *>(value);
167 if ((*val < PCS_WGS84_UTM_zone_1N) || ((*val > PCS_WGS84_UTM_zone_60S)))
168 {
169 return false;
170 }
171
172 #if 0
173 int zone;
174 int hemisph; // O for N, 1 for S
175 #endif // 0
176 if ((*val >= PCS_WGS84_UTM_zone_1N) && (*val <= PCS_WGS84_UTM_zone_60N))
177 {
178 zone = *val - 32600;
179 hemisph = NORTH;
180 }
181 else if ((*val >= PCS_WGS84_UTM_zone_1S) && (*val <= PCS_WGS84_UTM_zone_60S))
182 {
183 zone = *val - 32700;
184 hemisph = SOUTH;
185 }
186 return true;
187 }
188 else
189 {
190 hemisph = UNDEF;
191 return false;
192 }
193 }
194
195 //: returns true if in geographic coords (required), linear units (optional) are in meters,
196 // and angular units (required) are in degrees
197 bool
GCS_WGS84_MET_DEG()198 vil_geotiff_header::GCS_WGS84_MET_DEG()
199 {
200 modeltype_t type;
201 if (gtif_modeltype(type) && type == ModelTypeGeographic)
202 {
203 void * value;
204 int size;
205 int length;
206 tagtype_t ttype;
207 bool status;
208 short * val;
209
210 // confirm linear units (optional) are in meters
211 status = get_key_value(GeogLinearUnitsGeoKey, &value, size, length, ttype);
212 if (status)
213 {
214 if (length != 1 || ttype != TYPE_SHORT)
215 {
216 std::cerr << "Expected a single value with type int16 (short)!\n";
217 return false;
218 }
219 val = static_cast<short *>(value);
220
221 if (*val != Linear_Meter)
222 {
223 std::cerr << "Linear units are not in Meters!\n";
224 return false;
225 }
226 }
227
228 // confirm angular units (required) are in degrees
229 status = get_key_value(GeogAngularUnitsGeoKey, &value, size, length, ttype);
230 if (!status)
231 {
232 std::cerr << "Missing GeogAngularUnitsGeoKey (" << GeogAngularUnitsGeoKey << ") key!\n";
233 return false;
234 }
235 if (length != 1 || ttype != TYPE_SHORT)
236 {
237 std::cerr << "Expected a single value with type int16 (short)!\n";
238 return false;
239 }
240 val = static_cast<short *>(value);
241
242 if (*val != Angular_Degree)
243 {
244 std::cerr << "Angular units are not in Degrees!\n";
245 return false;
246 }
247
248 return true;
249 }
250 return false;
251 }
252
253 //: returns the Zone and the Hemisphere (0 for N, 1 for S);
254 bool
PCS_NAD83_UTM_zone(int & zone,GTIF_HEMISPH & hemisph)255 vil_geotiff_header::PCS_NAD83_UTM_zone(int & zone, GTIF_HEMISPH & hemisph)
256 {
257 modeltype_t type;
258 if (gtif_modeltype(type) && type == ModelTypeProjected)
259 {
260 void * value;
261 int size;
262 int length;
263 tagtype_t ttype;
264 bool status = get_key_value(ProjectedCSTypeGeoKey, &value, size, length, ttype);
265 if (!status)
266 {
267 std::cerr << "Missing ProjectedCSTypeGeoKey (" << ProjectedCSTypeGeoKey << ") key!\n";
268 return false;
269 }
270 if (length != 1 || ttype != TYPE_SHORT)
271 {
272 std::cerr << "Expected a single value with type int16 (short)!\n";
273 return false;
274 }
275
276 auto * val = static_cast<short *>(value);
277 if ((*val < PCS_NAD83_UTM_zone_3N) || ((*val > PCS_NAD83_Missouri_West)))
278 {
279 std::cerr << "NOT in RANGE PCS_NAD83_UTM_zone_3N and PCS_NAD83_Missouri_West!\n";
280 return false;
281 }
282 zone = *val - 26900;
283 hemisph = NORTH;
284
285 return true;
286 }
287 else
288 {
289 hemisph = UNDEF;
290 return false;
291 }
292 }
293
294
295 bool
get_key_value(geokey_t key,void ** value,int & size,int & length,tagtype_t & type)296 vil_geotiff_header::get_key_value(geokey_t key, void ** value, int & size, int & length, tagtype_t & type)
297 {
298 length = GTIFKeyInfo(gtif_, key, &size, &type);
299
300 // check if it is a valid key id
301 if (length == 0)
302 {
303 // key is not defined
304 return false;
305 }
306 else
307 {
308 *value = std::malloc(size * length);
309 GTIFKeyGet(gtif_, key, *value, 0, length);
310 return true;
311 }
312 }
313