1 : /******************************************************************************
2 : * $Id: coasp_dataset.cpp 25311 2012-12-15 12:48:14Z rouault $
3 : *
4 : * Project: DRDC Configurable Airborne SAR Processor (COASP) data reader
5 : * Purpose: Support in GDAL for the DRDC COASP format data, both Metadata
6 : * and complex imagery.
7 : * Author: Philippe Vachon <philippe@cowpig.ca>
8 : * Notes: I have seen a grand total of 2 COASP scenes (3 sets of headers).
9 : * This is based on my best observations, some educated guesses and
10 : * such. So if you have a scene that doesn't work, send it to me
11 : * please and I will make it work... with violence.
12 : *
13 : ******************************************************************************
14 : * Copyright (c) 2007, Philippe Vachon
15 : *
16 : * Permission is hereby granted, free of charge, to any person obtaining a
17 : * copy of this software and associated documentation files (the "Software"),
18 : * to deal in the Software without restriction, including without limitation
19 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20 : * and/or sell copies of the Software, and to permit persons to whom the
21 : * Software is furnished to do so, subject to the following conditions:
22 : *
23 : * The above copyright notice and this permission notice shall be included
24 : * in all copies or substantial portions of the Software.
25 : *
26 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
29 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 : * DEALINGS IN THE SOFTWARE.
33 : ****************************************************************************/
34 :
35 : #include "gdal_priv.h"
36 : #include "cpl_port.h"
37 : #include "cpl_conv.h"
38 : #include "cpl_vsi.h"
39 : #include "cpl_string.h"
40 :
41 : CPL_CVSID("$Id: coasp_dataset.cpp 25311 2012-12-15 12:48:14Z rouault $");
42 :
43 : CPL_C_START
44 : void GDALRegister_COASP(void);
45 : CPL_C_END
46 :
47 : #define TYPE_GENERIC 0
48 : #define TYPE_GEOREF 1
49 :
50 :
51 :
52 : enum ePolarization {
53 : hh = 0,
54 : hv,
55 : vh,
56 : vv
57 : };
58 :
59 :
60 : /*******************************************************************
61 : * Declaration of the COASPMetadata classes *
62 : *******************************************************************/
63 :
64 : class COASPMetadataItem;
65 :
66 : class COASPMetadataReader
67 : {
68 : VSILFILE *fp;
69 : char **papszMetadata;
70 : int nMetadataCount;
71 : int nCurrentItem;
72 : public:
73 : COASPMetadataReader(char *pszFname);
74 : COASPMetadataItem *GetNextItem();
75 : COASPMetadataItem *GetItem(int nItem);
76 : int GotoMetadataItem(int nItemNumber);
77 : int GotoMetadataItem(const char *pszName);
78 : int GetCurrentItem() { return nCurrentItem; }
79 : };
80 :
81 : /* Your average metadata item */
82 : class COASPMetadataItem
83 : {
84 : protected:
85 : char *pszItemName;
86 : char *pszItemValue;
87 : public:
88 0 : COASPMetadataItem() { }
89 : COASPMetadataItem(char *pszItemName, char *pszItemValue);
90 : char *GetItemName();
91 : char *GetItemValue();
92 : int GetType() { return TYPE_GENERIC; }
93 : };
94 :
95 : /* Same as MetadataItem class except parses GCP properly and returns
96 : * a GDAL_GCP struct
97 : */
98 : class COASPMetadataGeorefGridItem : public COASPMetadataItem
99 : {
100 : int nId;
101 : int nPixels;
102 : int nLines;
103 : double ndLat;
104 : double ndLong;
105 : public:
106 : COASPMetadataGeorefGridItem(int nId, int nPixels, int nLines,
107 : double ndLat, double ndLong);
108 : const char *GetItemName() { return "georef_grid"; }
109 : GDAL_GCP *GetItemValue();
110 : int GetType() { return TYPE_GEOREF; }
111 : };
112 :
113 : /********************************************************************
114 : * ================================================================ *
115 : * Implementation of the COASPMetadataItem Classes *
116 : * ================================================================ *
117 : ********************************************************************/
118 :
119 0 : COASPMetadataItem::COASPMetadataItem(char *pszItemName, char *pszItemValue)
120 : {
121 0 : this->pszItemName = VSIStrdup(pszItemName);
122 0 : this->pszItemValue = VSIStrdup(pszItemValue);
123 0 : }
124 :
125 0 : char *COASPMetadataItem::GetItemName()
126 : {
127 0 : return VSIStrdup(pszItemName);
128 : }
129 :
130 0 : char *COASPMetadataItem::GetItemValue()
131 : {
132 0 : return VSIStrdup(pszItemValue);
133 : }
134 :
135 0 : COASPMetadataGeorefGridItem::COASPMetadataGeorefGridItem(int nId, int nPixels,
136 0 : int nLines, double ndLat, double ndLong)
137 : {
138 0 : this->nId = nId;
139 0 : this->nPixels = nPixels;
140 0 : this->nLines = nLines;
141 0 : this->ndLat = ndLat;
142 0 : this->ndLong = ndLong;
143 0 : this->pszItemName = VSIStrdup("georef_grid");
144 :
145 0 : }
146 :
147 0 : GDAL_GCP *COASPMetadataGeorefGridItem::GetItemValue()
148 : {
149 0 : return NULL;
150 : }
151 :
152 :
153 : /********************************************************************
154 : * ================================================================ *
155 : * Implementation of the COASPMetadataReader Class *
156 : * ================================================================ *
157 : ********************************************************************/
158 :
159 0 : COASPMetadataReader::COASPMetadataReader(char *pszFname)
160 : {
161 0 : this->fp = NULL;
162 0 : this->nCurrentItem = 0;
163 0 : this->papszMetadata = CSLLoad(pszFname);
164 0 : this->nMetadataCount = CSLCount(this->papszMetadata);
165 0 : }
166 :
167 0 : COASPMetadataItem *COASPMetadataReader::GetNextItem()
168 : {
169 : COASPMetadataItem *poMetadata;
170 : char **papszMDTokens;
171 : char *pszItemName;
172 : char *pszItemValue;
173 0 : if (nCurrentItem >= nMetadataCount)
174 0 : return NULL;
175 :
176 :
177 0 : papszMDTokens = CSLTokenizeString2(papszMetadata[nCurrentItem], " ",
178 0 : CSLT_HONOURSTRINGS );
179 0 : pszItemName = papszMDTokens[0];
180 0 : if (EQUALN(pszItemName, "georef_grid", 11)) {
181 : double ndLat, ndLong;
182 : int nPixels, nLines;
183 : // georef_grid ( pixels lines ) ( lat long )
184 : // 0 1 2 3 4 5 6 7 8
185 0 : nPixels = atoi(papszMDTokens[2]);
186 0 : nLines = atoi(papszMDTokens[3]);
187 0 : ndLat = CPLAtof(papszMDTokens[6]);
188 0 : ndLong = CPLAtof(papszMDTokens[7]);
189 : poMetadata = new COASPMetadataGeorefGridItem(nCurrentItem, nPixels,
190 0 : nLines, ndLat, ndLong);
191 : }
192 : else {
193 0 : int nCount = CSLCount(papszMDTokens);
194 0 : pszItemValue = strdup(papszMDTokens[1]);
195 0 : for (int i = 2; i < nCount; i++) {
196 0 : int nSize = strlen(papszMDTokens[i]);
197 : pszItemValue = (char *)CPLRealloc(pszItemValue,
198 0 : strlen(pszItemValue) + 1 + nSize);
199 : sprintf(pszItemValue,"%s %s",pszItemValue,
200 0 : papszMDTokens[i]);
201 : }
202 :
203 : poMetadata = new COASPMetadataItem(pszItemName,
204 0 : pszItemValue);
205 :
206 0 : free(pszItemValue);
207 : }
208 0 : free(pszItemName);
209 0 : nCurrentItem++;
210 0 : return poMetadata;
211 : }
212 :
213 : /* Goto a particular metadata item, listed by number */
214 0 : int COASPMetadataReader::GotoMetadataItem(int nItemNumber)
215 : {
216 0 : if (nItemNumber > nMetadataCount || nItemNumber < 0) {
217 0 : nItemNumber = 0;
218 0 : return 0;
219 : }
220 0 : nCurrentItem = nItemNumber;
221 0 : return nCurrentItem;
222 : }
223 :
224 : /* Goto the first metadata item with a particular name */
225 0 : int COASPMetadataReader::GotoMetadataItem(const char *pszName)
226 : {
227 0 : nCurrentItem = CSLPartialFindString(papszMetadata, pszName);
228 0 : return nCurrentItem;
229 : }
230 :
231 : /*******************************************************************
232 : * Declaration of the COASPDataset class *
233 : *******************************************************************/
234 :
235 :
236 : class COASPRasterBand;
237 :
238 : /* A couple of observations based on the data I have available to me:
239 : * a) the headers don't really change, beyond indicating data sources
240 : * and such. As such, I only read the first header specified by the
241 : * user. Note that this is agnostic: you can specify hh, vv, vh, hv and
242 : * all the data needed will be immediately available.
243 : * b) Lots of GCPs are present in the headers. This is most excellent.
244 : * c) There is no documentation on this format. All the knowledge contained
245 : * herein is from harassing various Defence Scientists at DRDC Ottawa.
246 : */
247 :
248 : class COASPDataset : public GDALDataset
249 0 : {
250 : friend class COASPRasterBand;
251 : FILE *fpHdr; /* File pointer for the header file */
252 : VSILFILE *fpBinHH; /* File pointer for the binary matrix */
253 : VSILFILE *fpBinHV;
254 : VSILFILE *fpBinVH;
255 : VSILFILE *fpBinVV;
256 :
257 : char *pszFileName; /* line and mission ID, mostly, i.e. l27p7 */
258 :
259 : int nGCPCount;
260 : GDAL_GCP *pasGCP;
261 : public:
262 : static GDALDataset *Open( GDALOpenInfo * );
263 : static int Identify( GDALOpenInfo * poOpenInfo );
264 : int GetGCPCount();
265 : const GDAL_GCP *GetGCPs();
266 : };
267 :
268 : /********************************************************************
269 : * ================================================================ *
270 : * Declaration and implementation of the COASPRasterBand Class *
271 : * ================================================================ *
272 : ********************************************************************/
273 :
274 0 : class COASPRasterBand : public GDALRasterBand {
275 : VSILFILE *fp;
276 : int ePol;
277 : public:
278 : COASPRasterBand( COASPDataset *poDS, GDALDataType eDataType, int ePol, VSILFILE *fp );
279 : virtual CPLErr IReadBlock( int nBlockXOff, int nBlockYOff,
280 : void *pImage);
281 : };
282 :
283 0 : COASPRasterBand::COASPRasterBand( COASPDataset *poDS, GDALDataType eDataType,
284 0 : int ePol, VSILFILE *fp)
285 : {
286 0 : this->fp = fp;
287 0 : this->ePol = ePol;
288 0 : this->poDS = poDS;
289 0 : this->eDataType = eDataType;
290 0 : this->nBlockXSize = poDS->GetRasterXSize();
291 0 : this->nBlockYSize = 1;
292 0 : }
293 :
294 0 : CPLErr COASPRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
295 : void *pImage )
296 : {
297 0 : if (this->fp == NULL) {
298 0 : CPLError(CE_Fatal, 1, "file pointer freed unexpectedly\n");
299 0 : return CE_Fatal;
300 : }
301 :
302 : /* 8 bytes per pixel: 4 bytes I, 4 bytes Q */
303 0 : unsigned long nByteNum = poDS->GetRasterXSize() * 8 * nBlockYOff;
304 :
305 0 : VSIFSeekL(this->fp, nByteNum, SEEK_SET);
306 0 : int nReadSize = (GDALGetDataTypeSize(eDataType)/8) * poDS->GetRasterXSize();
307 : VSIFReadL((char *)pImage, 1, nReadSize,
308 0 : this->fp);
309 :
310 : #ifdef CPL_LSB
311 0 : GDALSwapWords( pImage, 4, nBlockXSize * 2, 4 );
312 : #endif
313 :
314 :
315 0 : return CE_None;
316 :
317 : }
318 :
319 :
320 : /********************************************************************
321 : * ================================================================ *
322 : * Implementation of the COASPDataset Class *
323 : * ================================================================ *
324 : ********************************************************************/
325 :
326 :
327 : /************************************************************************/
328 : /* GetGCPCount() */
329 : /************************************************************************/
330 :
331 0 : int COASPDataset::GetGCPCount()
332 : {
333 0 : return nGCPCount;
334 : }
335 :
336 : /************************************************************************/
337 : /* GetGCPs() */
338 : /************************************************************************/
339 :
340 0 : const GDAL_GCP *COASPDataset::GetGCPs()
341 : {
342 0 : return pasGCP;
343 : }
344 :
345 : /************************************************************************/
346 : /* Identify() */
347 : /************************************************************************/
348 :
349 12398 : int COASPDataset::Identify( GDALOpenInfo *poOpenInfo )
350 : {
351 12398 : if(poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 256)
352 11746 : return 0;
353 :
354 : /* With a COASP .hdr file, the first line or so is:
355 : * time_first_datarec
356 : */
357 652 : if(EQUALN((char *)poOpenInfo->pabyHeader,"time_first_datarec",18))
358 0 : return 1;
359 :
360 652 : return 0;
361 : }
362 :
363 : /************************************************************************/
364 : /* Open() */
365 : /************************************************************************/
366 :
367 2305 : GDALDataset *COASPDataset::Open( GDALOpenInfo *poOpenInfo )
368 : {
369 2305 : if (!COASPDataset::Identify(poOpenInfo))
370 2305 : return NULL;
371 :
372 : /* -------------------------------------------------------------------- */
373 : /* Confirm the requested access is supported. */
374 : /* -------------------------------------------------------------------- */
375 0 : if( poOpenInfo->eAccess == GA_Update )
376 : {
377 : CPLError( CE_Failure, CPLE_NotSupported,
378 : "The COASP driver does not support update access to existing"
379 0 : " datasets.\n" );
380 0 : return NULL;
381 : }
382 : /* Create a fresh dataset for us to work with */
383 : COASPDataset *poDS;
384 0 : poDS = new COASPDataset();
385 :
386 0 : if (poDS == NULL)
387 0 : return NULL;
388 :
389 : /* Steal the file pointer for the header */
390 0 : poDS->fpHdr = poOpenInfo->fp;
391 0 : poOpenInfo->fp = NULL;
392 :
393 : /* Set the binary matrix file pointers to NULL, for now */
394 0 : poDS->fpBinHH = NULL;
395 0 : poDS->fpBinHV = NULL;
396 0 : poDS->fpBinVH = NULL;
397 0 : poDS->fpBinVV = NULL;
398 :
399 0 : poDS->pszFileName = VSIStrdup(poOpenInfo->pszFilename);
400 :
401 : /* determine the file name prefix */
402 : const char *pszFilename;
403 0 : char *pszBaseName = VSIStrdup(CPLGetBasename(poDS->pszFileName));
404 0 : char *pszDir = VSIStrdup(CPLGetPath(poDS->pszFileName));
405 0 : const char *pszExt = "rc";
406 0 : int nNull = strlen(pszBaseName) - 1;
407 0 : char *pszBase = (char *)CPLMalloc(nNull);
408 0 : strncpy(pszBase, pszBaseName, nNull);
409 0 : pszBase[nNull - 1] = '\0';
410 0 : free(pszBaseName);
411 :
412 0 : char *psChan = strstr(pszBase,"hh");;
413 0 : if (psChan == NULL) {
414 0 : psChan = strstr(pszBase, "hv");
415 : }
416 0 : if (psChan == NULL) {
417 0 : psChan = strstr(pszBase, "vh");
418 : }
419 0 : if (psChan == NULL) {
420 0 : psChan = strstr(pszBase, "vv");
421 : }
422 :
423 0 : if (psChan == NULL) {
424 0 : CPLError(CE_Fatal, 1, "unable to recognize file as COASP.\n");
425 0 : free(poDS->pszFileName);
426 0 : free(pszBase);
427 0 : free(pszDir);
428 0 : delete poDS;
429 0 : return NULL;
430 : }
431 :
432 : /* Read Metadata, set GCPs as is appropriate */
433 : COASPMetadataReader *poReader = new COASPMetadataReader(
434 0 : poDS->pszFileName);
435 :
436 :
437 : /* Get Image X and Y widths */
438 0 : poReader->GotoMetadataItem("number_lines");
439 0 : COASPMetadataItem *poItem = poReader->GetNextItem();
440 0 : char *nValue = poItem->GetItemValue();
441 0 : poDS->nRasterYSize = atoi(nValue);
442 0 : free(nValue);
443 :
444 0 : poReader->GotoMetadataItem("number_samples");
445 0 : poItem = poReader->GetNextItem();
446 0 : nValue = poItem->GetItemValue();
447 0 : poDS->nRasterXSize = atoi(nValue);
448 0 : free(nValue);
449 :
450 :
451 : /* Horizontal transmit, horizontal receive */
452 0 : psChan[0] = 'h';
453 0 : psChan[1] = 'h';
454 0 : pszFilename = CPLFormFilename(pszDir, pszBase, pszExt);
455 :
456 0 : poDS->fpBinHH = VSIFOpenL(pszFilename, "r");
457 :
458 0 : if (poDS->fpBinHH != 0) {
459 : /* Set raster band */
460 : poDS->SetBand(1, new COASPRasterBand(poDS, GDT_CFloat32,
461 0 : hh , poDS->fpBinHH));
462 : }
463 :
464 : /* Horizontal transmit, vertical receive */
465 0 : psChan[0] = 'h';
466 0 : psChan[1] = 'v';
467 0 : pszFilename = CPLFormFilename(pszDir, pszBase, pszExt);
468 :
469 0 : poDS->fpBinHV = VSIFOpenL(pszFilename, "r");
470 :
471 0 : if (poDS->fpBinHV != 0) {
472 : poDS->SetBand(2, new COASPRasterBand(poDS, GDT_CFloat32,
473 0 : hv, poDS->fpBinHV));
474 : }
475 :
476 : /* Vertical transmit, horizontal receive */
477 0 : psChan[0] = 'v';
478 0 : psChan[1] = 'h';
479 0 : pszFilename = CPLFormFilename(pszDir, pszBase, pszExt);
480 :
481 0 : poDS->fpBinVH = VSIFOpenL(pszFilename, "r");
482 :
483 0 : if (poDS->fpBinVH != 0) {
484 : poDS->SetBand(3, new COASPRasterBand(poDS, GDT_CFloat32,
485 0 : vh, poDS->fpBinVH));
486 : }
487 :
488 : /* Vertical transmit, vertical receive */
489 0 : psChan[0] = 'v';
490 0 : psChan[1] = 'v';
491 0 : pszFilename = CPLFormFilename(pszDir, pszBase, pszExt);
492 :
493 0 : poDS->fpBinVV = VSIFOpenL(pszFilename, "r");
494 :
495 0 : if (poDS->fpBinVV != 0) {
496 : poDS->SetBand(4, new COASPRasterBand(poDS, GDT_CFloat32,
497 0 : vv, poDS->fpBinVV));
498 : }
499 :
500 :
501 : /* Oops, missing all the data? */
502 :
503 0 : if (poDS->fpBinHH == NULL && poDS->fpBinHV == NULL
504 : && poDS->fpBinVH == NULL && poDS->fpBinVV == NULL)
505 : {
506 0 : CPLError(CE_Fatal,1,"Unable to find any data! Aborting.");
507 0 : free(pszBase);
508 0 : free(pszDir);
509 0 : delete poDS;
510 :
511 0 : return NULL;
512 : }
513 :
514 0 : if ( poDS->GetRasterCount() == 4 ) {
515 0 : poDS->SetMetadataItem( "MATRIX_REPRESENTATION", "SCATTERING" );
516 : }
517 :
518 0 : free(pszBase);
519 0 : free(pszDir);
520 :
521 0 : poDS->nGCPCount = 0;
522 0 : poDS->pasGCP = NULL;
523 :
524 0 : delete poItem;
525 0 : delete poReader;
526 :
527 0 : return poDS;
528 :
529 : }
530 :
531 : /************************************************************************/
532 : /* GDALRegister_COASP() */
533 : /************************************************************************/
534 :
535 582 : void GDALRegister_COASP(void)
536 : {
537 : GDALDriver *poDriver;
538 582 : if ( GDALGetDriverByName( "COASP" ) == NULL ) {
539 561 : poDriver = new GDALDriver();
540 561 : poDriver->SetDescription( "COASP" );
541 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
542 561 : "DRDC COASP SAR Processor Raster" );
543 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION,
544 561 : "hdr" );
545 : /* poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
546 : "frmt_coasp.html"); */
547 561 : poDriver->pfnIdentify = COASPDataset::Identify;
548 561 : poDriver->pfnOpen = COASPDataset::Open;
549 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
550 : }
551 :
552 582 : }
|