1 : /******************************************************************************
2 : * $Id: grcdataset.cpp 23059 2011-09-05 17:30:20Z rouault $
3 : *
4 : * Project: GRC Reader
5 : * Purpose: GDAL driver for Northwood Classified Format
6 : * Author: Perry Casson
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2007, Waypoint Information Technology
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 : #include "northwood.h"
32 :
33 : #ifdef OGR_ENABLED
34 : #ifdef MSVC
35 : #include "..\..\ogr\ogrsf_frmts\mitab\mitab.h"
36 : #else
37 : #include "../../ogr/ogrsf_frmts/mitab/mitab.h"
38 : #endif
39 : #endif
40 :
41 :
42 : CPL_C_START void GDALRegister_NWT_GRC( void );
43 : CPL_C_END
44 : /************************************************************************/
45 : /* ==================================================================== */
46 : /* NWT_GRCDataset */
47 : /* ==================================================================== */
48 : /************************************************************************/
49 : class NWT_GRCRasterBand;
50 :
51 : class NWT_GRCDataset : public GDALPamDataset
52 : {
53 : friend class NWT_GRCRasterBand;
54 :
55 : private:
56 : VSILFILE * fp;
57 : GByte abyHeader[1024];
58 : NWT_GRID *pGrd;
59 : char **papszCategories;
60 : char *pszProjection;
61 :
62 : protected:
63 : GDALColorTable * poColorTable;
64 :
65 : public:
66 : NWT_GRCDataset();
67 : ~NWT_GRCDataset();
68 :
69 : static GDALDataset *Open( GDALOpenInfo * );
70 : static int Identify( GDALOpenInfo * poOpenInfo );
71 :
72 : CPLErr GetGeoTransform( double *padfTransform );
73 : const char *GetProjectionRef();
74 : };
75 :
76 : /************************************************************************/
77 : /* ==================================================================== */
78 : /* NWT_GRCRasterBand */
79 : /* ==================================================================== */
80 : /************************************************************************/
81 :
82 : class NWT_GRCRasterBand : public GDALPamRasterBand
83 : {
84 : friend class NWT_GRCDataset;
85 : int bHaveOffsetScale;
86 : double dfOffset;
87 : double dfScale;
88 :
89 : public:
90 :
91 : NWT_GRCRasterBand( NWT_GRCDataset *, int );
92 : virtual ~NWT_GRCRasterBand();
93 :
94 : virtual CPLErr IReadBlock( int, int, void * );
95 : virtual double GetNoDataValue( int *pbSuccess );
96 :
97 : virtual double GetOffset( int *pbSuccess = NULL );
98 : virtual CPLErr SetOffset( double dfNewValue );
99 : virtual double GetScale( int *pbSuccess = NULL );
100 : virtual CPLErr SetScale( double dfNewValue );
101 :
102 : virtual GDALColorInterp GetColorInterpretation();
103 : virtual char **GetCategoryNames();
104 : virtual GDALColorTable *GetColorTable();
105 : };
106 :
107 :
108 : /************************************************************************/
109 : /* NWT_GRCRasterBand() */
110 : /************************************************************************/
111 :
112 2 : NWT_GRCRasterBand::NWT_GRCRasterBand( NWT_GRCDataset * poDS, int nBand )
113 : {
114 2 : this->poDS = poDS;
115 2 : this->nBand = nBand;
116 2 : NWT_GRCDataset *poGDS =( NWT_GRCDataset * ) poDS;
117 :
118 2 : bHaveOffsetScale = FALSE;
119 2 : dfOffset = 0;
120 2 : dfScale = 1.0;
121 2 : if( poGDS->pGrd->nBitsPerPixel == 8 )
122 2 : eDataType = GDT_Byte;
123 0 : else if( poGDS->pGrd->nBitsPerPixel == 16 )
124 0 : eDataType = GDT_UInt16;
125 0 : else if( poGDS->pGrd->nBitsPerPixel == 32 )
126 0 : eDataType = GDT_UInt32; // this would be funny
127 :
128 2 : nBlockXSize = poDS->GetRasterXSize();
129 2 : nBlockYSize = 1;
130 :
131 : // load the color table and might as well to the ClassNames
132 2 : poGDS->poColorTable = new GDALColorTable();
133 :
134 : GDALColorEntry oEntry;
135 : // null value = 0 is transparent
136 2 : oEntry.c1 = 255;
137 2 : oEntry.c2 = 255;
138 2 : oEntry.c3 = 255;
139 2 : oEntry.c4 = 255; // alpha 255 = transparent
140 :
141 2 : poGDS->poColorTable->SetColorEntry( 0, &oEntry );
142 :
143 : int i;
144 8 : for( i=0; i < (int) poGDS->pGrd->stClassDict->nNumClassifiedItems; i++ )
145 : {
146 6 : oEntry.c1 = poGDS->pGrd->stClassDict->stClassifedItem[i]->r;
147 6 : oEntry.c2 = poGDS->pGrd->stClassDict->stClassifedItem[i]->g;
148 6 : oEntry.c3 = poGDS->pGrd->stClassDict->stClassifedItem[i]->b;
149 6 : oEntry.c4 = 0; // alpha 0 = solid
150 :
151 : poGDS->poColorTable->SetColorEntry( poDS->pGrd->
152 6 : stClassDict->stClassifedItem[i]->
153 6 : usPixVal, &oEntry );
154 : }
155 :
156 : // find the max value used in the grc
157 2 : int maxValue = 0;
158 8 : for( i=0; i < (int) poDS->pGrd->stClassDict->nNumClassifiedItems; i++ )
159 : {
160 6 : if( poDS->pGrd->stClassDict->stClassifedItem[i]->usPixVal > maxValue )
161 6 : maxValue = poDS->pGrd->stClassDict->stClassifedItem[i]->usPixVal;
162 : }
163 :
164 : // load a value for the null value
165 2 : poGDS->papszCategories = CSLAddString( poGDS->papszCategories, "No Data" );
166 :
167 : // for the class names we need to load nulls string for all classes that
168 : // are not defined
169 8 : for( int val = 1; val <= maxValue; val++ )
170 : {
171 : int i;
172 : // loop throught the GRC dictionary to see if the value is defined
173 12 : for( i=0; i < (int) poDS->pGrd->stClassDict->nNumClassifiedItems; i++ )
174 : {
175 12 : if( (int) poDS->pGrd->stClassDict->stClassifedItem[i]->usPixVal ==
176 : val )
177 : {
178 : poGDS->papszCategories =
179 : CSLAddString( poGDS->papszCategories,
180 : poDS->pGrd->stClassDict->
181 6 : stClassifedItem[i]->szClassName );
182 6 : break;
183 : }
184 : }
185 6 : if( i >= (int) poDS->pGrd->stClassDict->nNumClassifiedItems )
186 0 : poGDS->papszCategories = CSLAddString( poGDS->papszCategories, "" );
187 :
188 : }
189 2 : }
190 :
191 2 : NWT_GRCRasterBand::~NWT_GRCRasterBand()
192 : {
193 2 : }
194 :
195 0 : double NWT_GRCRasterBand::GetNoDataValue( int *pbSuccess )
196 : {
197 0 : if( pbSuccess != NULL )
198 0 : *pbSuccess = TRUE;
199 :
200 0 : return 0; //Northwood grid 0 is always null
201 : }
202 :
203 : // return an array of null terminated strings for the class names
204 0 : char **NWT_GRCRasterBand::GetCategoryNames()
205 : {
206 0 : NWT_GRCDataset *poGDS = (NWT_GRCDataset *) poDS;
207 :
208 0 : return poGDS->papszCategories;
209 : }
210 :
211 : // return the color table
212 0 : GDALColorTable *NWT_GRCRasterBand::GetColorTable()
213 : {
214 0 : NWT_GRCDataset *poGDS = (NWT_GRCDataset *) poDS;
215 :
216 0 : return poGDS->poColorTable;
217 : }
218 :
219 0 : GDALColorInterp NWT_GRCRasterBand::GetColorInterpretation()
220 : {
221 0 : if( nBand == 1 )
222 0 : return GCI_PaletteIndex;
223 : else
224 0 : return GCI_Undefined;
225 : }
226 :
227 : /************************************************************************/
228 : /* IReadBlock() */
229 : /************************************************************************/
230 362 : CPLErr NWT_GRCRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
231 : void *pImage )
232 : {
233 362 : NWT_GRCDataset *poGDS =(NWT_GRCDataset *) poDS;
234 362 : int nRecordSize = nBlockXSize *( poGDS->pGrd->nBitsPerPixel / 8 );
235 :
236 362 : if( nBand == 1 )
237 : { //grc's are just one band of indices
238 362 : VSIFSeekL( poGDS->fp, 1024 + nRecordSize * nBlockYOff, SEEK_SET );
239 362 : VSIFReadL( pImage, 1, nRecordSize, poGDS->fp );
240 : }
241 : else
242 : {
243 : CPLError( CE_Failure, CPLE_IllegalArg,
244 : "No band number %d",
245 0 : nBand );
246 0 : return CE_Failure;
247 : }
248 362 : return CE_None;
249 : }
250 :
251 :
252 : /************************************************************************/
253 : /* GetOffset() */
254 : /************************************************************************/
255 0 : double NWT_GRCRasterBand::GetOffset( int *pbSuccess )
256 : {
257 0 : if( pbSuccess )
258 0 : *pbSuccess = bHaveOffsetScale;
259 0 : return dfOffset;
260 : }
261 :
262 : /************************************************************************/
263 : /* SetOffset() */
264 : /************************************************************************/
265 0 : CPLErr NWT_GRCRasterBand::SetOffset( double dfNewValue )
266 : {
267 : //poGDS->bMetadataChanged = TRUE;
268 :
269 0 : bHaveOffsetScale = TRUE;
270 0 : dfOffset = dfNewValue;
271 0 : return CE_None;
272 : }
273 :
274 : /************************************************************************/
275 : /* GetScale() */
276 : /************************************************************************/
277 0 : double NWT_GRCRasterBand::GetScale( int *pbSuccess )
278 : {
279 0 : if( pbSuccess )
280 0 : *pbSuccess = bHaveOffsetScale;
281 0 : return dfScale;
282 : }
283 :
284 : /************************************************************************/
285 : /* SetScale() */
286 : /************************************************************************/
287 0 : CPLErr NWT_GRCRasterBand::SetScale( double dfNewValue )
288 : {
289 0 : bHaveOffsetScale = TRUE;
290 0 : dfScale = dfNewValue;
291 0 : return CE_None;
292 : }
293 :
294 : /************************************************************************/
295 : /* ==================================================================== */
296 : /* NWT_GRCDataset */
297 : /* ==================================================================== */
298 : /************************************************************************/
299 2 : NWT_GRCDataset::NWT_GRCDataset()
300 : {
301 2 : poColorTable = NULL;
302 2 : papszCategories = NULL;
303 2 : pszProjection = NULL;
304 2 : }
305 :
306 :
307 : /************************************************************************/
308 : /* ~NWT_GRCDataset() */
309 : /************************************************************************/
310 2 : NWT_GRCDataset::~NWT_GRCDataset()
311 : {
312 2 : delete poColorTable;
313 2 : CSLDestroy( papszCategories );
314 :
315 2 : FlushCache();
316 2 : pGrd->fp = NULL; // this prevents nwtCloseGrid from closing the fp
317 2 : nwtCloseGrid( pGrd );
318 :
319 2 : if( fp != NULL )
320 2 : VSIFCloseL( fp );
321 :
322 2 : CPLFree( pszProjection );
323 2 : }
324 :
325 : /************************************************************************/
326 : /* GetGeoTransform() */
327 : /************************************************************************/
328 0 : CPLErr NWT_GRCDataset::GetGeoTransform( double *padfTransform )
329 : {
330 0 : padfTransform[0] = pGrd->dfMinX - ( pGrd->dfStepSize * 0.5 );
331 0 : padfTransform[3] = pGrd->dfMaxY + ( pGrd->dfStepSize * 0.5 );
332 0 : padfTransform[1] = pGrd->dfStepSize;
333 0 : padfTransform[2] = 0.0;
334 :
335 0 : padfTransform[4] = 0.0;
336 0 : padfTransform[5] = -1 * pGrd->dfStepSize;
337 :
338 0 : return CE_None;
339 : }
340 :
341 : /************************************************************************/
342 : /* GetProjectionRef() */
343 : /************************************************************************/
344 0 : const char *NWT_GRCDataset::GetProjectionRef()
345 : {
346 : #ifdef OGR_ENABLED
347 0 : if (pszProjection == NULL)
348 : {
349 : OGRSpatialReference *poSpatialRef;
350 0 : poSpatialRef = MITABCoordSys2SpatialRef( pGrd->cMICoordSys );
351 0 : if (poSpatialRef)
352 : {
353 0 : poSpatialRef->exportToWkt( &pszProjection );
354 0 : poSpatialRef->Release();
355 : }
356 : }
357 : #endif
358 0 : return ( (const char *) pszProjection );
359 : }
360 :
361 : /************************************************************************/
362 : /* Identify() */
363 : /************************************************************************/
364 :
365 22234 : int NWT_GRCDataset::Identify( GDALOpenInfo * poOpenInfo )
366 : {
367 : /* -------------------------------------------------------------------- */
368 : /* Look for the header */
369 : /* -------------------------------------------------------------------- */
370 22234 : if( poOpenInfo->nHeaderBytes < 50 )
371 21244 : return FALSE;
372 :
373 1040 : if( poOpenInfo->pabyHeader[0] != 'H' ||
374 44 : poOpenInfo->pabyHeader[1] != 'G' ||
375 2 : poOpenInfo->pabyHeader[2] != 'P' ||
376 2 : poOpenInfo->pabyHeader[3] != 'C' ||
377 2 : poOpenInfo->pabyHeader[4] != '8' )
378 988 : return FALSE;
379 :
380 2 : return TRUE;
381 : }
382 :
383 : /************************************************************************/
384 : /* Open() */
385 : /************************************************************************/
386 :
387 3326 : GDALDataset *NWT_GRCDataset::Open( GDALOpenInfo * poOpenInfo )
388 : {
389 3326 : if( !Identify(poOpenInfo) )
390 3324 : return NULL;
391 :
392 : /* -------------------------------------------------------------------- */
393 : /* Create a corresponding GDALDataset. */
394 : /* -------------------------------------------------------------------- */
395 : NWT_GRCDataset *poDS;
396 :
397 2 : poDS = new NWT_GRCDataset();
398 :
399 2 : poDS->fp = VSIFOpenL(poOpenInfo->pszFilename, "rb");
400 2 : if (poDS->fp == NULL)
401 : {
402 0 : delete poDS;
403 0 : return NULL;
404 : }
405 :
406 : /* -------------------------------------------------------------------- */
407 : /* Read the header. */
408 : /* -------------------------------------------------------------------- */
409 2 : VSIFSeekL( poDS->fp, 0, SEEK_SET );
410 2 : VSIFReadL( poDS->abyHeader, 1, 1024, poDS->fp );
411 2 : poDS->pGrd = (NWT_GRID *) malloc( sizeof (NWT_GRID) );
412 :
413 2 : poDS->pGrd->fp = poDS->fp;
414 :
415 2 : if (!nwt_ParseHeader( poDS->pGrd, (char *) poDS->abyHeader ) ||
416 : !GDALCheckDatasetDimensions(poDS->pGrd->nXSide, poDS->pGrd->nYSide) ||
417 : poDS->pGrd->stClassDict == NULL)
418 : {
419 0 : delete poDS;
420 0 : return NULL;
421 : }
422 :
423 2 : poDS->nRasterXSize = poDS->pGrd->nXSide;
424 2 : poDS->nRasterYSize = poDS->pGrd->nYSide;
425 :
426 : /* -------------------------------------------------------------------- */
427 : /* Create band information objects. */
428 : /* -------------------------------------------------------------------- */
429 2 : poDS->SetBand( 1, new NWT_GRCRasterBand( poDS, 1) ); //Class Indexes
430 :
431 : /* -------------------------------------------------------------------- */
432 : /* Initialize any PAM information. */
433 : /* -------------------------------------------------------------------- */
434 2 : poDS->SetDescription( poOpenInfo->pszFilename );
435 2 : poDS->TryLoadXML();
436 :
437 : /* -------------------------------------------------------------------- */
438 : /* Check for external overviews. */
439 : /* -------------------------------------------------------------------- */
440 2 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
441 :
442 2 : return (poDS);
443 : }
444 :
445 :
446 : /************************************************************************/
447 : /* GDALRegister_GRC() */
448 : /************************************************************************/
449 :
450 : void
451 1135 : GDALRegister_NWT_GRC()
452 : {
453 : GDALDriver *poDriver;
454 :
455 1135 : if( GDALGetDriverByName( "NWT_GRC" ) == NULL )
456 : {
457 1093 : poDriver = new GDALDriver();
458 :
459 1093 : poDriver->SetDescription( "NWT_GRC" );
460 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
461 1093 : "Northwood Classified Grid Format .grc/.tab");
462 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
463 1093 : "frmt_various.html#northwood_grc" );
464 1093 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "grc" );
465 1093 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
466 :
467 1093 : poDriver->pfnOpen = NWT_GRCDataset::Open;
468 1093 : poDriver->pfnIdentify = NWT_GRCDataset::Identify;
469 :
470 1093 : GetGDALDriverManager()->RegisterDriver( poDriver );
471 : }
472 1135 : }
|