1 : /******************************************************************************
2 : * $Id: loslasdataset.cpp 20996 2010-10-28 18:38:15Z rouault $
3 : *
4 : * Project: Horizontal Datum Formats
5 : * Purpose: Implementation of NOAA/NADCON los/las datum shift format.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : * Financial Support: i-cubed (http://www.i-cubed.com)
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2010, Frank Warmerdam
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "rawdataset.h"
32 : #include "cpl_string.h"
33 : #include "ogr_srs_api.h"
34 :
35 : CPL_CVSID("$Id: loslasdataset.cpp 20996 2010-10-28 18:38:15Z rouault $");
36 :
37 : /**
38 :
39 : NOAA .LOS/.LAS Datum Grid Shift Format
40 :
41 : All values are little endian
42 :
43 : Header
44 : ------
45 :
46 : char[56] "NADCON EXTRACTED REGION"
47 : char[8] "NADGRD "
48 : int32 grid width
49 : int32 grid height
50 : int32 z count (1)
51 : float32 origin longitude
52 : float32 grid cell width longitude
53 : float32 origin latitude
54 : float32 grid cell height latitude
55 : float32 angle (0.0)
56 :
57 : Data
58 : ----
59 :
60 : int32 ? always 0
61 : float32*gridwidth offset in arcseconds.
62 :
63 : Note that the record length is always gridwidth*4 + 4, and
64 : even the header record is this length though it means some waste.
65 :
66 : **/
67 :
68 : /************************************************************************/
69 : /* ==================================================================== */
70 : /* LOSLASDataset */
71 : /* ==================================================================== */
72 : /************************************************************************/
73 :
74 : class LOSLASDataset : public RawDataset
75 : {
76 : public:
77 : VSILFILE *fpImage; // image data file.
78 :
79 : int nRecordLength;
80 :
81 : double adfGeoTransform[6];
82 :
83 : public:
84 : LOSLASDataset();
85 : ~LOSLASDataset();
86 :
87 : virtual CPLErr GetGeoTransform( double * padfTransform );
88 : virtual const char *GetProjectionRef();
89 :
90 : static GDALDataset *Open( GDALOpenInfo * );
91 : static int Identify( GDALOpenInfo * );
92 : };
93 :
94 : /************************************************************************/
95 : /* ==================================================================== */
96 : /* LOSLASDataset */
97 : /* ==================================================================== */
98 : /************************************************************************/
99 :
100 : /************************************************************************/
101 : /* LOSLASDataset() */
102 : /************************************************************************/
103 :
104 1 : LOSLASDataset::LOSLASDataset()
105 : {
106 1 : fpImage = NULL;
107 1 : }
108 :
109 : /************************************************************************/
110 : /* ~LOSLASDataset() */
111 : /************************************************************************/
112 :
113 1 : LOSLASDataset::~LOSLASDataset()
114 :
115 : {
116 1 : FlushCache();
117 :
118 1 : if( fpImage != NULL )
119 1 : VSIFCloseL( fpImage );
120 1 : }
121 :
122 : /************************************************************************/
123 : /* Identify() */
124 : /************************************************************************/
125 :
126 11945 : int LOSLASDataset::Identify( GDALOpenInfo *poOpenInfo )
127 :
128 : {
129 11945 : if( poOpenInfo->nHeaderBytes < 64 )
130 11360 : return FALSE;
131 :
132 585 : if( !EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"las")
133 : && !EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"los") )
134 584 : return FALSE;
135 :
136 1 : if( !EQUALN((const char *)poOpenInfo->pabyHeader + 56, "NADGRD", 6 ) )
137 0 : return FALSE;
138 :
139 1 : return TRUE;
140 : }
141 :
142 : /************************************************************************/
143 : /* Open() */
144 : /************************************************************************/
145 :
146 1852 : GDALDataset *LOSLASDataset::Open( GDALOpenInfo * poOpenInfo )
147 :
148 : {
149 1852 : if( !Identify( poOpenInfo ) )
150 1851 : return NULL;
151 :
152 : /* -------------------------------------------------------------------- */
153 : /* Create a corresponding GDALDataset. */
154 : /* -------------------------------------------------------------------- */
155 : LOSLASDataset *poDS;
156 :
157 1 : poDS = new LOSLASDataset();
158 :
159 : /* -------------------------------------------------------------------- */
160 : /* Open the file. */
161 : /* -------------------------------------------------------------------- */
162 1 : poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
163 :
164 1 : if( poDS->fpImage == NULL )
165 : {
166 0 : delete poDS;
167 0 : return NULL;
168 : }
169 :
170 : /* -------------------------------------------------------------------- */
171 : /* Read the header. */
172 : /* -------------------------------------------------------------------- */
173 1 : VSIFSeekL( poDS->fpImage, 64, SEEK_SET );
174 :
175 1 : VSIFReadL( &(poDS->nRasterXSize), 4, 1, poDS->fpImage );
176 1 : VSIFReadL( &(poDS->nRasterYSize), 4, 1, poDS->fpImage );
177 :
178 : CPL_LSBPTR32( &(poDS->nRasterXSize) );
179 : CPL_LSBPTR32( &(poDS->nRasterYSize) );
180 :
181 1 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
182 : {
183 0 : delete poDS;
184 0 : return NULL;
185 : }
186 :
187 1 : VSIFSeekL( poDS->fpImage, 76, SEEK_SET );
188 :
189 : float min_lon, min_lat, delta_lon, delta_lat;
190 :
191 1 : VSIFReadL( &min_lon, 4, 1, poDS->fpImage );
192 1 : VSIFReadL( &delta_lon, 4, 1, poDS->fpImage );
193 1 : VSIFReadL( &min_lat, 4, 1, poDS->fpImage );
194 1 : VSIFReadL( &delta_lat, 4, 1, poDS->fpImage );
195 :
196 : CPL_LSBPTR32( &min_lon );
197 : CPL_LSBPTR32( &delta_lon );
198 : CPL_LSBPTR32( &min_lat );
199 : CPL_LSBPTR32( &delta_lat );
200 :
201 1 : poDS->nRecordLength = poDS->nRasterXSize * 4 + 4;
202 :
203 : /* -------------------------------------------------------------------- */
204 : /* Create band information object. */
205 : /* */
206 : /* Note we are setting up to read from the last image record to */
207 : /* the first since the data comes with the southern most record */
208 : /* first, not the northernmost like we would want. */
209 : /* -------------------------------------------------------------------- */
210 : poDS->SetBand(
211 : 1, new RawRasterBand( poDS, 1, poDS->fpImage,
212 : poDS->nRasterYSize * poDS->nRecordLength + 4,
213 : 4, -1 * poDS->nRecordLength,
214 : GDT_Float32,
215 1 : CPL_IS_LSB, TRUE, FALSE ) );
216 :
217 : /* -------------------------------------------------------------------- */
218 : /* Setup georeferencing. */
219 : /* -------------------------------------------------------------------- */
220 1 : poDS->adfGeoTransform[0] = min_lon - delta_lon*0.5;
221 1 : poDS->adfGeoTransform[1] = delta_lon;
222 1 : poDS->adfGeoTransform[2] = 0.0;
223 1 : poDS->adfGeoTransform[3] = min_lat + (poDS->nRasterYSize-0.5) * delta_lat;
224 1 : poDS->adfGeoTransform[4] = 0.0;
225 1 : poDS->adfGeoTransform[5] = -1 * delta_lat;
226 :
227 : /* -------------------------------------------------------------------- */
228 : /* Initialize any PAM information. */
229 : /* -------------------------------------------------------------------- */
230 1 : poDS->SetDescription( poOpenInfo->pszFilename );
231 1 : poDS->TryLoadXML();
232 :
233 : /* -------------------------------------------------------------------- */
234 : /* Check for overviews. */
235 : /* -------------------------------------------------------------------- */
236 1 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
237 :
238 1 : return( poDS );
239 : }
240 :
241 : /************************************************************************/
242 : /* GetGeoTransform() */
243 : /************************************************************************/
244 :
245 1 : CPLErr LOSLASDataset::GetGeoTransform( double * padfTransform )
246 :
247 : {
248 1 : memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
249 1 : return CE_None;
250 : }
251 :
252 : /************************************************************************/
253 : /* GetProjectionRef() */
254 : /************************************************************************/
255 :
256 1 : const char *LOSLASDataset::GetProjectionRef()
257 :
258 : {
259 1 : return SRS_WKT_WGS84;
260 : }
261 :
262 : /************************************************************************/
263 : /* GDALRegister_LOSLAS() */
264 : /************************************************************************/
265 :
266 582 : void GDALRegister_LOSLAS()
267 :
268 : {
269 : GDALDriver *poDriver;
270 :
271 582 : if( GDALGetDriverByName( "LOSLAS" ) == NULL )
272 : {
273 561 : poDriver = new GDALDriver();
274 :
275 561 : poDriver->SetDescription( "LOSLAS" );
276 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
277 561 : "NADCON .los/.las Datum Grid Shift" );
278 561 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
279 :
280 561 : poDriver->pfnOpen = LOSLASDataset::Open;
281 561 : poDriver->pfnIdentify = LOSLASDataset::Identify;
282 :
283 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
284 : }
285 582 : }
286 :
|