1 : /******************************************************************************
2 : * $Id: coasp_dataset.cpp 17664 2009-09-21 21:16:45Z 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 17664 2009-09-21 21:16:45Z 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 : FILE *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 = fp;
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 : FILE *fpBinHH; /* File pointer for the binary matrix */
253 : FILE *fpBinHV;
254 : FILE *fpBinVH;
255 : FILE *fpBinVV;
256 :
257 : char *pszFileName; /* line and mission ID, mostly, i.e. l27p7 */
258 : char *pszPrefix; /* file name prefix */
259 :
260 : int nGCPCount;
261 : GDAL_GCP *pasGCP;
262 : public:
263 : static GDALDataset *Open( GDALOpenInfo * );
264 : static int Identify( GDALOpenInfo * poOpenInfo );
265 : int GetGCPCount();
266 : const GDAL_GCP *GetGCPs();
267 : };
268 :
269 : /********************************************************************
270 : * ================================================================ *
271 : * Declaration and implementation of the COASPRasterBand Class *
272 : * ================================================================ *
273 : ********************************************************************/
274 :
275 0 : class COASPRasterBand : public GDALRasterBand {
276 : FILE *fp;
277 : int ePol;
278 : public:
279 : COASPRasterBand( COASPDataset *poDS, GDALDataType eDataType, int ePol, FILE *fp );
280 : virtual CPLErr IReadBlock( int nBlockXOff, int nBlockYOff,
281 : void *pImage);
282 : };
283 :
284 0 : COASPRasterBand::COASPRasterBand( COASPDataset *poDS, GDALDataType eDataType,
285 0 : int ePol, FILE *fp)
286 : {
287 0 : this->fp = fp;
288 0 : this->ePol = ePol;
289 0 : this->poDS = poDS;
290 0 : this->eDataType = eDataType;
291 0 : this->nBlockXSize = poDS->GetRasterXSize();
292 0 : this->nBlockYSize = 1;
293 0 : }
294 :
295 0 : CPLErr COASPRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
296 : void *pImage )
297 : {
298 0 : if (this->fp == NULL) {
299 0 : CPLError(CE_Fatal, 1, "file pointer freed unexpectedly\n");
300 0 : return CE_Fatal;
301 : }
302 :
303 : /* 8 bytes per pixel: 4 bytes I, 4 bytes Q */
304 0 : unsigned long nByteNum = poDS->GetRasterXSize() * 8 * nBlockYOff;
305 :
306 0 : VSIFSeekL(this->fp, nByteNum, SEEK_SET);
307 0 : int nReadSize = (GDALGetDataTypeSize(eDataType)/8) * poDS->GetRasterXSize();
308 : VSIFReadL((char *)pImage, 1, nReadSize,
309 0 : this->fp);
310 :
311 : #ifdef CPL_LSB
312 0 : GDALSwapWords( pImage, 4, nBlockXSize * 2, 4 );
313 : #endif
314 :
315 :
316 0 : return CE_None;
317 :
318 : }
319 :
320 :
321 : /********************************************************************
322 : * ================================================================ *
323 : * Implementation of the COASPDataset Class *
324 : * ================================================================ *
325 : ********************************************************************/
326 :
327 :
328 : /************************************************************************/
329 : /* GetGCPCount() */
330 : /************************************************************************/
331 :
332 0 : int COASPDataset::GetGCPCount()
333 : {
334 0 : return nGCPCount;
335 : }
336 :
337 : /************************************************************************/
338 : /* GetGCPs() */
339 : /************************************************************************/
340 :
341 0 : const GDAL_GCP *COASPDataset::GetGCPs()
342 : {
343 0 : return pasGCP;
344 : }
345 :
346 : /************************************************************************/
347 : /* Identify() */
348 : /************************************************************************/
349 :
350 8784 : int COASPDataset::Identify( GDALOpenInfo *poOpenInfo )
351 : {
352 8784 : if(poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 256)
353 8507 : return 0;
354 :
355 : /* With a COASP .hdr file, the first line or so is:
356 : * time_first_datarec
357 : */
358 277 : if(EQUALN((char *)poOpenInfo->pabyHeader,"time_first_datarec",18))
359 0 : return 1;
360 :
361 277 : return 0;
362 : }
363 :
364 : /************************************************************************/
365 : /* Open() */
366 : /************************************************************************/
367 :
368 1057 : GDALDataset *COASPDataset::Open( GDALOpenInfo *poOpenInfo )
369 : {
370 1057 : if (!COASPDataset::Identify(poOpenInfo))
371 1057 : return NULL;
372 :
373 : /* -------------------------------------------------------------------- */
374 : /* Confirm the requested access is supported. */
375 : /* -------------------------------------------------------------------- */
376 0 : if( poOpenInfo->eAccess == GA_Update )
377 : {
378 : CPLError( CE_Failure, CPLE_NotSupported,
379 : "The COASP driver does not support update access to existing"
380 0 : " datasets.\n" );
381 0 : return NULL;
382 : }
383 : /* Create a fresh dataset for us to work with */
384 : COASPDataset *poDS;
385 0 : poDS = new COASPDataset();
386 :
387 0 : if (poDS == NULL)
388 0 : return NULL;
389 :
390 : /* Steal the file pointer for the header */
391 0 : poDS->fpHdr = poOpenInfo->fp;
392 0 : poOpenInfo->fp = NULL;
393 :
394 : /* Set the binary matrix file pointers to NULL, for now */
395 0 : poDS->fpBinHH = NULL;
396 0 : poDS->fpBinHV = NULL;
397 0 : poDS->fpBinVH = NULL;
398 0 : poDS->fpBinVV = NULL;
399 :
400 0 : poDS->pszFileName = VSIStrdup(poOpenInfo->pszFilename);
401 :
402 : /* determine the file name prefix */
403 : const char *pszFilename;
404 0 : char *pszBaseName = VSIStrdup(CPLGetBasename(poDS->pszFileName));
405 0 : char *pszDir = VSIStrdup(CPLGetPath(poDS->pszFileName));
406 0 : const char *pszExt = "rc";
407 0 : int nNull = strlen(pszBaseName) - 1;
408 0 : char *pszBase = (char *)CPLMalloc(nNull);
409 0 : strncpy(pszBase, pszBaseName, nNull);
410 0 : pszBase[nNull - 1] = '\0';
411 0 : free(pszBaseName);
412 :
413 0 : char *psChan = strstr(pszBase,"hh");;
414 0 : if (psChan == NULL) {
415 0 : psChan = strstr(pszBase, "hv");
416 : }
417 0 : if (psChan == NULL) {
418 0 : psChan = strstr(pszBase, "vh");
419 : }
420 0 : if (psChan == NULL) {
421 0 : psChan = strstr(pszBase, "vv");
422 : }
423 :
424 0 : if (psChan == NULL) {
425 0 : CPLError(CE_Fatal, 1, "unable to recognize file as COASP.\n");
426 0 : free(poDS->pszFileName);
427 0 : free(pszBase);
428 0 : free(pszDir);
429 0 : delete poDS;
430 0 : return NULL;
431 : }
432 :
433 : /* Read Metadata, set GCPs as is appropriate */
434 : COASPMetadataReader *poReader = new COASPMetadataReader(
435 0 : poDS->pszFileName);
436 :
437 :
438 : /* Get Image X and Y widths */
439 0 : poReader->GotoMetadataItem("number_lines");
440 0 : COASPMetadataItem *poItem = poReader->GetNextItem();
441 0 : char *nValue = poItem->GetItemValue();
442 0 : poDS->nRasterYSize = atoi(nValue);
443 0 : free(nValue);
444 :
445 0 : poReader->GotoMetadataItem("number_samples");
446 0 : poItem = poReader->GetNextItem();
447 0 : nValue = poItem->GetItemValue();
448 0 : poDS->nRasterXSize = atoi(nValue);
449 0 : free(nValue);
450 :
451 :
452 : /* Horizontal transmit, horizontal receive */
453 0 : psChan[0] = 'h';
454 0 : psChan[1] = 'h';
455 0 : pszFilename = CPLFormFilename(pszDir, pszBase, pszExt);
456 :
457 0 : poDS->fpBinHH = VSIFOpenL(pszFilename, "r");
458 :
459 0 : if (poDS->fpBinHH != 0) {
460 : /* Set raster band */
461 : poDS->SetBand(1, new COASPRasterBand(poDS, GDT_CFloat32,
462 0 : hh , poDS->fpBinHH));
463 : }
464 :
465 : /* Horizontal transmit, vertical receive */
466 0 : psChan[0] = 'h';
467 0 : psChan[1] = 'v';
468 0 : pszFilename = CPLFormFilename(pszDir, pszBase, pszExt);
469 :
470 0 : poDS->fpBinHV = VSIFOpenL(pszFilename, "r");
471 :
472 0 : if (poDS->fpBinHV != 0) {
473 : poDS->SetBand(2, new COASPRasterBand(poDS, GDT_CFloat32,
474 0 : hv, poDS->fpBinHV));
475 : }
476 :
477 : /* Vertical transmit, horizontal receive */
478 0 : psChan[0] = 'v';
479 0 : psChan[1] = 'h';
480 0 : pszFilename = CPLFormFilename(pszDir, pszBase, pszExt);
481 :
482 0 : poDS->fpBinVH = VSIFOpenL(pszFilename, "r");
483 :
484 0 : if (poDS->fpBinVH != 0) {
485 : poDS->SetBand(3, new COASPRasterBand(poDS, GDT_CFloat32,
486 0 : vh, poDS->fpBinVH));
487 : }
488 :
489 : /* Vertical transmit, vertical receive */
490 0 : psChan[0] = 'v';
491 0 : psChan[1] = 'v';
492 0 : pszFilename = CPLFormFilename(pszDir, pszBase, pszExt);
493 :
494 0 : poDS->fpBinVV = VSIFOpenL(pszFilename, "r");
495 :
496 0 : if (poDS->fpBinVV != 0) {
497 : poDS->SetBand(4, new COASPRasterBand(poDS, GDT_CFloat32,
498 0 : vv, poDS->fpBinVV));
499 : }
500 :
501 :
502 : /* Oops, missing all the data? */
503 :
504 0 : if (poDS->fpBinHH == NULL && poDS->fpBinHV == NULL
505 : && poDS->fpBinVH == NULL && poDS->fpBinVV == NULL)
506 : {
507 0 : CPLError(CE_Fatal,1,"Unable to find any data! Aborting.");
508 0 : free(pszBase);
509 0 : free(pszDir);
510 0 : delete poDS;
511 :
512 0 : return NULL;
513 : }
514 :
515 0 : if ( poDS->GetRasterCount() == 4 ) {
516 0 : poDS->SetMetadataItem( "MATRIX_REPRESENTATION", "SCATTERING" );
517 : }
518 :
519 0 : free(pszBase);
520 0 : free(pszDir);
521 :
522 0 : poDS->nGCPCount = 0;
523 0 : poDS->pasGCP = NULL;
524 :
525 0 : delete poItem;
526 0 : delete poReader;
527 :
528 0 : return poDS;
529 :
530 : }
531 :
532 : /************************************************************************/
533 : /* GDALRegister_COASP() */
534 : /************************************************************************/
535 :
536 338 : void GDALRegister_COASP(void)
537 : {
538 : GDALDriver *poDriver;
539 338 : if ( GDALGetDriverByName( "COASP" ) == NULL ) {
540 336 : poDriver = new GDALDriver();
541 336 : poDriver->SetDescription( "COASP" );
542 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
543 336 : "DRDC COASP SAR Processor Raster" );
544 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION,
545 336 : "hdr" );
546 : /* poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
547 : "frmt_coasp.html"); */
548 336 : poDriver->pfnIdentify = COASPDataset::Identify;
549 336 : poDriver->pfnOpen = COASPDataset::Open;
550 336 : GetGDALDriverManager()->RegisterDriver( poDriver );
551 : }
552 :
553 338 : }
|