1 : /******************************************************************************
2 : * $Id: lcpdataset.cpp 18125 2009-11-28 11:07:24Z rouault $
3 : *
4 : * Project: LCP Driver
5 : * Purpose: FARSITE v.4 Landscape file (.lcp) reader for GDAL
6 : * Author: Chris Toney
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2008, Chris Toney
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 "cpl_string.h"
32 : #include "ogr_spatialref.h"
33 :
34 : CPL_CVSID("$Id: lcpdataset.cpp 18125 2009-11-28 11:07:24Z rouault $");
35 :
36 : CPL_C_START
37 : void GDALRegister_LCP(void);
38 : CPL_C_END
39 :
40 : #define LCP_HEADER_SIZE 7316
41 :
42 : /************************************************************************/
43 : /* ==================================================================== */
44 : /* LCPDataset */
45 : /* ==================================================================== */
46 : /************************************************************************/
47 :
48 : class LCPDataset : public RawDataset
49 : {
50 : FILE *fpImage; // image data file.
51 : char pachHeader[LCP_HEADER_SIZE];
52 :
53 : CPLString osPrjFilename;
54 : char *pszProjection;
55 :
56 : public:
57 : LCPDataset();
58 : ~LCPDataset();
59 :
60 : virtual char **GetFileList(void);
61 :
62 : virtual CPLErr GetGeoTransform( double * );
63 :
64 : static int Identify( GDALOpenInfo * );
65 : static GDALDataset *Open( GDALOpenInfo * );
66 :
67 : virtual const char *GetProjectionRef(void);
68 : };
69 :
70 : /************************************************************************/
71 : /* LCPDataset() */
72 : /************************************************************************/
73 :
74 2 : LCPDataset::LCPDataset()
75 : {
76 2 : fpImage = NULL;
77 2 : pszProjection = NULL;
78 2 : }
79 :
80 : /************************************************************************/
81 : /* ~LCPDataset() */
82 : /************************************************************************/
83 :
84 4 : LCPDataset::~LCPDataset()
85 :
86 : {
87 2 : FlushCache();
88 2 : if( fpImage != NULL )
89 2 : VSIFCloseL( fpImage );
90 2 : CPLFree(pszProjection);
91 4 : }
92 :
93 : /************************************************************************/
94 : /* GetGeoTransform() */
95 : /************************************************************************/
96 :
97 2 : CPLErr LCPDataset::GetGeoTransform( double * padfTransform )
98 : {
99 : double dfEast, dfWest, dfNorth, dfSouth, dfCellX, dfCellY;
100 :
101 2 : memcpy(&dfEast, pachHeader + 4172, sizeof(double));
102 2 : memcpy(&dfWest, pachHeader + 4180, sizeof(double));
103 2 : memcpy(&dfNorth, pachHeader + 4188, sizeof(double));
104 2 : memcpy(&dfSouth, pachHeader + 4196, sizeof(double));
105 2 : memcpy(&dfCellX, pachHeader + 4208, sizeof(double));
106 2 : memcpy(&dfCellY, pachHeader + 4216, sizeof(double));
107 : CPL_LSBPTR64(&dfEast);
108 : CPL_LSBPTR64(&dfWest);
109 : CPL_LSBPTR64(&dfNorth);
110 : CPL_LSBPTR64(&dfSouth);
111 : CPL_LSBPTR64(&dfCellX);
112 : CPL_LSBPTR64(&dfCellY);
113 :
114 2 : padfTransform[0] = dfWest;
115 2 : padfTransform[3] = dfNorth;
116 2 : padfTransform[1] = dfCellX;
117 2 : padfTransform[2] = 0.0;
118 :
119 2 : padfTransform[4] = 0.0;
120 2 : padfTransform[5] = -1 * dfCellY;
121 :
122 2 : return CE_None;
123 : }
124 :
125 : /************************************************************************/
126 : /* Identify() */
127 : /************************************************************************/
128 :
129 8493 : int LCPDataset::Identify( GDALOpenInfo * poOpenInfo )
130 :
131 : {
132 : /* -------------------------------------------------------------------- */
133 : /* Verify that this is a FARSITE v.4 LCP file */
134 : /* -------------------------------------------------------------------- */
135 8493 : if( poOpenInfo->nHeaderBytes < 50 )
136 8297 : return FALSE;
137 :
138 : /* check if first three fields have valid data */
139 196 : if( (CPL_LSBINT32PTR(poOpenInfo->pabyHeader) != 20
140 : && CPL_LSBINT32PTR(poOpenInfo->pabyHeader) != 21)
141 : || (CPL_LSBINT32PTR(poOpenInfo->pabyHeader+4) != 20
142 : && CPL_LSBINT32PTR(poOpenInfo->pabyHeader+4) != 21)
143 : || (CPL_LSBINT32PTR(poOpenInfo->pabyHeader+8) < -90
144 : || CPL_LSBINT32PTR(poOpenInfo->pabyHeader+8) > 90) )
145 : {
146 194 : return FALSE;
147 : }
148 :
149 2 : return TRUE;
150 : }
151 :
152 : /************************************************************************/
153 : /* GetFileList() */
154 : /************************************************************************/
155 :
156 0 : char **LCPDataset::GetFileList()
157 :
158 : {
159 0 : char **papszFileList = GDALPamDataset::GetFileList();
160 :
161 0 : if( pszProjection != NULL )
162 0 : papszFileList = CSLAddString( papszFileList, osPrjFilename );
163 :
164 0 : return papszFileList;
165 : }
166 :
167 : /************************************************************************/
168 : /* Open() */
169 : /************************************************************************/
170 :
171 766 : GDALDataset *LCPDataset::Open( GDALOpenInfo * poOpenInfo )
172 :
173 : {
174 : /* -------------------------------------------------------------------- */
175 : /* Verify that this is a FARSITE LCP file */
176 : /* -------------------------------------------------------------------- */
177 766 : if( !Identify( poOpenInfo ) )
178 764 : return NULL;
179 :
180 : /* -------------------------------------------------------------------- */
181 : /* Confirm the requested access is supported. */
182 : /* -------------------------------------------------------------------- */
183 2 : if( poOpenInfo->eAccess == GA_Update )
184 : {
185 : CPLError( CE_Failure, CPLE_NotSupported,
186 : "The LCP driver does not support update access to existing"
187 0 : " datasets.\n" );
188 0 : return NULL;
189 : }
190 :
191 : /* -------------------------------------------------------------------- */
192 : /* Create a corresponding GDALDataset. */
193 : /* -------------------------------------------------------------------- */
194 : LCPDataset *poDS;
195 : FILE *fpImage;
196 :
197 2 : fpImage = VSIFOpenL(poOpenInfo->pszFilename, "rb");
198 2 : if (fpImage == NULL)
199 0 : return NULL;
200 :
201 2 : poDS = new LCPDataset();
202 2 : poDS->fpImage = fpImage;
203 :
204 : /* -------------------------------------------------------------------- */
205 : /* Read the header and extract some information. */
206 : /* -------------------------------------------------------------------- */
207 : int bHaveCrownFuels, bHaveGroundFuels;
208 : int nBands, i;
209 2 : long nWidth = -1, nHeight = -1;
210 : int nTemp, nTemp2;
211 : char szTemp[32];
212 : char* pszList;
213 :
214 2 : VSIFSeekL( poDS->fpImage, 0, SEEK_SET );
215 2 : if (VSIFReadL( poDS->pachHeader, 1, LCP_HEADER_SIZE, poDS->fpImage ) != LCP_HEADER_SIZE)
216 : {
217 0 : CPLError(CE_Failure, CPLE_FileIO, "File too short");
218 0 : delete poDS;
219 0 : return NULL;
220 : }
221 :
222 2 : nWidth = CPL_LSBINT32PTR (poDS->pachHeader + 4164);
223 2 : nHeight = CPL_LSBINT32PTR (poDS->pachHeader + 4168);
224 :
225 2 : poDS->nRasterXSize = nWidth;
226 2 : poDS->nRasterYSize = nHeight;
227 :
228 2 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
229 : {
230 0 : delete poDS;
231 0 : return NULL;
232 : }
233 :
234 : // crown fuels = canopy height, canopy base height, canopy bulk density
235 : // 21 = have them, 20 = don't have them
236 2 : bHaveCrownFuels = ( CPL_LSBINT32PTR (poDS->pachHeader + 0) - 20 );
237 : // ground fuels = duff loading, coarse woody
238 2 : bHaveGroundFuels = ( CPL_LSBINT32PTR (poDS->pachHeader + 4) - 20 );
239 :
240 2 : if( bHaveCrownFuels )
241 : {
242 2 : if( bHaveGroundFuels )
243 0 : nBands = 10;
244 : else
245 2 : nBands = 8;
246 : }
247 : else
248 : {
249 0 : if( bHaveGroundFuels )
250 0 : nBands = 7;
251 : else
252 0 : nBands = 5;
253 : }
254 :
255 : // add dataset-level metadata
256 :
257 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 8);
258 2 : sprintf(szTemp, "%d", nTemp);
259 2 : poDS->SetMetadataItem( "LATITUDE", szTemp );
260 :
261 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 4204);
262 2 : if ( nTemp == 0 )
263 2 : poDS->SetMetadataItem( "LINEAR_UNIT", "Meters" );
264 2 : if ( nTemp == 1 )
265 0 : poDS->SetMetadataItem( "LINEAR_UNIT", "Feet" );
266 :
267 2 : poDS->pachHeader[LCP_HEADER_SIZE-1] = '\0';
268 2 : poDS->SetMetadataItem( "DESCRIPTION", poDS->pachHeader + 6804 );
269 :
270 :
271 : /* -------------------------------------------------------------------- */
272 : /* Create band information objects. */
273 : /* -------------------------------------------------------------------- */
274 :
275 : int iPixelSize;
276 2 : iPixelSize = nBands * 2;
277 : int bNativeOrder;
278 :
279 2 : if (nWidth > INT_MAX / iPixelSize)
280 : {
281 0 : CPLError( CE_Failure, CPLE_AppDefined, "Int overflow occured");
282 0 : delete poDS;
283 0 : return NULL;
284 : }
285 :
286 : #ifdef CPL_LSB
287 2 : bNativeOrder = TRUE;
288 : #else
289 : bNativeOrder = FALSE;
290 : #endif
291 :
292 2 : pszList = (char*)CPLMalloc(2048);
293 :
294 18 : for( int iBand = 1; iBand <= nBands; iBand++ )
295 : {
296 16 : GDALRasterBand *poBand = NULL;
297 :
298 : poBand = new RawRasterBand(
299 : poDS, iBand, poDS->fpImage, LCP_HEADER_SIZE + ((iBand-1)*2),
300 16 : iPixelSize, iPixelSize * nWidth, GDT_Int16, bNativeOrder, TRUE );
301 :
302 16 : poDS->SetBand(iBand, poBand);
303 :
304 16 : switch ( iBand ) {
305 : case 1:
306 2 : poBand->SetDescription("Elevation");
307 :
308 2 : nTemp = CPL_LSBINT16PTR (poDS->pachHeader + 4224);
309 2 : sprintf(szTemp, "%d", nTemp);
310 2 : poBand->SetMetadataItem( "ELEVATION_UNIT", szTemp );
311 :
312 2 : if ( nTemp == 0 )
313 2 : poBand->SetMetadataItem( "ELEVATION_UNIT_NAME", "Meters" );
314 2 : if ( nTemp == 1 )
315 0 : poBand->SetMetadataItem( "ELEVATION_UNIT_NAME", "Feet" );
316 :
317 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 44);
318 2 : sprintf(szTemp, "%d", nTemp);
319 2 : poBand->SetMetadataItem( "ELEVATION_MIN", szTemp );
320 :
321 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 48);
322 2 : sprintf(szTemp, "%d", nTemp);
323 2 : poBand->SetMetadataItem( "ELEVATION_MAX", szTemp );
324 :
325 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 52);
326 2 : sprintf(szTemp, "%d", nTemp);
327 2 : poBand->SetMetadataItem( "ELEVATION_NUM_CLASSES", szTemp );
328 :
329 2 : *(poDS->pachHeader + 4244 + 255) = '\0';
330 2 : poBand->SetMetadataItem( "ELEVATION_FILE", poDS->pachHeader + 4244 );
331 :
332 2 : break;
333 :
334 : case 2:
335 2 : poBand->SetDescription("Slope");
336 :
337 2 : nTemp = CPL_LSBINT16PTR (poDS->pachHeader + 4226);
338 2 : sprintf(szTemp, "%d", nTemp);
339 2 : poBand->SetMetadataItem( "SLOPE_UNIT", szTemp );
340 :
341 2 : if ( nTemp == 0 )
342 2 : poBand->SetMetadataItem( "SLOPE_UNIT_NAME", "Degrees" );
343 2 : if ( nTemp == 1 )
344 0 : poBand->SetMetadataItem( "SLOPE_UNIT_NAME", "Percent" );
345 :
346 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 456);
347 2 : sprintf(szTemp, "%d", nTemp);
348 2 : poBand->SetMetadataItem( "SLOPE_MIN", szTemp );
349 :
350 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 460);
351 2 : sprintf(szTemp, "%d", nTemp);
352 2 : poBand->SetMetadataItem( "SLOPE_MAX", szTemp );
353 :
354 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 464);
355 2 : sprintf(szTemp, "%d", nTemp);
356 2 : poBand->SetMetadataItem( "SLOPE_NUM_CLASSES", szTemp );
357 :
358 2 : *(poDS->pachHeader + 4500 + 255) = '\0';
359 2 : poBand->SetMetadataItem( "SLOPE_FILE", poDS->pachHeader + 4500 );
360 :
361 2 : break;
362 :
363 : case 3:
364 2 : poBand->SetDescription("Aspect");
365 :
366 2 : nTemp = CPL_LSBINT16PTR (poDS->pachHeader + 4228);
367 2 : sprintf(szTemp, "%d", nTemp);
368 2 : poBand->SetMetadataItem( "ASPECT_UNIT", szTemp );
369 :
370 2 : if ( nTemp == 0 )
371 0 : poBand->SetMetadataItem( "ASPECT_UNIT_NAME", "Grass categories" );
372 2 : if ( nTemp == 1 )
373 0 : poBand->SetMetadataItem( "ASPECT_UNIT_NAME", "Grass degrees" );
374 2 : if ( nTemp == 2 )
375 2 : poBand->SetMetadataItem( "ASPECT_UNIT_NAME", "Azimuth degrees" );
376 :
377 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 868);
378 2 : sprintf(szTemp, "%d", nTemp);
379 2 : poBand->SetMetadataItem( "ASPECT_MIN", szTemp );
380 :
381 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 872);
382 2 : sprintf(szTemp, "%d", nTemp);
383 2 : poBand->SetMetadataItem( "ASPECT_MAX", szTemp );
384 :
385 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 876);
386 2 : sprintf(szTemp, "%d", nTemp);
387 2 : poBand->SetMetadataItem( "ASPECT_NUM_CLASSES", szTemp );
388 :
389 2 : *(poDS->pachHeader + 4756 + 255) = '\0';
390 2 : poBand->SetMetadataItem( "ASPECT_FILE", poDS->pachHeader + 4756 );
391 :
392 2 : break;
393 :
394 : case 4:
395 : int nMinFM, nMaxFM;
396 :
397 2 : poBand->SetDescription("Fuel models");
398 :
399 2 : nTemp = CPL_LSBINT16PTR (poDS->pachHeader + 4230);
400 2 : sprintf(szTemp, "%d", nTemp);
401 2 : poBand->SetMetadataItem( "FUEL_MODEL_OPTION", szTemp );
402 :
403 2 : if ( nTemp == 0 )
404 2 : poBand->SetMetadataItem( "FUEL_MODEL_OPTION_DESC", "no custom models AND no conversion file needed" );
405 2 : if ( nTemp == 1 )
406 0 : poBand->SetMetadataItem( "FUEL_MODEL_OPTION_DESC", "custom models BUT no conversion file needed" );
407 2 : if ( nTemp == 2 )
408 0 : poBand->SetMetadataItem( "FUEL_MODEL_OPTION_DESC", "no custom models BUT conversion file needed" );
409 2 : if ( nTemp == 3 )
410 0 : poBand->SetMetadataItem( "FUEL_MODEL_OPTION_DESC", "custom models AND conversion file needed" );
411 :
412 2 : nMinFM = CPL_LSBINT32PTR (poDS->pachHeader + 1280);
413 2 : sprintf(szTemp, "%d", nMinFM);
414 2 : poBand->SetMetadataItem( "FUEL_MODEL_MIN", szTemp );
415 :
416 2 : nMaxFM = CPL_LSBINT32PTR (poDS->pachHeader + 1284);
417 2 : sprintf(szTemp, "%d", nMaxFM);
418 2 : poBand->SetMetadataItem( "FUEL_MODEL_MAX", szTemp );
419 :
420 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 1288);
421 2 : sprintf(szTemp, "%d", nTemp);
422 2 : poBand->SetMetadataItem( "FUEL_MODEL_NUM_CLASSES", szTemp );
423 :
424 2 : if (nTemp > 0 && nTemp <= 100) {
425 2 : strcpy(pszList, "");
426 15 : for ( i = 0; i <= nTemp; i++ ) {
427 13 : nTemp2 = CPL_LSBINT32PTR (poDS->pachHeader + (1292+(i*4))) ;
428 13 : if ( nTemp2 >= nMinFM && nTemp2 <= nMaxFM ) {
429 11 : sprintf(szTemp, "%d", nTemp2);
430 11 : strcat(pszList, szTemp);
431 11 : if (i < (nTemp) )
432 9 : strcat(pszList, ",");
433 : }
434 : }
435 : }
436 2 : poBand->SetMetadataItem( "FUEL_MODEL_VALUES", pszList );
437 :
438 2 : *(poDS->pachHeader + 5012 + 255) = '\0';
439 2 : poBand->SetMetadataItem( "FUEL_MODEL_FILE", poDS->pachHeader + 5012 );
440 :
441 2 : break;
442 :
443 : case 5:
444 2 : poBand->SetDescription("Canopy cover");
445 :
446 2 : nTemp = CPL_LSBINT16PTR (poDS->pachHeader + 4232);
447 2 : sprintf(szTemp, "%d", nTemp);
448 2 : poBand->SetMetadataItem( "CANOPY_COV_UNIT", szTemp );
449 :
450 2 : if ( nTemp == 0 )
451 1 : poBand->SetMetadataItem( "CANOPY_COV_UNIT_NAME", "Categories (0-4)" );
452 2 : if ( nTemp == 1 )
453 1 : poBand->SetMetadataItem( "CANOPY_COV_UNIT_NAME", "Percent" );
454 :
455 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 1692);
456 2 : sprintf(szTemp, "%d", nTemp);
457 2 : poBand->SetMetadataItem( "CANOPY_COV_MIN", szTemp );
458 :
459 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 1696);
460 2 : sprintf(szTemp, "%d", nTemp);
461 2 : poBand->SetMetadataItem( "CANOPY_COV_MAX", szTemp );
462 :
463 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 1700);
464 2 : sprintf(szTemp, "%d", nTemp);
465 2 : poBand->SetMetadataItem( "CANOPY_COV_NUM_CLASSES", szTemp );
466 :
467 2 : *(poDS->pachHeader + 5268 + 255) = '\0';
468 2 : poBand->SetMetadataItem( "CANOPY_COV_FILE", poDS->pachHeader + 5268 );
469 :
470 2 : break;
471 :
472 : case 6:
473 2 : if(bHaveCrownFuels) {
474 2 : poBand->SetDescription("Canopy height");
475 :
476 2 : nTemp = CPL_LSBINT16PTR (poDS->pachHeader + 4234);
477 2 : sprintf(szTemp, "%d", nTemp);
478 2 : poBand->SetMetadataItem( "CANOPY_HT_UNIT", szTemp );
479 :
480 2 : if ( nTemp == 1 )
481 0 : poBand->SetMetadataItem( "CANOPY_HT_UNIT_NAME", "Meters" );
482 2 : if ( nTemp == 2 )
483 0 : poBand->SetMetadataItem( "CANOPY_HT_UNIT_NAME", "Feet" );
484 2 : if ( nTemp == 3 )
485 2 : poBand->SetMetadataItem( "CANOPY_HT_UNIT_NAME", "Meters x 10" );
486 2 : if ( nTemp == 4 )
487 0 : poBand->SetMetadataItem( "CANOPY_HT_UNIT_NAME", "Feet x 10" );
488 :
489 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 2104);
490 2 : sprintf(szTemp, "%d", nTemp);
491 2 : poBand->SetMetadataItem( "CANOPY_HT_MIN", szTemp );
492 :
493 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 2108);
494 2 : sprintf(szTemp, "%d", nTemp);
495 2 : poBand->SetMetadataItem( "CANOPY_HT_MAX", szTemp );
496 :
497 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 2112);
498 2 : sprintf(szTemp, "%d", nTemp);
499 2 : poBand->SetMetadataItem( "CANOPY_HT_NUM_CLASSES", szTemp );
500 :
501 2 : *(poDS->pachHeader + 5524 + 255) = '\0';
502 2 : poBand->SetMetadataItem( "CANOPY_HT_FILE", poDS->pachHeader + 5524 );
503 : }
504 : else {
505 0 : poBand->SetDescription("Duff");
506 :
507 0 : nTemp = CPL_LSBINT16PTR (poDS->pachHeader + 4240);
508 0 : sprintf(szTemp, "%d", nTemp);
509 0 : poBand->SetMetadataItem( "DUFF_UNIT", szTemp );
510 :
511 0 : if ( nTemp == 1 )
512 0 : poBand->SetMetadataItem( "DUFF_UNIT_NAME", "Mg/ha" );
513 0 : if ( nTemp == 2 )
514 0 : poBand->SetMetadataItem( "DUFF_UNIT_NAME", "t/ac" );
515 :
516 0 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 3340);
517 0 : sprintf(szTemp, "%d", nTemp);
518 0 : poBand->SetMetadataItem( "DUFF_MIN", szTemp );
519 :
520 0 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 3344);
521 0 : sprintf(szTemp, "%d", nTemp);
522 0 : poBand->SetMetadataItem( "DUFF_MAX", szTemp );
523 :
524 0 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 3348);
525 0 : sprintf(szTemp, "%d", nTemp);
526 0 : poBand->SetMetadataItem( "DUFF_NUM_CLASSES", szTemp );
527 :
528 0 : *(poDS->pachHeader + 6292 + 255) = '\0';
529 0 : poBand->SetMetadataItem( "DUFF_FILE", poDS->pachHeader + 6292 );
530 : }
531 2 : break;
532 :
533 : case 7:
534 2 : if(bHaveCrownFuels) {
535 2 : poBand->SetDescription("Canopy base height");
536 :
537 2 : nTemp = CPL_LSBINT16PTR (poDS->pachHeader + 4236);
538 2 : sprintf(szTemp, "%d", nTemp);
539 2 : poBand->SetMetadataItem( "CBH_UNIT", szTemp );
540 :
541 2 : if ( nTemp == 1 )
542 0 : poBand->SetMetadataItem( "CBH_UNIT_NAME", "Meters" );
543 2 : if ( nTemp == 2 )
544 0 : poBand->SetMetadataItem( "CBH_UNIT_NAME", "Feet" );
545 2 : if ( nTemp == 3 )
546 2 : poBand->SetMetadataItem( "CBH_UNIT_NAME", "Meters x 10" );
547 2 : if ( nTemp == 4 )
548 0 : poBand->SetMetadataItem( "CBH_UNIT_NAME", "Feet x 10" );
549 :
550 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 2516);
551 2 : sprintf(szTemp, "%d", nTemp);
552 2 : poBand->SetMetadataItem( "CBH_MIN", szTemp );
553 :
554 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 2520);
555 2 : sprintf(szTemp, "%d", nTemp);
556 2 : poBand->SetMetadataItem( "CBH_MAX", szTemp );
557 :
558 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 2524);
559 2 : sprintf(szTemp, "%d", nTemp);
560 2 : poBand->SetMetadataItem( "CBH_NUM_CLASSES", szTemp );
561 :
562 2 : *(poDS->pachHeader + 5780 + 255) = '\0';
563 2 : poBand->SetMetadataItem( "CBH_FILE", poDS->pachHeader + 5780 );
564 : }
565 : else {
566 0 : poBand->SetDescription("Coarse woody debris");
567 :
568 0 : nTemp = CPL_LSBINT16PTR (poDS->pachHeader + 4242);
569 0 : sprintf(szTemp, "%d", nTemp);
570 0 : poBand->SetMetadataItem( "CWD_OPTION", szTemp );
571 :
572 : //if ( nTemp == 1 )
573 : // poBand->SetMetadataItem( "CWD_UNIT_DESC", "?" );
574 : //if ( nTemp == 2 )
575 : // poBand->SetMetadataItem( "CWD_UNIT_DESC", "?" );
576 :
577 0 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 3752);
578 0 : sprintf(szTemp, "%d", nTemp);
579 0 : poBand->SetMetadataItem( "CWD_MIN", szTemp );
580 :
581 0 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 3756);
582 0 : sprintf(szTemp, "%d", nTemp);
583 0 : poBand->SetMetadataItem( "CWD_MAX", szTemp );
584 :
585 0 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 3760);
586 0 : sprintf(szTemp, "%d", nTemp);
587 0 : poBand->SetMetadataItem( "CWD_NUM_CLASSES", szTemp );
588 :
589 0 : *(poDS->pachHeader + 6548 + 255) = '\0';
590 0 : poBand->SetMetadataItem( "CWD_FILE", poDS->pachHeader + 6548 );
591 : }
592 2 : break;
593 :
594 : case 8:
595 2 : poBand->SetDescription("Canopy bulk density");
596 :
597 2 : nTemp = CPL_LSBINT16PTR (poDS->pachHeader + 4238);
598 2 : sprintf(szTemp, "%d", nTemp);
599 2 : poBand->SetMetadataItem( "CBD_UNIT", szTemp );
600 :
601 2 : if ( nTemp == 1 )
602 0 : poBand->SetMetadataItem( "CBD_UNIT_NAME", "kg/m^3" );
603 2 : if ( nTemp == 2 )
604 0 : poBand->SetMetadataItem( "CBD_UNIT_NAME", "lb/ft^3" );
605 2 : if ( nTemp == 3 )
606 2 : poBand->SetMetadataItem( "CBD_UNIT_NAME", "kg/m^3 x 100" );
607 2 : if ( nTemp == 4 )
608 0 : poBand->SetMetadataItem( "CBD_UNIT_NAME", "lb/ft^3 x 1000" );
609 :
610 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 2928);
611 2 : sprintf(szTemp, "%d", nTemp);
612 2 : poBand->SetMetadataItem( "CBD_MIN", szTemp );
613 :
614 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 2932);
615 2 : sprintf(szTemp, "%d", nTemp);
616 2 : poBand->SetMetadataItem( "CBD_MAX", szTemp );
617 :
618 2 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 2936);
619 2 : sprintf(szTemp, "%d", nTemp);
620 2 : poBand->SetMetadataItem( "CBD_NUM_CLASSES", szTemp );
621 :
622 2 : *(poDS->pachHeader + 6036 + 255) = '\0';
623 2 : poBand->SetMetadataItem( "CBD_FILE", poDS->pachHeader + 6036 );
624 :
625 2 : break;
626 :
627 : case 9:
628 0 : poBand->SetDescription("Duff");
629 :
630 0 : nTemp = CPL_LSBINT16PTR (poDS->pachHeader + 4240);
631 0 : sprintf(szTemp, "%d", nTemp);
632 0 : poBand->SetMetadataItem( "DUFF_UNIT", szTemp );
633 :
634 0 : if ( nTemp == 1 )
635 0 : poBand->SetMetadataItem( "DUFF_UNIT_NAME", "Mg/ha" );
636 0 : if ( nTemp == 2 )
637 0 : poBand->SetMetadataItem( "DUFF_UNIT_NAME", "t/ac" );
638 :
639 0 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 3340);
640 0 : sprintf(szTemp, "%d", nTemp);
641 0 : poBand->SetMetadataItem( "DUFF_MIN", szTemp );
642 :
643 0 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 3344);
644 0 : sprintf(szTemp, "%d", nTemp);
645 0 : poBand->SetMetadataItem( "DUFF_MAX", szTemp );
646 :
647 0 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 3348);
648 0 : sprintf(szTemp, "%d", nTemp);
649 0 : poBand->SetMetadataItem( "DUFF_NUM_CLASSES", szTemp );
650 :
651 0 : *(poDS->pachHeader + 6292 + 255) = '\0';
652 0 : poBand->SetMetadataItem( "DUFF_FILE", poDS->pachHeader + 6292 );
653 :
654 0 : break;
655 :
656 : case 10:
657 0 : poBand->SetDescription("Coarse woody debris");
658 :
659 0 : nTemp = CPL_LSBINT16PTR (poDS->pachHeader + 4242);
660 0 : sprintf(szTemp, "%d", nTemp);
661 0 : poBand->SetMetadataItem( "CWD_OPTION", szTemp );
662 :
663 : //if ( nTemp == 1 )
664 : // poBand->SetMetadataItem( "CWD_UNIT_DESC", "?" );
665 : //if ( nTemp == 2 )
666 : // poBand->SetMetadataItem( "CWD_UNIT_DESC", "?" );
667 :
668 0 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 3752);
669 0 : sprintf(szTemp, "%d", nTemp);
670 0 : poBand->SetMetadataItem( "CWD_MIN", szTemp );
671 :
672 0 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 3756);
673 0 : sprintf(szTemp, "%d", nTemp);
674 0 : poBand->SetMetadataItem( "CWD_MAX", szTemp );
675 :
676 0 : nTemp = CPL_LSBINT32PTR (poDS->pachHeader + 3760);
677 0 : sprintf(szTemp, "%d", nTemp);
678 0 : poBand->SetMetadataItem( "CWD_NUM_CLASSES", szTemp );
679 :
680 0 : *(poDS->pachHeader + 6548 + 255) = '\0';
681 0 : poBand->SetMetadataItem( "CWD_FILE", poDS->pachHeader + 6548 );
682 :
683 : break;
684 : }
685 : }
686 :
687 : /* -------------------------------------------------------------------- */
688 : /* Try to read projection file. */
689 : /* -------------------------------------------------------------------- */
690 : char *pszDirname, *pszBasename;
691 : VSIStatBufL sStatBuf;
692 :
693 2 : pszDirname = CPLStrdup(CPLGetPath(poOpenInfo->pszFilename));
694 2 : pszBasename = CPLStrdup(CPLGetBasename(poOpenInfo->pszFilename));
695 :
696 2 : poDS->osPrjFilename = CPLFormFilename( pszDirname, pszBasename, "prj" );
697 2 : int nRet = VSIStatL( poDS->osPrjFilename, &sStatBuf );
698 :
699 : #ifndef WIN32
700 2 : if( nRet != 0 )
701 : {
702 1 : poDS->osPrjFilename = CPLFormFilename( pszDirname, pszBasename, "PRJ" );
703 1 : nRet = VSIStatL( poDS->osPrjFilename, &sStatBuf );
704 : }
705 : #endif
706 :
707 2 : if( nRet == 0 )
708 : {
709 1 : OGRSpatialReference oSRS;
710 :
711 1 : char** papszPrj = CSLLoad( poDS->osPrjFilename );
712 :
713 : CPLDebug( "LCP", "Loaded SRS from %s",
714 1 : poDS->osPrjFilename.c_str() );
715 :
716 1 : if( oSRS.importFromESRI( papszPrj ) == OGRERR_NONE )
717 : {
718 1 : oSRS.exportToWkt( &(poDS->pszProjection) );
719 : }
720 :
721 1 : CSLDestroy(papszPrj);
722 : }
723 :
724 2 : CPLFree( pszDirname );
725 2 : CPLFree( pszBasename );
726 :
727 : /* -------------------------------------------------------------------- */
728 : /* Initialize any PAM information. */
729 : /* -------------------------------------------------------------------- */
730 2 : poDS->SetDescription( poOpenInfo->pszFilename );
731 2 : poDS->TryLoadXML();
732 :
733 2 : CPLFree(pszList);
734 :
735 2 : return( poDS );
736 : }
737 :
738 : /************************************************************************/
739 : /* GetProjectionRef() */
740 : /************************************************************************/
741 :
742 1 : const char *LCPDataset::GetProjectionRef()
743 :
744 : {
745 1 : return pszProjection;
746 : }
747 :
748 : /************************************************************************/
749 : /* GDALRegister_LCP() */
750 : /************************************************************************/
751 :
752 338 : void GDALRegister_LCP()
753 :
754 : {
755 : GDALDriver *poDriver;
756 :
757 338 : if( GDALGetDriverByName( "LCP" ) == NULL )
758 : {
759 336 : poDriver = new GDALDriver();
760 :
761 336 : poDriver->SetDescription( "LCP" );
762 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
763 336 : "FARSITE v.4 Landscape File (.lcp)" );
764 336 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "lcp" );
765 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
766 336 : "frmt_lcp.html" );
767 :
768 336 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
769 :
770 336 : poDriver->pfnOpen = LCPDataset::Open;
771 336 : poDriver->pfnIdentify = LCPDataset::Identify;
772 :
773 336 : GetGDALDriverManager()->RegisterDriver( poDriver );
774 : }
775 338 : }
|