Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Polarimetric Workstation
4 : * Purpose: Convair PolGASP data (.img/.hdr format).
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2009, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_string.h"
15 : #include "gdal_frmts.h"
16 : #include "gdal_priv.h"
17 : #include "ogr_spatialref.h"
18 : #include "rawdataset.h"
19 :
20 : #include <cinttypes>
21 : #include <vector>
22 :
23 : /************************************************************************/
24 : /* ==================================================================== */
25 : /* CPGDataset */
26 : /* ==================================================================== */
27 : /************************************************************************/
28 :
29 : class SIRC_QSLCRasterBand;
30 : class CPG_STOKESRasterBand;
31 :
32 : class CPGDataset final : public RawDataset
33 : {
34 : friend class SIRC_QSLCRasterBand;
35 : friend class CPG_STOKESRasterBand;
36 :
37 : static constexpr int NUMBER_OF_BANDS = 4;
38 : std::vector<VSILFILE *> afpImage{NUMBER_OF_BANDS};
39 : std::vector<CPLString> aosImageFilenames{};
40 :
41 : int nGCPCount;
42 : GDAL_GCP *pasGCPList;
43 : OGRSpatialReference m_oGCPSRS{};
44 :
45 : GDALGeoTransform m_gt{};
46 : OGRSpatialReference m_oSRS{};
47 :
48 : int nLoadedStokesLine;
49 : float *padfStokesMatrix;
50 :
51 : Interleave eInterleave = Interleave::BSQ;
52 : static int AdjustFilename(char **, const char *, const char *);
53 : static int FindType1(const char *pszWorkname);
54 : static int FindType2(const char *pszWorkname);
55 : #ifdef notdef
56 : static int FindType3(const char *pszWorkname);
57 : #endif
58 : static GDALDataset *InitializeType1Or2Dataset(const char *pszWorkname);
59 : #ifdef notdef
60 : static GDALDataset *InitializeType3Dataset(const char *pszWorkname);
61 : #endif
62 : CPLErr LoadStokesLine(int iLine, int bNativeOrder);
63 :
64 : CPL_DISALLOW_COPY_ASSIGN(CPGDataset)
65 :
66 : CPLErr Close() override;
67 :
68 : public:
69 : CPGDataset();
70 : ~CPGDataset() override;
71 :
72 : int GetGCPCount() override;
73 :
74 0 : const OGRSpatialReference *GetGCPSpatialRef() const override
75 : {
76 0 : return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
77 : }
78 :
79 : const GDAL_GCP *GetGCPs() override;
80 :
81 0 : const OGRSpatialReference *GetSpatialRef() const override
82 : {
83 0 : return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
84 : }
85 :
86 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
87 :
88 : char **GetFileList() override;
89 :
90 : static GDALDataset *Open(GDALOpenInfo *);
91 : };
92 :
93 : /************************************************************************/
94 : /* CPGDataset() */
95 : /************************************************************************/
96 :
97 2 : CPGDataset::CPGDataset()
98 : : nGCPCount(0), pasGCPList(nullptr), nLoadedStokesLine(-1),
99 2 : padfStokesMatrix(nullptr)
100 : {
101 2 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
102 2 : m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
103 2 : }
104 :
105 : /************************************************************************/
106 : /* ~CPGDataset() */
107 : /************************************************************************/
108 :
109 4 : CPGDataset::~CPGDataset()
110 :
111 : {
112 2 : CPGDataset::Close();
113 4 : }
114 :
115 : /************************************************************************/
116 : /* Close() */
117 : /************************************************************************/
118 :
119 4 : CPLErr CPGDataset::Close()
120 : {
121 4 : CPLErr eErr = CE_None;
122 4 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
123 : {
124 2 : if (CPGDataset::FlushCache(true) != CE_None)
125 0 : eErr = CE_Failure;
126 :
127 10 : for (auto poFile : afpImage)
128 : {
129 8 : if (poFile != nullptr)
130 2 : VSIFCloseL(poFile);
131 : }
132 :
133 2 : if (nGCPCount > 0)
134 : {
135 2 : GDALDeinitGCPs(nGCPCount, pasGCPList);
136 2 : CPLFree(pasGCPList);
137 : }
138 :
139 2 : CPLFree(padfStokesMatrix);
140 :
141 2 : if (GDALPamDataset::Close() != CE_None)
142 0 : eErr = CE_Failure;
143 : }
144 4 : return eErr;
145 : }
146 :
147 : /************************************************************************/
148 : /* GetFileList() */
149 : /************************************************************************/
150 :
151 1 : char **CPGDataset::GetFileList()
152 :
153 : {
154 1 : char **papszFileList = RawDataset::GetFileList();
155 2 : for (size_t i = 0; i < aosImageFilenames.size(); ++i)
156 1 : papszFileList = CSLAddString(papszFileList, aosImageFilenames[i]);
157 1 : return papszFileList;
158 : }
159 :
160 : /************************************************************************/
161 : /* ==================================================================== */
162 : /* SIRC_QSLCPRasterBand */
163 : /* ==================================================================== */
164 : /************************************************************************/
165 :
166 : class SIRC_QSLCRasterBand final : public GDALRasterBand
167 : {
168 : friend class CPGDataset;
169 :
170 : public:
171 : SIRC_QSLCRasterBand(CPGDataset *, int, GDALDataType);
172 :
173 16 : ~SIRC_QSLCRasterBand() override
174 8 : {
175 16 : }
176 :
177 : CPLErr IReadBlock(int, int, void *) override;
178 : };
179 :
180 : constexpr int M11 = 0;
181 : // constexpr int M12 = 1;
182 : constexpr int M13 = 2;
183 : constexpr int M14 = 3;
184 : // constexpr int M21 = 4;
185 : constexpr int M22 = 5;
186 : constexpr int M23 = 6;
187 : constexpr int M24 = 7;
188 : constexpr int M31 = 8;
189 : constexpr int M32 = 9;
190 : constexpr int M33 = 10;
191 : constexpr int M34 = 11;
192 : constexpr int M41 = 12;
193 : constexpr int M42 = 13;
194 : constexpr int M43 = 14;
195 : constexpr int M44 = 15;
196 :
197 : /************************************************************************/
198 : /* ==================================================================== */
199 : /* CPG_STOKESRasterBand */
200 : /* ==================================================================== */
201 : /************************************************************************/
202 :
203 : class CPG_STOKESRasterBand final : public GDALRasterBand
204 : {
205 : friend class CPGDataset;
206 :
207 : int bNativeOrder;
208 :
209 : public:
210 : CPG_STOKESRasterBand(GDALDataset *poDS, GDALDataType eType,
211 : int bNativeOrder);
212 :
213 0 : ~CPG_STOKESRasterBand() override
214 0 : {
215 0 : }
216 :
217 : CPLErr IReadBlock(int, int, void *) override;
218 : };
219 :
220 : /************************************************************************/
221 : /* AdjustFilename() */
222 : /* */
223 : /* Try to find the file with the request polarization and */
224 : /* extension and update the passed filename accordingly. */
225 : /* */
226 : /* Return TRUE if file found otherwise FALSE. */
227 : /************************************************************************/
228 :
229 9 : int CPGDataset::AdjustFilename(char **pszFilename, const char *pszPolarization,
230 : const char *pszExtension)
231 :
232 : {
233 : // TODO: Eventually we should handle upper/lower case.
234 9 : if (EQUAL(pszPolarization, "stokes"))
235 : {
236 : const std::string osNewName =
237 0 : CPLResetExtensionSafe(*pszFilename, pszExtension);
238 0 : CPLFree(*pszFilename);
239 0 : *pszFilename = CPLStrdup(osNewName.c_str());
240 : }
241 9 : else if (strlen(pszPolarization) == 2)
242 : {
243 3 : char *subptr = strstr(*pszFilename, "hh");
244 3 : if (subptr == nullptr)
245 3 : subptr = strstr(*pszFilename, "hv");
246 3 : if (subptr == nullptr)
247 3 : subptr = strstr(*pszFilename, "vv");
248 3 : if (subptr == nullptr)
249 3 : subptr = strstr(*pszFilename, "vh");
250 3 : if (subptr == nullptr)
251 3 : return FALSE;
252 :
253 0 : strncpy(subptr, pszPolarization, 2);
254 : const std::string osNewName =
255 0 : CPLResetExtensionSafe(*pszFilename, pszExtension);
256 0 : CPLFree(*pszFilename);
257 0 : *pszFilename = CPLStrdup(osNewName.c_str());
258 : }
259 : else
260 : {
261 : const std::string osNewName =
262 6 : CPLResetExtensionSafe(*pszFilename, pszExtension);
263 6 : CPLFree(*pszFilename);
264 6 : *pszFilename = CPLStrdup(osNewName.c_str());
265 : }
266 : VSIStatBufL sStatBuf;
267 6 : return VSIStatL(*pszFilename, &sStatBuf) == 0;
268 : }
269 :
270 : /************************************************************************/
271 : /* Search for the various types of Convair filesets */
272 : /* Return TRUE for a match, FALSE for no match */
273 : /************************************************************************/
274 34055 : int CPGDataset::FindType1(const char *pszFilename)
275 : {
276 34055 : const int nNameLen = static_cast<int>(strlen(pszFilename));
277 :
278 34055 : if ((strstr(pszFilename, "sso") == nullptr) &&
279 34054 : (strstr(pszFilename, "polgasp") == nullptr))
280 34054 : return FALSE;
281 :
282 1 : if ((strlen(pszFilename) < 5) ||
283 2 : (!EQUAL(pszFilename + nNameLen - 4, ".hdr") &&
284 2 : !EQUAL(pszFilename + nNameLen - 4, ".img")))
285 1 : return FALSE;
286 :
287 : /* Expect all bands and headers to be present */
288 0 : char *pszTemp = CPLStrdup(pszFilename);
289 :
290 1 : const bool bNotFound = !AdjustFilename(&pszTemp, "hh", "img") ||
291 0 : !AdjustFilename(&pszTemp, "hh", "hdr") ||
292 0 : !AdjustFilename(&pszTemp, "hv", "img") ||
293 0 : !AdjustFilename(&pszTemp, "hv", "hdr") ||
294 0 : !AdjustFilename(&pszTemp, "vh", "img") ||
295 0 : !AdjustFilename(&pszTemp, "vh", "hdr") ||
296 1 : !AdjustFilename(&pszTemp, "vv", "img") ||
297 0 : !AdjustFilename(&pszTemp, "vv", "hdr");
298 :
299 1 : CPLFree(pszTemp);
300 :
301 1 : return !bNotFound;
302 : }
303 :
304 34055 : int CPGDataset::FindType2(const char *pszFilename)
305 : {
306 34055 : const int nNameLen = static_cast<int>(strlen(pszFilename));
307 :
308 34055 : if ((strlen(pszFilename) < 9) ||
309 33251 : (!EQUAL(pszFilename + nNameLen - 8, "SIRC.hdr") &&
310 33250 : !EQUAL(pszFilename + nNameLen - 8, "SIRC.img")))
311 34053 : return FALSE;
312 :
313 2 : char *pszTemp = CPLStrdup(pszFilename);
314 4 : const bool bNotFound = !AdjustFilename(&pszTemp, "", "img") ||
315 2 : !AdjustFilename(&pszTemp, "", "hdr");
316 2 : CPLFree(pszTemp);
317 :
318 2 : return !bNotFound;
319 : }
320 :
321 : #ifdef notdef
322 : int CPGDataset::FindType3(const char *pszFilename)
323 : {
324 : const int nNameLen = static_cast<int>(strlen(pszFilename));
325 :
326 : if ((strstr(pszFilename, "sso") == NULL) &&
327 : (strstr(pszFilename, "polgasp") == NULL))
328 : return FALSE;
329 :
330 : if ((strlen(pszFilename) < 9) ||
331 : (!EQUAL(pszFilename + nNameLen - 4, ".img") &&
332 : !EQUAL(pszFilename + nNameLen - 8, ".img_def")))
333 : return FALSE;
334 :
335 : char *pszTemp = CPLStrdup(pszFilename);
336 : const bool bNotFound = !AdjustFilename(&pszTemp, "stokes", "img") ||
337 : !AdjustFilename(&pszTemp, "stokes", "img_def");
338 : CPLFree(pszTemp);
339 :
340 : return !bNotFound;
341 : }
342 : #endif
343 :
344 : /************************************************************************/
345 : /* LoadStokesLine() */
346 : /************************************************************************/
347 :
348 0 : CPLErr CPGDataset::LoadStokesLine(int iLine, int bNativeOrder)
349 :
350 : {
351 0 : if (iLine == nLoadedStokesLine)
352 0 : return CE_None;
353 :
354 0 : constexpr int nDataSize = static_cast<int>(sizeof(float));
355 :
356 : /* -------------------------------------------------------------------- */
357 : /* allocate working buffers if we don't have them already. */
358 : /* -------------------------------------------------------------------- */
359 0 : if (padfStokesMatrix == nullptr)
360 : {
361 0 : padfStokesMatrix = reinterpret_cast<float *>(
362 0 : CPLMalloc(sizeof(float) * nRasterXSize * 16));
363 : }
364 :
365 : /* -------------------------------------------------------------------- */
366 : /* Load all the pixel data associated with this scanline. */
367 : /* Retains same interleaving as original dataset. */
368 : /* -------------------------------------------------------------------- */
369 0 : if (eInterleave == Interleave::BIP)
370 : {
371 0 : const int offset = nRasterXSize * iLine * nDataSize * 16;
372 0 : const int nBytesToRead = nDataSize * nRasterXSize * 16;
373 0 : if ((VSIFSeekL(afpImage[0], offset, SEEK_SET) != 0) ||
374 : static_cast<int>(
375 0 : VSIFReadL(reinterpret_cast<GByte *>(padfStokesMatrix), 1,
376 0 : nBytesToRead, afpImage[0])) != nBytesToRead)
377 : {
378 0 : CPLError(CE_Failure, CPLE_FileIO,
379 : "Error reading %d bytes of Stokes Convair at offset %d.\n"
380 : "Reading file %s failed.",
381 0 : nBytesToRead, offset, GetDescription());
382 0 : CPLFree(padfStokesMatrix);
383 0 : padfStokesMatrix = nullptr;
384 0 : nLoadedStokesLine = -1;
385 0 : return CE_Failure;
386 : }
387 : }
388 0 : else if (eInterleave == Interleave::BIL)
389 : {
390 0 : for (int band_index = 0; band_index < 16; band_index++)
391 : {
392 0 : const int offset =
393 0 : nDataSize * (nRasterXSize * iLine + nRasterXSize * band_index);
394 0 : const int nBytesToRead = nDataSize * nRasterXSize;
395 0 : if ((VSIFSeekL(afpImage[0], offset, SEEK_SET) != 0) ||
396 : static_cast<int>(
397 0 : VSIFReadL(reinterpret_cast<GByte *>(
398 0 : padfStokesMatrix + nBytesToRead * band_index),
399 0 : 1, nBytesToRead, afpImage[0])) != nBytesToRead)
400 : {
401 0 : CPLError(
402 : CE_Failure, CPLE_FileIO,
403 : "Error reading %d bytes of Stokes Convair at offset %d.\n"
404 : "Reading file %s failed.",
405 0 : nBytesToRead, offset, GetDescription());
406 0 : CPLFree(padfStokesMatrix);
407 0 : padfStokesMatrix = nullptr;
408 0 : nLoadedStokesLine = -1;
409 0 : return CE_Failure;
410 : }
411 : }
412 : }
413 : else
414 : {
415 0 : for (int band_index = 0; band_index < 16; band_index++)
416 : {
417 0 : const int offset =
418 0 : nDataSize * (nRasterXSize * iLine +
419 0 : nRasterXSize * nRasterYSize * band_index);
420 0 : const int nBytesToRead = nDataSize * nRasterXSize;
421 0 : if ((VSIFSeekL(afpImage[0], offset, SEEK_SET) != 0) ||
422 : static_cast<int>(
423 0 : VSIFReadL(reinterpret_cast<GByte *>(
424 0 : padfStokesMatrix + nBytesToRead * band_index),
425 0 : 1, nBytesToRead, afpImage[0])) != nBytesToRead)
426 : {
427 0 : CPLError(
428 : CE_Failure, CPLE_FileIO,
429 : "Error reading %d bytes of Stokes Convair at offset %d.\n"
430 : "Reading file %s failed.",
431 0 : nBytesToRead, offset, GetDescription());
432 0 : CPLFree(padfStokesMatrix);
433 0 : padfStokesMatrix = nullptr;
434 0 : nLoadedStokesLine = -1;
435 0 : return CE_Failure;
436 : }
437 : }
438 : }
439 :
440 0 : if (!bNativeOrder)
441 0 : GDALSwapWords(padfStokesMatrix, nDataSize, nRasterXSize * 16,
442 : nDataSize);
443 :
444 0 : nLoadedStokesLine = iLine;
445 :
446 0 : return CE_None;
447 : }
448 :
449 : /************************************************************************/
450 : /* Parse header information and initialize dataset for the */
451 : /* appropriate Convair dataset style. */
452 : /* Returns dataset if successful; NULL if there was a problem. */
453 : /************************************************************************/
454 :
455 2 : GDALDataset *CPGDataset::InitializeType1Or2Dataset(const char *pszFilename)
456 : {
457 :
458 : /* -------------------------------------------------------------------- */
459 : /* Read the .hdr file (the hh one for the .sso and polgasp cases) */
460 : /* and parse it. */
461 : /* -------------------------------------------------------------------- */
462 2 : int nLines = 0;
463 2 : int nSamples = 0;
464 2 : int nError = 0;
465 :
466 : /* Parameters required for pseudo-geocoding. GCPs map */
467 : /* slant range to ground range at 16 points. */
468 2 : int iGeoParamsFound = 0;
469 2 : int itransposed = 0;
470 2 : double dfaltitude = 0.0;
471 2 : double dfnear_srd = 0.0;
472 2 : double dfsample_size = 0.0;
473 2 : double dfsample_size_az = 0.0;
474 :
475 : /* Parameters in geogratis geocoded images */
476 2 : int iUTMParamsFound = 0;
477 2 : int iUTMZone = 0;
478 : // int iCorner = 0;
479 2 : double dfnorth = 0.0;
480 2 : double dfeast = 0.0;
481 :
482 4 : std::string osWorkName;
483 : {
484 2 : char *pszWorkname = CPLStrdup(pszFilename);
485 2 : AdjustFilename(&pszWorkname, "hh", "hdr");
486 2 : osWorkName = pszWorkname;
487 2 : CPLFree(pszWorkname);
488 : }
489 :
490 2 : char **papszHdrLines = CSLLoad(osWorkName.c_str());
491 :
492 16 : for (int iLine = 0; papszHdrLines && papszHdrLines[iLine] != nullptr;
493 : iLine++)
494 : {
495 14 : char **papszTokens = CSLTokenizeString(papszHdrLines[iLine]);
496 :
497 : /* Note: some cv580 file seem to have comments with #, hence the >=
498 : * instead of = for token checking, and the equalN for the corner.
499 : */
500 :
501 14 : if (CSLCount(papszTokens) < 2)
502 : {
503 : /* ignore */;
504 : }
505 14 : else if ((CSLCount(papszTokens) >= 3) &&
506 14 : EQUAL(papszTokens[0], "reference") &&
507 0 : EQUAL(papszTokens[1], "north"))
508 : {
509 0 : dfnorth = CPLAtof(papszTokens[2]);
510 0 : iUTMParamsFound++;
511 : }
512 14 : else if ((CSLCount(papszTokens) >= 3) &&
513 14 : EQUAL(papszTokens[0], "reference") &&
514 0 : EQUAL(papszTokens[1], "east"))
515 : {
516 0 : dfeast = CPLAtof(papszTokens[2]);
517 0 : iUTMParamsFound++;
518 : }
519 14 : else if ((CSLCount(papszTokens) >= 5) &&
520 0 : EQUAL(papszTokens[0], "reference") &&
521 0 : EQUAL(papszTokens[1], "projection") &&
522 14 : EQUAL(papszTokens[2], "UTM") && EQUAL(papszTokens[3], "zone"))
523 : {
524 0 : iUTMZone = atoi(papszTokens[4]);
525 0 : iUTMParamsFound++;
526 : }
527 14 : else if ((CSLCount(papszTokens) >= 3) &&
528 0 : EQUAL(papszTokens[0], "reference") &&
529 14 : EQUAL(papszTokens[1], "corner") &&
530 0 : STARTS_WITH_CI(papszTokens[2], "Upper_Left"))
531 : {
532 : /* iCorner = 0; */
533 0 : iUTMParamsFound++;
534 : }
535 14 : else if (EQUAL(papszTokens[0], "number_lines"))
536 2 : nLines = atoi(papszTokens[1]);
537 :
538 12 : else if (EQUAL(papszTokens[0], "number_samples"))
539 2 : nSamples = atoi(papszTokens[1]);
540 :
541 10 : else if ((EQUAL(papszTokens[0], "header_offset") &&
542 0 : atoi(papszTokens[1]) != 0) ||
543 10 : (EQUAL(papszTokens[0], "number_channels") &&
544 0 : (atoi(papszTokens[1]) != 1) &&
545 0 : (atoi(papszTokens[1]) != 10)) ||
546 10 : (EQUAL(papszTokens[0], "datatype") &&
547 0 : atoi(papszTokens[1]) != 1) ||
548 10 : (EQUAL(papszTokens[0], "number_format") &&
549 0 : !EQUAL(papszTokens[1], "float32") &&
550 0 : !EQUAL(papszTokens[1], "int8")))
551 : {
552 0 : CPLError(CE_Failure, CPLE_AppDefined,
553 : "Keyword %s has value %s which does not match CPG driver "
554 : "expectation.",
555 0 : papszTokens[0], papszTokens[1]);
556 0 : nError = 1;
557 : }
558 10 : else if (EQUAL(papszTokens[0], "altitude"))
559 : {
560 2 : dfaltitude = CPLAtof(papszTokens[1]);
561 2 : iGeoParamsFound++;
562 : }
563 8 : else if (EQUAL(papszTokens[0], "near_srd"))
564 : {
565 2 : dfnear_srd = CPLAtof(papszTokens[1]);
566 2 : iGeoParamsFound++;
567 : }
568 :
569 6 : else if (EQUAL(papszTokens[0], "sample_size"))
570 : {
571 2 : dfsample_size = CPLAtof(papszTokens[1]);
572 2 : iGeoParamsFound++;
573 2 : iUTMParamsFound++;
574 : }
575 4 : else if (EQUAL(papszTokens[0], "sample_size_az"))
576 : {
577 2 : dfsample_size_az = CPLAtof(papszTokens[1]);
578 2 : iGeoParamsFound++;
579 2 : iUTMParamsFound++;
580 : }
581 2 : else if (EQUAL(papszTokens[0], "transposed"))
582 : {
583 2 : itransposed = atoi(papszTokens[1]);
584 2 : iGeoParamsFound++;
585 2 : iUTMParamsFound++;
586 : }
587 :
588 14 : CSLDestroy(papszTokens);
589 : }
590 2 : CSLDestroy(papszHdrLines);
591 : /* -------------------------------------------------------------------- */
592 : /* Check for successful completion. */
593 : /* -------------------------------------------------------------------- */
594 2 : if (nError)
595 : {
596 0 : return nullptr;
597 : }
598 :
599 2 : if (nLines <= 0 || nSamples <= 0)
600 : {
601 0 : CPLError(
602 : CE_Failure, CPLE_AppDefined,
603 : "Did not find valid number_lines or number_samples keywords in %s.",
604 : osWorkName.c_str());
605 0 : return nullptr;
606 : }
607 :
608 : /* -------------------------------------------------------------------- */
609 : /* Initialize dataset. */
610 : /* -------------------------------------------------------------------- */
611 4 : auto poDS = std::make_unique<CPGDataset>();
612 :
613 2 : poDS->nRasterXSize = nSamples;
614 2 : poDS->nRasterYSize = nLines;
615 :
616 : /* -------------------------------------------------------------------- */
617 : /* Open the four bands. */
618 : /* -------------------------------------------------------------------- */
619 : static const char *const apszPolarizations[NUMBER_OF_BANDS] = {"hh", "hv",
620 : "vv", "vh"};
621 :
622 2 : const int nNameLen = static_cast<int>(osWorkName.size());
623 :
624 2 : if (EQUAL(osWorkName.c_str() + nNameLen - 7, "IRC.hdr") ||
625 0 : EQUAL(osWorkName.c_str() + nNameLen - 7, "IRC.img"))
626 : {
627 : {
628 2 : char *pszWorkname = CPLStrdup(osWorkName.c_str());
629 2 : AdjustFilename(&pszWorkname, "", "img");
630 2 : osWorkName = pszWorkname;
631 2 : CPLFree(pszWorkname);
632 : }
633 :
634 2 : poDS->afpImage[0] = VSIFOpenL(osWorkName.c_str(), "rb");
635 2 : if (poDS->afpImage[0] == nullptr)
636 : {
637 0 : CPLError(CE_Failure, CPLE_OpenFailed,
638 : "Failed to open .img file: %s", osWorkName.c_str());
639 0 : return nullptr;
640 : }
641 2 : poDS->aosImageFilenames.push_back(osWorkName.c_str());
642 10 : for (int iBand = 0; iBand < NUMBER_OF_BANDS; iBand++)
643 : {
644 : SIRC_QSLCRasterBand *poBand =
645 8 : new SIRC_QSLCRasterBand(poDS.get(), iBand + 1, GDT_CFloat32);
646 8 : poDS->SetBand(iBand + 1, poBand);
647 8 : poBand->SetMetadataItem("POLARIMETRIC_INTERP",
648 8 : apszPolarizations[iBand]);
649 : }
650 : }
651 : else
652 : {
653 0 : constexpr int SIZEOF_CFLOAT32 = 2 * static_cast<int>(sizeof(float));
654 0 : if (nSamples > INT_MAX / SIZEOF_CFLOAT32)
655 : {
656 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too large nBlockXSize");
657 0 : return nullptr;
658 : }
659 :
660 0 : CPLAssert(poDS->afpImage.size() == NUMBER_OF_BANDS);
661 0 : for (int iBand = 0; iBand < NUMBER_OF_BANDS; iBand++)
662 : {
663 : {
664 0 : char *pszWorkname = CPLStrdup(osWorkName.c_str());
665 0 : AdjustFilename(&pszWorkname, apszPolarizations[iBand], "img");
666 0 : osWorkName = pszWorkname;
667 0 : CPLFree(pszWorkname);
668 : }
669 :
670 0 : poDS->afpImage[iBand] = VSIFOpenL(osWorkName.c_str(), "rb");
671 0 : if (poDS->afpImage[iBand] == nullptr)
672 : {
673 0 : CPLError(CE_Failure, CPLE_OpenFailed,
674 : "Failed to open .img file: %s", osWorkName.c_str());
675 0 : return nullptr;
676 : }
677 0 : poDS->aosImageFilenames.push_back(osWorkName.c_str());
678 :
679 : auto poBand = RawRasterBand::Create(
680 0 : poDS.get(), iBand + 1, poDS->afpImage[iBand], 0, 8,
681 : SIZEOF_CFLOAT32 * nSamples, GDT_CFloat32,
682 : RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
683 0 : RawRasterBand::OwnFP::NO);
684 0 : if (!poBand)
685 0 : return nullptr;
686 0 : poBand->SetMetadataItem("POLARIMETRIC_INTERP",
687 0 : apszPolarizations[iBand]);
688 0 : poDS->SetBand(iBand + 1, std::move(poBand));
689 : }
690 : }
691 :
692 : /* Set an appropriate matrix representation metadata item for the set */
693 2 : poDS->SetMetadataItem("MATRIX_REPRESENTATION", "SCATTERING");
694 :
695 : /* -------------------------------------------------------------------------
696 : */
697 : /* Add georeferencing or pseudo-geocoding, if enough information found. */
698 : /* -------------------------------------------------------------------------
699 : */
700 2 : if (iUTMParamsFound == 7)
701 : {
702 0 : poDS->m_gt[1] = 0.0;
703 0 : poDS->m_gt[2] = 0.0;
704 0 : poDS->m_gt[4] = 0.0;
705 0 : poDS->m_gt[5] = 0.0;
706 :
707 : double dfnorth_center;
708 0 : if (itransposed == 1)
709 : {
710 0 : CPLError(CE_Warning, CPLE_AppDefined,
711 : "Did not have a convair SIRC-style test dataset\n"
712 : "with transposed=1 for testing. Georeferencing may be "
713 : "wrong.\n");
714 0 : dfnorth_center = dfnorth - nSamples * dfsample_size / 2.0;
715 0 : poDS->m_gt[0] = dfeast;
716 0 : poDS->m_gt[2] = dfsample_size_az;
717 0 : poDS->m_gt[3] = dfnorth;
718 0 : poDS->m_gt[4] = -1 * dfsample_size;
719 : }
720 : else
721 : {
722 0 : dfnorth_center = dfnorth - nLines * dfsample_size / 2.0;
723 0 : poDS->m_gt[0] = dfeast;
724 0 : poDS->m_gt[1] = dfsample_size_az;
725 0 : poDS->m_gt[3] = dfnorth;
726 0 : poDS->m_gt[5] = -1 * dfsample_size;
727 : }
728 :
729 0 : if (dfnorth_center < 0)
730 0 : poDS->m_oSRS.SetUTM(iUTMZone, 0);
731 : else
732 0 : poDS->m_oSRS.SetUTM(iUTMZone, 1);
733 :
734 : /* Assuming WGS84 */
735 0 : poDS->m_oSRS.SetWellKnownGeogCS("WGS84");
736 : }
737 2 : else if (iGeoParamsFound == 5)
738 : {
739 : double dfgcpLine, dfgcpPixel, dfgcpX, dfgcpY, dftemp;
740 :
741 2 : poDS->nGCPCount = 16;
742 4 : poDS->pasGCPList = reinterpret_cast<GDAL_GCP *>(
743 2 : CPLCalloc(sizeof(GDAL_GCP), poDS->nGCPCount));
744 2 : GDALInitGCPs(poDS->nGCPCount, poDS->pasGCPList);
745 :
746 34 : for (int ngcp = 0; ngcp < 16; ngcp++)
747 : {
748 : char szID[32];
749 :
750 32 : snprintf(szID, sizeof(szID), "%d", ngcp + 1);
751 32 : if (itransposed == 1)
752 : {
753 0 : if (ngcp < 4)
754 0 : dfgcpPixel = 0.0;
755 0 : else if (ngcp < 8)
756 0 : dfgcpPixel = nSamples / 3.0;
757 0 : else if (ngcp < 12)
758 0 : dfgcpPixel = 2.0 * nSamples / 3.0;
759 : else
760 0 : dfgcpPixel = nSamples;
761 :
762 0 : dfgcpLine = nLines * (ngcp % 4) / 3.0;
763 :
764 0 : dftemp = dfnear_srd + (dfsample_size * dfgcpLine);
765 : /* -1 so that 0,0 maps to largest Y */
766 0 : dfgcpY = -1 * sqrt(dftemp * dftemp - dfaltitude * dfaltitude);
767 0 : dfgcpX = dfgcpPixel * dfsample_size_az;
768 : }
769 : else
770 : {
771 32 : if (ngcp < 4)
772 8 : dfgcpLine = 0.0;
773 24 : else if (ngcp < 8)
774 8 : dfgcpLine = nLines / 3.0;
775 16 : else if (ngcp < 12)
776 8 : dfgcpLine = 2.0 * nLines / 3.0;
777 : else
778 8 : dfgcpLine = nLines;
779 :
780 32 : dfgcpPixel = nSamples * ((ngcp % 4) / 3.0);
781 :
782 32 : dftemp = dfnear_srd + (dfsample_size * dfgcpPixel);
783 32 : dfgcpX = sqrt(dftemp * dftemp - dfaltitude * dfaltitude);
784 32 : dfgcpY = (nLines - dfgcpLine) * dfsample_size_az;
785 : }
786 32 : poDS->pasGCPList[ngcp].dfGCPX = dfgcpX;
787 32 : poDS->pasGCPList[ngcp].dfGCPY = dfgcpY;
788 32 : poDS->pasGCPList[ngcp].dfGCPZ = 0.0;
789 :
790 32 : poDS->pasGCPList[ngcp].dfGCPPixel = dfgcpPixel;
791 32 : poDS->pasGCPList[ngcp].dfGCPLine = dfgcpLine;
792 :
793 32 : CPLFree(poDS->pasGCPList[ngcp].pszId);
794 32 : poDS->pasGCPList[ngcp].pszId = CPLStrdup(szID);
795 : }
796 :
797 2 : poDS->m_oGCPSRS.importFromWkt(
798 : "LOCAL_CS[\"Ground range view / unreferenced meters\","
799 : "UNIT[\"Meter\",1.0]]");
800 : }
801 :
802 2 : return poDS.release();
803 : }
804 :
805 : #ifdef notdef
806 : GDALDataset *CPGDataset::InitializeType3Dataset(const char *pszFilename)
807 : {
808 : int iBytesPerPixel = 0;
809 : Interleave::eInterleave = Interleave::BSQ;
810 : bool bInterleaveSpecified = false;
811 : int nLines = 0;
812 : int nSamples = 0;
813 : int nBands = 0;
814 : int nError = 0;
815 :
816 : /* Parameters in geogratis geocoded images */
817 : int iUTMParamsFound = 0;
818 : int iUTMZone = 0;
819 : double dfnorth = 0.0;
820 : double dfeast = 0.0;
821 : double dfOffsetX = 0.0;
822 : double dfOffsetY = 0.0;
823 : double dfxsize = 0.0;
824 : double dfysize = 0.0;
825 :
826 : char *pszWorkname = CPLStrdup(pszFilename);
827 : AdjustFilename(&pszWorkname, "stokes", "img_def");
828 : char **papszHdrLines = CSLLoad(pszWorkname);
829 :
830 : for (int iLine = 0; papszHdrLines && papszHdrLines[iLine] != NULL; iLine++)
831 : {
832 : char **papszTokens =
833 : CSLTokenizeString2(papszHdrLines[iLine], " \t",
834 : CSLT_HONOURSTRINGS & CSLT_ALLOWEMPTYTOKENS);
835 :
836 : /* Note: some cv580 file seem to have comments with #, hence the >=
837 : * instead of = for token checking, and the equalN for the corner.
838 : */
839 :
840 : if ((CSLCount(papszTokens) >= 3) && EQUAL(papszTokens[0], "data") &&
841 : EQUAL(papszTokens[1], "organization:"))
842 : {
843 :
844 : if (STARTS_WITH_CI(papszTokens[2], "BSQ"))
845 : {
846 : bInterleaveSpecified = true;
847 : eInterleave = Interleave::BSQ;
848 : }
849 : else if (STARTS_WITH_CI(papszTokens[2], "BIL"))
850 : {
851 : bInterleaveSpecified = true;
852 : eInterleave = Interleave::BIL;
853 : }
854 : else if (STARTS_WITH_CI(papszTokens[2], "BIP"))
855 : {
856 : bInterleaveSpecified = true;
857 : eInterleave = Interleave::BIP;
858 : }
859 : else
860 : {
861 : CPLError(
862 : CE_Failure, CPLE_AppDefined,
863 : "The interleaving type of the file (%s) is not supported.",
864 : papszTokens[2]);
865 : nError = 1;
866 : }
867 : }
868 : else if ((CSLCount(papszTokens) >= 3) &&
869 : EQUAL(papszTokens[0], "data") &&
870 : EQUAL(papszTokens[1], "state:"))
871 : {
872 :
873 : if (!STARTS_WITH_CI(papszTokens[2], "RAW") &&
874 : !STARTS_WITH_CI(papszTokens[2], "GEO"))
875 : {
876 : CPLError(CE_Failure, CPLE_AppDefined,
877 : "The data state of the file (%s) is not "
878 : "supported.\n. Only RAW and GEO are currently "
879 : "recognized.",
880 : papszTokens[2]);
881 : nError = 1;
882 : }
883 : }
884 : else if ((CSLCount(papszTokens) >= 4) &&
885 : EQUAL(papszTokens[0], "data") &&
886 : EQUAL(papszTokens[1], "origin") &&
887 : EQUAL(papszTokens[2], "point:"))
888 : {
889 : if (!STARTS_WITH_CI(papszTokens[3], "Upper_Left"))
890 : {
891 : CPLError(CE_Failure, CPLE_AppDefined,
892 : "Unexpected value (%s) for data origin point- expect "
893 : "Upper_Left.",
894 : papszTokens[3]);
895 : nError = 1;
896 : }
897 : iUTMParamsFound++;
898 : }
899 : else if ((CSLCount(papszTokens) >= 5) && EQUAL(papszTokens[0], "map") &&
900 : EQUAL(papszTokens[1], "projection:") &&
901 : EQUAL(papszTokens[2], "UTM") && EQUAL(papszTokens[3], "zone"))
902 : {
903 : iUTMZone = atoi(papszTokens[4]);
904 : iUTMParamsFound++;
905 : }
906 : else if ((CSLCount(papszTokens) >= 4) &&
907 : EQUAL(papszTokens[0], "project") &&
908 : EQUAL(papszTokens[1], "origin:"))
909 : {
910 : dfeast = CPLAtof(papszTokens[2]);
911 : dfnorth = CPLAtof(papszTokens[3]);
912 : iUTMParamsFound += 2;
913 : }
914 : else if ((CSLCount(papszTokens) >= 4) &&
915 : EQUAL(papszTokens[0], "file") &&
916 : EQUAL(papszTokens[1], "start:"))
917 : {
918 : dfOffsetX = CPLAtof(papszTokens[2]);
919 : dfOffsetY = CPLAtof(papszTokens[3]);
920 : iUTMParamsFound += 2;
921 : }
922 : else if ((CSLCount(papszTokens) >= 6) &&
923 : EQUAL(papszTokens[0], "pixel") &&
924 : EQUAL(papszTokens[1], "size") && EQUAL(papszTokens[2], "on") &&
925 : EQUAL(papszTokens[3], "ground:"))
926 : {
927 : dfxsize = CPLAtof(papszTokens[4]);
928 : dfysize = CPLAtof(papszTokens[5]);
929 : iUTMParamsFound += 2;
930 : }
931 : else if ((CSLCount(papszTokens) >= 4) &&
932 : EQUAL(papszTokens[0], "number") &&
933 : EQUAL(papszTokens[1], "of") &&
934 : EQUAL(papszTokens[2], "pixels:"))
935 : {
936 : nSamples = atoi(papszTokens[3]);
937 : }
938 : else if ((CSLCount(papszTokens) >= 4) &&
939 : EQUAL(papszTokens[0], "number") &&
940 : EQUAL(papszTokens[1], "of") && EQUAL(papszTokens[2], "lines:"))
941 : {
942 : nLines = atoi(papszTokens[3]);
943 : }
944 : else if ((CSLCount(papszTokens) >= 4) &&
945 : EQUAL(papszTokens[0], "number") &&
946 : EQUAL(papszTokens[1], "of") && EQUAL(papszTokens[2], "bands:"))
947 : {
948 : nBands = atoi(papszTokens[3]);
949 : if (nBands != 16)
950 : {
951 : CPLError(CE_Failure, CPLE_AppDefined,
952 : "Number of bands has a value %s which does not match "
953 : "CPG driver\nexpectation (expect a value of 16).",
954 : papszTokens[3]);
955 : nError = 1;
956 : }
957 : }
958 : else if ((CSLCount(papszTokens) >= 4) &&
959 : EQUAL(papszTokens[0], "bytes") &&
960 : EQUAL(papszTokens[1], "per") &&
961 : EQUAL(papszTokens[2], "pixel:"))
962 : {
963 : iBytesPerPixel = atoi(papszTokens[3]);
964 : if (iBytesPerPixel != 4)
965 : {
966 : CPLError(CE_Failure, CPLE_AppDefined,
967 : "Bytes per pixel has a value %s which does not match "
968 : "CPG driver\nexpectation (expect a value of 4).",
969 : papszTokens[1]);
970 : nError = 1;
971 : }
972 : }
973 : CSLDestroy(papszTokens);
974 : }
975 :
976 : CSLDestroy(papszHdrLines);
977 :
978 : /* -------------------------------------------------------------------- */
979 : /* Check for successful completion. */
980 : /* -------------------------------------------------------------------- */
981 : if (nError)
982 : {
983 : CPLFree(pszWorkname);
984 : return NULL;
985 : }
986 :
987 : if (!GDALCheckDatasetDimensions(nSamples, nLines) ||
988 : !GDALCheckBandCount(nBands, FALSE) || !bInterleaveSpecified ||
989 : iBytesPerPixel == 0)
990 : {
991 : CPLError(CE_Failure, CPLE_AppDefined,
992 : "%s is missing a required parameter (number of pixels, "
993 : "number of lines,\number of bands, bytes per pixel, or "
994 : "data organization).",
995 : pszWorkname);
996 : CPLFree(pszWorkname);
997 : return NULL;
998 : }
999 :
1000 : /* -------------------------------------------------------------------- */
1001 : /* Initialize dataset. */
1002 : /* -------------------------------------------------------------------- */
1003 : CPGDataset *poDS = new CPGDataset();
1004 :
1005 : poDS->nRasterXSize = nSamples;
1006 : poDS->nRasterYSize = nLines;
1007 : poDS->eInterleave = eInterleave;
1008 :
1009 : /* -------------------------------------------------------------------- */
1010 : /* Open the 16 bands. */
1011 : /* -------------------------------------------------------------------- */
1012 :
1013 : AdjustFilename(&pszWorkname, "stokes", "img");
1014 : poDS->afpImage[0] = VSIFOpenL(pszWorkname, "rb");
1015 : if (poDS->afpImage[0] == NULL)
1016 : {
1017 : CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open .img file: %s",
1018 : pszWorkname);
1019 : CPLFree(pszWorkname);
1020 : delete poDS;
1021 : return NULL;
1022 : }
1023 : aosImageFilenames.push_back(pszWorkname);
1024 : for (int iBand = 0; iBand < 16; iBand++)
1025 : {
1026 : CPG_STOKESRasterBand *poBand =
1027 : new CPG_STOKESRasterBand(poDS, GDT_CFloat32, !CPL_IS_LSB);
1028 : poDS->SetBand(iBand + 1, poBand);
1029 : }
1030 :
1031 : /* -------------------------------------------------------------------- */
1032 : /* Set appropriate MATRIX_REPRESENTATION. */
1033 : /* -------------------------------------------------------------------- */
1034 : if (poDS->GetRasterCount() == 6)
1035 : {
1036 : poDS->SetMetadataItem("MATRIX_REPRESENTATION", "COVARIANCE");
1037 : }
1038 :
1039 : /* -------------------------------------------------------------------------
1040 : */
1041 : /* Add georeferencing, if enough information found. */
1042 : /* -------------------------------------------------------------------------
1043 : */
1044 : if (iUTMParamsFound == 8)
1045 : {
1046 : double dfnorth_center = dfnorth - nLines * dfysize / 2.0;
1047 : poDS->m_gt[0] = dfeast + dfOffsetX;
1048 : poDS->m_gt[1] = dfxsize;
1049 : poDS->m_gt[2] = 0.0;
1050 : poDS->m_gt[3] = dfnorth + dfOffsetY;
1051 : poDS->m_gt[4] = 0.0;
1052 : poDS->m_gt[5] = -1 * dfysize;
1053 :
1054 : OGRSpatialReference oUTM;
1055 : if (dfnorth_center < 0)
1056 : oUTM.SetUTM(iUTMZone, 0);
1057 : else
1058 : oUTM.SetUTM(iUTMZone, 1);
1059 :
1060 : /* Assuming WGS84 */
1061 : oUTM.SetWellKnownGeogCS("WGS84");
1062 : CPLFree(poDS->pszProjection);
1063 : poDS->pszProjection = NULL;
1064 : oUTM.exportToWkt(&(poDS->pszProjection));
1065 : }
1066 :
1067 : return poDS;
1068 : }
1069 : #endif
1070 :
1071 : /************************************************************************/
1072 : /* Open() */
1073 : /************************************************************************/
1074 :
1075 34055 : GDALDataset *CPGDataset::Open(GDALOpenInfo *poOpenInfo)
1076 :
1077 : {
1078 : /* -------------------------------------------------------------------- */
1079 : /* Is this a PolGASP fileset? We expect fileset to follow */
1080 : /* one of these patterns: */
1081 : /* 1) <stuff>hh<stuff2>.img, <stuff>hh<stuff2>.hdr, */
1082 : /* <stuff>hv<stuff2>.img, <stuff>hv<stuff2>.hdr, */
1083 : /* <stuff>vh<stuff2>.img, <stuff>vh<stuff2>.hdr, */
1084 : /* <stuff>vv<stuff2>.img, <stuff>vv<stuff2>.hdr, */
1085 : /* where <stuff> or <stuff2> should contain the */
1086 : /* substring "sso" or "polgasp" */
1087 : /* 2) <stuff>SIRC.hdr and <stuff>SIRC.img */
1088 : /* 3) <stuff>.img and <stuff>.img_def */
1089 : /* where <stuff> should contain the */
1090 : /* substring "sso" or "polgasp" */
1091 : /* -------------------------------------------------------------------- */
1092 34055 : int CPGType = 0;
1093 34055 : if (FindType1(poOpenInfo->pszFilename))
1094 0 : CPGType = 1;
1095 34057 : else if (FindType2(poOpenInfo->pszFilename))
1096 2 : CPGType = 2;
1097 :
1098 : /* Stokes matrix convair data: not quite working yet- something
1099 : * is wrong in the interpretation of the matrix elements in terms
1100 : * of hh, hv, vv, vh. Data will load if the next two lines are
1101 : * uncommented, but values will be incorrect. Expect C11 = hh*conj(hh),
1102 : * C12 = hh*conj(hv), etc. Used geogratis data in both scattering
1103 : * matrix and stokes format for comparison.
1104 : */
1105 : // else if ( FindType3( poOpenInfo->pszFilename ))
1106 : // CPGType = 3;
1107 :
1108 : /* Set working name back to original */
1109 :
1110 34055 : if (CPGType == 0)
1111 : {
1112 34055 : int nNameLen = static_cast<int>(strlen(poOpenInfo->pszFilename));
1113 34055 : if ((nNameLen > 8) &&
1114 33251 : ((strstr(poOpenInfo->pszFilename, "sso") != nullptr) ||
1115 33248 : (strstr(poOpenInfo->pszFilename, "polgasp") != nullptr)) &&
1116 3 : (EQUAL(poOpenInfo->pszFilename + nNameLen - 4, "img") ||
1117 2 : EQUAL(poOpenInfo->pszFilename + nNameLen - 4, "hdr") ||
1118 2 : EQUAL(poOpenInfo->pszFilename + nNameLen - 7, "img_def")))
1119 : {
1120 1 : CPLError(
1121 : CE_Failure, CPLE_OpenFailed,
1122 : "Apparent attempt to open Convair PolGASP data failed as\n"
1123 : "one or more of the required files is missing (eight files\n"
1124 : "are expected for scattering matrix format, two for Stokes).");
1125 : }
1126 34054 : else if ((nNameLen > 8) &&
1127 33249 : (strstr(poOpenInfo->pszFilename, "SIRC") != nullptr) &&
1128 0 : (EQUAL(poOpenInfo->pszFilename + nNameLen - 4, "img") ||
1129 0 : EQUAL(poOpenInfo->pszFilename + nNameLen - 4, "hdr")))
1130 : {
1131 0 : CPLError(
1132 : CE_Failure, CPLE_OpenFailed,
1133 : "Apparent attempt to open SIRC Convair PolGASP data failed \n"
1134 : "as one of the expected files is missing (hdr or img)!");
1135 : }
1136 34052 : return nullptr;
1137 : }
1138 :
1139 : /* -------------------------------------------------------------------- */
1140 : /* Confirm the requested access is supported. */
1141 : /* -------------------------------------------------------------------- */
1142 0 : if (poOpenInfo->eAccess == GA_Update)
1143 : {
1144 0 : ReportUpdateNotSupportedByDriver("CPG");
1145 0 : return nullptr;
1146 : }
1147 :
1148 : /* Read the header info and create the dataset */
1149 : #ifdef notdef
1150 : if (CPGType < 3)
1151 : #endif
1152 : CPGDataset *poDS = reinterpret_cast<CPGDataset *>(
1153 0 : InitializeType1Or2Dataset(poOpenInfo->pszFilename));
1154 : #ifdef notdef
1155 : else
1156 : poDS = reinterpret_cast<CPGDataset *>(
1157 : InitializeType3Dataset(poOpenInfo->pszFilename));
1158 : #endif
1159 2 : if (poDS == nullptr)
1160 0 : return nullptr;
1161 :
1162 : /* -------------------------------------------------------------------- */
1163 : /* Check for overviews. */
1164 : /* -------------------------------------------------------------------- */
1165 : // Need to think about this.
1166 : // poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
1167 :
1168 : /* -------------------------------------------------------------------- */
1169 : /* Initialize any PAM information. */
1170 : /* -------------------------------------------------------------------- */
1171 2 : poDS->SetDescription(poOpenInfo->pszFilename);
1172 2 : poDS->TryLoadXML();
1173 :
1174 2 : return poDS;
1175 : }
1176 :
1177 : /************************************************************************/
1178 : /* GetGCPCount() */
1179 : /************************************************************************/
1180 :
1181 0 : int CPGDataset::GetGCPCount()
1182 :
1183 : {
1184 0 : return nGCPCount;
1185 : }
1186 :
1187 : /************************************************************************/
1188 : /* GetGCPs() */
1189 : /************************************************************************/
1190 :
1191 0 : const GDAL_GCP *CPGDataset::GetGCPs()
1192 :
1193 : {
1194 0 : return pasGCPList;
1195 : }
1196 :
1197 : /************************************************************************/
1198 : /* GetGeoTransform() */
1199 : /************************************************************************/
1200 :
1201 0 : CPLErr CPGDataset::GetGeoTransform(GDALGeoTransform >) const
1202 :
1203 : {
1204 0 : gt = m_gt;
1205 0 : return CE_None;
1206 : }
1207 :
1208 : /************************************************************************/
1209 : /* SIRC_QSLCRasterBand() */
1210 : /************************************************************************/
1211 :
1212 8 : SIRC_QSLCRasterBand::SIRC_QSLCRasterBand(CPGDataset *poGDSIn, int nBandIn,
1213 8 : GDALDataType eType)
1214 :
1215 : {
1216 8 : poDS = poGDSIn;
1217 8 : nBand = nBandIn;
1218 :
1219 8 : eDataType = eType;
1220 :
1221 8 : nBlockXSize = poGDSIn->nRasterXSize;
1222 8 : nBlockYSize = 1;
1223 :
1224 8 : if (nBand == 1)
1225 2 : SetMetadataItem("POLARIMETRIC_INTERP", "HH");
1226 6 : else if (nBand == 2)
1227 2 : SetMetadataItem("POLARIMETRIC_INTERP", "HV");
1228 4 : else if (nBand == 3)
1229 2 : SetMetadataItem("POLARIMETRIC_INTERP", "VH");
1230 2 : else if (nBand == 4)
1231 2 : SetMetadataItem("POLARIMETRIC_INTERP", "VV");
1232 8 : }
1233 :
1234 : /************************************************************************/
1235 : /* IReadBlock() */
1236 : /************************************************************************/
1237 :
1238 : /* From: http://southport.jpl.nasa.gov/software/dcomp/dcomp.html
1239 :
1240 : ysca = sqrt{ [ (Byte(2) / 254 ) + 1.5] 2Byte(1) }
1241 : Re(SHH) = byte(3) ysca/127
1242 : Im(SHH) = byte(4) ysca/127
1243 : Re(SHV) = byte(5) ysca/127
1244 : Im(SHV) = byte(6) ysca/127
1245 : Re(SVH) = byte(7) ysca/127
1246 : Im(SVH) = byte(8) ysca/127
1247 : Re(SVV) = byte(9) ysca/127
1248 : Im(SVV) = byte(10) ysca/127
1249 : */
1250 :
1251 1 : CPLErr SIRC_QSLCRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
1252 : int nBlockYOff, void *pImage)
1253 : {
1254 1 : const int nBytesPerSample = 10;
1255 1 : CPGDataset *poGDS = cpl::down_cast<CPGDataset *>(poDS);
1256 1 : const vsi_l_offset offset =
1257 1 : static_cast<vsi_l_offset>(nBlockXSize) * nBlockYOff * nBytesPerSample;
1258 :
1259 : /* -------------------------------------------------------------------- */
1260 : /* Load all the pixel data associated with this scanline. */
1261 : /* -------------------------------------------------------------------- */
1262 1 : if (nBytesPerSample > INT_MAX / nBlockXSize)
1263 : {
1264 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too large nBlockXSize");
1265 0 : return CE_Failure;
1266 : }
1267 1 : const int nBytesToRead = nBytesPerSample * nBlockXSize;
1268 :
1269 : signed char *pabyRecord =
1270 1 : static_cast<signed char *>(VSI_MALLOC_VERBOSE(nBytesToRead));
1271 1 : if (!pabyRecord)
1272 0 : return CE_Failure;
1273 :
1274 2 : if (VSIFSeekL(poGDS->afpImage[0], offset, SEEK_SET) != 0 ||
1275 1 : static_cast<int>(VSIFReadL(pabyRecord, 1, nBytesToRead,
1276 2 : poGDS->afpImage[0])) != nBytesToRead)
1277 : {
1278 0 : CPLError(CE_Failure, CPLE_FileIO,
1279 : "Error reading %d bytes of SIRC Convair at offset %" PRIu64
1280 : ".\n"
1281 : "Reading file %s failed.",
1282 : nBytesToRead, static_cast<uint64_t>(offset),
1283 0 : poGDS->GetDescription());
1284 0 : CPLFree(pabyRecord);
1285 0 : return CE_Failure;
1286 : }
1287 :
1288 : /* -------------------------------------------------------------------- */
1289 : /* Initialize our power table if this is our first time through. */
1290 : /* -------------------------------------------------------------------- */
1291 : static float afPowTable[256];
1292 1 : [[maybe_unused]] static bool bPowTableInitialized = []()
1293 : {
1294 257 : for (int i = 0; i < 256; i++)
1295 : {
1296 256 : afPowTable[i] = static_cast<float>(pow(2.0, i - 128));
1297 : }
1298 1 : return true;
1299 1 : }();
1300 :
1301 : /* -------------------------------------------------------------------- */
1302 : /* Copy the desired band out based on the size of the type, and */
1303 : /* the interleaving mode. */
1304 : /* -------------------------------------------------------------------- */
1305 2 : for (int iX = 0; iX < nBlockXSize; iX++)
1306 : {
1307 : /* A ones based alias */
1308 1 : const signed char *pabyIn = pabyRecord + iX * nBytesPerSample - 1;
1309 :
1310 : /* coverity[tainted_data] */
1311 : const float fScale = static_cast<float>(
1312 1 : sqrt((static_cast<double>(pabyIn[2]) / 254 + 1.5) *
1313 1 : afPowTable[pabyIn[1] + 128]) /
1314 1 : 127.0);
1315 :
1316 1 : float *pafImage = static_cast<float *>(pImage);
1317 :
1318 1 : if (nBand == 1)
1319 : {
1320 1 : const float fReSHH = static_cast<float>(pabyIn[3] * fScale);
1321 1 : const float fImSHH = static_cast<float>(pabyIn[4] * fScale);
1322 :
1323 1 : pafImage[iX * 2] = fReSHH;
1324 1 : pafImage[iX * 2 + 1] = fImSHH;
1325 : }
1326 0 : else if (nBand == 2)
1327 : {
1328 0 : const float fReSHV = static_cast<float>(pabyIn[5] * fScale);
1329 0 : const float fImSHV = static_cast<float>(pabyIn[6] * fScale);
1330 :
1331 0 : pafImage[iX * 2] = fReSHV;
1332 0 : pafImage[iX * 2 + 1] = fImSHV;
1333 : }
1334 0 : else if (nBand == 3)
1335 : {
1336 0 : const float fReSVH = static_cast<float>(pabyIn[7] * fScale);
1337 0 : const float fImSVH = static_cast<float>(pabyIn[8] * fScale);
1338 :
1339 0 : pafImage[iX * 2] = fReSVH;
1340 0 : pafImage[iX * 2 + 1] = fImSVH;
1341 : }
1342 0 : else if (nBand == 4)
1343 : {
1344 0 : const float fReSVV = static_cast<float>(pabyIn[9] * fScale);
1345 0 : const float fImSVV = static_cast<float>(pabyIn[10] * fScale);
1346 :
1347 0 : pafImage[iX * 2] = fReSVV;
1348 0 : pafImage[iX * 2 + 1] = fImSVV;
1349 : }
1350 : }
1351 :
1352 1 : CPLFree(pabyRecord);
1353 :
1354 1 : return CE_None;
1355 : }
1356 :
1357 : /************************************************************************/
1358 : /* CPG_STOKESRasterBand() */
1359 : /************************************************************************/
1360 :
1361 0 : CPG_STOKESRasterBand::CPG_STOKESRasterBand(GDALDataset *poDSIn,
1362 : GDALDataType eType,
1363 0 : int bNativeOrderIn)
1364 0 : : bNativeOrder(bNativeOrderIn)
1365 : {
1366 : static const char *const apszPolarizations[16] = {
1367 : "Covariance_11", "Covariance_12", "Covariance_13", "Covariance_14",
1368 : "Covariance_21", "Covariance_22", "Covariance_23", "Covariance_24",
1369 : "Covariance_31", "Covariance_32", "Covariance_33", "Covariance_34",
1370 : "Covariance_41", "Covariance_42", "Covariance_43", "Covariance_44"};
1371 :
1372 0 : poDS = poDSIn;
1373 0 : eDataType = eType;
1374 :
1375 0 : nBlockXSize = poDSIn->GetRasterXSize();
1376 0 : nBlockYSize = 1;
1377 :
1378 0 : SetMetadataItem("POLARIMETRIC_INTERP", apszPolarizations[nBand - 1]);
1379 0 : SetDescription(apszPolarizations[nBand - 1]);
1380 0 : }
1381 :
1382 : /************************************************************************/
1383 : /* IReadBlock() */
1384 : /************************************************************************/
1385 :
1386 : /* Convert from Stokes to Covariance representation */
1387 :
1388 0 : CPLErr CPG_STOKESRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
1389 : int nBlockYOff, void *pImage)
1390 :
1391 : {
1392 0 : CPLAssert(nBlockXOff == 0);
1393 :
1394 : int m11, /* m12, */ m13, m14, /* m21, */ m22, m23, m24, step;
1395 : int m31, m32, m33, m34, m41, m42, m43, m44;
1396 0 : CPGDataset *poGDS = cpl::down_cast<CPGDataset *>(poDS);
1397 :
1398 0 : CPLErr eErr = poGDS->LoadStokesLine(nBlockYOff, bNativeOrder);
1399 0 : if (eErr != CE_None)
1400 0 : return eErr;
1401 :
1402 0 : float *M = poGDS->padfStokesMatrix;
1403 0 : float *pafLine = reinterpret_cast<float *>(pImage);
1404 :
1405 0 : if (poGDS->eInterleave == RawDataset::Interleave::BIP)
1406 : {
1407 0 : step = 16;
1408 0 : m11 = M11;
1409 : // m12 = M12;
1410 0 : m13 = M13;
1411 0 : m14 = M14;
1412 : // m21 = M21;
1413 0 : m22 = M22;
1414 0 : m23 = M23;
1415 0 : m24 = M24;
1416 0 : m31 = M31;
1417 0 : m32 = M32;
1418 0 : m33 = M33;
1419 0 : m34 = M34;
1420 0 : m41 = M41;
1421 0 : m42 = M42;
1422 0 : m43 = M43;
1423 0 : m44 = M44;
1424 : }
1425 : else
1426 : {
1427 0 : step = 1;
1428 0 : m11 = 0;
1429 : // m12=nRasterXSize;
1430 0 : m13 = nRasterXSize * 2;
1431 0 : m14 = nRasterXSize * 3;
1432 : // m21=nRasterXSize*4;
1433 0 : m22 = nRasterXSize * 5;
1434 0 : m23 = nRasterXSize * 6;
1435 0 : m24 = nRasterXSize * 7;
1436 0 : m31 = nRasterXSize * 8;
1437 0 : m32 = nRasterXSize * 9;
1438 0 : m33 = nRasterXSize * 10;
1439 0 : m34 = nRasterXSize * 11;
1440 0 : m41 = nRasterXSize * 12;
1441 0 : m42 = nRasterXSize * 13;
1442 0 : m43 = nRasterXSize * 14;
1443 0 : m44 = nRasterXSize * 15;
1444 : }
1445 0 : if (nBand == 1) /* C11 */
1446 : {
1447 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1448 : {
1449 0 : pafLine[iPixel * 2 + 0] = M[m11] - M[m22] - M[m33] + M[m44];
1450 0 : pafLine[iPixel * 2 + 1] = 0.0;
1451 0 : m11 += step;
1452 0 : m22 += step;
1453 0 : m33 += step;
1454 0 : m44 += step;
1455 : }
1456 : }
1457 0 : else if (nBand == 2) /* C12 */
1458 : {
1459 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1460 : {
1461 0 : pafLine[iPixel * 2 + 0] = M[m13] - M[m23];
1462 0 : pafLine[iPixel * 2 + 1] = M[m14] - M[m24];
1463 0 : m13 += step;
1464 0 : m23 += step;
1465 0 : m14 += step;
1466 0 : m24 += step;
1467 : }
1468 : }
1469 0 : else if (nBand == 3) /* C13 */
1470 : {
1471 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1472 : {
1473 0 : pafLine[iPixel * 2 + 0] = M[m33] - M[m44];
1474 0 : pafLine[iPixel * 2 + 1] = M[m43] + M[m34];
1475 0 : m33 += step;
1476 0 : m44 += step;
1477 0 : m43 += step;
1478 0 : m34 += step;
1479 : }
1480 : }
1481 0 : else if (nBand == 4) /* C14 */
1482 : {
1483 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1484 : {
1485 0 : pafLine[iPixel * 2 + 0] = M[m31] - M[m32];
1486 0 : pafLine[iPixel * 2 + 1] = M[m41] - M[m42];
1487 0 : m31 += step;
1488 0 : m32 += step;
1489 0 : m41 += step;
1490 0 : m42 += step;
1491 : }
1492 : }
1493 0 : else if (nBand == 5) /* C21 */
1494 : {
1495 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1496 : {
1497 0 : pafLine[iPixel * 2 + 0] = M[m13] - M[m23];
1498 0 : pafLine[iPixel * 2 + 1] = M[m24] - M[m14];
1499 0 : m13 += step;
1500 0 : m23 += step;
1501 0 : m14 += step;
1502 0 : m24 += step;
1503 : }
1504 : }
1505 0 : else if (nBand == 6) /* C22 */
1506 : {
1507 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1508 : {
1509 0 : pafLine[iPixel * 2 + 0] = M[m11] + M[m22] - M[m33] - M[m44];
1510 0 : pafLine[iPixel * 2 + 1] = 0.0;
1511 0 : m11 += step;
1512 0 : m22 += step;
1513 0 : m33 += step;
1514 0 : m44 += step;
1515 : }
1516 : }
1517 0 : else if (nBand == 7) /* C23 */
1518 : {
1519 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1520 : {
1521 0 : pafLine[iPixel * 2 + 0] = M[m31] + M[m32];
1522 0 : pafLine[iPixel * 2 + 1] = M[m41] + M[m42];
1523 0 : m31 += step;
1524 0 : m32 += step;
1525 0 : m41 += step;
1526 0 : m42 += step;
1527 : }
1528 : }
1529 0 : else if (nBand == 8) /* C24 */
1530 : {
1531 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1532 : {
1533 0 : pafLine[iPixel * 2 + 0] = M[m33] + M[m44];
1534 0 : pafLine[iPixel * 2 + 1] = M[m43] - M[m34];
1535 0 : m33 += step;
1536 0 : m44 += step;
1537 0 : m43 += step;
1538 0 : m34 += step;
1539 : }
1540 : }
1541 0 : else if (nBand == 9) /* C31 */
1542 : {
1543 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1544 : {
1545 0 : pafLine[iPixel * 2 + 0] = M[m33] - M[m44];
1546 0 : pafLine[iPixel * 2 + 1] = -1 * M[m43] - M[m34];
1547 0 : m33 += step;
1548 0 : m44 += step;
1549 0 : m43 += step;
1550 0 : m34 += step;
1551 : }
1552 : }
1553 0 : else if (nBand == 10) /* C32 */
1554 : {
1555 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1556 : {
1557 0 : pafLine[iPixel * 2 + 0] = M[m31] + M[m32];
1558 0 : pafLine[iPixel * 2 + 1] = -1 * M[m41] - M[m42];
1559 0 : m31 += step;
1560 0 : m32 += step;
1561 0 : m41 += step;
1562 0 : m42 += step;
1563 : }
1564 : }
1565 0 : else if (nBand == 11) /* C33 */
1566 : {
1567 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1568 : {
1569 0 : pafLine[iPixel * 2 + 0] = M[m11] + M[m22] + M[m33] + M[m44];
1570 0 : pafLine[iPixel * 2 + 1] = 0.0;
1571 0 : m11 += step;
1572 0 : m22 += step;
1573 0 : m33 += step;
1574 0 : m44 += step;
1575 : }
1576 : }
1577 0 : else if (nBand == 12) /* C34 */
1578 : {
1579 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1580 : {
1581 0 : pafLine[iPixel * 2 + 0] = M[m13] - M[m23];
1582 0 : pafLine[iPixel * 2 + 1] = -1 * M[m14] - M[m24];
1583 0 : m13 += step;
1584 0 : m23 += step;
1585 0 : m14 += step;
1586 0 : m24 += step;
1587 : }
1588 : }
1589 0 : else if (nBand == 13) /* C41 */
1590 : {
1591 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1592 : {
1593 0 : pafLine[iPixel * 2 + 0] = M[m31] - M[m32];
1594 0 : pafLine[iPixel * 2 + 1] = M[m42] - M[m41];
1595 0 : m31 += step;
1596 0 : m32 += step;
1597 0 : m41 += step;
1598 0 : m42 += step;
1599 : }
1600 : }
1601 0 : else if (nBand == 14) /* C42 */
1602 : {
1603 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1604 : {
1605 0 : pafLine[iPixel * 2 + 0] = M[m33] + M[m44];
1606 0 : pafLine[iPixel * 2 + 1] = M[m34] - M[m43];
1607 0 : m33 += step;
1608 0 : m44 += step;
1609 0 : m43 += step;
1610 0 : m34 += step;
1611 : }
1612 : }
1613 0 : else if (nBand == 15) /* C43 */
1614 : {
1615 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1616 : {
1617 0 : pafLine[iPixel * 2 + 0] = M[m13] - M[m23];
1618 0 : pafLine[iPixel * 2 + 1] = M[m14] + M[m24];
1619 0 : m13 += step;
1620 0 : m23 += step;
1621 0 : m14 += step;
1622 0 : m24 += step;
1623 : }
1624 : }
1625 : else /* C44 */
1626 : {
1627 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1628 : {
1629 0 : pafLine[iPixel * 2 + 0] = M[m11] - M[m22] + M[m33] - M[m44];
1630 0 : pafLine[iPixel * 2 + 1] = 0.0;
1631 0 : m11 += step;
1632 0 : m22 += step;
1633 0 : m33 += step;
1634 0 : m44 += step;
1635 : }
1636 : }
1637 :
1638 0 : return CE_None;
1639 : }
1640 :
1641 : /************************************************************************/
1642 : /* GDALRegister_CPG() */
1643 : /************************************************************************/
1644 :
1645 2033 : void GDALRegister_CPG()
1646 :
1647 : {
1648 2033 : if (GDALGetDriverByName("CPG") != nullptr)
1649 283 : return;
1650 :
1651 1750 : GDALDriver *poDriver = new GDALDriver();
1652 :
1653 1750 : poDriver->SetDescription("CPG");
1654 1750 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1655 1750 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Convair PolGASP");
1656 1750 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1657 :
1658 1750 : poDriver->pfnOpen = CPGDataset::Open;
1659 :
1660 1750 : GetGDALDriverManager()->RegisterDriver(poDriver);
1661 : }
|