1 : /******************************************************************************
2 : * $Id $
3 : *
4 : * Project: SPOT Dimap Driver
5 : * Purpose: Implementation of SPOT Dimap driver.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : * Docs: http://www.spotimage.fr/dimap/spec/documentation/refdoc.htm
9 : *
10 : ******************************************************************************
11 : * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #include "gdal_pam.h"
33 : #include "cpl_minixml.h"
34 : #include "ogr_spatialref.h"
35 : #include "gdal_proxy.h"
36 :
37 : CPL_CVSID("$Id: dimapdataset.cpp 23850 2012-01-31 21:12:50Z rouault $");
38 :
39 : CPL_C_START
40 : void GDALRegister_DIMAP(void);
41 : CPL_C_END
42 :
43 : /************************************************************************/
44 : /* ==================================================================== */
45 : /* DIMAPDataset */
46 : /* ==================================================================== */
47 : /************************************************************************/
48 :
49 : class DIMAPDataset : public GDALPamDataset
50 : {
51 : CPLXMLNode *psProduct;
52 :
53 : CPLXMLNode *psProductDim; /* DIMAP2, DIM_<product_id>.XML */
54 : CPLXMLNode *psProductStrip; /* DIMAP2, STRIP_<product_id>.XML */
55 :
56 : GDALDataset *poImageDS;
57 :
58 : int nGCPCount;
59 : GDAL_GCP *pasGCPList;
60 : char *pszGCPProjection;
61 :
62 : CPLString osProjection;
63 :
64 : int bHaveGeoTransform;
65 : double adfGeoTransform[6];
66 :
67 : CPLString osMDFilename;
68 : CPLString osImageDSFilename;
69 : int nProductVersion;
70 :
71 : char **papszXMLDimapMetadata;
72 :
73 : protected:
74 : virtual int CloseDependentDatasets();
75 :
76 : int ReadImageInformation();
77 : int ReadImageInformation2(); /* DIMAP 2 */
78 :
79 : void SetMetadata(CPLXMLNode *psProduct, const char *apszMetadataTranslation[]);
80 : public:
81 : DIMAPDataset();
82 : ~DIMAPDataset();
83 :
84 : virtual const char *GetProjectionRef(void);
85 : virtual CPLErr GetGeoTransform( double * );
86 : virtual int GetGCPCount();
87 : virtual const char *GetGCPProjection();
88 : virtual const GDAL_GCP *GetGCPs();
89 : virtual char **GetMetadata( const char *pszDomain );
90 : virtual char **GetFileList(void);
91 :
92 : static int Identify( GDALOpenInfo * );
93 : static GDALDataset *Open( GDALOpenInfo * );
94 :
95 : CPLXMLNode *GetProduct() { return psProduct; }
96 : };
97 :
98 : /************************************************************************/
99 : /* ==================================================================== */
100 : /* DIMAPWrapperRasterBand */
101 : /* ==================================================================== */
102 : /************************************************************************/
103 : class DIMAPWrapperRasterBand : public GDALProxyRasterBand
104 : {
105 : GDALRasterBand* poBaseBand;
106 :
107 : protected:
108 224 : virtual GDALRasterBand* RefUnderlyingRasterBand() { return poBaseBand; }
109 :
110 : public:
111 4 : DIMAPWrapperRasterBand( GDALRasterBand* poBaseBand )
112 4 : {
113 4 : this->poBaseBand = poBaseBand;
114 4 : eDataType = poBaseBand->GetRasterDataType();
115 4 : poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
116 4 : }
117 4 : ~DIMAPWrapperRasterBand() {}
118 : };
119 : /************************************************************************/
120 : /* ==================================================================== */
121 : /* DIMAPDataset */
122 : /* ==================================================================== */
123 : /************************************************************************/
124 :
125 : /************************************************************************/
126 : /* DIMAPDataset() */
127 : /************************************************************************/
128 :
129 4 : DIMAPDataset::DIMAPDataset()
130 : {
131 4 : psProduct = NULL;
132 :
133 4 : psProductDim = NULL;
134 4 : psProductStrip = NULL;
135 :
136 4 : nGCPCount = 0;
137 4 : pasGCPList = NULL;
138 4 : pszGCPProjection = CPLStrdup("");
139 :
140 4 : poImageDS = NULL;
141 4 : bHaveGeoTransform = FALSE;
142 :
143 4 : nProductVersion = 1;
144 :
145 4 : papszXMLDimapMetadata = NULL;
146 4 : }
147 :
148 : /************************************************************************/
149 : /* ~DIMAPDataset() */
150 : /************************************************************************/
151 :
152 4 : DIMAPDataset::~DIMAPDataset()
153 :
154 : {
155 4 : FlushCache();
156 :
157 4 : CPLDestroyXMLNode( psProduct );
158 :
159 4 : if( nProductVersion == 2 )
160 : {
161 0 : CPLDestroyXMLNode( psProductDim );
162 0 : CPLDestroyXMLNode( psProductStrip );
163 : }
164 :
165 4 : CPLFree( pszGCPProjection );
166 4 : if( nGCPCount > 0 )
167 : {
168 4 : GDALDeinitGCPs( nGCPCount, pasGCPList );
169 4 : CPLFree( pasGCPList );
170 : }
171 :
172 4 : CSLDestroy(papszXMLDimapMetadata);
173 :
174 4 : CloseDependentDatasets();
175 4 : }
176 :
177 :
178 : /************************************************************************/
179 : /* CloseDependentDatasets() */
180 : /************************************************************************/
181 :
182 4 : int DIMAPDataset::CloseDependentDatasets()
183 : {
184 4 : int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets();
185 :
186 4 : if( poImageDS != NULL )
187 : {
188 4 : delete poImageDS;
189 4 : poImageDS = NULL;
190 4 : bHasDroppedRef = TRUE;
191 : }
192 :
193 : /* -------------------------------------------------------------------- */
194 : /* Disconnect the bands so our destructor doesn't try and */
195 : /* delete them since they really belonged to poImageDS. */
196 : /* -------------------------------------------------------------------- */
197 : int iBand;
198 8 : for( iBand = 0; iBand < nBands; iBand++ )
199 4 : delete papoBands[iBand];
200 4 : nBands = 0;
201 :
202 4 : return bHasDroppedRef;
203 : }
204 :
205 : /************************************************************************/
206 : /* GetMetadata() */
207 : /* */
208 : /* We implement special support for fetching the full product */
209 : /* metadata as xml. */
210 : /************************************************************************/
211 :
212 4 : char **DIMAPDataset::GetMetadata( const char *pszDomain )
213 :
214 : {
215 4 : if( pszDomain && EQUAL(pszDomain,"xml:dimap") )
216 : {
217 0 : if (papszXMLDimapMetadata == NULL)
218 : {
219 0 : papszXMLDimapMetadata = (char **) CPLCalloc(sizeof(char*),2);
220 0 : papszXMLDimapMetadata[0] = CPLSerializeXMLTree( psProduct );
221 : }
222 0 : return papszXMLDimapMetadata;
223 : }
224 : else
225 4 : return GDALPamDataset::GetMetadata( pszDomain );
226 : }
227 :
228 : /************************************************************************/
229 : /* GetProjectionRef() */
230 : /************************************************************************/
231 :
232 0 : const char *DIMAPDataset::GetProjectionRef()
233 :
234 : {
235 0 : if( strlen(osProjection) > 0 )
236 0 : return osProjection;
237 : else
238 0 : return GDALPamDataset::GetProjectionRef();
239 : }
240 :
241 : /************************************************************************/
242 : /* GetGeoTransform() */
243 : /************************************************************************/
244 :
245 0 : CPLErr DIMAPDataset::GetGeoTransform( double *padfGeoTransform )
246 :
247 : {
248 0 : if( bHaveGeoTransform )
249 : {
250 0 : memcpy( padfGeoTransform, adfGeoTransform, sizeof(double)*6 );
251 0 : return CE_None;
252 : }
253 : else
254 0 : return GDALPamDataset::GetGeoTransform( padfGeoTransform );
255 : }
256 :
257 : /************************************************************************/
258 : /* GetFileList() */
259 : /************************************************************************/
260 :
261 0 : char **DIMAPDataset::GetFileList()
262 :
263 : {
264 0 : char **papszFileList = GDALPamDataset::GetFileList();
265 0 : char **papszImageFiles = poImageDS->GetFileList();
266 :
267 0 : papszFileList = CSLInsertStrings( papszFileList, -1, papszImageFiles );
268 :
269 0 : CSLDestroy( papszImageFiles );
270 :
271 0 : return papszFileList;
272 : }
273 :
274 : /************************************************************************/
275 : /* Identify() */
276 : /************************************************************************/
277 :
278 25708 : int DIMAPDataset::Identify( GDALOpenInfo * poOpenInfo )
279 :
280 : {
281 25708 : if( poOpenInfo->nHeaderBytes >= 100 )
282 : {
283 3196 : if( ( strstr((const char *) poOpenInfo->pabyHeader,
284 : "<Dimap_Document" ) == NULL ) &&
285 : ( strstr((const char *) poOpenInfo->pabyHeader,
286 : "<PHR_DIMAP_Document" ) == NULL ) )
287 3192 : return FALSE;
288 : else
289 4 : return TRUE;
290 : }
291 22512 : else if( poOpenInfo->bIsDirectory )
292 : {
293 : VSIStatBufL sStat;
294 :
295 : /* DIMAP file */
296 : CPLString osMDFilename =
297 84 : CPLFormCIFilename( poOpenInfo->pszFilename, "METADATA.DIM", NULL );
298 :
299 84 : if( VSIStatL( osMDFilename, &sStat ) == 0 )
300 : {
301 : /* Make sure this is really a Dimap format */
302 0 : GDALOpenInfo oOpenInfo( osMDFilename, GA_ReadOnly, NULL );
303 0 : if( oOpenInfo.nHeaderBytes >= 100 )
304 : {
305 0 : if( strstr((const char *) oOpenInfo.pabyHeader,
306 : "<Dimap_Document" ) == NULL )
307 0 : return FALSE;
308 : else
309 0 : return TRUE;
310 0 : }
311 : }
312 : else
313 : {
314 : /* DIMAP 2 file */
315 : osMDFilename =
316 84 : CPLFormCIFilename( poOpenInfo->pszFilename, "VOL_PHR.XML", NULL );
317 :
318 84 : if( VSIStatL( osMDFilename, &sStat ) == 0 )
319 0 : return TRUE;
320 : else
321 84 : return FALSE;
322 0 : }
323 : }
324 :
325 22428 : return FALSE;
326 : }
327 :
328 : /************************************************************************/
329 : /* Open() */
330 : /************************************************************************/
331 :
332 6796 : GDALDataset *DIMAPDataset::Open( GDALOpenInfo * poOpenInfo )
333 :
334 : {
335 6796 : int nProductVersion = 1;
336 :
337 6796 : if( !Identify( poOpenInfo ) )
338 6792 : return NULL;
339 :
340 : /* -------------------------------------------------------------------- */
341 : /* Confirm the requested access is supported. */
342 : /* -------------------------------------------------------------------- */
343 4 : if( poOpenInfo->eAccess == GA_Update )
344 : {
345 : CPLError( CE_Failure, CPLE_NotSupported,
346 : "The DIMAP driver does not support update access to existing"
347 0 : " datasets.\n" );
348 0 : return NULL;
349 : }
350 : /* -------------------------------------------------------------------- */
351 : /* Get the metadata filename. */
352 : /* -------------------------------------------------------------------- */
353 4 : CPLString osMDFilename, osImageDSFilename;;
354 :
355 4 : if( poOpenInfo->bIsDirectory )
356 : {
357 : VSIStatBufL sStat;
358 :
359 : osMDFilename =
360 0 : CPLFormCIFilename( poOpenInfo->pszFilename, "METADATA.DIM", NULL );
361 :
362 : /* DIMAP2 */
363 0 : if( VSIStatL( osMDFilename, &sStat ) != 0 )
364 : osMDFilename =
365 0 : CPLFormCIFilename( poOpenInfo->pszFilename, "VOL_PHR.XML", NULL );
366 : }
367 : else
368 4 : osMDFilename = poOpenInfo->pszFilename;
369 :
370 : /* -------------------------------------------------------------------- */
371 : /* Ingest the xml file. */
372 : /* -------------------------------------------------------------------- */
373 : CPLXMLNode *psProduct, *psImageAttributes;
374 4 : CPLXMLNode *psProductDim = NULL, *psProductStrip = NULL;
375 :
376 : float nMetadataFormatVersion;
377 :
378 4 : psProduct = CPLParseXMLFile( osMDFilename );
379 4 : if( psProduct == NULL )
380 0 : return NULL;
381 :
382 4 : CPLXMLNode *psDoc = CPLGetXMLNode( psProduct, "=Dimap_Document" );
383 4 : if( !psDoc )
384 0 : psDoc = CPLGetXMLNode( psProduct, "=PHR_DIMAP_Document" );
385 :
386 : /* We check the for the tag Metadata_Identification.METADATA_FORMAT.
387 : * The metadata will be set to 2.0 for DIMAP2 */
388 : nMetadataFormatVersion = atof( CPLGetXMLValue(CPLGetXMLNode(psDoc, "Metadata_Identification.METADATA_FORMAT"),
389 4 : "version", "1") );
390 4 : if( nMetadataFormatVersion >= 2.0 )
391 : {
392 0 : nProductVersion = 2;
393 : }
394 :
395 : /* Check needed information for the DIMAP format */
396 4 : if (nProductVersion == 1)
397 : {
398 4 : psImageAttributes = CPLGetXMLNode( psDoc, "Raster_Dimensions" );
399 4 : if( psImageAttributes == NULL )
400 : {
401 : CPLError( CE_Failure, CPLE_OpenFailed,
402 0 : "Failed to find <Raster_Dimensions> in document." );
403 0 : return NULL;
404 : }
405 : }
406 : else /* DIMAP2 */
407 : {
408 : /* Verify the presence of the DIMAP product file */
409 0 : CPLXMLNode *psDatasetComponents = CPLGetXMLNode(psDoc, "Dataset_Content.Dataset_Components");
410 :
411 0 : if( psDatasetComponents == NULL )
412 : {
413 : CPLError( CE_Failure, CPLE_OpenFailed,
414 0 : "Failed to find <Dataset_Components> in document." );
415 0 : return NULL;
416 : }
417 :
418 0 : CPLString osDIMAPFilename;
419 0 : CPLXMLNode *psDatasetComponent = psDatasetComponents->psChild;
420 :
421 0 : for( ; psDatasetComponent != NULL; psDatasetComponent = psDatasetComponent->psNext )
422 : {
423 0 : const char* pszComponentType = CPLGetXMLValue(psDatasetComponent, "COMPONENT_TYPE","");
424 0 : if( strcmp(pszComponentType, "DIMAP") == 0 )
425 : {
426 : const char *pszHref = CPLGetXMLValue(
427 0 : psDatasetComponent, "COMPONENT_PATH.href", "" );
428 :
429 0 : if( strlen(pszHref) > 0 ) /* DIMAP product found*/
430 : {
431 0 : if( poOpenInfo->bIsDirectory )
432 : {
433 : osDIMAPFilename =
434 0 : CPLFormCIFilename( poOpenInfo->pszFilename, pszHref, NULL );
435 : }
436 : else
437 : {
438 0 : CPLString osPath = CPLGetPath(osMDFilename);
439 : osDIMAPFilename =
440 0 : CPLFormFilename( osPath, pszHref, NULL );
441 : }
442 :
443 : /* Data file might be specified there */
444 : const char *pszDataFileHref = CPLGetXMLValue(
445 0 : psDatasetComponent, "Data_Files.Data_File.DATA_FILE_PATH.href", "" );
446 :
447 0 : if( strlen(pszDataFileHref) > 0 )
448 : {
449 0 : CPLString osPath = CPLGetPath(osMDFilename);
450 : osImageDSFilename =
451 0 : CPLFormFilename( osPath, pszDataFileHref, NULL );
452 : }
453 :
454 0 : break;
455 : }
456 : }
457 : }
458 :
459 0 : psProductDim = CPLParseXMLFile( osDIMAPFilename );
460 0 : if( psProductDim == NULL )
461 0 : return NULL;
462 :
463 : /* We need the STRIP_<product_id>.XML file for a few metadata */
464 0 : CPLXMLNode *psDocDim = CPLGetXMLNode( psProductDim, "=Dimap_Document" );
465 0 : if( !psDocDim )
466 0 : psDocDim = CPLGetXMLNode( psProductDim, "=PHR_DIMAP_Document" );
467 :
468 0 : CPLXMLNode *psDatasetSources = CPLGetXMLNode(psDocDim, "Dataset_Sources");
469 0 : if( psDatasetSources != NULL )
470 : {
471 0 : CPLString osSTRIPFilename;
472 0 : CPLXMLNode *psDatasetSource = psDatasetSources->psChild;
473 :
474 0 : for( ; psDatasetSource != NULL; psDatasetSource = psDatasetSource->psNext )
475 : {
476 0 : const char* pszSourceType = CPLGetXMLValue(psDatasetSource, "SOURCE_TYPE","");
477 0 : if( strcmp(pszSourceType, "Strip_Source") == 0 )
478 : {
479 : const char *pszHref = CPLGetXMLValue(
480 0 : psDatasetSource, "Component.COMPONENT_PATH.href", "" );
481 :
482 0 : if( strlen(pszHref) > 0 ) /* STRIP product found*/
483 : {
484 0 : CPLString osPath = CPLGetPath(osDIMAPFilename);
485 : osSTRIPFilename =
486 0 : CPLFormFilename( osPath, pszHref, NULL );
487 :
488 0 : break;
489 : }
490 : }
491 : }
492 :
493 0 : psProductStrip = CPLParseXMLFile( osSTRIPFilename );
494 0 : if( psProductStrip == NULL )
495 0 : return NULL;
496 0 : }
497 : }
498 :
499 : /* -------------------------------------------------------------------- */
500 : /* Create the dataset. */
501 : /* -------------------------------------------------------------------- */
502 4 : DIMAPDataset *poDS = new DIMAPDataset();
503 :
504 4 : poDS->psProduct = psProduct;
505 4 : poDS->psProductDim = psProductDim;
506 4 : poDS->psProductStrip = psProductStrip;
507 4 : poDS->nProductVersion = nProductVersion;
508 4 : poDS->osMDFilename = osMDFilename;
509 4 : poDS->osImageDSFilename = osImageDSFilename;
510 :
511 4 : int res = TRUE;
512 4 : if( nProductVersion == 2 )
513 0 : res = poDS->ReadImageInformation2();
514 : else
515 4 : res = poDS->ReadImageInformation();
516 :
517 4 : if( res == FALSE )
518 : {
519 0 : delete poDS;
520 0 : return NULL;
521 : }
522 :
523 4 : return( poDS );
524 : }
525 :
526 :
527 : /************************************************************************/
528 : /* ReadImageInformation() DIMAP Version 1 */
529 : /************************************************************************/
530 :
531 4 : int DIMAPDataset::ReadImageInformation()
532 : {
533 4 : CPLXMLNode *psDoc = CPLGetXMLNode( psProduct, "=Dimap_Document" );
534 4 : if( !psDoc )
535 0 : psDoc = CPLGetXMLNode( psProduct, "=PHR_DIMAP_Document" );
536 :
537 4 : CPLXMLNode *psImageAttributes = CPLGetXMLNode( psDoc, "Raster_Dimensions" );
538 :
539 : /* -------------------------------------------------------------------- */
540 : /* Get overall image information. */
541 : /* -------------------------------------------------------------------- */
542 : #ifdef DEBUG
543 : int nBands =
544 4 : atoi(CPLGetXMLValue( psImageAttributes, "NBANDS", "-1" ));
545 : #endif
546 :
547 : nRasterXSize =
548 4 : atoi(CPLGetXMLValue( psImageAttributes, "NCOLS", "-1" ));
549 : nRasterYSize =
550 4 : atoi(CPLGetXMLValue( psImageAttributes, "NROWS", "-1" ));
551 :
552 : /* -------------------------------------------------------------------- */
553 : /* Get the name of the underlying file. */
554 : /* -------------------------------------------------------------------- */
555 :
556 : const char *pszHref = CPLGetXMLValue(
557 4 : psDoc, "Data_Access.Data_File.DATA_FILE_PATH.href", "" );
558 4 : CPLString osPath = CPLGetPath(osMDFilename);
559 : CPLString osImageFilename =
560 4 : CPLFormFilename( osPath, pszHref, NULL );
561 :
562 : /* -------------------------------------------------------------------- */
563 : /* Try and open the file. */
564 : /* -------------------------------------------------------------------- */
565 :
566 4 : poImageDS = (GDALDataset *) GDALOpen( osImageFilename, GA_ReadOnly );
567 4 : if( poImageDS == NULL )
568 : {
569 0 : return FALSE;
570 : }
571 :
572 : /* -------------------------------------------------------------------- */
573 : /* Attach the bands. */
574 : /* -------------------------------------------------------------------- */
575 : int iBand;
576 4 : CPLAssert( nBands == poImageDS->GetRasterCount() );
577 :
578 8 : for( iBand = 1; iBand <= poImageDS->GetRasterCount(); iBand++ )
579 4 : SetBand( iBand, new DIMAPWrapperRasterBand(poImageDS->GetRasterBand( iBand )) );
580 :
581 : /* -------------------------------------------------------------------- */
582 : /* Try to collect simple insertion point. */
583 : /* -------------------------------------------------------------------- */
584 : CPLXMLNode *psGeoLoc =
585 4 : CPLGetXMLNode( psDoc, "Geoposition.Geoposition_Insert" );
586 :
587 4 : if( psGeoLoc != NULL )
588 : {
589 0 : bHaveGeoTransform = TRUE;
590 0 : adfGeoTransform[0] = atof(CPLGetXMLValue(psGeoLoc,"ULXMAP","0"));
591 0 : adfGeoTransform[1] = atof(CPLGetXMLValue(psGeoLoc,"XDIM","0"));
592 0 : adfGeoTransform[2] = 0.0;
593 0 : adfGeoTransform[3] = atof(CPLGetXMLValue(psGeoLoc,"ULYMAP","0"));
594 0 : adfGeoTransform[4] = 0.0;
595 0 : adfGeoTransform[5] = -atof(CPLGetXMLValue(psGeoLoc,"YDIM","0"));
596 : }
597 :
598 : /* -------------------------------------------------------------------- */
599 : /* Collect GCPs. */
600 : /* -------------------------------------------------------------------- */
601 4 : psGeoLoc = CPLGetXMLNode( psDoc, "Geoposition.Geoposition_Points" );
602 :
603 4 : if( psGeoLoc != NULL )
604 : {
605 : CPLXMLNode *psNode;
606 :
607 : // count gcps.
608 4 : nGCPCount = 0;
609 20 : for( psNode = psGeoLoc->psChild; psNode != NULL;
610 : psNode = psNode->psNext )
611 : {
612 16 : if( EQUAL(psNode->pszValue,"Tie_Point") )
613 16 : nGCPCount++ ;
614 : }
615 :
616 : pasGCPList = (GDAL_GCP *)
617 4 : CPLCalloc(sizeof(GDAL_GCP),nGCPCount);
618 :
619 4 : nGCPCount = 0;
620 :
621 20 : for( psNode = psGeoLoc->psChild; psNode != NULL;
622 : psNode = psNode->psNext )
623 : {
624 : char szID[32];
625 16 : GDAL_GCP *psGCP = pasGCPList + nGCPCount;
626 :
627 16 : if( !EQUAL(psNode->pszValue,"Tie_Point") )
628 0 : continue;
629 :
630 16 : nGCPCount++ ;
631 :
632 16 : sprintf( szID, "%d", nGCPCount );
633 16 : psGCP->pszId = CPLStrdup( szID );
634 16 : psGCP->pszInfo = CPLStrdup("");
635 : psGCP->dfGCPPixel =
636 16 : atof(CPLGetXMLValue(psNode,"TIE_POINT_DATA_X","0"))-0.5;
637 : psGCP->dfGCPLine =
638 16 : atof(CPLGetXMLValue(psNode,"TIE_POINT_DATA_Y","0"))-0.5;
639 : psGCP->dfGCPX =
640 16 : atof(CPLGetXMLValue(psNode,"TIE_POINT_CRS_X",""));
641 : psGCP->dfGCPY =
642 16 : atof(CPLGetXMLValue(psNode,"TIE_POINT_CRS_Y",""));
643 : psGCP->dfGCPZ =
644 16 : atof(CPLGetXMLValue(psNode,"TIE_POINT_CRS_Z",""));
645 : }
646 : }
647 :
648 : /* -------------------------------------------------------------------- */
649 : /* Collect the CRS. For now we look only for EPSG codes. */
650 : /* -------------------------------------------------------------------- */
651 : const char *pszSRS = CPLGetXMLValue(
652 : psDoc,
653 : "Coordinate_Reference_System.Horizontal_CS.HORIZONTAL_CS_CODE",
654 4 : NULL );
655 :
656 4 : if( pszSRS != NULL )
657 : {
658 4 : OGRSpatialReference oSRS;
659 4 : if( oSRS.SetFromUserInput( pszSRS ) == OGRERR_NONE )
660 : {
661 4 : if( nGCPCount > 0 )
662 : {
663 4 : CPLFree(pszGCPProjection);
664 4 : oSRS.exportToWkt( &(pszGCPProjection) );
665 : }
666 : else
667 : {
668 0 : char *pszProjection = NULL;
669 0 : oSRS.exportToWkt( &pszProjection );
670 0 : osProjection = pszProjection;
671 0 : CPLFree( pszProjection );
672 : }
673 4 : }
674 : }
675 : else
676 : {
677 : // Check underlying raster for SRS. We have cases where
678 : // HORIZONTAL_CS_CODE is empty and the underlying raster
679 : // is georeferenced (rprinceley).
680 0 : if ( poImageDS->GetProjectionRef() )
681 : {
682 0 : osProjection = poImageDS->GetProjectionRef();
683 : }
684 : }
685 :
686 : /* -------------------------------------------------------------------- */
687 : /* Translate other metadata of interest. */
688 : /* -------------------------------------------------------------------- */
689 : static const char *apszMetadataTranslation[] =
690 : {
691 : "Production", "",
692 : "Production.Facility", "FACILITY_",
693 : "Dataset_Sources.Source_Information.Scene_Source", "",
694 : "Data_Processing", "",
695 : "Image_Interpretation.Spectral_Band_Info", "SPECTRAL_",
696 : NULL, NULL
697 : };
698 :
699 4 : SetMetadata(psProduct, apszMetadataTranslation);
700 :
701 : /* -------------------------------------------------------------------- */
702 : /* Set Band metadata from the <Spectral_Band_Info> content */
703 : /* -------------------------------------------------------------------- */
704 :
705 : CPLXMLNode *psImageInterpretationNode =
706 4 : CPLGetXMLNode( psDoc, "Image_Interpretation" );
707 4 : if (psImageInterpretationNode != NULL)
708 : {
709 4 : CPLXMLNode *psSpectralBandInfoNode = psImageInterpretationNode->psChild;
710 12 : while (psSpectralBandInfoNode != NULL)
711 : {
712 4 : if (psSpectralBandInfoNode->eType == CXT_Element &&
713 : EQUAL(psSpectralBandInfoNode->pszValue, "Spectral_Band_Info"))
714 : {
715 4 : CPLXMLNode *psTag = psSpectralBandInfoNode->psChild;
716 4 : int nBandIndex = 0;
717 32 : while(psTag != NULL)
718 : {
719 24 : if (psTag->eType == CXT_Element && psTag->psChild != NULL &&
720 : psTag->psChild->eType == CXT_Text && psTag->pszValue != NULL)
721 : {
722 24 : if (EQUAL(psTag->pszValue, "BAND_INDEX"))
723 : {
724 4 : nBandIndex = atoi(psTag->psChild->pszValue);
725 4 : if (nBandIndex <= 0 ||
726 : nBandIndex > poImageDS->GetRasterCount())
727 : {
728 : CPLError(CE_Warning, CPLE_AppDefined,
729 0 : "Bad BAND_INDEX value : %s", psTag->psChild->pszValue);
730 0 : nBandIndex = 0;
731 : }
732 : }
733 20 : else if (nBandIndex >= 1)
734 : {
735 : GetRasterBand(nBandIndex)->SetMetadataItem(
736 20 : psTag->pszValue, psTag->psChild->pszValue);
737 : }
738 : }
739 24 : psTag = psTag->psNext;
740 : }
741 : }
742 4 : psSpectralBandInfoNode = psSpectralBandInfoNode->psNext;
743 : }
744 : }
745 :
746 : /* -------------------------------------------------------------------- */
747 : /* Initialize any PAM information. */
748 : /* -------------------------------------------------------------------- */
749 4 : SetDescription( osMDFilename );
750 4 : TryLoadXML();
751 :
752 : /* -------------------------------------------------------------------- */
753 : /* Check for overviews. */
754 : /* -------------------------------------------------------------------- */
755 4 : oOvManager.Initialize( this, osMDFilename );
756 :
757 4 : return TRUE;
758 : }
759 :
760 :
761 : /************************************************************************/
762 : /* ReadImageInformation() DIMAP Version 2 */
763 : /************************************************************************/
764 :
765 0 : int DIMAPDataset::ReadImageInformation2()
766 : {
767 0 : CPLXMLNode *psDoc = CPLGetXMLNode( psProductDim, "=Dimap_Document" );
768 0 : if( !psDoc )
769 0 : psDoc = CPLGetXMLNode( psProductDim, "=PHR_DIMAP_Document" );
770 :
771 0 : CPLXMLNode *psImageAttributes = CPLGetXMLNode( psDoc, "Raster_Data.Raster_Dimensions" );
772 0 : if( psImageAttributes == NULL )
773 : {
774 : CPLError( CE_Failure, CPLE_OpenFailed,
775 0 : "Failed to find <Raster_Dimensions> in document." );
776 0 : return FALSE;
777 : }
778 :
779 : /* -------------------------------------------------------------------- */
780 : /* Get overall image information. */
781 : /* -------------------------------------------------------------------- */
782 : #ifdef DEBUG
783 : int nBands =
784 0 : atoi(CPLGetXMLValue( psImageAttributes, "NBANDS", "-1" ));
785 : #endif
786 :
787 : nRasterXSize =
788 0 : atoi(CPLGetXMLValue( psImageAttributes, "NCOLS", "-1" ));
789 : nRasterYSize =
790 0 : atoi(CPLGetXMLValue( psImageAttributes, "NROWS", "-1" ));
791 :
792 : /* -------------------------------------------------------------------- */
793 : /* Get the name of the underlying file. */
794 : /* -------------------------------------------------------------------- */
795 :
796 : /* If the data file was not in the product file, it should be here */
797 0 : if ( osImageDSFilename.size() == 0 )
798 : {
799 : const char *pszHref = CPLGetXMLValue(
800 0 : psDoc, "Raster_Data.Data_Access.Data_Files.Data_File.DATA_FILE_PATH.href", "" );
801 0 : if( strlen(pszHref) > 0 )
802 : {
803 0 : CPLString osPath = CPLGetPath(osMDFilename);
804 : osImageDSFilename =
805 0 : CPLFormFilename( osPath, pszHref, NULL );
806 : }
807 : else
808 : {
809 : CPLError( CE_Failure, CPLE_OpenFailed,
810 0 : "Failed to find <DATA_FILE_PATH> in document." );
811 0 : return FALSE;
812 : }
813 : }
814 :
815 :
816 : /* -------------------------------------------------------------------- */
817 : /* Try and open the file. */
818 : /* -------------------------------------------------------------------- */
819 0 : poImageDS = (GDALDataset *) GDALOpen( osImageDSFilename, GA_ReadOnly );
820 0 : if( poImageDS == NULL )
821 : {
822 0 : return FALSE;
823 : }
824 :
825 :
826 : /* -------------------------------------------------------------------- */
827 : /* Attach the bands. */
828 : /* -------------------------------------------------------------------- */
829 : int iBand;
830 0 : CPLAssert( nBands == poImageDS->GetRasterCount() );
831 :
832 0 : for( iBand = 1; iBand <= poImageDS->GetRasterCount(); iBand++ )
833 0 : SetBand( iBand, new DIMAPWrapperRasterBand(poImageDS->GetRasterBand( iBand )) );
834 :
835 : /* -------------------------------------------------------------------- */
836 : /* Try to collect simple insertion point. */
837 : /* -------------------------------------------------------------------- */
838 : CPLXMLNode *psGeoLoc =
839 0 : CPLGetXMLNode( psDoc, "Geoposition.Geoposition_Insert" );
840 :
841 0 : if( psGeoLoc != NULL )
842 : {
843 0 : bHaveGeoTransform = TRUE;
844 0 : adfGeoTransform[0] = atof(CPLGetXMLValue(psGeoLoc,"ULXMAP","0"));
845 0 : adfGeoTransform[1] = atof(CPLGetXMLValue(psGeoLoc,"XDIM","0"));
846 0 : adfGeoTransform[2] = 0.0;
847 0 : adfGeoTransform[3] = atof(CPLGetXMLValue(psGeoLoc,"ULYMAP","0"));
848 0 : adfGeoTransform[4] = 0.0;
849 0 : adfGeoTransform[5] = -atof(CPLGetXMLValue(psGeoLoc,"YDIM","0"));
850 : }
851 :
852 : /* -------------------------------------------------------------------- */
853 : /* Collect the CRS. For now we look only for EPSG codes. */
854 : /* -------------------------------------------------------------------- */
855 : const char *pszSRS = CPLGetXMLValue(
856 : psDoc,
857 : "Coordinate_Reference_System.Projected_CRS..PROJECTED_CRS_CODE",
858 0 : NULL );
859 :
860 0 : if( pszSRS != NULL )
861 : {
862 0 : OGRSpatialReference oSRS;
863 0 : if( oSRS.SetFromUserInput( pszSRS ) == OGRERR_NONE )
864 : {
865 0 : if( nGCPCount > 0 )
866 : {
867 0 : CPLFree(pszGCPProjection);
868 0 : oSRS.exportToWkt( &(pszGCPProjection) );
869 : }
870 : else
871 : {
872 0 : char *pszProjection = NULL;
873 0 : oSRS.exportToWkt( &pszProjection );
874 0 : osProjection = pszProjection;
875 0 : CPLFree( pszProjection );
876 : }
877 0 : }
878 : }
879 : else
880 : {
881 : // Check underlying raster for SRS. We have cases where
882 : // HORIZONTAL_CS_CODE is empty and the underlying raster
883 : // is georeferenced (rprinceley).
884 0 : if ( poImageDS->GetProjectionRef() )
885 : {
886 0 : osProjection = poImageDS->GetProjectionRef();
887 : }
888 : }
889 :
890 : /* -------------------------------------------------------------------- */
891 : /* Translate other metadata of interest: DIM_<product_name>.XML */
892 : /* -------------------------------------------------------------------- */
893 :
894 : static const char *apszMetadataTranslationDim[] =
895 : {
896 : "Product_Information.Delivery_Identification", "DATASET_",
897 : "Product_Information.Producer_Information", "DATASET_",
898 : "Dataset_Sources.Source_Identification.Strip_Source", "",
899 : "Processing_Information.Production_Facility", "FACILITY_",
900 : "Processing_Information.Product_Settings", "",
901 : "Processing_Information.Product_Settings.Geometric_Settings", "GEOMETRIC_",
902 : "Quality_Assessment.Imaging_Quality_Measurement", "CLOUDCOVER_",
903 : NULL, NULL
904 : };
905 :
906 0 : SetMetadata(psProductDim, apszMetadataTranslationDim);
907 :
908 : /* -------------------------------------------------------------------- */
909 : /* Translate other metadata of interest: STRIP_<product_name>.XML */
910 : /* -------------------------------------------------------------------- */
911 :
912 : static const char *apszMetadataTranslationStrip[] =
913 : {
914 : "Catalog.Full_Strip.Notations.Cloud_And_Quality_Notation.Data_Strip_Notation", "CLOUDCOVER_",
915 : "Acquisition_Configuration.Platform_Configuration.Ephemeris_Configuration", "EPHEMERIS_",
916 : NULL, NULL
917 : };
918 :
919 0 : SetMetadata(psProductStrip, apszMetadataTranslationStrip);
920 :
921 : /* -------------------------------------------------------------------- */
922 : /* Set Band metadata from the <Band_Radiance> and */
923 : /* <Band_Spectral_Range> content */
924 : /* -------------------------------------------------------------------- */
925 :
926 : CPLXMLNode *psImageInterpretationNode =
927 : CPLGetXMLNode( psDoc,
928 0 : "Radiometric_Data.Radiometric_Calibration.Instrument_Calibration.Band_Measurement_List" );
929 0 : if (psImageInterpretationNode != NULL)
930 : {
931 0 : CPLXMLNode *psSpectralBandInfoNode = psImageInterpretationNode->psChild;
932 0 : while (psSpectralBandInfoNode != NULL)
933 : {
934 0 : if (psSpectralBandInfoNode->eType == CXT_Element &&
935 : (EQUAL(psSpectralBandInfoNode->pszValue, "Band_Radiance") ||
936 : EQUAL(psSpectralBandInfoNode->pszValue, "Band_Spectral_Range") ||
937 : EQUAL(psSpectralBandInfoNode->pszValue, "Band_Solar_Irradiance")))
938 : {
939 0 : CPLString osName;
940 :
941 0 : if (EQUAL(psSpectralBandInfoNode->pszValue, "Band_Radiance"))
942 0 : osName = "RADIANCE_";
943 0 : else if (EQUAL(psSpectralBandInfoNode->pszValue, "Band_Spectral_Range"))
944 0 : osName = "SPECTRAL_RANGE_";
945 0 : else if (EQUAL(psSpectralBandInfoNode->pszValue, "Band_Solar_Irradiance"))
946 0 : osName = "SOLAR_IRRADIANCE_";
947 :
948 0 : CPLXMLNode *psTag = psSpectralBandInfoNode->psChild;
949 0 : int nBandIndex = 0;
950 0 : while(psTag != NULL)
951 : {
952 0 : if (psTag->eType == CXT_Element && psTag->psChild != NULL &&
953 : psTag->psChild->eType == CXT_Text && psTag->pszValue != NULL)
954 : {
955 0 : if (EQUAL(psTag->pszValue, "BAND_ID"))
956 : {
957 : /* BAND_ID is: B0, B1, .... P */
958 0 : if (!EQUAL(psTag->psChild->pszValue, "P"))
959 : {
960 0 : if (strlen(psTag->psChild->pszValue) < 2) /* shouldn't happen */
961 : {
962 : CPLError(CE_Warning, CPLE_AppDefined,
963 0 : "Bad BAND_INDEX value : %s", psTag->psChild->pszValue);
964 0 : nBandIndex = 0;
965 : }
966 : else
967 : {
968 0 : nBandIndex = atoi(&psTag->psChild->pszValue[1]) + 1;
969 0 : if (nBandIndex <= 0 ||
970 : nBandIndex > poImageDS->GetRasterCount())
971 : {
972 : CPLError(CE_Warning, CPLE_AppDefined,
973 0 : "Bad BAND_INDEX value : %s", psTag->psChild->pszValue);
974 0 : nBandIndex = 0;
975 : }
976 : }
977 : }
978 : }
979 0 : else if (nBandIndex >= 1)
980 : {
981 0 : CPLString osMDName = osName;
982 0 : osMDName += psTag->pszValue;
983 :
984 : GetRasterBand(nBandIndex)->SetMetadataItem(
985 0 : osMDName, psTag->psChild->pszValue);
986 : }
987 :
988 : }
989 0 : psTag = psTag->psNext;
990 0 : }
991 : }
992 0 : psSpectralBandInfoNode = psSpectralBandInfoNode->psNext;
993 : }
994 : }
995 :
996 : /* -------------------------------------------------------------------- */
997 : /* Initialize any PAM information. */
998 : /* -------------------------------------------------------------------- */
999 0 : SetDescription( osMDFilename );
1000 0 : TryLoadXML();
1001 :
1002 : /* -------------------------------------------------------------------- */
1003 : /* Check for overviews. */
1004 : /* -------------------------------------------------------------------- */
1005 0 : oOvManager.Initialize( this, osMDFilename );
1006 :
1007 0 : return TRUE;
1008 : }
1009 :
1010 : /************************************************************************/
1011 : /* SetMetadata() */
1012 : /************************************************************************/
1013 :
1014 4 : void DIMAPDataset::SetMetadata(CPLXMLNode *psProduct, const char *apszMetadataTranslation[])
1015 : {
1016 4 : CPLXMLNode *psDoc = CPLGetXMLNode( psProduct, "=Dimap_Document" );
1017 4 : if( psDoc == NULL )
1018 : {
1019 0 : psDoc = CPLGetXMLNode( psProduct, "=PHR_DIMAP_Document" );
1020 : }
1021 :
1022 : int iTrItem;
1023 :
1024 24 : for( iTrItem = 0; apszMetadataTranslation[iTrItem] != NULL; iTrItem += 2 )
1025 : {
1026 : CPLXMLNode *psParent =
1027 20 : CPLGetXMLNode( psDoc, apszMetadataTranslation[iTrItem] );
1028 :
1029 20 : if( psParent == NULL )
1030 4 : continue;
1031 :
1032 : // hackey logic to support directly access a name/value entry
1033 : // or a parent element with many name/values.
1034 :
1035 : CPLXMLNode *psTarget;
1036 16 : if( psParent->psChild != NULL
1037 : && psParent->psChild->eType == CXT_Text )
1038 0 : psTarget = psParent;
1039 : else
1040 16 : psTarget = psParent->psChild;
1041 :
1042 140 : for( ; psTarget != NULL && psTarget != psParent;
1043 : psTarget = psTarget->psNext )
1044 : {
1045 124 : if( psTarget->eType == CXT_Element
1046 : && psTarget->psChild != NULL)
1047 : {
1048 124 : CPLString osName = apszMetadataTranslation[iTrItem+1];
1049 :
1050 124 : if (psTarget->psChild->eType == CXT_Text)
1051 : {
1052 108 : osName += psTarget->pszValue;
1053 108 : SetMetadataItem( osName, psTarget->psChild->pszValue );
1054 16 : } else if (psTarget->psChild->eType == CXT_Attribute)
1055 : {
1056 : /* find the tag value, at the end of the attributes */
1057 4 : CPLXMLNode *psNode = psTarget->psChild;
1058 8 : for( ; psNode != NULL; psNode = psNode->psNext )
1059 : {
1060 4 : if (psNode->eType == CXT_Attribute)
1061 4 : continue;
1062 0 : else if (psNode->eType == CXT_Text)
1063 : {
1064 0 : osName += psTarget->pszValue;
1065 0 : SetMetadataItem( osName, psNode->pszValue );
1066 : }
1067 : }
1068 124 : }
1069 : }
1070 : }
1071 : }
1072 4 : }
1073 :
1074 : /************************************************************************/
1075 : /* GetGCPCount() */
1076 : /************************************************************************/
1077 :
1078 2 : int DIMAPDataset::GetGCPCount()
1079 :
1080 : {
1081 2 : return nGCPCount;
1082 : }
1083 :
1084 : /************************************************************************/
1085 : /* GetGCPProjection() */
1086 : /************************************************************************/
1087 :
1088 2 : const char *DIMAPDataset::GetGCPProjection()
1089 :
1090 : {
1091 2 : return pszGCPProjection;
1092 : }
1093 :
1094 : /************************************************************************/
1095 : /* GetGCPs() */
1096 : /************************************************************************/
1097 :
1098 2 : const GDAL_GCP *DIMAPDataset::GetGCPs()
1099 :
1100 : {
1101 2 : return pasGCPList;
1102 : }
1103 :
1104 : /************************************************************************/
1105 : /* GDALRegister_DIMAP() */
1106 : /************************************************************************/
1107 :
1108 1135 : void GDALRegister_DIMAP()
1109 :
1110 : {
1111 : GDALDriver *poDriver;
1112 :
1113 1135 : if( GDALGetDriverByName( "DIMAP" ) == NULL )
1114 : {
1115 1093 : poDriver = new GDALDriver();
1116 :
1117 1093 : poDriver->SetDescription( "DIMAP" );
1118 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1119 1093 : "SPOT DIMAP" );
1120 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1121 1093 : "frmt_various.html#DIMAP" );
1122 1093 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1123 :
1124 1093 : poDriver->pfnOpen = DIMAPDataset::Open;
1125 1093 : poDriver->pfnIdentify = DIMAPDataset::Identify;
1126 :
1127 1093 : GetGDALDriverManager()->RegisterDriver( poDriver );
1128 : }
1129 1135 : }
1130 :
|