1 : /******************************************************************************
2 : * $Id: idadataset.cpp 25311 2012-12-15 12:48:14Z rouault $
3 : *
4 : * Project: IDA Raster Driver
5 : * Purpose: Implemenents IDA driver/dataset/rasterband.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2004, 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 "rawdataset.h"
31 : #include "ogr_spatialref.h"
32 : #include "gdal_rat.h"
33 :
34 : CPL_CVSID("$Id: idadataset.cpp 25311 2012-12-15 12:48:14Z rouault $");
35 :
36 : CPL_C_START
37 : void GDALRegister_IDA(void);
38 : CPL_C_END
39 :
40 : // convert a Turbo Pascal real into a double
41 : static double tp2c(GByte *r);
42 :
43 : // convert a double into a Turbo Pascal real
44 : static void c2tp(double n, GByte *r);
45 :
46 : /************************************************************************/
47 : /* ==================================================================== */
48 : /* IDADataset */
49 : /* ==================================================================== */
50 : /************************************************************************/
51 :
52 : class IDADataset : public RawDataset
53 : {
54 : friend class IDARasterBand;
55 :
56 : int nImageType;
57 : int nProjection;
58 : char szTitle[81];
59 : double dfLatCenter;
60 : double dfLongCenter;
61 : double dfXCenter;
62 : double dfYCenter;
63 : double dfDX;
64 : double dfDY;
65 : double dfParallel1;
66 : double dfParallel2;
67 : int nMissing;
68 : double dfM;
69 : double dfB;
70 :
71 : FILE *fpRaw;
72 :
73 : char *pszProjection;
74 : double adfGeoTransform[6];
75 :
76 : void ProcessGeoref();
77 :
78 : GByte abyHeader[512];
79 : int bHeaderDirty;
80 :
81 : void ReadColorTable();
82 :
83 : public:
84 : IDADataset();
85 : ~IDADataset();
86 :
87 : virtual void FlushCache();
88 : virtual const char *GetProjectionRef(void);
89 : virtual CPLErr SetProjection( const char * );
90 :
91 : virtual CPLErr GetGeoTransform( double * );
92 : virtual CPLErr SetGeoTransform( double * );
93 :
94 : static GDALDataset *Open( GDALOpenInfo * );
95 : static GDALDataset *Create( const char * pszFilename,
96 : int nXSize, int nYSize, int nBands,
97 : GDALDataType eType,
98 : char ** /* papszParmList */ );
99 :
100 : };
101 :
102 : /************************************************************************/
103 : /* ==================================================================== */
104 : /* IDARasterBand */
105 : /* ==================================================================== */
106 : /************************************************************************/
107 :
108 : class IDARasterBand : public RawRasterBand
109 : {
110 : friend class IDADataset;
111 :
112 : GDALRasterAttributeTable *poRAT;
113 : GDALColorTable *poColorTable;
114 :
115 : public:
116 : IDARasterBand( IDADataset *poDSIn, FILE *fpRaw, int nXSize );
117 : virtual ~IDARasterBand();
118 :
119 : virtual const GDALRasterAttributeTable *GetDefaultRAT();
120 : virtual GDALColorInterp GetColorInterpretation();
121 : virtual GDALColorTable *GetColorTable();
122 : virtual double GetOffset( int *pbSuccess = NULL );
123 : virtual CPLErr SetOffset( double dfNewValue );
124 : virtual double GetScale( int *pbSuccess = NULL );
125 : virtual CPLErr SetScale( double dfNewValue );
126 : virtual double GetNoDataValue( int *pbSuccess = NULL );
127 : };
128 :
129 : /************************************************************************/
130 : /* IDARasterBand */
131 : /************************************************************************/
132 :
133 25 : IDARasterBand::IDARasterBand( IDADataset *poDSIn,
134 : FILE *fpRaw, int nXSize )
135 : : RawRasterBand( poDSIn, 1, fpRaw, 512, 1, nXSize,
136 25 : GDT_Byte, FALSE, FALSE )
137 :
138 : {
139 25 : poColorTable = NULL;
140 25 : poRAT = NULL;
141 25 : }
142 :
143 : /************************************************************************/
144 : /* ~IDARasterBand() */
145 : /************************************************************************/
146 :
147 25 : IDARasterBand::~IDARasterBand()
148 :
149 : {
150 25 : delete poColorTable;
151 25 : delete poRAT;
152 25 : }
153 :
154 : /************************************************************************/
155 : /* GetNoDataValue() */
156 : /************************************************************************/
157 :
158 7 : double IDARasterBand::GetNoDataValue( int *pbSuccess )
159 :
160 : {
161 7 : if( pbSuccess != NULL )
162 6 : *pbSuccess = TRUE;
163 7 : return ((IDADataset *) poDS)->nMissing;
164 : }
165 :
166 : /************************************************************************/
167 : /* GetOffset() */
168 : /************************************************************************/
169 :
170 1 : double IDARasterBand::GetOffset( int *pbSuccess )
171 :
172 : {
173 1 : if( pbSuccess != NULL )
174 1 : *pbSuccess = TRUE;
175 1 : return ((IDADataset *) poDS)->dfB;
176 : }
177 :
178 : /************************************************************************/
179 : /* SetOffset() */
180 : /************************************************************************/
181 :
182 0 : CPLErr IDARasterBand::SetOffset( double dfNewValue )
183 :
184 : {
185 0 : IDADataset *poIDS = (IDADataset *) poDS;
186 :
187 0 : if( dfNewValue == poIDS->dfB )
188 0 : return CE_None;
189 :
190 0 : if( poIDS->nImageType != 200 )
191 : {
192 : CPLError( CE_Failure, CPLE_AppDefined,
193 0 : "Setting explicit offset only support for image type 200.");
194 0 : return CE_Failure;
195 : }
196 :
197 0 : poIDS->dfB = dfNewValue;
198 0 : c2tp( dfNewValue, poIDS->abyHeader + 177 );
199 0 : poIDS->bHeaderDirty = TRUE;
200 :
201 0 : return CE_None;
202 : }
203 :
204 : /************************************************************************/
205 : /* GetScale() */
206 : /************************************************************************/
207 :
208 1 : double IDARasterBand::GetScale( int *pbSuccess )
209 :
210 : {
211 1 : if( pbSuccess != NULL )
212 1 : *pbSuccess = TRUE;
213 1 : return ((IDADataset *) poDS)->dfM;
214 : }
215 :
216 : /************************************************************************/
217 : /* SetScale() */
218 : /************************************************************************/
219 :
220 1 : CPLErr IDARasterBand::SetScale( double dfNewValue )
221 :
222 : {
223 1 : IDADataset *poIDS = (IDADataset *) poDS;
224 :
225 1 : if( dfNewValue == poIDS->dfM )
226 0 : return CE_None;
227 :
228 1 : if( poIDS->nImageType != 200 )
229 : {
230 : CPLError( CE_Failure, CPLE_AppDefined,
231 0 : "Setting explicit scale only support for image type 200.");
232 0 : return CE_Failure;
233 : }
234 :
235 1 : poIDS->dfM = dfNewValue;
236 1 : c2tp( dfNewValue, poIDS->abyHeader + 171 );
237 1 : poIDS->bHeaderDirty = TRUE;
238 :
239 1 : return CE_None;
240 : }
241 :
242 : /************************************************************************/
243 : /* GetColorTable() */
244 : /************************************************************************/
245 :
246 1 : GDALColorTable *IDARasterBand::GetColorTable()
247 :
248 : {
249 1 : if( poColorTable )
250 0 : return poColorTable;
251 : else
252 1 : return RawRasterBand::GetColorTable();
253 : }
254 :
255 : /************************************************************************/
256 : /* GetColorInterpretation() */
257 : /************************************************************************/
258 :
259 2 : GDALColorInterp IDARasterBand::GetColorInterpretation()
260 :
261 : {
262 2 : if( poColorTable )
263 0 : return GCI_PaletteIndex;
264 : else
265 2 : return RawRasterBand::GetColorInterpretation();
266 : }
267 :
268 : /************************************************************************/
269 : /* GetDefaultRAT() */
270 : /************************************************************************/
271 :
272 0 : const GDALRasterAttributeTable *IDARasterBand::GetDefaultRAT()
273 :
274 : {
275 0 : if( poRAT )
276 0 : return poRAT;
277 : else
278 0 : return RawRasterBand::GetDefaultRAT();
279 : }
280 :
281 : /************************************************************************/
282 : /* ==================================================================== */
283 : /* IDADataset */
284 : /* ==================================================================== */
285 : /************************************************************************/
286 :
287 : /************************************************************************/
288 : /* IDADataset() */
289 : /************************************************************************/
290 :
291 25 : IDADataset::IDADataset()
292 : {
293 25 : fpRaw = NULL;
294 25 : pszProjection = NULL;
295 :
296 25 : adfGeoTransform[0] = 0.0;
297 25 : adfGeoTransform[1] = 1.0;
298 25 : adfGeoTransform[2] = 0.0;
299 25 : adfGeoTransform[3] = 0.0;
300 25 : adfGeoTransform[4] = 0.0;
301 25 : adfGeoTransform[5] = 1.0;
302 :
303 25 : bHeaderDirty = FALSE;
304 25 : }
305 :
306 : /************************************************************************/
307 : /* ~IDADataset() */
308 : /************************************************************************/
309 :
310 25 : IDADataset::~IDADataset()
311 :
312 : {
313 25 : FlushCache();
314 :
315 25 : if( fpRaw != NULL )
316 25 : VSIFClose( fpRaw );
317 25 : CPLFree( pszProjection );
318 25 : }
319 :
320 : /************************************************************************/
321 : /* ProcessGeoref() */
322 : /************************************************************************/
323 :
324 25 : void IDADataset::ProcessGeoref()
325 :
326 : {
327 25 : OGRSpatialReference oSRS;
328 :
329 25 : if( nProjection == 3 )
330 : {
331 10 : oSRS.SetWellKnownGeogCS( "WGS84" );
332 : }
333 15 : else if( nProjection == 4 )
334 : {
335 : oSRS.SetLCC( dfParallel1, dfParallel2,
336 : dfLatCenter, dfLongCenter,
337 2 : 0.0, 0.0 );
338 : oSRS.SetGeogCS( "Clarke 1866", "Clarke 1866", "Clarke 1866",
339 2 : 6378206.4, 293.97869821389662 );
340 : }
341 13 : else if( nProjection == 6 )
342 : {
343 2 : oSRS.SetLAEA( dfLatCenter, dfLongCenter, 0.0, 0.0 );
344 : oSRS.SetGeogCS( "Sphere", "Sphere", "Sphere",
345 2 : 6370997.0, 0.0 );
346 : }
347 11 : else if( nProjection == 8 )
348 : {
349 : oSRS.SetACEA( dfParallel1, dfParallel2,
350 : dfLatCenter, dfLongCenter,
351 2 : 0.0, 0.0 );
352 : oSRS.SetGeogCS( "Clarke 1866", "Clarke 1866", "Clarke 1866",
353 2 : 6378206.4, 293.97869821389662 );
354 : }
355 9 : else if( nProjection == 9 )
356 : {
357 2 : oSRS.SetGH( dfLongCenter, 0.0, 0.0 );
358 : oSRS.SetGeogCS( "Sphere", "Sphere", "Sphere",
359 2 : 6370997.0, 0.0 );
360 : }
361 :
362 25 : if( oSRS.GetRoot() != NULL )
363 : {
364 18 : CPLFree( pszProjection );
365 18 : pszProjection = NULL;
366 :
367 18 : oSRS.exportToWkt( &pszProjection );
368 : }
369 :
370 25 : adfGeoTransform[0] = 0 - dfDX * dfXCenter;
371 25 : adfGeoTransform[1] = dfDX;
372 25 : adfGeoTransform[2] = 0.0;
373 25 : adfGeoTransform[3] = dfDY * dfYCenter;
374 25 : adfGeoTransform[4] = 0.0;
375 25 : adfGeoTransform[5] = -dfDY;
376 :
377 25 : if( nProjection == 3 )
378 : {
379 10 : adfGeoTransform[0] += dfLongCenter;
380 10 : adfGeoTransform[3] += dfLatCenter;
381 25 : }
382 25 : }
383 :
384 : /************************************************************************/
385 : /* FlushCache() */
386 : /************************************************************************/
387 :
388 25 : void IDADataset::FlushCache()
389 :
390 : {
391 25 : RawDataset::FlushCache();
392 :
393 25 : if( bHeaderDirty )
394 : {
395 7 : VSIFSeek( fpRaw, 0, SEEK_SET );
396 7 : VSIFWrite( abyHeader, 512, 1, fpRaw );
397 7 : bHeaderDirty = FALSE;
398 : }
399 25 : }
400 :
401 : /************************************************************************/
402 : /* GetGeoTransform() */
403 : /************************************************************************/
404 :
405 4 : CPLErr IDADataset::GetGeoTransform( double *padfGeoTransform )
406 :
407 : {
408 4 : memcpy( padfGeoTransform, adfGeoTransform, sizeof(double) * 6 );
409 4 : return CE_None;
410 : }
411 :
412 : /************************************************************************/
413 : /* SetGeoTransform() */
414 : /************************************************************************/
415 :
416 7 : CPLErr IDADataset::SetGeoTransform( double *padfGeoTransform )
417 :
418 : {
419 7 : if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0.0 )
420 0 : return GDALPamDataset::SetGeoTransform( padfGeoTransform );
421 :
422 7 : memcpy( adfGeoTransform, padfGeoTransform, sizeof(double) * 6 );
423 7 : bHeaderDirty = TRUE;
424 :
425 7 : dfDX = adfGeoTransform[1];
426 7 : dfDY = -adfGeoTransform[5];
427 7 : dfXCenter = -adfGeoTransform[0] / dfDX;
428 7 : dfYCenter = adfGeoTransform[3] / dfDY;
429 :
430 7 : c2tp( dfDX, abyHeader + 144 );
431 7 : c2tp( dfDY, abyHeader + 150 );
432 7 : c2tp( dfXCenter, abyHeader + 132 );
433 7 : c2tp( dfYCenter, abyHeader + 138 );
434 :
435 7 : return CE_None;
436 : }
437 :
438 : /************************************************************************/
439 : /* GetProjectionRef() */
440 : /************************************************************************/
441 :
442 10 : const char *IDADataset::GetProjectionRef()
443 :
444 : {
445 10 : if( pszProjection )
446 10 : return pszProjection;
447 : else
448 0 : return "";
449 : }
450 :
451 : /************************************************************************/
452 : /* SetProjection() */
453 : /************************************************************************/
454 :
455 7 : CPLErr IDADataset::SetProjection( const char *pszWKTIn )
456 :
457 : {
458 7 : OGRSpatialReference oSRS;
459 :
460 7 : oSRS.importFromWkt( (char **) &pszWKTIn );
461 :
462 7 : if( !oSRS.IsGeographic() && !oSRS.IsProjected() )
463 0 : GDALPamDataset::SetProjection( pszWKTIn );
464 :
465 : /* -------------------------------------------------------------------- */
466 : /* Clear projection parameters. */
467 : /* -------------------------------------------------------------------- */
468 7 : dfParallel1 = 0.0;
469 7 : dfParallel2 = 0.0;
470 7 : dfLatCenter = 0.0;
471 7 : dfLongCenter = 0.0;
472 :
473 : /* -------------------------------------------------------------------- */
474 : /* Geographic. */
475 : /* -------------------------------------------------------------------- */
476 7 : if( oSRS.IsGeographic() )
477 : {
478 : // If no change, just return.
479 3 : if( nProjection == 3 )
480 0 : return CE_None;
481 :
482 3 : nProjection = 3;
483 : }
484 :
485 : /* -------------------------------------------------------------------- */
486 : /* Verify we don't have a false easting or northing as these */
487 : /* will be ignored for the projections we do support. */
488 : /* -------------------------------------------------------------------- */
489 7 : if( oSRS.GetProjParm( SRS_PP_FALSE_EASTING ) != 0.0
490 : || oSRS.GetProjParm( SRS_PP_FALSE_NORTHING ) != 0.0 )
491 : {
492 : CPLError( CE_Failure, CPLE_AppDefined,
493 : "Attempt to set a projection on an IDA file with a non-zero\n"
494 0 : "false easting and/or northing. This is not supported." );
495 0 : return CE_Failure;
496 : }
497 :
498 : /* -------------------------------------------------------------------- */
499 : /* Lambert Conformal Conic. Note that we don't support false */
500 : /* eastings or nothings. */
501 : /* -------------------------------------------------------------------- */
502 7 : const char *pszProjection = oSRS.GetAttrValue( "PROJECTION" );
503 :
504 7 : if( pszProjection == NULL )
505 : {
506 : /* do nothing - presumably geographic */;
507 : }
508 4 : else if( EQUAL(pszProjection,SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP) )
509 : {
510 1 : nProjection = 4;
511 1 : dfParallel1 = oSRS.GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0);
512 1 : dfParallel2 = oSRS.GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0);
513 1 : dfLatCenter = oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
514 1 : dfLongCenter = oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
515 : }
516 3 : else if( EQUAL(pszProjection,SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA) )
517 : {
518 1 : nProjection = 6;
519 1 : dfLatCenter = oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
520 1 : dfLongCenter = oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
521 : }
522 2 : else if( EQUAL(pszProjection,SRS_PT_ALBERS_CONIC_EQUAL_AREA) )
523 : {
524 1 : nProjection = 8;
525 1 : dfParallel1 = oSRS.GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0);
526 1 : dfParallel2 = oSRS.GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0);
527 1 : dfLatCenter = oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
528 1 : dfLongCenter = oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
529 : }
530 1 : else if( EQUAL(pszProjection,SRS_PT_GOODE_HOMOLOSINE) )
531 : {
532 1 : nProjection = 9;
533 1 : dfLongCenter = oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
534 : }
535 : else
536 : {
537 0 : return GDALPamDataset::SetProjection( pszWKTIn );
538 : }
539 :
540 : /* -------------------------------------------------------------------- */
541 : /* Update header and mark it as dirty. */
542 : /* -------------------------------------------------------------------- */
543 7 : bHeaderDirty = TRUE;
544 :
545 7 : abyHeader[23] = (GByte) nProjection;
546 7 : c2tp( dfLatCenter, abyHeader + 120 );
547 7 : c2tp( dfLongCenter, abyHeader + 126 );
548 7 : c2tp( dfParallel1, abyHeader + 156 );
549 7 : c2tp( dfParallel2, abyHeader + 162 );
550 :
551 7 : return CE_None;
552 : }
553 :
554 : /************************************************************************/
555 : /* ReadColorTable() */
556 : /************************************************************************/
557 :
558 25 : void IDADataset::ReadColorTable()
559 :
560 : {
561 : /* -------------------------------------------------------------------- */
562 : /* Decide what .clr file to look for and try to open. */
563 : /* -------------------------------------------------------------------- */
564 25 : CPLString osCLRFilename;
565 :
566 25 : osCLRFilename = CPLGetConfigOption( "IDA_COLOR_FILE", "" );
567 25 : if( strlen(osCLRFilename) == 0 )
568 25 : osCLRFilename = CPLResetExtension(GetDescription(), "clr" );
569 :
570 :
571 25 : FILE *fp = VSIFOpen( osCLRFilename, "r" );
572 25 : if( fp == NULL )
573 : {
574 25 : osCLRFilename = CPLResetExtension(osCLRFilename, "CLR" );
575 25 : fp = VSIFOpen( osCLRFilename, "r" );
576 : }
577 :
578 25 : if( fp == NULL )
579 : return;
580 :
581 : /* -------------------------------------------------------------------- */
582 : /* Skip first line, with the column titles. */
583 : /* -------------------------------------------------------------------- */
584 0 : CPLReadLine( fp );
585 :
586 : /* -------------------------------------------------------------------- */
587 : /* Create a RAT to populate. */
588 : /* -------------------------------------------------------------------- */
589 0 : GDALRasterAttributeTable *poRAT = new GDALRasterAttributeTable();
590 :
591 0 : poRAT->CreateColumn( "FROM", GFT_Integer, GFU_Min );
592 0 : poRAT->CreateColumn( "TO", GFT_Integer, GFU_Max );
593 0 : poRAT->CreateColumn( "RED", GFT_Integer, GFU_Red );
594 0 : poRAT->CreateColumn( "GREEN", GFT_Integer, GFU_Green );
595 0 : poRAT->CreateColumn( "BLUE", GFT_Integer, GFU_Blue );
596 0 : poRAT->CreateColumn( "LEGEND", GFT_String, GFU_Name );
597 :
598 : /* -------------------------------------------------------------------- */
599 : /* Apply lines. */
600 : /* -------------------------------------------------------------------- */
601 0 : const char *pszLine = CPLReadLine( fp );
602 0 : int iRow = 0;
603 :
604 0 : while( pszLine != NULL )
605 : {
606 : char **papszTokens =
607 0 : CSLTokenizeStringComplex( pszLine, " \t", FALSE, FALSE );
608 :
609 0 : if( CSLCount( papszTokens ) >= 5 )
610 : {
611 0 : poRAT->SetValue( iRow, 0, atoi(papszTokens[0]) );
612 0 : poRAT->SetValue( iRow, 1, atoi(papszTokens[1]) );
613 0 : poRAT->SetValue( iRow, 2, atoi(papszTokens[2]) );
614 0 : poRAT->SetValue( iRow, 3, atoi(papszTokens[3]) );
615 0 : poRAT->SetValue( iRow, 4, atoi(papszTokens[4]) );
616 :
617 : // find name, first nonspace after 5th token.
618 0 : const char *pszName = pszLine;
619 :
620 : // skip from
621 0 : while( *pszName == ' ' || *pszName == '\t' )
622 0 : pszName++;
623 0 : while( *pszName != ' ' && *pszName != '\t' && *pszName != '\0' )
624 0 : pszName++;
625 :
626 : // skip to
627 0 : while( *pszName == ' ' || *pszName == '\t' )
628 0 : pszName++;
629 0 : while( *pszName != ' ' && *pszName != '\t' && *pszName != '\0' )
630 0 : pszName++;
631 :
632 : // skip red
633 0 : while( *pszName == ' ' || *pszName == '\t' )
634 0 : pszName++;
635 0 : while( *pszName != ' ' && *pszName != '\t' && *pszName != '\0' )
636 0 : pszName++;
637 :
638 : // skip green
639 0 : while( *pszName == ' ' || *pszName == '\t' )
640 0 : pszName++;
641 0 : while( *pszName != ' ' && *pszName != '\t' && *pszName != '\0' )
642 0 : pszName++;
643 :
644 : // skip blue
645 0 : while( *pszName == ' ' || *pszName == '\t' )
646 0 : pszName++;
647 0 : while( *pszName != ' ' && *pszName != '\t' && *pszName != '\0' )
648 0 : pszName++;
649 :
650 : // skip pre-name white space
651 0 : while( *pszName == ' ' || *pszName == '\t' )
652 0 : pszName++;
653 :
654 0 : poRAT->SetValue( iRow, 5, pszName );
655 :
656 0 : iRow++;
657 : }
658 :
659 0 : CSLDestroy( papszTokens );
660 0 : pszLine = CPLReadLine( fp );
661 : }
662 :
663 0 : VSIFClose( fp );
664 :
665 : /* -------------------------------------------------------------------- */
666 : /* Attach RAT to band. */
667 : /* -------------------------------------------------------------------- */
668 0 : ((IDARasterBand *) GetRasterBand( 1 ))->poRAT = poRAT;
669 :
670 : /* -------------------------------------------------------------------- */
671 : /* Build a conventional color table from this. */
672 : /* -------------------------------------------------------------------- */
673 : ((IDARasterBand *) GetRasterBand( 1 ))->poColorTable =
674 0 : poRAT->TranslateToColorTable();
675 : }
676 :
677 : /************************************************************************/
678 : /* Open() */
679 : /************************************************************************/
680 :
681 11981 : GDALDataset *IDADataset::Open( GDALOpenInfo * poOpenInfo )
682 :
683 : {
684 : /* -------------------------------------------------------------------- */
685 : /* Is this an IDA file? */
686 : /* -------------------------------------------------------------------- */
687 : int nXSize, nYSize;
688 : GIntBig nExpectedFileSize, nActualFileSize;
689 :
690 11981 : if( poOpenInfo->fp == NULL )
691 11308 : return NULL;
692 :
693 673 : if( poOpenInfo->nHeaderBytes < 512 )
694 180 : return NULL;
695 :
696 : // projection legal?
697 493 : if( poOpenInfo->pabyHeader[23] > 10 )
698 388 : return NULL;
699 :
700 : // imagetype legal?
701 278 : if( (poOpenInfo->pabyHeader[22] > 14
702 34 : && poOpenInfo->pabyHeader[22] < 100)
703 105 : || (poOpenInfo->pabyHeader[22] > 114
704 34 : && poOpenInfo->pabyHeader[22] != 200 ) )
705 8 : return NULL;
706 :
707 97 : nXSize = poOpenInfo->pabyHeader[30] + poOpenInfo->pabyHeader[31] * 256;
708 97 : nYSize = poOpenInfo->pabyHeader[32] + poOpenInfo->pabyHeader[33] * 256;
709 :
710 97 : if( nXSize == 0 || nYSize == 0 )
711 70 : return NULL;
712 :
713 : // The file just be exactly the image size + header size in length.
714 27 : nExpectedFileSize = nXSize * nYSize + 512;
715 :
716 27 : VSIFSeek( poOpenInfo->fp, 0, SEEK_END );
717 27 : nActualFileSize = VSIFTell( poOpenInfo->fp );
718 27 : VSIRewind( poOpenInfo->fp );
719 :
720 27 : if( nActualFileSize != nExpectedFileSize )
721 2 : return NULL;
722 :
723 : /* -------------------------------------------------------------------- */
724 : /* Create the dataset. */
725 : /* -------------------------------------------------------------------- */
726 25 : IDADataset *poDS = new IDADataset();
727 :
728 25 : memcpy( poDS->abyHeader, poOpenInfo->pabyHeader, 512 );
729 :
730 : /* -------------------------------------------------------------------- */
731 : /* Parse various values out of the header. */
732 : /* -------------------------------------------------------------------- */
733 25 : poDS->nImageType = poOpenInfo->pabyHeader[22];
734 25 : poDS->nProjection = poOpenInfo->pabyHeader[23];
735 :
736 25 : poDS->nRasterYSize = poOpenInfo->pabyHeader[30]
737 25 : + poOpenInfo->pabyHeader[31] * 256;
738 25 : poDS->nRasterXSize = poOpenInfo->pabyHeader[32]
739 25 : + poOpenInfo->pabyHeader[33] * 256;
740 :
741 25 : strncpy( poDS->szTitle, (const char *) poOpenInfo->pabyHeader+38, 80 );
742 25 : poDS->szTitle[80] = '\0';
743 :
744 25 : int nLastTitleChar = strlen(poDS->szTitle)-1;
745 1527 : while( nLastTitleChar > -1
746 371 : && (poDS->szTitle[nLastTitleChar] == 10
747 371 : || poDS->szTitle[nLastTitleChar] == 13
748 371 : || poDS->szTitle[nLastTitleChar] == ' ') )
749 364 : poDS->szTitle[nLastTitleChar--] = '\0';
750 :
751 25 : poDS->dfLatCenter = tp2c( poOpenInfo->pabyHeader + 120 );
752 25 : poDS->dfLongCenter = tp2c( poOpenInfo->pabyHeader + 126 );
753 25 : poDS->dfXCenter = tp2c( poOpenInfo->pabyHeader + 132 );
754 25 : poDS->dfYCenter = tp2c( poOpenInfo->pabyHeader + 138 );
755 25 : poDS->dfDX = tp2c( poOpenInfo->pabyHeader + 144 );
756 25 : poDS->dfDY = tp2c( poOpenInfo->pabyHeader + 150 );
757 25 : poDS->dfParallel1 = tp2c( poOpenInfo->pabyHeader + 156 );
758 25 : poDS->dfParallel2 = tp2c( poOpenInfo->pabyHeader + 162 );
759 :
760 25 : poDS->ProcessGeoref();
761 :
762 25 : poDS->SetMetadataItem( "TITLE", poDS->szTitle );
763 :
764 : /* -------------------------------------------------------------------- */
765 : /* Handle various image types. */
766 : /* -------------------------------------------------------------------- */
767 :
768 : /*
769 : GENERIC = 0
770 : FEW S NDVI = 1
771 : EROS NDVI = 6
772 : ARTEMIS CUTOFF = 10
773 : ARTEMIS RECODE = 11
774 : ARTEMIS NDVI = 12
775 : ARTEMIS FEWS = 13
776 : ARTEMIS NEWNASA = 14
777 : GENERIC DIFF = 100
778 : FEW S NDVI DIFF = 101
779 : EROS NDVI DIFF = 106
780 : ARTEMIS CUTOFF DIFF = 110
781 : ARTEMIS RECODE DIFF = 111
782 : ARTEMIS NDVI DIFF = 112
783 : ARTEMIS FEWS DIFF = 113
784 : ARTEMIS NEWNASA DIFF = 114
785 : CALCULATED =200
786 : */
787 :
788 25 : poDS->nMissing = 0;
789 :
790 25 : switch( poDS->nImageType )
791 : {
792 : case 1:
793 0 : poDS->SetMetadataItem( "IMAGETYPE", "1, FEWS NDVI" );
794 0 : poDS->dfM = 1/256.0;
795 0 : poDS->dfB = -82/256.0;
796 0 : break;
797 :
798 : case 6:
799 0 : poDS->SetMetadataItem( "IMAGETYPE", "6, EROS NDVI" );
800 0 : poDS->dfM = 1/100.0;
801 0 : poDS->dfB = -100/100.0;
802 0 : break;
803 :
804 : case 10:
805 0 : poDS->SetMetadataItem( "IMAGETYPE", "10, ARTEMIS CUTOFF" );
806 0 : poDS->dfM = 1.0;
807 0 : poDS->dfB = 0.0;
808 0 : poDS->nMissing = 254;
809 0 : break;
810 :
811 : case 11:
812 0 : poDS->SetMetadataItem( "IMAGETYPE", "11, ARTEMIS RECODE" );
813 0 : poDS->dfM = 4.0;
814 0 : poDS->dfB = 0.0;
815 0 : poDS->nMissing = 254;
816 0 : break;
817 :
818 : case 12: /* ANDVI */
819 0 : poDS->SetMetadataItem( "IMAGETYPE", "12, ARTEMIS NDVI" );
820 0 : poDS->dfM = 4/500.0;
821 0 : poDS->dfB = -3/500.0 - 1.0;
822 0 : poDS->nMissing = 254;
823 0 : break;
824 :
825 : case 13: /* AFEWS */
826 0 : poDS->SetMetadataItem( "IMAGETYPE", "13, ARTEMIS FEWS" );
827 0 : poDS->dfM = 1/256.0;
828 0 : poDS->dfB = -82/256.0;
829 0 : poDS->nMissing = 254;
830 0 : break;
831 :
832 : case 14: /* NEWNASA */
833 0 : poDS->SetMetadataItem( "IMAGETYPE", "13, ARTEMIS NEWNASA" );
834 0 : poDS->dfM = 0.75/250.0;
835 0 : poDS->dfB = 0.0;
836 0 : poDS->nMissing = 254;
837 0 : break;
838 :
839 : case 101: /* NDVI_DIFF (FEW S) */
840 0 : poDS->dfM = 1/128.0;
841 0 : poDS->dfB = -1.0;
842 0 : poDS->nMissing = 0;
843 0 : break;
844 :
845 : case 106: /* EROS_DIFF */
846 0 : poDS->dfM = 1/50.0;
847 0 : poDS->dfB = -128/50.0;
848 0 : poDS->nMissing = 0;
849 0 : break;
850 :
851 : case 110: /* CUTOFF_DIFF */
852 0 : poDS->dfM = 2.0;
853 0 : poDS->dfB = -128*2;
854 0 : poDS->nMissing = 254;
855 0 : break;
856 :
857 : case 111: /* RECODE_DIFF */
858 0 : poDS->dfM = 8;
859 0 : poDS->dfB = -128*8;
860 0 : poDS->nMissing = 254;
861 0 : break;
862 :
863 : case 112: /* ANDVI_DIFF */
864 0 : poDS->dfM = 8/1000.0;
865 0 : poDS->dfB = (-128*8)/1000.0;
866 0 : poDS->nMissing = 254;
867 0 : break;
868 :
869 : case 113: /* AFEWS_DIFF */
870 0 : poDS->dfM = 1/128.0;
871 0 : poDS->dfB = -1;
872 0 : poDS->nMissing = 254;
873 0 : break;
874 :
875 : case 114: /* NEWNASA_DIFF */
876 0 : poDS->dfM = 0.75/125.0;
877 0 : poDS->dfB = -128*poDS->dfM;
878 0 : poDS->nMissing = 254;
879 0 : break;
880 :
881 : case 200:
882 : /* we use the values from the header */
883 25 : poDS->dfM = tp2c( poOpenInfo->pabyHeader + 171 );
884 25 : poDS->dfB = tp2c( poOpenInfo->pabyHeader + 177 );
885 25 : poDS->nMissing = poOpenInfo->pabyHeader[170];
886 25 : break;
887 :
888 : default:
889 0 : poDS->dfM = 1.0;
890 0 : poDS->dfB = 0.0;
891 : break;
892 : }
893 :
894 : /* -------------------------------------------------------------------- */
895 : /* Create the band. */
896 : /* -------------------------------------------------------------------- */
897 25 : if( poOpenInfo->eAccess == GA_ReadOnly )
898 : {
899 18 : poDS->fpRaw = poOpenInfo->fp;
900 18 : poOpenInfo->fp = NULL;
901 : }
902 : else
903 : {
904 7 : poDS->fpRaw = VSIFOpen( poOpenInfo->pszFilename, "rb+" );
905 7 : poDS->eAccess = GA_Update;
906 7 : if( poDS->fpRaw == NULL )
907 : {
908 : CPLError( CE_Failure, CPLE_OpenFailed,
909 : "Failed to open %s for write access.",
910 0 : poOpenInfo->pszFilename );
911 0 : return NULL;
912 : }
913 : }
914 :
915 : poDS->SetBand( 1, new IDARasterBand( poDS, poDS->fpRaw,
916 25 : poDS->nRasterXSize ) );
917 :
918 : /* -------------------------------------------------------------------- */
919 : /* Check for a color table. */
920 : /* -------------------------------------------------------------------- */
921 25 : poDS->SetDescription( poOpenInfo->pszFilename );
922 25 : poDS->ReadColorTable();
923 :
924 : /* -------------------------------------------------------------------- */
925 : /* Initialize any PAM information. */
926 : /* -------------------------------------------------------------------- */
927 25 : poDS->TryLoadXML();
928 :
929 : /* -------------------------------------------------------------------- */
930 : /* Check for overviews. */
931 : /* -------------------------------------------------------------------- */
932 25 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
933 :
934 25 : return( poDS );
935 : }
936 :
937 : /************************************************************************/
938 : /* tp2c() */
939 : /* */
940 : /* convert a Turbo Pascal real into a double */
941 : /************************************************************************/
942 :
943 250 : static double tp2c(GByte *r)
944 : {
945 : double mant;
946 : int sign, exp, i;
947 :
948 : // handle 0 case
949 250 : if (r[0] == 0)
950 105 : return 0.0;
951 :
952 : // extract sign: bit 7 of byte 5
953 145 : sign = r[5] & 0x80 ? -1 : 1;
954 :
955 : // extract mantissa from first bit of byte 1 to bit 7 of byte 5
956 145 : mant = 0;
957 725 : for (i = 1; i < 5; i++)
958 580 : mant = (r[i] + mant) / 256;
959 145 : mant = (mant + (r[5] & 0x7F)) / 128 + 1;
960 :
961 : // extract exponent
962 145 : exp = r[0] - 129;
963 :
964 : // compute the damned number
965 145 : return sign * ldexp(mant, exp);
966 : }
967 :
968 : /************************************************************************/
969 : /* c2tp() */
970 : /* */
971 : /* convert a double into a Turbo Pascal real */
972 : /************************************************************************/
973 :
974 85 : static void c2tp(double x, GByte *r)
975 : {
976 : double mant, temp;
977 : int negative, exp, i;
978 :
979 : // handle 0 case
980 85 : if (x == 0.0)
981 : {
982 25 : for (i = 0; i < 6; r[i++] = 0);
983 25 : return;
984 : }
985 :
986 : // compute mantissa, sign and exponent
987 60 : mant = frexp(x, &exp) * 2 - 1;
988 60 : exp--;
989 60 : negative = 0;
990 60 : if (mant < 0)
991 : {
992 9 : mant = -mant;
993 9 : negative = 1;
994 : }
995 : // stuff mantissa into Turbo Pascal real
996 60 : mant = modf(mant * 128, &temp);
997 60 : r[5] = (unsigned char) temp;
998 300 : for (i = 4; i >= 1; i--)
999 : {
1000 240 : mant = modf(mant * 256, &temp);
1001 240 : r[i] = (unsigned char) temp;
1002 : }
1003 : // add sign
1004 60 : if (negative)
1005 9 : r[5] |= 0x80;
1006 :
1007 : // put exponent
1008 60 : r[0] = (GByte) (exp + 129);
1009 : }
1010 :
1011 : /************************************************************************/
1012 : /* Create() */
1013 : /************************************************************************/
1014 :
1015 49 : GDALDataset *IDADataset::Create( const char * pszFilename,
1016 : int nXSize, int nYSize, int nBands,
1017 : GDALDataType eType,
1018 : char ** /* papszParmList */ )
1019 :
1020 : {
1021 : /* -------------------------------------------------------------------- */
1022 : /* Verify input options. */
1023 : /* -------------------------------------------------------------------- */
1024 49 : if( eType != GDT_Byte || nBands != 1 )
1025 : {
1026 : CPLError( CE_Failure, CPLE_AppDefined,
1027 39 : "Only 1 band, Byte datasets supported for IDA format." );
1028 :
1029 39 : return NULL;
1030 : }
1031 :
1032 : /* -------------------------------------------------------------------- */
1033 : /* Try to create the file. */
1034 : /* -------------------------------------------------------------------- */
1035 : FILE *fp;
1036 :
1037 10 : fp = VSIFOpen( pszFilename, "wb" );
1038 :
1039 10 : if( fp == NULL )
1040 : {
1041 : CPLError( CE_Failure, CPLE_OpenFailed,
1042 : "Attempt to create file `%s' failed.\n",
1043 3 : pszFilename );
1044 3 : return NULL;
1045 : }
1046 :
1047 : /* -------------------------------------------------------------------- */
1048 : /* Prepare formatted header. */
1049 : /* -------------------------------------------------------------------- */
1050 : GByte abyHeader[512];
1051 :
1052 7 : memset( abyHeader, 0, sizeof(abyHeader) );
1053 :
1054 7 : abyHeader[22] = 200; /* image type - CALCULATED */
1055 7 : abyHeader[23] = 0; /* projection - NONE */
1056 7 : abyHeader[30] = nYSize % 256;
1057 7 : abyHeader[31] = (GByte) (nYSize / 256);
1058 7 : abyHeader[32] = nXSize % 256;
1059 7 : abyHeader[33] = (GByte) (nXSize / 256);
1060 :
1061 7 : abyHeader[170] = 255; /* missing = 255 */
1062 7 : c2tp( 1.0, abyHeader + 171 ); /* slope = 1.0 */
1063 7 : c2tp( 0.0, abyHeader + 177 ); /* offset = 0 */
1064 7 : abyHeader[168] = 0; // lower limit
1065 7 : abyHeader[169] = 254; // upper limit
1066 :
1067 : // pixel size = 1.0
1068 7 : c2tp( 1.0, abyHeader + 144 );
1069 7 : c2tp( 1.0, abyHeader + 150 );
1070 :
1071 7 : if( VSIFWrite( abyHeader, 1, 512, fp ) != 512 )
1072 : {
1073 : CPLError( CE_Failure, CPLE_AppDefined,
1074 : "IO error writing %s.\n%s",
1075 0 : pszFilename, VSIStrerror( errno ) );
1076 0 : VSIFClose( fp );
1077 0 : return NULL;
1078 : }
1079 :
1080 : /* -------------------------------------------------------------------- */
1081 : /* Now we need to extend the file to just the right number of */
1082 : /* bytes for the data we have to ensure it will open again */
1083 : /* properly. */
1084 : /* -------------------------------------------------------------------- */
1085 7 : if( VSIFSeek( fp, nXSize * nYSize - 1, SEEK_CUR ) != 0
1086 : || VSIFWrite( abyHeader, 1, 1, fp ) != 1 )
1087 : {
1088 : CPLError( CE_Failure, CPLE_AppDefined,
1089 : "IO error writing %s.\n%s",
1090 0 : pszFilename, VSIStrerror( errno ) );
1091 0 : VSIFClose( fp );
1092 0 : return NULL;
1093 : }
1094 :
1095 7 : VSIFClose( fp );
1096 :
1097 7 : return (GDALDataset *) GDALOpen( pszFilename, GA_Update );
1098 : }
1099 :
1100 : /************************************************************************/
1101 : /* GDALRegister_IDA() */
1102 : /************************************************************************/
1103 :
1104 582 : void GDALRegister_IDA()
1105 :
1106 : {
1107 : GDALDriver *poDriver;
1108 :
1109 582 : if( GDALGetDriverByName( "IDA" ) == NULL )
1110 : {
1111 561 : poDriver = new GDALDriver();
1112 :
1113 561 : poDriver->SetDescription( "IDA" );
1114 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1115 561 : "Image Data and Analysis" );
1116 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1117 561 : "frmt_various.html#IDA" );
1118 561 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte" );
1119 :
1120 561 : poDriver->pfnOpen = IDADataset::Open;
1121 561 : poDriver->pfnCreate = IDADataset::Create;
1122 :
1123 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
1124 : }
1125 582 : }
1126 :
|