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