1 : /******************************************************************************
2 : * $Id: jdemdataset.cpp 21837 2011-02-24 21:16:42Z rouault $
3 : *
4 : * Project: JDEM Reader
5 : * Purpose: All code for Japanese DEM Reader
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2000, Frank Warmerdam <warmerdam@pobox.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdal_pam.h"
31 :
32 : CPL_CVSID("$Id: jdemdataset.cpp 21837 2011-02-24 21:16:42Z rouault $");
33 :
34 : CPL_C_START
35 : void GDALRegister_JDEM(void);
36 : CPL_C_END
37 :
38 : /************************************************************************/
39 : /* JDEMGetField() */
40 : /************************************************************************/
41 :
42 8 : static int JDEMGetField( char *pszField, int nWidth )
43 :
44 : {
45 : char szWork[32];
46 :
47 8 : CPLAssert( nWidth < (int) sizeof(szWork) );
48 :
49 8 : strncpy( szWork, pszField, nWidth );
50 8 : szWork[nWidth] = '\0';
51 :
52 8 : return atoi(szWork);
53 : }
54 :
55 : /************************************************************************/
56 : /* JDEMGetAngle() */
57 : /************************************************************************/
58 :
59 0 : static double JDEMGetAngle( char *pszField )
60 :
61 : {
62 0 : int nAngle = JDEMGetField( pszField, 7 );
63 : int nDegree, nMin, nSec;
64 :
65 : // Note, this isn't very general purpose, but it would appear
66 : // from the field widths that angles are never negative. Nice
67 : // to be a country in the "first quadrant".
68 :
69 0 : nDegree = nAngle / 10000;
70 0 : nMin = (nAngle / 100) % 100;
71 0 : nSec = nAngle % 100;
72 :
73 0 : return nDegree + nMin / 60.0 + nSec / 3600.0;
74 : }
75 :
76 : /************************************************************************/
77 : /* ==================================================================== */
78 : /* JDEMDataset */
79 : /* ==================================================================== */
80 : /************************************************************************/
81 :
82 : class JDEMRasterBand;
83 :
84 : class JDEMDataset : public GDALPamDataset
85 : {
86 : friend class JDEMRasterBand;
87 :
88 : VSILFILE *fp;
89 : GByte abyHeader[1012];
90 :
91 : public:
92 : JDEMDataset();
93 : ~JDEMDataset();
94 :
95 : static GDALDataset *Open( GDALOpenInfo * );
96 : static int Identify( GDALOpenInfo * );
97 :
98 : CPLErr GetGeoTransform( double * padfTransform );
99 : const char *GetProjectionRef();
100 : };
101 :
102 : /************************************************************************/
103 : /* ==================================================================== */
104 : /* JDEMRasterBand */
105 : /* ==================================================================== */
106 : /************************************************************************/
107 :
108 : class JDEMRasterBand : public GDALPamRasterBand
109 : {
110 : friend class JDEMDataset;
111 :
112 : int nRecordSize;
113 : char* pszRecord;
114 :
115 : public:
116 :
117 : JDEMRasterBand( JDEMDataset *, int );
118 : ~JDEMRasterBand();
119 :
120 : virtual CPLErr IReadBlock( int, int, void * );
121 : };
122 :
123 :
124 : /************************************************************************/
125 : /* JDEMRasterBand() */
126 : /************************************************************************/
127 :
128 1 : JDEMRasterBand::JDEMRasterBand( JDEMDataset *poDS, int nBand )
129 :
130 : {
131 1 : this->poDS = poDS;
132 1 : this->nBand = nBand;
133 :
134 1 : eDataType = GDT_Float32;
135 :
136 1 : nBlockXSize = poDS->GetRasterXSize();
137 1 : nBlockYSize = 1;
138 :
139 : /* Cannot overflow as nBlockXSize <= 999 */
140 1 : nRecordSize = nBlockXSize*5 + 9 + 2;
141 1 : pszRecord = NULL;
142 1 : }
143 :
144 : /************************************************************************/
145 : /* ~JDEMRasterBand() */
146 : /************************************************************************/
147 :
148 1 : JDEMRasterBand::~JDEMRasterBand()
149 : {
150 1 : VSIFree(pszRecord);
151 1 : }
152 :
153 : /************************************************************************/
154 : /* IReadBlock() */
155 : /************************************************************************/
156 :
157 2 : CPLErr JDEMRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
158 : void * pImage )
159 :
160 : {
161 2 : JDEMDataset *poGDS = (JDEMDataset *) poDS;
162 : int i;
163 :
164 2 : if (pszRecord == NULL)
165 : {
166 1 : if (nRecordSize < 0)
167 0 : return CE_Failure;
168 :
169 1 : pszRecord = (char *) VSIMalloc(nRecordSize);
170 1 : if (pszRecord == NULL)
171 : {
172 : CPLError(CE_Failure, CPLE_OutOfMemory,
173 0 : "Cannot allocate scanline buffer");
174 0 : nRecordSize = -1;
175 0 : return CE_Failure;
176 : }
177 : }
178 :
179 2 : VSIFSeekL( poGDS->fp, 1011 + nRecordSize*nBlockYOff, SEEK_SET );
180 :
181 2 : VSIFReadL( pszRecord, 1, nRecordSize, poGDS->fp );
182 :
183 2 : if( !EQUALN((char *) poGDS->abyHeader,pszRecord,6) )
184 : {
185 : CPLError( CE_Failure, CPLE_AppDefined,
186 : "JDEM Scanline corrupt. Perhaps file was not transferred\n"
187 0 : "in binary mode?" );
188 0 : return CE_Failure;
189 : }
190 :
191 2 : if( JDEMGetField( pszRecord + 6, 3 ) != nBlockYOff + 1 )
192 : {
193 : CPLError( CE_Failure, CPLE_AppDefined,
194 : "JDEM scanline out of order, JDEM driver does not\n"
195 0 : "currently support partial datasets." );
196 0 : return CE_Failure;
197 : }
198 :
199 6 : for( i = 0; i < nBlockXSize; i++ )
200 4 : ((float *) pImage)[i] = (float)
201 4 : (JDEMGetField( pszRecord + 9 + 5 * i, 5) * 0.1);
202 :
203 2 : return CE_None;
204 : }
205 :
206 : /************************************************************************/
207 : /* ==================================================================== */
208 : /* JDEMDataset */
209 : /* ==================================================================== */
210 : /************************************************************************/
211 :
212 : /************************************************************************/
213 : /* JDEMDataset() */
214 : /************************************************************************/
215 :
216 1 : JDEMDataset::JDEMDataset() : fp(NULL)
217 :
218 : {
219 1 : fp = NULL;
220 1 : }
221 :
222 : /************************************************************************/
223 : /* ~JDEMDataset() */
224 : /************************************************************************/
225 :
226 1 : JDEMDataset::~JDEMDataset()
227 :
228 : {
229 1 : FlushCache();
230 1 : if( fp != NULL )
231 1 : VSIFCloseL( fp );
232 1 : }
233 :
234 : /************************************************************************/
235 : /* GetGeoTransform() */
236 : /************************************************************************/
237 :
238 0 : CPLErr JDEMDataset::GetGeoTransform( double * padfTransform )
239 :
240 : {
241 : double dfLLLat, dfLLLong, dfURLat, dfURLong;
242 :
243 0 : dfLLLat = JDEMGetAngle( (char *) abyHeader + 29 );
244 0 : dfLLLong = JDEMGetAngle( (char *) abyHeader + 36 );
245 0 : dfURLat = JDEMGetAngle( (char *) abyHeader + 43 );
246 0 : dfURLong = JDEMGetAngle( (char *) abyHeader + 50 );
247 :
248 0 : padfTransform[0] = dfLLLong;
249 0 : padfTransform[3] = dfURLat;
250 0 : padfTransform[1] = (dfURLong - dfLLLong) / GetRasterXSize();
251 0 : padfTransform[2] = 0.0;
252 :
253 0 : padfTransform[4] = 0.0;
254 0 : padfTransform[5] = -1 * (dfURLat - dfLLLat) / GetRasterYSize();
255 :
256 :
257 0 : return CE_None;
258 : }
259 :
260 : /************************************************************************/
261 : /* GetProjectionRef() */
262 : /************************************************************************/
263 :
264 0 : const char *JDEMDataset::GetProjectionRef()
265 :
266 : {
267 0 : return( "GEOGCS[\"Tokyo\",DATUM[\"Tokyo\",SPHEROID[\"Bessel 1841\",6377397.155,299.1528128,AUTHORITY[\"EPSG\",7004]],TOWGS84[-148,507,685,0,0,0,0],AUTHORITY[\"EPSG\",6301]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",8901]],UNIT[\"DMSH\",0.0174532925199433,AUTHORITY[\"EPSG\",9108]],AUTHORITY[\"EPSG\",4301]]" );
268 : }
269 :
270 : /************************************************************************/
271 : /* Identify() */
272 : /************************************************************************/
273 :
274 12459 : int JDEMDataset::Identify( GDALOpenInfo * poOpenInfo )
275 :
276 : {
277 : /* -------------------------------------------------------------------- */
278 : /* Confirm that the header has what appears to be dates in the */
279 : /* expected locations. Sadly this is a relatively weak test. */
280 : /* -------------------------------------------------------------------- */
281 12459 : if( poOpenInfo->nHeaderBytes < 50 )
282 10923 : return FALSE;
283 :
284 : /* check if century values seem reasonable */
285 1536 : if( (!EQUALN((char *)poOpenInfo->pabyHeader+11,"19",2)
286 : && !EQUALN((char *)poOpenInfo->pabyHeader+11,"20",2))
287 : || (!EQUALN((char *)poOpenInfo->pabyHeader+15,"19",2)
288 : && !EQUALN((char *)poOpenInfo->pabyHeader+15,"20",2))
289 : || (!EQUALN((char *)poOpenInfo->pabyHeader+19,"19",2)
290 : && !EQUALN((char *)poOpenInfo->pabyHeader+19,"20",2)) )
291 : {
292 1535 : return FALSE;
293 : }
294 :
295 1 : return TRUE;
296 : }
297 :
298 : /************************************************************************/
299 : /* Open() */
300 : /************************************************************************/
301 :
302 3213 : GDALDataset *JDEMDataset::Open( GDALOpenInfo * poOpenInfo )
303 :
304 : {
305 3213 : if (!Identify(poOpenInfo))
306 3212 : return NULL;
307 :
308 : /* -------------------------------------------------------------------- */
309 : /* Confirm the requested access is supported. */
310 : /* -------------------------------------------------------------------- */
311 1 : if( poOpenInfo->eAccess == GA_Update )
312 : {
313 : CPLError( CE_Failure, CPLE_NotSupported,
314 : "The JDEM driver does not support update access to existing"
315 0 : " datasets.\n" );
316 0 : return NULL;
317 : }
318 :
319 : /* -------------------------------------------------------------------- */
320 : /* Create a corresponding GDALDataset. */
321 : /* -------------------------------------------------------------------- */
322 : JDEMDataset *poDS;
323 :
324 1 : poDS = new JDEMDataset();
325 :
326 1 : poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
327 1 : if (poDS->fp == NULL)
328 : {
329 0 : delete poDS;
330 0 : return NULL;
331 : }
332 :
333 : /* -------------------------------------------------------------------- */
334 : /* Read the header. */
335 : /* -------------------------------------------------------------------- */
336 1 : VSIFReadL( poDS->abyHeader, 1, 1012, poDS->fp );
337 :
338 1 : poDS->nRasterXSize = JDEMGetField( (char *) poDS->abyHeader + 23, 3 );
339 1 : poDS->nRasterYSize = JDEMGetField( (char *) poDS->abyHeader + 26, 3 );
340 1 : if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0 )
341 : {
342 : CPLError( CE_Failure, CPLE_AppDefined,
343 : "Invalid dimensions : %d x %d",
344 0 : poDS->nRasterXSize, poDS->nRasterYSize);
345 0 : delete poDS;
346 0 : return NULL;
347 : }
348 :
349 : /* -------------------------------------------------------------------- */
350 : /* Create band information objects. */
351 : /* -------------------------------------------------------------------- */
352 1 : poDS->SetBand( 1, new JDEMRasterBand( poDS, 1 ));
353 :
354 : /* -------------------------------------------------------------------- */
355 : /* Initialize any PAM information. */
356 : /* -------------------------------------------------------------------- */
357 1 : poDS->SetDescription( poOpenInfo->pszFilename );
358 1 : poDS->TryLoadXML();
359 :
360 : /* -------------------------------------------------------------------- */
361 : /* Check for overviews. */
362 : /* -------------------------------------------------------------------- */
363 1 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
364 :
365 1 : return( poDS );
366 : }
367 :
368 : /************************************************************************/
369 : /* GDALRegister_JDEM() */
370 : /************************************************************************/
371 :
372 558 : void GDALRegister_JDEM()
373 :
374 : {
375 : GDALDriver *poDriver;
376 :
377 558 : if( GDALGetDriverByName( "JDEM" ) == NULL )
378 : {
379 537 : poDriver = new GDALDriver();
380 :
381 537 : poDriver->SetDescription( "JDEM" );
382 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
383 537 : "Japanese DEM (.mem)" );
384 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
385 537 : "frmt_various.html#JDEM" );
386 537 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "mem" );
387 537 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
388 :
389 537 : poDriver->pfnOpen = JDEMDataset::Open;
390 537 : poDriver->pfnIdentify = JDEMDataset::Identify;
391 :
392 537 : GetGDALDriverManager()->RegisterDriver( poDriver );
393 : }
394 558 : }
|