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