1 : /******************************************************************************
2 : * $Id: bagdataset.cpp 19430 2010-04-17 00:49:53Z warmerdam $
3 : *
4 : * Project: Hierarchical Data Format Release 5 (HDF5)
5 : * Purpose: Read BAG datasets.
6 : * Author: Frank Warmerdam <warmerdam@pobox.com>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2009, 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 "gh5_convenience.h"
31 :
32 : #include "gdal_pam.h"
33 : #include "gdal_priv.h"
34 : #include "ogr_spatialref.h"
35 : #include "cpl_string.h"
36 :
37 : CPL_CVSID("$Id: bagdataset.cpp 19430 2010-04-17 00:49:53Z warmerdam $");
38 :
39 : CPL_C_START
40 : void GDALRegister_BAG(void);
41 : CPL_C_END
42 :
43 : OGRErr OGR_SRS_ImportFromISO19115( OGRSpatialReference *poThis,
44 : const char *pszISOXML );
45 :
46 : /************************************************************************/
47 : /* ==================================================================== */
48 : /* BAGDataset */
49 : /* ==================================================================== */
50 : /************************************************************************/
51 : class BAGDataset : public GDALPamDataset
52 : {
53 :
54 : friend class BAGRasterBand;
55 :
56 : hid_t hHDF5;
57 :
58 : char *pszProjection;
59 : double adfGeoTransform[6];
60 :
61 : void LoadMetadata();
62 :
63 : char *pszXMLMetadata;
64 : char *apszMDList[2];
65 :
66 : public:
67 : BAGDataset();
68 : ~BAGDataset();
69 :
70 : virtual CPLErr GetGeoTransform( double * );
71 : virtual const char *GetProjectionRef(void);
72 : virtual char **GetMetadata( const char * pszDomain = "" );
73 :
74 : static GDALDataset *Open( GDALOpenInfo * );
75 : static int Identify( GDALOpenInfo * );
76 : };
77 :
78 : /************************************************************************/
79 : /* ==================================================================== */
80 : /* BAGRasterBand */
81 : /* ==================================================================== */
82 : /************************************************************************/
83 : class BAGRasterBand : public GDALPamRasterBand
84 : {
85 : friend class BAGDataset;
86 :
87 : hid_t hDatasetID;
88 : hid_t native;
89 : hid_t dataspace;
90 :
91 : bool bMinMaxSet;
92 : double dfMinimum;
93 : double dfMaximum;
94 :
95 : public:
96 :
97 : BAGRasterBand( BAGDataset *, int );
98 : ~BAGRasterBand();
99 :
100 : bool Initialize( hid_t hDataset, const char *pszName );
101 :
102 : virtual CPLErr IReadBlock( int, int, void * );
103 : virtual double GetNoDataValue( int * );
104 :
105 : virtual double GetMinimum( int *pbSuccess = NULL );
106 : virtual double GetMaximum(int *pbSuccess = NULL );
107 : };
108 :
109 : /************************************************************************/
110 : /* BAGRasterBand() */
111 : /************************************************************************/
112 3 : BAGRasterBand::BAGRasterBand( BAGDataset *poDS, int nBand )
113 :
114 : {
115 3 : this->poDS = poDS;
116 3 : this->nBand = nBand;
117 :
118 3 : hDatasetID = -1;
119 3 : bMinMaxSet = false;
120 3 : }
121 :
122 : /************************************************************************/
123 : /* ~BAGRasterBand() */
124 : /************************************************************************/
125 :
126 3 : BAGRasterBand::~BAGRasterBand()
127 : {
128 3 : }
129 :
130 : /************************************************************************/
131 : /* Initialize() */
132 : /************************************************************************/
133 :
134 3 : bool BAGRasterBand::Initialize( hid_t hDatasetID, const char *pszName )
135 :
136 : {
137 3 : SetDescription( pszName );
138 :
139 3 : this->hDatasetID = hDatasetID;
140 :
141 3 : hid_t datatype = H5Dget_type( hDatasetID );
142 3 : dataspace = H5Dget_space( hDatasetID );
143 3 : hid_t n_dims = H5Sget_simple_extent_ndims( dataspace );
144 3 : native = H5Tget_native_type( datatype, H5T_DIR_ASCEND );
145 : hsize_t dims[3], maxdims[3];
146 :
147 3 : eDataType = GH5_GetDataType( native );
148 :
149 3 : if( n_dims == 2 )
150 : {
151 3 : H5Sget_simple_extent_dims( dataspace, dims, maxdims );
152 :
153 3 : nRasterXSize = dims[1];
154 3 : nRasterYSize = dims[0];
155 : }
156 : else
157 : {
158 : CPLError( CE_Failure, CPLE_AppDefined,
159 0 : "Dataset not of rank 2." );
160 0 : return false;
161 : }
162 :
163 3 : nBlockXSize = nRasterXSize;
164 3 : nBlockYSize = 1;
165 :
166 : /* -------------------------------------------------------------------- */
167 : /* Check for chunksize, and use it as blocksize for optimized */
168 : /* reading. */
169 : /* -------------------------------------------------------------------- */
170 3 : hid_t listid = H5Dget_create_plist( hDatasetID );
171 3 : if (listid>0)
172 : {
173 3 : if(H5Pget_layout(listid) == H5D_CHUNKED)
174 : {
175 : hsize_t panChunkDims[3];
176 0 : int nDimSize = H5Pget_chunk(listid, 3, panChunkDims);
177 0 : nBlockXSize = panChunkDims[nDimSize-1];
178 0 : nBlockYSize = panChunkDims[nDimSize-2];
179 : }
180 3 : H5Pclose(listid);
181 : }
182 :
183 : /* -------------------------------------------------------------------- */
184 : /* Load min/max information. */
185 : /* -------------------------------------------------------------------- */
186 3 : if( EQUAL(pszName,"elevation")
187 : && GH5_FetchAttribute( hDatasetID, "Maximum Elevation Value",
188 : dfMaximum )
189 : && GH5_FetchAttribute( hDatasetID, "Minimum Elevation Value",
190 : dfMinimum ) )
191 1 : bMinMaxSet = true;
192 2 : else if( EQUAL(pszName,"uncertainty")
193 : && GH5_FetchAttribute( hDatasetID, "Maximum Uncertainty Value",
194 : dfMaximum )
195 : && GH5_FetchAttribute( hDatasetID, "Minimum Uncertainty Value",
196 : dfMinimum ) )
197 1 : bMinMaxSet = true;
198 1 : else if( EQUAL(pszName,"nominal_elevation")
199 : && GH5_FetchAttribute( hDatasetID, "max_value",
200 : dfMaximum )
201 : && GH5_FetchAttribute( hDatasetID, "min_value",
202 : dfMinimum ) )
203 1 : bMinMaxSet = true;
204 :
205 3 : return true;
206 : }
207 :
208 : /************************************************************************/
209 : /* GetMinimum() */
210 : /************************************************************************/
211 :
212 1 : double BAGRasterBand::GetMinimum( int * pbSuccess )
213 :
214 : {
215 1 : if( bMinMaxSet )
216 : {
217 1 : if( pbSuccess )
218 1 : *pbSuccess = TRUE;
219 1 : return dfMinimum;
220 : }
221 : else
222 0 : return GDALRasterBand::GetMinimum( pbSuccess );
223 : }
224 :
225 : /************************************************************************/
226 : /* GetMaximum() */
227 : /************************************************************************/
228 :
229 1 : double BAGRasterBand::GetMaximum( int * pbSuccess )
230 :
231 : {
232 1 : if( bMinMaxSet )
233 : {
234 1 : if( pbSuccess )
235 1 : *pbSuccess = TRUE;
236 1 : return dfMaximum;
237 : }
238 : else
239 0 : return GDALRasterBand::GetMaximum( pbSuccess );
240 : }
241 :
242 : /************************************************************************/
243 : /* GetNoDataValue() */
244 : /************************************************************************/
245 1 : double BAGRasterBand::GetNoDataValue( int * pbSuccess )
246 :
247 : {
248 1 : if( pbSuccess )
249 1 : *pbSuccess = TRUE;
250 :
251 1 : if( EQUAL(GetDescription(),"elevation") )
252 1 : return 1000000.0;
253 0 : else if( EQUAL(GetDescription(),"uncertainty") )
254 0 : return 0.0;
255 0 : else if( EQUAL(GetDescription(),"nominal_elevation") )
256 0 : return 1000000.0;
257 : else
258 0 : return GDALPamRasterBand::GetNoDataValue( pbSuccess );
259 : }
260 :
261 : /************************************************************************/
262 : /* IReadBlock() */
263 : /************************************************************************/
264 : CPLErr BAGRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
265 30 : void * pImage )
266 : {
267 : herr_t status;
268 : hsize_t count[3];
269 : H5OFFSET_TYPE offset[3];
270 : hid_t memspace;
271 : hsize_t col_dims[3];
272 30 : hsize_t rank = 2;
273 :
274 30 : offset[0] = nRasterYSize - nBlockYOff*nBlockYSize - 1;
275 30 : offset[1] = nBlockXOff*nBlockXSize;
276 30 : count[0] = nBlockYSize;
277 30 : count[1] = nBlockXSize;
278 :
279 : /* -------------------------------------------------------------------- */
280 : /* Select block from file space */
281 : /* -------------------------------------------------------------------- */
282 : status = H5Sselect_hyperslab( dataspace,
283 : H5S_SELECT_SET,
284 : offset, NULL,
285 30 : count, NULL );
286 :
287 : /* -------------------------------------------------------------------- */
288 : /* Create memory space to receive the data */
289 : /* -------------------------------------------------------------------- */
290 30 : col_dims[0]=nBlockYSize;
291 30 : col_dims[1]=nBlockXSize;
292 30 : memspace = H5Screate_simple( rank, col_dims, NULL );
293 30 : H5OFFSET_TYPE mem_offset[3] = {0, 0, 0};
294 : status = H5Sselect_hyperslab(memspace,
295 : H5S_SELECT_SET,
296 : mem_offset, NULL,
297 30 : count, NULL);
298 :
299 : status = H5Dread ( hDatasetID,
300 : native,
301 : memspace,
302 : dataspace,
303 : H5P_DEFAULT,
304 30 : pImage );
305 :
306 30 : return CE_None;
307 : }
308 :
309 : /************************************************************************/
310 : /* ==================================================================== */
311 : /* BAGDataset */
312 : /* ==================================================================== */
313 : /************************************************************************/
314 :
315 : /************************************************************************/
316 : /* BAGDataset() */
317 : /************************************************************************/
318 :
319 1 : BAGDataset::BAGDataset()
320 : {
321 1 : hHDF5 = -1;
322 1 : pszXMLMetadata = NULL;
323 1 : pszProjection = NULL;
324 :
325 1 : adfGeoTransform[0] = 0.0;
326 1 : adfGeoTransform[1] = 1.0;
327 1 : adfGeoTransform[2] = 0.0;
328 1 : adfGeoTransform[3] = 0.0;
329 1 : adfGeoTransform[4] = 0.0;
330 1 : adfGeoTransform[5] = 1.0;
331 1 : }
332 :
333 : /************************************************************************/
334 : /* ~BAGDataset() */
335 : /************************************************************************/
336 1 : BAGDataset::~BAGDataset( )
337 : {
338 1 : FlushCache();
339 :
340 1 : if( hHDF5 >= 0 )
341 1 : H5Fclose( hHDF5 );
342 :
343 1 : CPLFree( pszXMLMetadata );
344 1 : CPLFree( pszProjection );
345 1 : }
346 :
347 : /************************************************************************/
348 : /* Identify() */
349 : /************************************************************************/
350 :
351 9583 : int BAGDataset::Identify( GDALOpenInfo * poOpenInfo )
352 :
353 : {
354 : /* -------------------------------------------------------------------- */
355 : /* Is it an HDF5 file? */
356 : /* -------------------------------------------------------------------- */
357 : static const char achSignature[] = "\211HDF\r\n\032\n";
358 :
359 9583 : if( poOpenInfo->pabyHeader == NULL
360 : || memcmp(poOpenInfo->pabyHeader,achSignature,8) != 0 )
361 9581 : return FALSE;
362 :
363 : /* -------------------------------------------------------------------- */
364 : /* Does it have the extension .bag? */
365 : /* -------------------------------------------------------------------- */
366 2 : if( !EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"bag") )
367 1 : return FALSE;
368 :
369 1 : return TRUE;
370 : }
371 :
372 : /************************************************************************/
373 : /* Open() */
374 : /************************************************************************/
375 :
376 1338 : GDALDataset *BAGDataset::Open( GDALOpenInfo * poOpenInfo )
377 :
378 : {
379 : /* -------------------------------------------------------------------- */
380 : /* Confirm that this appears to be a BAG file. */
381 : /* -------------------------------------------------------------------- */
382 1338 : if( !Identify( poOpenInfo ) )
383 1337 : return NULL;
384 :
385 : /* -------------------------------------------------------------------- */
386 : /* Confirm the requested access is supported. */
387 : /* -------------------------------------------------------------------- */
388 1 : if( poOpenInfo->eAccess == GA_Update )
389 : {
390 : CPLError( CE_Failure, CPLE_NotSupported,
391 0 : "The BAG driver does not support update access." );
392 0 : return NULL;
393 : }
394 :
395 : /* -------------------------------------------------------------------- */
396 : /* Open the file as an HDF5 file. */
397 : /* -------------------------------------------------------------------- */
398 : hid_t hHDF5 = H5Fopen( poOpenInfo->pszFilename,
399 1 : H5F_ACC_RDONLY, H5P_DEFAULT );
400 :
401 1 : if( hHDF5 < 0 )
402 0 : return NULL;
403 :
404 : /* -------------------------------------------------------------------- */
405 : /* Confirm it is a BAG dataset by checking for the */
406 : /* BAG_Root/Bag Version attribute. */
407 : /* -------------------------------------------------------------------- */
408 1 : hid_t hBagRoot = H5Gopen( hHDF5, "/BAG_root" );
409 1 : hid_t hVersion = -1;
410 :
411 1 : if( hBagRoot >= 0 )
412 1 : hVersion = H5Aopen_name( hBagRoot, "Bag Version" );
413 :
414 1 : if( hVersion < 0 )
415 : {
416 0 : H5Fclose( hHDF5 );
417 0 : return NULL;
418 : }
419 1 : H5Aclose( hVersion );
420 :
421 : /* -------------------------------------------------------------------- */
422 : /* Create a corresponding dataset. */
423 : /* -------------------------------------------------------------------- */
424 1 : BAGDataset *poDS = new BAGDataset();
425 :
426 1 : poDS->hHDF5 = hHDF5;
427 :
428 : /* -------------------------------------------------------------------- */
429 : /* Extract version as metadata. */
430 : /* -------------------------------------------------------------------- */
431 1 : CPLString osVersion;
432 :
433 2 : if( GH5_FetchAttribute( hBagRoot, "Bag Version", osVersion ) )
434 1 : poDS->SetMetadataItem( "BagVersion", osVersion );
435 :
436 : /* -------------------------------------------------------------------- */
437 : /* Fetch the elevation dataset and attach as a band. */
438 : /* -------------------------------------------------------------------- */
439 1 : int nNextBand = 1;
440 1 : hid_t hElevation = H5Dopen( hHDF5, "/BAG_root/elevation" );
441 1 : if( hElevation < 0 )
442 : {
443 0 : delete poDS;
444 1 : return NULL;
445 : }
446 :
447 1 : BAGRasterBand *poElevBand = new BAGRasterBand( poDS, nNextBand );
448 :
449 2 : if( !poElevBand->Initialize( hElevation, "elevation" ) )
450 : {
451 0 : delete poElevBand;
452 0 : delete poDS;
453 0 : return NULL;
454 : }
455 :
456 1 : poDS->nRasterXSize = poElevBand->nRasterXSize;
457 1 : poDS->nRasterYSize = poElevBand->nRasterYSize;
458 :
459 1 : poDS->SetBand( nNextBand++, poElevBand );
460 :
461 : /* -------------------------------------------------------------------- */
462 : /* Try to do the same for the uncertainty band. */
463 : /* -------------------------------------------------------------------- */
464 1 : hid_t hUncertainty = H5Dopen( hHDF5, "/BAG_root/uncertainty" );
465 1 : BAGRasterBand *poUBand = new BAGRasterBand( poDS, nNextBand );
466 :
467 2 : if( hUncertainty >= 0 && poUBand->Initialize( hUncertainty, "uncertainty") )
468 : {
469 1 : poDS->SetBand( nNextBand++, poUBand );
470 : }
471 : else
472 0 : delete poUBand;
473 :
474 : /* -------------------------------------------------------------------- */
475 : /* Try to do the same for the uncertainty band. */
476 : /* -------------------------------------------------------------------- */
477 1 : hid_t hNominal = -1;
478 :
479 1 : H5E_BEGIN_TRY {
480 1 : hNominal = H5Dopen( hHDF5, "/BAG_root/nominal_elevation" );
481 1 : } H5E_END_TRY;
482 :
483 1 : BAGRasterBand *poNBand = new BAGRasterBand( poDS, nNextBand );
484 2 : if( hNominal >= 0 && poNBand->Initialize( hNominal,
485 : "nominal_elevation" ) )
486 : {
487 1 : poDS->SetBand( nNextBand++, poNBand );
488 : }
489 : else
490 0 : delete poNBand;
491 :
492 : /* -------------------------------------------------------------------- */
493 : /* Load the XML metadata. */
494 : /* -------------------------------------------------------------------- */
495 1 : poDS->LoadMetadata();
496 :
497 : /* -------------------------------------------------------------------- */
498 : /* Setup/check for pam .aux.xml. */
499 : /* -------------------------------------------------------------------- */
500 1 : poDS->SetDescription( poOpenInfo->pszFilename );
501 1 : poDS->TryLoadXML();
502 :
503 : /* -------------------------------------------------------------------- */
504 : /* Setup overviews. */
505 : /* -------------------------------------------------------------------- */
506 1 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
507 :
508 1 : return( poDS );
509 : }
510 :
511 : /************************************************************************/
512 : /* LoadMetadata() */
513 : /************************************************************************/
514 :
515 1 : void BAGDataset::LoadMetadata()
516 :
517 : {
518 : /* -------------------------------------------------------------------- */
519 : /* Load the metadata from the file. */
520 : /* -------------------------------------------------------------------- */
521 1 : hid_t hMDDS = H5Dopen( hHDF5, "/BAG_root/metadata" );
522 1 : hid_t datatype = H5Dget_type( hMDDS );
523 1 : hid_t dataspace = H5Dget_space( hMDDS );
524 1 : hid_t native = H5Tget_native_type( datatype, H5T_DIR_ASCEND );
525 : hsize_t dims[3], maxdims[3];
526 :
527 1 : H5Sget_simple_extent_dims( dataspace, dims, maxdims );
528 :
529 1 : pszXMLMetadata = (char *) CPLCalloc(dims[0]+1,1);
530 :
531 1 : H5Dread( hMDDS, native, H5S_ALL, dataspace, H5P_DEFAULT, pszXMLMetadata );
532 :
533 1 : H5Dclose( hMDDS );
534 :
535 1 : if( strlen(pszXMLMetadata) == 0 )
536 0 : return;
537 :
538 : /* -------------------------------------------------------------------- */
539 : /* Try to get the geotransform. */
540 : /* -------------------------------------------------------------------- */
541 1 : CPLXMLNode *psRoot = CPLParseXMLString( pszXMLMetadata );
542 :
543 1 : if( psRoot == NULL )
544 0 : return;
545 :
546 1 : CPLStripXMLNamespace( psRoot, NULL, TRUE );
547 :
548 1 : CPLXMLNode *psGeo = CPLSearchXMLNode( psRoot, "=MD_Georectified" );
549 :
550 1 : if( psGeo != NULL )
551 : {
552 : char **papszCornerTokens =
553 : CSLTokenizeStringComplex(
554 : CPLGetXMLValue( psGeo, "cornerPoints.Point.coordinates", "" ),
555 1 : " ,", FALSE, FALSE );
556 :
557 1 : if( CSLCount(papszCornerTokens ) == 4 )
558 : {
559 1 : double dfLLX = atof( papszCornerTokens[0] );
560 1 : double dfLLY = atof( papszCornerTokens[1] );
561 1 : double dfURX = atof( papszCornerTokens[2] );
562 1 : double dfURY = atof( papszCornerTokens[3] );
563 :
564 1 : adfGeoTransform[0] = dfLLX;
565 1 : adfGeoTransform[1] = (dfURX - dfLLX) / (GetRasterXSize()-1);
566 1 : adfGeoTransform[3] = dfURY;
567 1 : adfGeoTransform[5] = (dfLLY - dfURY) / (GetRasterYSize()-1);
568 :
569 1 : adfGeoTransform[0] -= adfGeoTransform[1] * 0.5;
570 1 : adfGeoTransform[3] -= adfGeoTransform[5] * 0.5;
571 : }
572 1 : CSLDestroy( papszCornerTokens );
573 : }
574 :
575 1 : CPLDestroyXMLNode( psRoot );
576 :
577 : /* -------------------------------------------------------------------- */
578 : /* Try to get the coordinate system. */
579 : /* -------------------------------------------------------------------- */
580 1 : OGRSpatialReference oSRS;
581 :
582 1 : if( OGR_SRS_ImportFromISO19115( &oSRS, pszXMLMetadata )
583 : == OGRERR_NONE )
584 : {
585 0 : oSRS.exportToWkt( &pszProjection );
586 1 : }
587 : }
588 :
589 : /************************************************************************/
590 : /* GetGeoTransform() */
591 : /************************************************************************/
592 :
593 0 : CPLErr BAGDataset::GetGeoTransform( double *padfGeoTransform )
594 :
595 : {
596 0 : if( adfGeoTransform[0] != 0.0 || adfGeoTransform[3] != 0.0 )
597 : {
598 0 : memcpy( padfGeoTransform, adfGeoTransform, sizeof(double)*6 );
599 0 : return CE_None;
600 : }
601 : else
602 0 : return GDALPamDataset::GetGeoTransform( padfGeoTransform );
603 : }
604 :
605 : /************************************************************************/
606 : /* GetProjectionRef() */
607 : /************************************************************************/
608 :
609 0 : const char *BAGDataset::GetProjectionRef()
610 :
611 : {
612 0 : if( pszProjection )
613 0 : return pszProjection;
614 : else
615 0 : return GDALPamDataset::GetProjectionRef();
616 : }
617 :
618 : /************************************************************************/
619 : /* GetMetadata() */
620 : /************************************************************************/
621 :
622 0 : char **BAGDataset::GetMetadata( const char *pszDomain )
623 :
624 : {
625 0 : if( pszDomain != NULL && EQUAL(pszDomain,"xml:BAG") )
626 : {
627 0 : apszMDList[0] = pszXMLMetadata;
628 0 : apszMDList[1] = NULL;
629 :
630 0 : return apszMDList;
631 : }
632 : else
633 0 : return GDALPamDataset::GetMetadata( pszDomain );
634 : }
635 :
636 : /************************************************************************/
637 : /* GDALRegister_BAG() */
638 : /************************************************************************/
639 409 : void GDALRegister_BAG( )
640 :
641 : {
642 : GDALDriver *poDriver;
643 :
644 409 : if (! GDAL_CHECK_VERSION("BAG"))
645 0 : return;
646 :
647 409 : if( GDALGetDriverByName( "BAG" ) == NULL )
648 : {
649 392 : poDriver = new GDALDriver();
650 :
651 392 : poDriver->SetDescription( "BAG" );
652 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
653 392 : "Bathymetry Attributed Grid" );
654 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
655 392 : "frmt_bag.html" );
656 392 : poDriver->pfnOpen = BAGDataset::Open;
657 392 : poDriver->pfnIdentify = BAGDataset::Identify;
658 :
659 392 : GetGDALDriverManager( )->RegisterDriver( poDriver );
660 : }
661 : }
|