Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GView
4 : * Purpose: Implementation of Atlantis HKV labelled blob support
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2000, Frank Warmerdam
9 : * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include <ctype.h>
15 :
16 : #include "atlsci_spheroid.h"
17 : #include "cpl_string.h"
18 : #include "gdal_frmts.h"
19 : #include "ogr_spatialref.h"
20 : #include "rawdataset.h"
21 :
22 : #include <cmath>
23 :
24 : #include <algorithm>
25 :
26 : /************************************************************************/
27 : /* ==================================================================== */
28 : /* HKVRasterBand */
29 : /* ==================================================================== */
30 : /************************************************************************/
31 :
32 : class HKVDataset;
33 :
34 : class HKVRasterBand final : public RawRasterBand
35 : {
36 : friend class HKVDataset;
37 :
38 : public:
39 : HKVRasterBand(HKVDataset *poDS, int nBand, VSILFILE *fpRaw,
40 : unsigned int nImgOffset, int nPixelOffset, int nLineOffset,
41 : GDALDataType eDataType, int bNativeOrder);
42 :
43 188 : ~HKVRasterBand() override
44 94 : {
45 188 : }
46 :
47 : CPLErr SetNoDataValue(double) override;
48 : };
49 :
50 : /************************************************************************/
51 : /* HKV Spheroids */
52 : /************************************************************************/
53 :
54 : class HKVSpheroidList : public SpheroidList
55 : {
56 : public:
57 : HKVSpheroidList();
58 :
59 44 : ~HKVSpheroidList()
60 44 : {
61 44 : }
62 : };
63 :
64 44 : HKVSpheroidList ::HKVSpheroidList()
65 : {
66 44 : num_spheroids = 58;
67 44 : epsilonR = 0.1;
68 44 : epsilonI = 0.000001;
69 :
70 44 : spheroids[0].SetValuesByEqRadiusAndInvFlattening("airy-1830", 6377563.396,
71 : 299.3249646);
72 44 : spheroids[1].SetValuesByEqRadiusAndInvFlattening("modified-airy",
73 : 6377340.189, 299.3249646);
74 44 : spheroids[2].SetValuesByEqRadiusAndInvFlattening("australian-national",
75 : 6378160, 298.25);
76 44 : spheroids[3].SetValuesByEqRadiusAndInvFlattening("bessel-1841-namibia",
77 : 6377483.865, 299.1528128);
78 44 : spheroids[4].SetValuesByEqRadiusAndInvFlattening("bessel-1841", 6377397.155,
79 : 299.1528128);
80 44 : spheroids[5].SetValuesByEqRadiusAndInvFlattening("clarke-1858", 6378294.0,
81 : 294.297);
82 44 : spheroids[6].SetValuesByEqRadiusAndInvFlattening("clarke-1866", 6378206.4,
83 : 294.9786982);
84 44 : spheroids[7].SetValuesByEqRadiusAndInvFlattening("clarke-1880", 6378249.145,
85 : 293.465);
86 44 : spheroids[8].SetValuesByEqRadiusAndInvFlattening("everest-india-1830",
87 : 6377276.345, 300.8017);
88 44 : spheroids[9].SetValuesByEqRadiusAndInvFlattening("everest-sabah-sarawak",
89 : 6377298.556, 300.8017);
90 44 : spheroids[10].SetValuesByEqRadiusAndInvFlattening("everest-india-1956",
91 : 6377301.243, 300.8017);
92 44 : spheroids[11].SetValuesByEqRadiusAndInvFlattening("everest-malaysia-1969",
93 : 6377295.664, 300.8017);
94 44 : spheroids[12].SetValuesByEqRadiusAndInvFlattening("everest-malay-sing",
95 : 6377304.063, 300.8017);
96 44 : spheroids[13].SetValuesByEqRadiusAndInvFlattening("everest-pakistan",
97 : 6377309.613, 300.8017);
98 44 : spheroids[14].SetValuesByEqRadiusAndInvFlattening("modified-fisher-1960",
99 : 6378155, 298.3);
100 44 : spheroids[15].SetValuesByEqRadiusAndInvFlattening("helmert-1906", 6378200,
101 : 298.3);
102 44 : spheroids[16].SetValuesByEqRadiusAndInvFlattening("hough-1960", 6378270,
103 : 297);
104 44 : spheroids[17].SetValuesByEqRadiusAndInvFlattening("hughes", 6378273.0,
105 : 298.279);
106 44 : spheroids[18].SetValuesByEqRadiusAndInvFlattening("indonesian-1974",
107 : 6378160, 298.247);
108 44 : spheroids[19].SetValuesByEqRadiusAndInvFlattening("international-1924",
109 : 6378388, 297);
110 44 : spheroids[20].SetValuesByEqRadiusAndInvFlattening("iugc-67", 6378160.0,
111 : 298.254);
112 44 : spheroids[21].SetValuesByEqRadiusAndInvFlattening("iugc-75", 6378140.0,
113 : 298.25298);
114 44 : spheroids[22].SetValuesByEqRadiusAndInvFlattening("krassovsky-1940",
115 : 6378245, 298.3);
116 44 : spheroids[23].SetValuesByEqRadiusAndInvFlattening("kaula", 6378165.0,
117 : 292.308);
118 44 : spheroids[24].SetValuesByEqRadiusAndInvFlattening("grs-80", 6378137,
119 : 298.257222101);
120 44 : spheroids[25].SetValuesByEqRadiusAndInvFlattening("south-american-1969",
121 : 6378160, 298.25);
122 44 : spheroids[26].SetValuesByEqRadiusAndInvFlattening("wgs-72", 6378135,
123 : 298.26);
124 44 : spheroids[27].SetValuesByEqRadiusAndInvFlattening("wgs-84", 6378137,
125 : 298.257223563);
126 44 : spheroids[28].SetValuesByEqRadiusAndInvFlattening("ev-wgs-84", 6378137.0,
127 : 298.252841);
128 44 : spheroids[29].SetValuesByEqRadiusAndInvFlattening("ev-bessel", 6377397.0,
129 : 299.1976073);
130 :
131 44 : spheroids[30].SetValuesByEqRadiusAndInvFlattening("airy_1830", 6377563.396,
132 : 299.3249646);
133 44 : spheroids[31].SetValuesByEqRadiusAndInvFlattening("modified_airy",
134 : 6377340.189, 299.3249646);
135 44 : spheroids[32].SetValuesByEqRadiusAndInvFlattening("australian_national",
136 : 6378160, 298.25);
137 44 : spheroids[33].SetValuesByEqRadiusAndInvFlattening("bessel_1841_namibia",
138 : 6377483.865, 299.1528128);
139 44 : spheroids[34].SetValuesByEqRadiusAndInvFlattening("bessel_1841",
140 : 6377397.155, 299.1528128);
141 44 : spheroids[35].SetValuesByEqRadiusAndInvFlattening("clarke_1858", 6378294.0,
142 : 294.297);
143 44 : spheroids[36].SetValuesByEqRadiusAndInvFlattening("clarke_1866", 6378206.4,
144 : 294.9786982);
145 44 : spheroids[37].SetValuesByEqRadiusAndInvFlattening("clarke_1880",
146 : 6378249.145, 293.465);
147 44 : spheroids[38].SetValuesByEqRadiusAndInvFlattening("everest_india_1830",
148 : 6377276.345, 300.8017);
149 44 : spheroids[39].SetValuesByEqRadiusAndInvFlattening("everest_sabah_sarawak",
150 : 6377298.556, 300.8017);
151 44 : spheroids[40].SetValuesByEqRadiusAndInvFlattening("everest_india_1956",
152 : 6377301.243, 300.8017);
153 44 : spheroids[41].SetValuesByEqRadiusAndInvFlattening("everest_malaysia_1969",
154 : 6377295.664, 300.8017);
155 44 : spheroids[42].SetValuesByEqRadiusAndInvFlattening("everest_malay_sing",
156 : 6377304.063, 300.8017);
157 44 : spheroids[43].SetValuesByEqRadiusAndInvFlattening("everest_pakistan",
158 : 6377309.613, 300.8017);
159 44 : spheroids[44].SetValuesByEqRadiusAndInvFlattening("modified_fisher_1960",
160 : 6378155, 298.3);
161 44 : spheroids[45].SetValuesByEqRadiusAndInvFlattening("helmert_1906", 6378200,
162 : 298.3);
163 44 : spheroids[46].SetValuesByEqRadiusAndInvFlattening("hough_1960", 6378270,
164 : 297);
165 44 : spheroids[47].SetValuesByEqRadiusAndInvFlattening("indonesian_1974",
166 : 6378160, 298.247);
167 44 : spheroids[48].SetValuesByEqRadiusAndInvFlattening("international_1924",
168 : 6378388, 297);
169 44 : spheroids[49].SetValuesByEqRadiusAndInvFlattening("iugc_67", 6378160.0,
170 : 298.254);
171 44 : spheroids[50].SetValuesByEqRadiusAndInvFlattening("iugc_75", 6378140.0,
172 : 298.25298);
173 44 : spheroids[51].SetValuesByEqRadiusAndInvFlattening("krassovsky_1940",
174 : 6378245, 298.3);
175 44 : spheroids[52].SetValuesByEqRadiusAndInvFlattening("grs_80", 6378137,
176 : 298.257222101);
177 44 : spheroids[53].SetValuesByEqRadiusAndInvFlattening("south_american_1969",
178 : 6378160, 298.25);
179 44 : spheroids[54].SetValuesByEqRadiusAndInvFlattening("wgs_72", 6378135,
180 : 298.26);
181 44 : spheroids[55].SetValuesByEqRadiusAndInvFlattening("wgs_84", 6378137,
182 : 298.257223563);
183 44 : spheroids[56].SetValuesByEqRadiusAndInvFlattening("ev_wgs_84", 6378137.0,
184 : 298.252841);
185 44 : spheroids[57].SetValuesByEqRadiusAndInvFlattening("ev_bessel", 6377397.0,
186 : 299.1976073);
187 44 : }
188 :
189 : CPLErr SaveHKVAttribFile(const char *pszFilenameIn, int nXSize, int nYSize,
190 : int nBands, GDALDataType eType, int bNoDataSet,
191 : double dfNoDataValue);
192 :
193 : /************************************************************************/
194 : /* ==================================================================== */
195 : /* HKVDataset */
196 : /* ==================================================================== */
197 : /************************************************************************/
198 :
199 : class HKVDataset final : public RawDataset
200 : {
201 : friend class HKVRasterBand;
202 :
203 : char *pszPath;
204 : VSILFILE *fpBlob;
205 :
206 : int nGCPCount;
207 : GDAL_GCP *pasGCPList;
208 :
209 : void ProcessGeoref(const char *);
210 : void ProcessGeorefGCP(char **, const char *, double, double);
211 :
212 44 : void SetVersion(float version_number)
213 : {
214 : // Update stored info.
215 44 : MFF2version = version_number;
216 44 : }
217 :
218 : float MFF2version;
219 :
220 : GDALDataType eRasterType;
221 :
222 : void SetNoDataValue(double);
223 :
224 : OGRSpatialReference m_oSRS{};
225 : OGRSpatialReference m_oGCPSRS{};
226 : double adfGeoTransform[6];
227 :
228 : char **papszAttrib;
229 :
230 : bool bGeorefChanged;
231 : char **papszGeoref;
232 :
233 : // NOTE: The MFF2 format goes against GDAL's API in that nodata values are
234 : // set per-dataset rather than per-band. To compromise, for writing out,
235 : // the dataset's nodata value will be set to the last value set on any of
236 : // the raster bands.
237 :
238 : bool bNoDataSet;
239 : bool bNoDataChanged;
240 : double dfNoDataValue;
241 :
242 : CPL_DISALLOW_COPY_ASSIGN(HKVDataset)
243 :
244 : CPLErr Close() override;
245 :
246 : public:
247 : HKVDataset();
248 : ~HKVDataset() override;
249 :
250 2 : int GetGCPCount() override /* const */
251 : {
252 2 : return nGCPCount;
253 : }
254 :
255 0 : const OGRSpatialReference *GetGCPSpatialRef() const override
256 : {
257 0 : return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
258 : }
259 :
260 : const GDAL_GCP *GetGCPs() override;
261 :
262 15 : const OGRSpatialReference *GetSpatialRef() const override
263 : {
264 15 : return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
265 : }
266 :
267 : CPLErr GetGeoTransform(double *) override;
268 :
269 : CPLErr SetGeoTransform(double *) override;
270 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
271 :
272 : static GDALDataset *Open(GDALOpenInfo *);
273 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
274 : int nBands, GDALDataType eType,
275 : char **papszParamList);
276 : static GDALDataset *CreateCopy(const char *pszFilename,
277 : GDALDataset *poSrcDS, int bStrict,
278 : char **papszOptions,
279 : GDALProgressFunc pfnProgress,
280 : void *pProgressData);
281 :
282 : static CPLErr Delete(const char *pszName);
283 : };
284 :
285 : /************************************************************************/
286 : /* ==================================================================== */
287 : /* HKVRasterBand */
288 : /* ==================================================================== */
289 : /************************************************************************/
290 :
291 : /************************************************************************/
292 : /* HKVRasterBand() */
293 : /************************************************************************/
294 :
295 94 : HKVRasterBand::HKVRasterBand(HKVDataset *poDSIn, int nBandIn, VSILFILE *fpRawIn,
296 : unsigned int nImgOffsetIn, int nPixelOffsetIn,
297 : int nLineOffsetIn, GDALDataType eDataTypeIn,
298 94 : int bNativeOrderIn)
299 : : RawRasterBand(GDALDataset::FromHandle(poDSIn), nBandIn, fpRawIn,
300 : nImgOffsetIn, nPixelOffsetIn, nLineOffsetIn, eDataTypeIn,
301 94 : bNativeOrderIn, RawRasterBand::OwnFP::NO)
302 :
303 : {
304 94 : poDS = poDSIn;
305 94 : nBand = nBandIn;
306 :
307 94 : nBlockXSize = poDS->GetRasterXSize();
308 94 : nBlockYSize = 1;
309 94 : }
310 :
311 : /************************************************************************/
312 : /* SetNoDataValue() */
313 : /************************************************************************/
314 :
315 0 : CPLErr HKVRasterBand::SetNoDataValue(double dfNewValue)
316 :
317 : {
318 0 : HKVDataset *poHKVDS = reinterpret_cast<HKVDataset *>(poDS);
319 0 : RawRasterBand::SetNoDataValue(dfNewValue);
320 0 : poHKVDS->SetNoDataValue(dfNewValue);
321 :
322 0 : return CE_None;
323 : }
324 :
325 : /************************************************************************/
326 : /* ==================================================================== */
327 : /* HKVDataset */
328 : /* ==================================================================== */
329 : /************************************************************************/
330 :
331 : /************************************************************************/
332 : /* HKVDataset() */
333 : /************************************************************************/
334 :
335 44 : HKVDataset::HKVDataset()
336 : : pszPath(nullptr), fpBlob(nullptr), nGCPCount(0), pasGCPList(nullptr),
337 : // Initialize datasets to new version; change if necessary.
338 : MFF2version(1.1f), eRasterType(GDT_Unknown), papszAttrib(nullptr),
339 : bGeorefChanged(false), papszGeoref(nullptr), bNoDataSet(false),
340 44 : bNoDataChanged(false), dfNoDataValue(0.0)
341 : {
342 44 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
343 44 : m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
344 44 : adfGeoTransform[0] = 0.0;
345 44 : adfGeoTransform[1] = 1.0;
346 44 : adfGeoTransform[2] = 0.0;
347 44 : adfGeoTransform[3] = 0.0;
348 44 : adfGeoTransform[4] = 0.0;
349 44 : adfGeoTransform[5] = 1.0;
350 44 : }
351 :
352 : /************************************************************************/
353 : /* ~HKVDataset() */
354 : /************************************************************************/
355 :
356 88 : HKVDataset::~HKVDataset()
357 :
358 : {
359 44 : HKVDataset::Close();
360 88 : }
361 :
362 : /************************************************************************/
363 : /* Close() */
364 : /************************************************************************/
365 :
366 88 : CPLErr HKVDataset::Close()
367 : {
368 88 : CPLErr eErr = CE_None;
369 88 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
370 : {
371 44 : if (HKVDataset::FlushCache(true) != CE_None)
372 0 : eErr = CE_Failure;
373 :
374 44 : if (bGeorefChanged)
375 : {
376 : const std::string osFilename =
377 52 : CPLFormFilenameSafe(pszPath, "georef", nullptr);
378 26 : CSLSave(papszGeoref, osFilename.c_str());
379 : }
380 :
381 44 : if (bNoDataChanged)
382 : {
383 0 : SaveHKVAttribFile(pszPath, nRasterXSize, nRasterYSize, nBands,
384 0 : eRasterType, bNoDataSet, dfNoDataValue);
385 : }
386 :
387 44 : if (fpBlob)
388 : {
389 44 : if (VSIFCloseL(fpBlob) != 0)
390 : {
391 0 : eErr = CE_Failure;
392 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
393 : }
394 : }
395 :
396 44 : if (nGCPCount > 0)
397 : {
398 14 : GDALDeinitGCPs(nGCPCount, pasGCPList);
399 14 : CPLFree(pasGCPList);
400 : }
401 :
402 44 : CPLFree(pszPath);
403 44 : CSLDestroy(papszGeoref);
404 44 : CSLDestroy(papszAttrib);
405 :
406 44 : if (GDALPamDataset::Close() != CE_None)
407 0 : eErr = CE_Failure;
408 : }
409 88 : return eErr;
410 : }
411 :
412 : /************************************************************************/
413 : /* SetNoDataValue() */
414 : /************************************************************************/
415 :
416 0 : void HKVDataset::SetNoDataValue(double dfNewValue)
417 :
418 : {
419 0 : bNoDataSet = true;
420 0 : bNoDataChanged = true;
421 0 : dfNoDataValue = dfNewValue;
422 0 : }
423 :
424 : /************************************************************************/
425 : /* SaveHKVAttribFile() */
426 : /************************************************************************/
427 :
428 26 : CPLErr SaveHKVAttribFile(const char *pszFilenameIn, int nXSize, int nYSize,
429 : int nBands, GDALDataType eType, int bNoDataSet,
430 : double dfNoDataValue)
431 :
432 : {
433 : const std::string osFilename =
434 52 : CPLFormFilenameSafe(pszFilenameIn, "attrib", nullptr);
435 :
436 26 : FILE *fp = VSIFOpen(osFilename.c_str(), "wt");
437 26 : if (fp == nullptr)
438 : {
439 0 : CPLError(CE_Failure, CPLE_OpenFailed, "Couldn't create %s.",
440 : osFilename.c_str());
441 0 : return CE_Failure;
442 : }
443 :
444 26 : fprintf(fp, "channel.enumeration = %d\n", nBands);
445 26 : fprintf(fp, "channel.interleave = { *pixel tile sequential }\n");
446 26 : fprintf(fp, "extent.cols = %d\n", nXSize);
447 26 : fprintf(fp, "extent.rows = %d\n", nYSize);
448 :
449 26 : switch (eType)
450 : {
451 11 : case GDT_Byte:
452 11 : fprintf(fp, "pixel.encoding = "
453 : "{ *unsigned twos-complement ieee-754 }\n");
454 11 : break;
455 :
456 3 : case GDT_UInt16:
457 3 : fprintf(fp, "pixel.encoding = "
458 : "{ *unsigned twos-complement ieee-754 }\n");
459 3 : break;
460 :
461 6 : case GDT_CInt16:
462 : case GDT_Int16:
463 6 : fprintf(fp, "pixel.encoding = "
464 : "{ unsigned *twos-complement ieee-754 }\n");
465 6 : break;
466 :
467 6 : case GDT_CFloat32:
468 : case GDT_Float32:
469 6 : fprintf(fp, "pixel.encoding = "
470 : "{ unsigned twos-complement *ieee-754 }\n");
471 6 : break;
472 :
473 0 : default:
474 0 : CPLAssert(false);
475 : }
476 :
477 26 : fprintf(fp, "pixel.size = %d\n", GDALGetDataTypeSizeBits(eType));
478 26 : if (GDALDataTypeIsComplex(eType))
479 6 : fprintf(fp, "pixel.field = { real *complex }\n");
480 : else
481 20 : fprintf(fp, "pixel.field = { *real complex }\n");
482 :
483 : #ifdef CPL_MSB
484 : fprintf(fp, "pixel.order = { lsbf *msbf }\n");
485 : #else
486 26 : fprintf(fp, "pixel.order = { *lsbf msbf }\n");
487 : #endif
488 :
489 26 : if (bNoDataSet)
490 0 : fprintf(fp, "pixel.no_data = %s\n", CPLSPrintf("%f", dfNoDataValue));
491 :
492 : // Version information- only create the new style.
493 26 : fprintf(fp, "version = 1.1");
494 :
495 26 : if (VSIFClose(fp) != 0)
496 0 : return CE_Failure;
497 26 : return CE_None;
498 : }
499 :
500 : /************************************************************************/
501 : /* GetGeoTransform() */
502 : /************************************************************************/
503 :
504 29 : CPLErr HKVDataset::GetGeoTransform(double *padfTransform)
505 :
506 : {
507 29 : memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
508 29 : return CE_None;
509 : }
510 :
511 : /************************************************************************/
512 : /* SetGeoTransform() */
513 : /************************************************************************/
514 :
515 26 : CPLErr HKVDataset::SetGeoTransform(double *padfTransform)
516 :
517 : {
518 : // NOTE: Geotransform coordinates must match the current projection
519 : // of the dataset being changed (not the geotransform source).
520 : // i.e. be in lat/longs for LL projected; UTM for UTM projected.
521 : // SET PROJECTION BEFORE SETTING GEOTRANSFORM TO AVOID SYNCHRONIZATION
522 : // PROBLEMS.
523 :
524 : // Update the geotransform itself.
525 26 : memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6);
526 :
527 : // Clear previous gcps.
528 26 : if (nGCPCount > 0)
529 : {
530 0 : GDALDeinitGCPs(nGCPCount, pasGCPList);
531 0 : CPLFree(pasGCPList);
532 : }
533 26 : nGCPCount = 0;
534 26 : pasGCPList = nullptr;
535 :
536 : // Return if the identity transform is set.
537 26 : if (adfGeoTransform[0] == 0.0 && adfGeoTransform[1] == 1.0 &&
538 0 : adfGeoTransform[2] == 0.0 && adfGeoTransform[3] == 0.0 &&
539 0 : adfGeoTransform[4] == 0.0 && adfGeoTransform[5] == 1.0)
540 0 : return CE_None;
541 :
542 : // Update georef text info for saving later, and update GCPs to match
543 : // geotransform.
544 :
545 26 : OGRCoordinateTransformation *poTransform = nullptr;
546 26 : bool bSuccess = true;
547 :
548 : // Projection parameter checking will have been done in SetProjection.
549 37 : if ((CSLFetchNameValue(papszGeoref, "projection.name") != nullptr) &&
550 11 : (EQUAL(CSLFetchNameValue(papszGeoref, "projection.name"), "UTM")))
551 : {
552 1 : auto poLLSRS = m_oSRS.CloneGeogCS();
553 1 : if (poLLSRS)
554 : {
555 1 : poLLSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
556 1 : poTransform = OGRCreateCoordinateTransformation(&m_oSRS, poLLSRS);
557 1 : delete poLLSRS;
558 1 : if (poTransform == nullptr)
559 : {
560 0 : bSuccess = false;
561 0 : CPLErrorReset();
562 : }
563 : }
564 : else
565 : {
566 0 : bSuccess = false;
567 : }
568 : }
569 25 : else if (((CSLFetchNameValue(papszGeoref, "projection.name") != nullptr) &&
570 10 : (!EQUAL(CSLFetchNameValue(papszGeoref, "projection.name"),
571 50 : "LL"))) ||
572 25 : (CSLFetchNameValue(papszGeoref, "projection.name") == nullptr))
573 : {
574 15 : return CE_Failure;
575 : }
576 :
577 11 : nGCPCount = 0;
578 11 : pasGCPList = static_cast<GDAL_GCP *>(CPLCalloc(sizeof(GDAL_GCP), 5));
579 :
580 : /* -------------------------------------------------------------------- */
581 : /* top left */
582 : /* -------------------------------------------------------------------- */
583 11 : GDALInitGCPs(1, pasGCPList + nGCPCount);
584 11 : CPLFree(pasGCPList[nGCPCount].pszId);
585 11 : pasGCPList[nGCPCount].pszId = CPLStrdup("top_left");
586 :
587 11 : double temp_lat = 0.0;
588 11 : double temp_long = 0.0;
589 11 : if (MFF2version > 1.0)
590 : {
591 11 : temp_lat = padfTransform[3];
592 11 : temp_long = padfTransform[0];
593 11 : pasGCPList[nGCPCount].dfGCPPixel = 0.0;
594 11 : pasGCPList[nGCPCount].dfGCPLine = 0.0;
595 : }
596 : else
597 : {
598 0 : temp_lat =
599 0 : padfTransform[3] + 0.5 * padfTransform[4] + 0.5 * padfTransform[5];
600 0 : temp_long =
601 0 : padfTransform[0] + 0.5 * padfTransform[1] + 0.5 * padfTransform[2];
602 0 : pasGCPList[nGCPCount].dfGCPPixel = 0.5;
603 0 : pasGCPList[nGCPCount].dfGCPLine = 0.5;
604 : }
605 11 : pasGCPList[nGCPCount].dfGCPX = temp_long;
606 11 : pasGCPList[nGCPCount].dfGCPY = temp_lat;
607 11 : pasGCPList[nGCPCount].dfGCPZ = 0.0;
608 11 : nGCPCount++;
609 :
610 11 : if (poTransform != nullptr)
611 : {
612 1 : if (!bSuccess || !poTransform->Transform(1, &temp_long, &temp_lat))
613 0 : bSuccess = false;
614 : }
615 :
616 11 : if (bSuccess)
617 : {
618 11 : char szValue[128] = {'\0'};
619 11 : CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_lat);
620 11 : papszGeoref =
621 11 : CSLSetNameValue(papszGeoref, "top_left.latitude", szValue);
622 :
623 11 : CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_long);
624 11 : papszGeoref =
625 11 : CSLSetNameValue(papszGeoref, "top_left.longitude", szValue);
626 : }
627 :
628 : /* -------------------------------------------------------------------- */
629 : /* top_right */
630 : /* -------------------------------------------------------------------- */
631 11 : GDALInitGCPs(1, pasGCPList + nGCPCount);
632 11 : CPLFree(pasGCPList[nGCPCount].pszId);
633 11 : pasGCPList[nGCPCount].pszId = CPLStrdup("top_right");
634 :
635 11 : if (MFF2version > 1.0)
636 : {
637 11 : temp_lat = padfTransform[3] + GetRasterXSize() * padfTransform[4];
638 11 : temp_long = padfTransform[0] + GetRasterXSize() * padfTransform[1];
639 11 : pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize();
640 11 : pasGCPList[nGCPCount].dfGCPLine = 0.0;
641 : }
642 : else
643 : {
644 0 : temp_lat = padfTransform[3] +
645 0 : (GetRasterXSize() - 0.5) * padfTransform[4] +
646 0 : 0.5 * padfTransform[5];
647 0 : temp_long = padfTransform[0] +
648 0 : (GetRasterXSize() - 0.5) * padfTransform[1] +
649 0 : 0.5 * padfTransform[2];
650 0 : pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() - 0.5;
651 0 : pasGCPList[nGCPCount].dfGCPLine = 0.5;
652 : }
653 11 : pasGCPList[nGCPCount].dfGCPX = temp_long;
654 11 : pasGCPList[nGCPCount].dfGCPY = temp_lat;
655 11 : pasGCPList[nGCPCount].dfGCPZ = 0.0;
656 11 : nGCPCount++;
657 :
658 11 : if (poTransform != nullptr)
659 : {
660 1 : if (!bSuccess || !poTransform->Transform(1, &temp_long, &temp_lat))
661 0 : bSuccess = false;
662 : }
663 :
664 11 : if (bSuccess)
665 : {
666 11 : char szValue[128] = {'\0'};
667 11 : CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_lat);
668 11 : papszGeoref =
669 11 : CSLSetNameValue(papszGeoref, "top_right.latitude", szValue);
670 :
671 11 : CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_long);
672 11 : papszGeoref =
673 11 : CSLSetNameValue(papszGeoref, "top_right.longitude", szValue);
674 : }
675 :
676 : /* -------------------------------------------------------------------- */
677 : /* bottom_left */
678 : /* -------------------------------------------------------------------- */
679 11 : GDALInitGCPs(1, pasGCPList + nGCPCount);
680 11 : CPLFree(pasGCPList[nGCPCount].pszId);
681 11 : pasGCPList[nGCPCount].pszId = CPLStrdup("bottom_left");
682 :
683 11 : if (MFF2version > 1.0)
684 : {
685 11 : temp_lat = padfTransform[3] + GetRasterYSize() * padfTransform[5];
686 11 : temp_long = padfTransform[0] + GetRasterYSize() * padfTransform[2];
687 11 : pasGCPList[nGCPCount].dfGCPPixel = 0.0;
688 11 : pasGCPList[nGCPCount].dfGCPLine = GetRasterYSize();
689 : }
690 : else
691 : {
692 0 : temp_lat = padfTransform[3] + 0.5 * padfTransform[4] +
693 0 : (GetRasterYSize() - 0.5) * padfTransform[5];
694 0 : temp_long = padfTransform[0] + 0.5 * padfTransform[1] +
695 0 : (GetRasterYSize() - 0.5) * padfTransform[2];
696 0 : pasGCPList[nGCPCount].dfGCPPixel = 0.5;
697 0 : pasGCPList[nGCPCount].dfGCPLine = GetRasterYSize() - 0.5;
698 : }
699 11 : pasGCPList[nGCPCount].dfGCPX = temp_long;
700 11 : pasGCPList[nGCPCount].dfGCPY = temp_lat;
701 11 : pasGCPList[nGCPCount].dfGCPZ = 0.0;
702 11 : nGCPCount++;
703 :
704 11 : if (poTransform != nullptr)
705 : {
706 1 : if (!bSuccess || !poTransform->Transform(1, &temp_long, &temp_lat))
707 0 : bSuccess = false;
708 : }
709 :
710 11 : if (bSuccess)
711 : {
712 11 : char szValue[128] = {'\0'};
713 11 : CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_lat);
714 11 : papszGeoref =
715 11 : CSLSetNameValue(papszGeoref, "bottom_left.latitude", szValue);
716 :
717 11 : CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_long);
718 11 : papszGeoref =
719 11 : CSLSetNameValue(papszGeoref, "bottom_left.longitude", szValue);
720 : }
721 :
722 : /* -------------------------------------------------------------------- */
723 : /* bottom_right */
724 : /* -------------------------------------------------------------------- */
725 11 : GDALInitGCPs(1, pasGCPList + nGCPCount);
726 11 : CPLFree(pasGCPList[nGCPCount].pszId);
727 11 : pasGCPList[nGCPCount].pszId = CPLStrdup("bottom_right");
728 :
729 11 : if (MFF2version > 1.0)
730 : {
731 11 : temp_lat = padfTransform[3] + GetRasterXSize() * padfTransform[4] +
732 11 : GetRasterYSize() * padfTransform[5];
733 11 : temp_long = padfTransform[0] + GetRasterXSize() * padfTransform[1] +
734 11 : GetRasterYSize() * padfTransform[2];
735 11 : pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize();
736 11 : pasGCPList[nGCPCount].dfGCPLine = GetRasterYSize();
737 : }
738 : else
739 : {
740 0 : temp_lat = padfTransform[3] +
741 0 : (GetRasterXSize() - 0.5) * padfTransform[4] +
742 0 : (GetRasterYSize() - 0.5) * padfTransform[5];
743 0 : temp_long = padfTransform[0] +
744 0 : (GetRasterXSize() - 0.5) * padfTransform[1] +
745 0 : (GetRasterYSize() - 0.5) * padfTransform[2];
746 0 : pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() - 0.5;
747 0 : pasGCPList[nGCPCount].dfGCPLine = GetRasterYSize() - 0.5;
748 : }
749 11 : pasGCPList[nGCPCount].dfGCPX = temp_long;
750 11 : pasGCPList[nGCPCount].dfGCPY = temp_lat;
751 11 : pasGCPList[nGCPCount].dfGCPZ = 0.0;
752 11 : nGCPCount++;
753 :
754 11 : if (poTransform != nullptr)
755 : {
756 1 : if (!bSuccess || !poTransform->Transform(1, &temp_long, &temp_lat))
757 0 : bSuccess = false;
758 : }
759 :
760 11 : if (bSuccess)
761 : {
762 11 : char szValue[128] = {'\0'};
763 11 : CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_lat);
764 11 : papszGeoref =
765 11 : CSLSetNameValue(papszGeoref, "bottom_right.latitude", szValue);
766 :
767 11 : CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_long);
768 11 : papszGeoref =
769 11 : CSLSetNameValue(papszGeoref, "bottom_right.longitude", szValue);
770 : }
771 :
772 : /* -------------------------------------------------------------------- */
773 : /* Center */
774 : /* -------------------------------------------------------------------- */
775 11 : GDALInitGCPs(1, pasGCPList + nGCPCount);
776 11 : CPLFree(pasGCPList[nGCPCount].pszId);
777 11 : pasGCPList[nGCPCount].pszId = CPLStrdup("centre");
778 :
779 11 : temp_lat = padfTransform[3] + GetRasterXSize() * padfTransform[4] * 0.5 +
780 11 : GetRasterYSize() * padfTransform[5] * 0.5;
781 11 : temp_long = padfTransform[0] + GetRasterXSize() * padfTransform[1] * 0.5 +
782 11 : GetRasterYSize() * padfTransform[2] * 0.5;
783 11 : pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() / 2.0;
784 11 : pasGCPList[nGCPCount].dfGCPLine = GetRasterYSize() / 2.0;
785 :
786 11 : pasGCPList[nGCPCount].dfGCPX = temp_long;
787 11 : pasGCPList[nGCPCount].dfGCPY = temp_lat;
788 11 : pasGCPList[nGCPCount].dfGCPZ = 0.0;
789 11 : nGCPCount++;
790 :
791 11 : if (poTransform != nullptr)
792 : {
793 1 : if (!bSuccess || !poTransform->Transform(1, &temp_long, &temp_lat))
794 0 : bSuccess = false;
795 : }
796 :
797 11 : if (bSuccess)
798 : {
799 11 : char szValue[128] = {'\0'};
800 11 : CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_lat);
801 11 : papszGeoref = CSLSetNameValue(papszGeoref, "centre.latitude", szValue);
802 :
803 11 : CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_long);
804 11 : papszGeoref = CSLSetNameValue(papszGeoref, "centre.longitude", szValue);
805 : }
806 :
807 11 : if (!bSuccess)
808 : {
809 0 : CPLError(CE_Warning, CPLE_AppDefined,
810 : "Error setting header info in SetGeoTransform. "
811 : "Changes may not be saved properly.");
812 : }
813 :
814 11 : if (poTransform != nullptr)
815 1 : delete poTransform;
816 :
817 11 : bGeorefChanged = true;
818 :
819 11 : return CE_None;
820 : }
821 :
822 : /************************************************************************/
823 : /* SetSpatialRef() */
824 : /* */
825 : /* We provide very limited support for setting the projection. */
826 : /************************************************************************/
827 :
828 26 : CPLErr HKVDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
829 :
830 : {
831 : // Update a georef file.
832 26 : if (poSRS == nullptr)
833 : {
834 0 : m_oSRS.Clear();
835 0 : return CE_None;
836 : }
837 26 : m_oSRS = *poSRS;
838 :
839 27 : if ((m_oSRS.GetAttrValue("PROJECTION") != nullptr) &&
840 1 : (EQUAL(m_oSRS.GetAttrValue("PROJECTION"), SRS_PT_TRANSVERSE_MERCATOR)))
841 : {
842 1 : papszGeoref = CSLSetNameValue(papszGeoref, "projection.name", "utm");
843 1 : OGRErr ogrerrorOl = OGRERR_NONE;
844 1 : papszGeoref = CSLSetNameValue(
845 : papszGeoref, "projection.origin_longitude",
846 : CPLSPrintf("%f", m_oSRS.GetProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0,
847 : &ogrerrorOl)));
848 : }
849 50 : else if (m_oSRS.GetAttrValue("PROJECTION") == nullptr &&
850 25 : m_oSRS.IsGeographic())
851 : {
852 25 : papszGeoref = CSLSetNameValue(papszGeoref, "projection.name", "LL");
853 : }
854 : else
855 : {
856 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unrecognized projection.");
857 0 : return CE_Failure;
858 : }
859 :
860 26 : OGRErr ogrerrorEq = OGRERR_NONE;
861 26 : const double eq_radius = m_oSRS.GetSemiMajor(&ogrerrorEq);
862 :
863 26 : OGRErr ogrerrorInvf = OGRERR_NONE;
864 26 : const double inv_flattening = m_oSRS.GetInvFlattening(&ogrerrorInvf);
865 :
866 26 : if ((ogrerrorEq == OGRERR_NONE) && (ogrerrorInvf == OGRERR_NONE))
867 : {
868 26 : HKVSpheroidList *hkvEllipsoids = new HKVSpheroidList;
869 : char *spheroid_name =
870 26 : hkvEllipsoids->GetSpheroidNameByEqRadiusAndInvFlattening(
871 : eq_radius, inv_flattening);
872 26 : if (spheroid_name != nullptr)
873 : {
874 26 : papszGeoref =
875 26 : CSLSetNameValue(papszGeoref, "spheroid.name", spheroid_name);
876 : }
877 26 : CPLFree(spheroid_name);
878 26 : delete hkvEllipsoids;
879 : }
880 : else
881 : {
882 : // Default to previous behavior if spheroid not found by radius and
883 : // inverse flattening.
884 0 : char *pszProjection = nullptr;
885 0 : m_oSRS.exportToWkt(&pszProjection);
886 0 : if (pszProjection && strstr(pszProjection, "Bessel") != nullptr)
887 : {
888 0 : papszGeoref =
889 0 : CSLSetNameValue(papszGeoref, "spheroid.name", "ev-bessel");
890 : }
891 : else
892 : {
893 0 : papszGeoref =
894 0 : CSLSetNameValue(papszGeoref, "spheroid.name", "ev-wgs-84");
895 : }
896 0 : CPLFree(pszProjection);
897 : }
898 26 : bGeorefChanged = true;
899 26 : return CE_None;
900 : }
901 :
902 : /************************************************************************/
903 : /* GetGCP() */
904 : /************************************************************************/
905 :
906 0 : const GDAL_GCP *HKVDataset::GetGCPs()
907 :
908 : {
909 0 : return pasGCPList;
910 : }
911 :
912 : /************************************************************************/
913 : /* ProcessGeorefGCP() */
914 : /************************************************************************/
915 :
916 90 : void HKVDataset::ProcessGeorefGCP(char **papszGeorefIn, const char *pszBase,
917 : double dfRasterX, double dfRasterY)
918 :
919 : {
920 : /* -------------------------------------------------------------------- */
921 : /* Fetch the GCP from the string list. */
922 : /* -------------------------------------------------------------------- */
923 90 : char szFieldName[128] = {'\0'};
924 90 : snprintf(szFieldName, sizeof(szFieldName), "%s.latitude", pszBase);
925 90 : double dfLat = 0.0;
926 90 : if (CSLFetchNameValue(papszGeorefIn, szFieldName) == nullptr)
927 75 : return;
928 : else
929 15 : dfLat = CPLAtof(CSLFetchNameValue(papszGeorefIn, szFieldName));
930 :
931 15 : snprintf(szFieldName, sizeof(szFieldName), "%s.longitude", pszBase);
932 15 : double dfLong = 0.0;
933 15 : if (CSLFetchNameValue(papszGeorefIn, szFieldName) == nullptr)
934 0 : return;
935 : else
936 15 : dfLong = CPLAtof(CSLFetchNameValue(papszGeorefIn, szFieldName));
937 :
938 : /* -------------------------------------------------------------------- */
939 : /* Add the gcp to the internal list. */
940 : /* -------------------------------------------------------------------- */
941 15 : GDALInitGCPs(1, pasGCPList + nGCPCount);
942 :
943 15 : CPLFree(pasGCPList[nGCPCount].pszId);
944 :
945 15 : pasGCPList[nGCPCount].pszId = CPLStrdup(pszBase);
946 :
947 15 : pasGCPList[nGCPCount].dfGCPX = dfLong;
948 15 : pasGCPList[nGCPCount].dfGCPY = dfLat;
949 15 : pasGCPList[nGCPCount].dfGCPZ = 0.0;
950 :
951 15 : pasGCPList[nGCPCount].dfGCPPixel = dfRasterX;
952 15 : pasGCPList[nGCPCount].dfGCPLine = dfRasterY;
953 :
954 15 : nGCPCount++;
955 : }
956 :
957 : /************************************************************************/
958 : /* ProcessGeoref() */
959 : /************************************************************************/
960 :
961 18 : void HKVDataset::ProcessGeoref(const char *pszFilename)
962 :
963 : {
964 : /* -------------------------------------------------------------------- */
965 : /* Load the georef file, and boil white space away from around */
966 : /* the equal sign. */
967 : /* -------------------------------------------------------------------- */
968 18 : CSLDestroy(papszGeoref);
969 18 : papszGeoref = CSLLoad(pszFilename);
970 18 : if (papszGeoref == nullptr)
971 0 : return;
972 :
973 18 : HKVSpheroidList *hkvEllipsoids = new HKVSpheroidList;
974 :
975 87 : for (int i = 0; papszGeoref[i] != nullptr; i++)
976 : {
977 69 : int iDst = 0;
978 69 : char *pszLine = papszGeoref[i];
979 :
980 1899 : for (int iSrc = 0; pszLine[iSrc] != '\0'; iSrc++)
981 : {
982 1830 : if (pszLine[iSrc] != ' ')
983 : {
984 1830 : pszLine[iDst++] = pszLine[iSrc];
985 : }
986 : }
987 69 : pszLine[iDst] = '\0';
988 : }
989 :
990 : /* -------------------------------------------------------------------- */
991 : /* Try to get GCPs, in lat/longs . */
992 : /* -------------------------------------------------------------------- */
993 18 : nGCPCount = 0;
994 18 : pasGCPList = reinterpret_cast<GDAL_GCP *>(CPLCalloc(sizeof(GDAL_GCP), 5));
995 :
996 18 : if (MFF2version > 1.0)
997 : {
998 18 : ProcessGeorefGCP(papszGeoref, "top_left", 0, 0);
999 18 : ProcessGeorefGCP(papszGeoref, "top_right", GetRasterXSize(), 0);
1000 18 : ProcessGeorefGCP(papszGeoref, "bottom_left", 0, GetRasterYSize());
1001 18 : ProcessGeorefGCP(papszGeoref, "bottom_right", GetRasterXSize(),
1002 18 : GetRasterYSize());
1003 18 : ProcessGeorefGCP(papszGeoref, "centre", GetRasterXSize() / 2.0,
1004 18 : GetRasterYSize() / 2.0);
1005 : }
1006 : else
1007 : {
1008 0 : ProcessGeorefGCP(papszGeoref, "top_left", 0.5, 0.5);
1009 0 : ProcessGeorefGCP(papszGeoref, "top_right", GetRasterXSize() - 0.5, 0.5);
1010 0 : ProcessGeorefGCP(papszGeoref, "bottom_left", 0.5,
1011 0 : GetRasterYSize() - 0.5);
1012 0 : ProcessGeorefGCP(papszGeoref, "bottom_right", GetRasterXSize() - 0.5,
1013 0 : GetRasterYSize() - 0.5);
1014 0 : ProcessGeorefGCP(papszGeoref, "centre", GetRasterXSize() / 2.0,
1015 0 : GetRasterYSize() / 2.0);
1016 : }
1017 :
1018 18 : if (nGCPCount == 0)
1019 : {
1020 15 : CPLFree(pasGCPList);
1021 15 : pasGCPList = nullptr;
1022 : }
1023 :
1024 : /* -------------------------------------------------------------------- */
1025 : /* Do we have a recognised projection? */
1026 : /* -------------------------------------------------------------------- */
1027 18 : const char *pszProjName = CSLFetchNameValue(papszGeoref, "projection.name");
1028 : const char *pszOriginLong =
1029 18 : CSLFetchNameValue(papszGeoref, "projection.origin_longitude");
1030 : const char *pszSpheroidName =
1031 18 : CSLFetchNameValue(papszGeoref, "spheroid.name");
1032 :
1033 36 : if (pszSpheroidName != nullptr &&
1034 18 : hkvEllipsoids->SpheroidInList(pszSpheroidName))
1035 : {
1036 : #if 0
1037 : // TODO(schwehr): Enable in trunk after 2.1 branch and fix.
1038 : // Breaks tests on some platforms.
1039 : CPLError( CE_Failure, CPLE_AppDefined,
1040 : "Unrecognized ellipsoid. Not handled. "
1041 : "Spheroid name not in spheroid list: '%s'",
1042 : pszSpheroidName );
1043 : #endif
1044 : // Why were eq_radius and inv_flattening never used?
1045 : // eq_radius = hkvEllipsoids->GetSpheroidEqRadius(pszSpheroidName);
1046 : // inv_flattening =
1047 : // hkvEllipsoids->GetSpheroidInverseFlattening(pszSpheroidName);
1048 : }
1049 0 : else if (pszProjName != nullptr)
1050 : {
1051 0 : CPLError(CE_Warning, CPLE_AppDefined,
1052 : "Unrecognized ellipsoid. Not handled.");
1053 : // TODO(schwehr): This error is was never what was happening.
1054 : // CPLError( CE_Warning, CPLE_AppDefined,
1055 : // "Unrecognized ellipsoid. Using wgs-84 parameters.");
1056 : // eq_radius=hkvEllipsoids->GetSpheroidEqRadius("wgs-84"); */
1057 : // inv_flattening=hkvEllipsoids->GetSpheroidInverseFlattening("wgs-84");
1058 : }
1059 :
1060 18 : if (pszProjName != nullptr && EQUAL(pszProjName, "utm") && nGCPCount == 5)
1061 : {
1062 : // int nZone = (int)((CPLAtof(pszOriginLong)+184.5) / 6.0);
1063 3 : int nZone = 31; // TODO(schwehr): Where does 31 come from?
1064 :
1065 3 : if (pszOriginLong == nullptr)
1066 : {
1067 : // If origin not specified, assume 0.0.
1068 0 : CPLError(
1069 : CE_Warning, CPLE_AppDefined,
1070 : "No projection origin longitude specified. Assuming 0.0.");
1071 : }
1072 : else
1073 : {
1074 3 : nZone = 31 + static_cast<int>(floor(CPLAtof(pszOriginLong) / 6.0));
1075 : }
1076 :
1077 6 : OGRSpatialReference oUTM;
1078 :
1079 3 : if (pasGCPList[4].dfGCPY < 0)
1080 0 : oUTM.SetUTM(nZone, 0);
1081 : else
1082 3 : oUTM.SetUTM(nZone, 1);
1083 :
1084 6 : OGRSpatialReference oLL;
1085 3 : oLL.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1086 3 : if (pszOriginLong != nullptr)
1087 : {
1088 3 : oUTM.SetProjParm(SRS_PP_CENTRAL_MERIDIAN, CPLAtof(pszOriginLong));
1089 3 : oLL.SetProjParm(SRS_PP_LONGITUDE_OF_ORIGIN, CPLAtof(pszOriginLong));
1090 : }
1091 :
1092 3 : if ((pszSpheroidName == nullptr) ||
1093 3 : (EQUAL(pszSpheroidName, "wgs-84")) ||
1094 3 : (EQUAL(pszSpheroidName, "wgs_84")))
1095 : {
1096 0 : oUTM.SetWellKnownGeogCS("WGS84");
1097 0 : oLL.SetWellKnownGeogCS("WGS84");
1098 : }
1099 : else
1100 : {
1101 3 : if (hkvEllipsoids->SpheroidInList(pszSpheroidName))
1102 : {
1103 3 : oUTM.SetGeogCS(
1104 : "unknown", "unknown", pszSpheroidName,
1105 : hkvEllipsoids->GetSpheroidEqRadius(pszSpheroidName),
1106 : hkvEllipsoids->GetSpheroidInverseFlattening(
1107 : pszSpheroidName));
1108 3 : oLL.SetGeogCS(
1109 : "unknown", "unknown", pszSpheroidName,
1110 : hkvEllipsoids->GetSpheroidEqRadius(pszSpheroidName),
1111 : hkvEllipsoids->GetSpheroidInverseFlattening(
1112 : pszSpheroidName));
1113 : }
1114 : else
1115 : {
1116 0 : CPLError(CE_Warning, CPLE_AppDefined,
1117 : "Unrecognized ellipsoid. Using wgs-84 parameters.");
1118 0 : oUTM.SetWellKnownGeogCS("WGS84");
1119 0 : oLL.SetWellKnownGeogCS("WGS84");
1120 : }
1121 : }
1122 :
1123 : OGRCoordinateTransformation *poTransform =
1124 3 : OGRCreateCoordinateTransformation(&oLL, &oUTM);
1125 :
1126 3 : bool bSuccess = true;
1127 3 : if (poTransform == nullptr)
1128 : {
1129 0 : CPLErrorReset();
1130 0 : bSuccess = false;
1131 : }
1132 :
1133 3 : double dfUtmX[5] = {0.0};
1134 3 : double dfUtmY[5] = {0.0};
1135 :
1136 3 : if (poTransform != nullptr)
1137 : {
1138 18 : for (int gcp_index = 0; gcp_index < 5; gcp_index++)
1139 : {
1140 15 : dfUtmX[gcp_index] = pasGCPList[gcp_index].dfGCPX;
1141 15 : dfUtmY[gcp_index] = pasGCPList[gcp_index].dfGCPY;
1142 :
1143 15 : if (bSuccess && !poTransform->Transform(1, &(dfUtmX[gcp_index]),
1144 : &(dfUtmY[gcp_index])))
1145 0 : bSuccess = false;
1146 : }
1147 : }
1148 :
1149 3 : if (bSuccess)
1150 : {
1151 : // Update GCPS to proper projection.
1152 18 : for (int gcp_index = 0; gcp_index < 5; gcp_index++)
1153 : {
1154 15 : pasGCPList[gcp_index].dfGCPX = dfUtmX[gcp_index];
1155 15 : pasGCPList[gcp_index].dfGCPY = dfUtmY[gcp_index];
1156 : }
1157 :
1158 3 : m_oGCPSRS = oUTM;
1159 :
1160 3 : bool transform_ok = CPL_TO_BOOL(
1161 3 : GDALGCPsToGeoTransform(5, pasGCPList, adfGeoTransform, 0));
1162 :
1163 3 : if (!transform_ok)
1164 : {
1165 : // Transform may not be sufficient in all cases (slant range
1166 : // projection).
1167 0 : adfGeoTransform[0] = 0.0;
1168 0 : adfGeoTransform[1] = 1.0;
1169 0 : adfGeoTransform[2] = 0.0;
1170 0 : adfGeoTransform[3] = 0.0;
1171 0 : adfGeoTransform[4] = 0.0;
1172 0 : adfGeoTransform[5] = 1.0;
1173 0 : m_oGCPSRS.Clear();
1174 : }
1175 : else
1176 : {
1177 3 : m_oSRS = std::move(oUTM);
1178 : }
1179 : }
1180 :
1181 3 : if (poTransform != nullptr)
1182 6 : delete poTransform;
1183 : }
1184 15 : else if (pszProjName != nullptr && nGCPCount == 5)
1185 : {
1186 0 : OGRSpatialReference oLL;
1187 0 : oLL.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1188 :
1189 0 : if (pszOriginLong != nullptr)
1190 : {
1191 0 : oLL.SetProjParm(SRS_PP_LONGITUDE_OF_ORIGIN, CPLAtof(pszOriginLong));
1192 : }
1193 :
1194 0 : if (pszSpheroidName == nullptr ||
1195 0 : EQUAL(pszSpheroidName, "wgs-84") || // Dash.
1196 0 : EQUAL(pszSpheroidName, "wgs_84")) // Underscore.
1197 : {
1198 0 : oLL.SetWellKnownGeogCS("WGS84");
1199 : }
1200 : else
1201 : {
1202 0 : if (hkvEllipsoids->SpheroidInList(pszSpheroidName))
1203 : {
1204 0 : oLL.SetGeogCS(
1205 : "", "", pszSpheroidName,
1206 : hkvEllipsoids->GetSpheroidEqRadius(pszSpheroidName),
1207 : hkvEllipsoids->GetSpheroidInverseFlattening(
1208 : pszSpheroidName));
1209 : }
1210 : else
1211 : {
1212 0 : CPLError(CE_Warning, CPLE_AppDefined,
1213 : "Unrecognized ellipsoid. "
1214 : "Using wgs-84 parameters.");
1215 0 : oLL.SetWellKnownGeogCS("WGS84");
1216 : }
1217 : }
1218 :
1219 0 : const bool transform_ok = CPL_TO_BOOL(
1220 0 : GDALGCPsToGeoTransform(5, pasGCPList, adfGeoTransform, 0));
1221 :
1222 0 : m_oSRS.Clear();
1223 :
1224 0 : if (!transform_ok)
1225 : {
1226 0 : adfGeoTransform[0] = 0.0;
1227 0 : adfGeoTransform[1] = 1.0;
1228 0 : adfGeoTransform[2] = 0.0;
1229 0 : adfGeoTransform[3] = 0.0;
1230 0 : adfGeoTransform[4] = 0.0;
1231 0 : adfGeoTransform[5] = 1.0;
1232 : }
1233 : else
1234 : {
1235 0 : m_oSRS = oLL;
1236 : }
1237 :
1238 0 : m_oGCPSRS = std::move(oLL);
1239 : }
1240 :
1241 18 : delete hkvEllipsoids;
1242 : }
1243 :
1244 : /************************************************************************/
1245 : /* Open() */
1246 : /************************************************************************/
1247 :
1248 31034 : GDALDataset *HKVDataset::Open(GDALOpenInfo *poOpenInfo)
1249 :
1250 : {
1251 : /* -------------------------------------------------------------------- */
1252 : /* We assume the dataset is passed as a directory. Check for */
1253 : /* an attrib and blob file as a minimum. */
1254 : /* -------------------------------------------------------------------- */
1255 31034 : if (!poOpenInfo->bIsDirectory)
1256 30762 : return nullptr;
1257 :
1258 : std::string osFilename =
1259 544 : CPLFormFilenameSafe(poOpenInfo->pszFilename, "image_data", nullptr);
1260 : VSIStatBuf sStat;
1261 272 : if (VSIStat(osFilename.c_str(), &sStat) != 0)
1262 : osFilename =
1263 228 : CPLFormFilenameSafe(poOpenInfo->pszFilename, "blob", nullptr);
1264 272 : if (VSIStat(osFilename.c_str(), &sStat) != 0)
1265 228 : return nullptr;
1266 :
1267 : osFilename =
1268 44 : CPLFormFilenameSafe(poOpenInfo->pszFilename, "attrib", nullptr);
1269 44 : if (VSIStat(osFilename.c_str(), &sStat) != 0)
1270 0 : return nullptr;
1271 :
1272 : /* -------------------------------------------------------------------- */
1273 : /* Load the attrib file, and boil white space away from around */
1274 : /* the equal sign. */
1275 : /* -------------------------------------------------------------------- */
1276 44 : char **papszAttrib = CSLLoad(osFilename.c_str());
1277 44 : if (papszAttrib == nullptr)
1278 0 : return nullptr;
1279 :
1280 440 : for (int i = 0; papszAttrib[i] != nullptr; i++)
1281 : {
1282 396 : int iDst = 0;
1283 396 : char *pszLine = papszAttrib[i];
1284 :
1285 11173 : for (int iSrc = 0; pszLine[iSrc] != '\0'; iSrc++)
1286 : {
1287 10777 : if (pszLine[iSrc] != ' ')
1288 : {
1289 9369 : pszLine[iDst++] = pszLine[iSrc];
1290 : }
1291 : }
1292 396 : pszLine[iDst] = '\0';
1293 : }
1294 :
1295 : /* -------------------------------------------------------------------- */
1296 : /* Create a corresponding GDALDataset. */
1297 : /* -------------------------------------------------------------------- */
1298 88 : auto poDS = std::make_unique<HKVDataset>();
1299 :
1300 44 : poDS->pszPath = CPLStrdup(poOpenInfo->pszFilename);
1301 44 : poDS->papszAttrib = papszAttrib;
1302 :
1303 44 : poDS->eAccess = poOpenInfo->eAccess;
1304 :
1305 : /* -------------------------------------------------------------------- */
1306 : /* Set some dataset wide information. */
1307 : /* -------------------------------------------------------------------- */
1308 44 : bool bNative = false;
1309 44 : bool bComplex = false;
1310 44 : int nRawBands = 0;
1311 :
1312 88 : if (CSLFetchNameValue(papszAttrib, "extent.cols") == nullptr ||
1313 44 : CSLFetchNameValue(papszAttrib, "extent.rows") == nullptr)
1314 : {
1315 0 : return nullptr;
1316 : }
1317 :
1318 44 : poDS->nRasterXSize = atoi(CSLFetchNameValue(papszAttrib, "extent.cols"));
1319 44 : poDS->nRasterYSize = atoi(CSLFetchNameValue(papszAttrib, "extent.rows"));
1320 :
1321 44 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
1322 : {
1323 0 : return nullptr;
1324 : }
1325 :
1326 44 : const char *pszValue = CSLFetchNameValue(papszAttrib, "pixel.order");
1327 44 : if (pszValue == nullptr)
1328 0 : bNative = true;
1329 : else
1330 : {
1331 : #ifdef CPL_MSB
1332 : bNative = strstr(pszValue, "*msbf") != NULL;
1333 : #else
1334 44 : bNative = strstr(pszValue, "*lsbf") != nullptr;
1335 : #endif
1336 : }
1337 :
1338 44 : bool bNoDataSet = false;
1339 44 : double dfNoDataValue = 0.0;
1340 44 : pszValue = CSLFetchNameValue(papszAttrib, "pixel.no_data");
1341 44 : if (pszValue != nullptr)
1342 : {
1343 0 : bNoDataSet = true;
1344 0 : dfNoDataValue = CPLAtof(pszValue);
1345 : }
1346 :
1347 44 : pszValue = CSLFetchNameValue(papszAttrib, "channel.enumeration");
1348 44 : if (pszValue != nullptr)
1349 44 : nRawBands = atoi(pszValue);
1350 : else
1351 0 : nRawBands = 1;
1352 :
1353 44 : if (!GDALCheckBandCount(nRawBands, TRUE))
1354 : {
1355 0 : return nullptr;
1356 : }
1357 :
1358 44 : pszValue = CSLFetchNameValue(papszAttrib, "pixel.field");
1359 44 : if (pszValue != nullptr && strstr(pszValue, "*complex") != nullptr)
1360 10 : bComplex = true;
1361 : else
1362 34 : bComplex = false;
1363 :
1364 : /* Get the version number, if present (if not, assume old version. */
1365 : /* Versions differ in their interpretation of corner coordinates. */
1366 :
1367 44 : if (CSLFetchNameValue(papszAttrib, "version") != nullptr)
1368 44 : poDS->SetVersion(static_cast<float>(
1369 44 : CPLAtof(CSLFetchNameValue(papszAttrib, "version"))));
1370 : else
1371 0 : poDS->SetVersion(1.0);
1372 :
1373 : /* -------------------------------------------------------------------- */
1374 : /* Figure out the datatype */
1375 : /* -------------------------------------------------------------------- */
1376 44 : const char *pszEncoding = CSLFetchNameValue(papszAttrib, "pixel.encoding");
1377 44 : if (pszEncoding == nullptr)
1378 0 : pszEncoding = "{ *unsigned }";
1379 :
1380 44 : int nSize = 1;
1381 44 : if (CSLFetchNameValue(papszAttrib, "pixel.size") != nullptr)
1382 44 : nSize = atoi(CSLFetchNameValue(papszAttrib, "pixel.size")) / 8;
1383 : #if 0
1384 : int nPseudoBands;
1385 : if( bComplex )
1386 : nPseudoBands = 2;
1387 : else
1388 : nPseudoBands = 1;
1389 : #endif
1390 :
1391 : GDALDataType eType;
1392 44 : if (nSize == 1)
1393 19 : eType = GDT_Byte;
1394 25 : else if (nSize == 2 && strstr(pszEncoding, "*unsigned") != nullptr)
1395 5 : eType = GDT_UInt16;
1396 20 : else if (nSize == 4 && bComplex)
1397 5 : eType = GDT_CInt16;
1398 15 : else if (nSize == 2)
1399 5 : eType = GDT_Int16;
1400 10 : else if (nSize == 4 && strstr(pszEncoding, "*unsigned") != nullptr)
1401 0 : eType = GDT_UInt32;
1402 10 : else if (nSize == 8 && strstr(pszEncoding, "*two") != nullptr && bComplex)
1403 0 : eType = GDT_CInt32;
1404 10 : else if (nSize == 4 && strstr(pszEncoding, "*two") != nullptr)
1405 0 : eType = GDT_Int32;
1406 10 : else if (nSize == 8 && bComplex)
1407 5 : eType = GDT_CFloat32;
1408 5 : else if (nSize == 4)
1409 5 : eType = GDT_Float32;
1410 0 : else if (nSize == 16 && bComplex)
1411 0 : eType = GDT_CFloat64;
1412 0 : else if (nSize == 8)
1413 0 : eType = GDT_Float64;
1414 : else
1415 : {
1416 0 : CPLError(CE_Failure, CPLE_AppDefined,
1417 : "Unsupported pixel data type in %s.\n"
1418 : "pixel.size=%d pixel.encoding=%s",
1419 0 : poDS->pszPath, nSize, pszEncoding);
1420 0 : return nullptr;
1421 : }
1422 :
1423 : /* -------------------------------------------------------------------- */
1424 : /* Open the blob file. */
1425 : /* -------------------------------------------------------------------- */
1426 44 : osFilename = CPLFormFilenameSafe(poDS->pszPath, "image_data", nullptr);
1427 44 : if (VSIStat(osFilename.c_str(), &sStat) != 0)
1428 0 : osFilename = CPLFormFilenameSafe(poDS->pszPath, "blob", nullptr);
1429 44 : if (poOpenInfo->eAccess == GA_ReadOnly)
1430 : {
1431 18 : poDS->fpBlob = VSIFOpenL(osFilename.c_str(), "rb");
1432 18 : if (poDS->fpBlob == nullptr)
1433 : {
1434 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1435 : "Unable to open file %s for read access.",
1436 : osFilename.c_str());
1437 0 : return nullptr;
1438 : }
1439 : }
1440 : else
1441 : {
1442 26 : poDS->fpBlob = VSIFOpenL(osFilename.c_str(), "rb+");
1443 26 : if (poDS->fpBlob == nullptr)
1444 : {
1445 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1446 : "Unable to open file %s for update access.",
1447 : osFilename.c_str());
1448 0 : return nullptr;
1449 : }
1450 : }
1451 :
1452 : /* -------------------------------------------------------------------- */
1453 : /* Build the overview filename, as blob file = "_ovr". */
1454 : /* -------------------------------------------------------------------- */
1455 88 : std::string osOvrFilename(osFilename);
1456 44 : osOvrFilename += "_ovr";
1457 :
1458 : /* -------------------------------------------------------------------- */
1459 : /* Define the bands. */
1460 : /* -------------------------------------------------------------------- */
1461 44 : const int nPixelOffset = nRawBands * nSize;
1462 44 : const int nLineOffset = nPixelOffset * poDS->GetRasterXSize();
1463 44 : int nOffset = 0;
1464 :
1465 138 : for (int iRawBand = 0; iRawBand < nRawBands; iRawBand++)
1466 : {
1467 : auto poBand = std::make_unique<HKVRasterBand>(
1468 94 : poDS.get(), poDS->GetRasterCount() + 1, poDS->fpBlob, nOffset,
1469 94 : nPixelOffset, nLineOffset, eType, bNative);
1470 94 : if (!poBand->IsValid())
1471 0 : return nullptr;
1472 :
1473 94 : if (bNoDataSet)
1474 0 : poBand->SetNoDataValue(dfNoDataValue);
1475 94 : poDS->SetBand(poDS->GetRasterCount() + 1, std::move(poBand));
1476 94 : nOffset += GDALGetDataTypeSizeBytes(eType);
1477 : }
1478 :
1479 44 : poDS->eRasterType = eType;
1480 :
1481 : /* -------------------------------------------------------------------- */
1482 : /* Process the georef file if there is one. */
1483 : /* -------------------------------------------------------------------- */
1484 44 : osFilename = CPLFormFilenameSafe(poDS->pszPath, "georef", nullptr);
1485 44 : if (VSIStat(osFilename.c_str(), &sStat) == 0)
1486 18 : poDS->ProcessGeoref(osFilename.c_str());
1487 :
1488 : /* -------------------------------------------------------------------- */
1489 : /* Initialize any PAM information. */
1490 : /* -------------------------------------------------------------------- */
1491 44 : poDS->SetDescription(osOvrFilename.c_str());
1492 44 : poDS->TryLoadXML();
1493 :
1494 : /* -------------------------------------------------------------------- */
1495 : /* Handle overviews. */
1496 : /* -------------------------------------------------------------------- */
1497 44 : poDS->oOvManager.Initialize(poDS.get(), osOvrFilename.c_str(), nullptr,
1498 : TRUE);
1499 :
1500 44 : return poDS.release();
1501 : }
1502 :
1503 : /************************************************************************/
1504 : /* Create() */
1505 : /************************************************************************/
1506 :
1507 51 : GDALDataset *HKVDataset::Create(const char *pszFilenameIn, int nXSize,
1508 : int nYSize, int nBandsIn, GDALDataType eType,
1509 : char ** /* papszParamList */)
1510 :
1511 : {
1512 : /* -------------------------------------------------------------------- */
1513 : /* Verify input options. */
1514 : /* -------------------------------------------------------------------- */
1515 51 : if (nBandsIn <= 0)
1516 : {
1517 1 : CPLError(CE_Failure, CPLE_NotSupported,
1518 : "HKV driver does not support %d bands.", nBandsIn);
1519 1 : return nullptr;
1520 : }
1521 :
1522 50 : if (eType != GDT_Byte && eType != GDT_UInt16 && eType != GDT_Int16 &&
1523 27 : eType != GDT_CInt16 && eType != GDT_Float32 && eType != GDT_CFloat32)
1524 : {
1525 21 : CPLError(CE_Failure, CPLE_AppDefined,
1526 : "Attempt to create HKV file with currently unsupported\n"
1527 : "data type (%s).",
1528 : GDALGetDataTypeName(eType));
1529 :
1530 21 : return nullptr;
1531 : }
1532 :
1533 : /* -------------------------------------------------------------------- */
1534 : /* Establish the name of the directory we will be creating the */
1535 : /* new HKV directory in. Verify that this is a directory. */
1536 : /* -------------------------------------------------------------------- */
1537 29 : char *pszBaseDir = nullptr;
1538 :
1539 29 : if (strlen(CPLGetPathSafe(pszFilenameIn).c_str()) == 0)
1540 0 : pszBaseDir = CPLStrdup(".");
1541 : else
1542 29 : pszBaseDir = CPLStrdup(CPLGetPathSafe(pszFilenameIn).c_str());
1543 :
1544 : VSIStatBuf sStat;
1545 29 : if (CPLStat(pszBaseDir, &sStat) != 0 || !VSI_ISDIR(sStat.st_mode))
1546 : {
1547 3 : CPLError(CE_Failure, CPLE_AppDefined,
1548 : "Attempt to create HKV dataset under %s,\n"
1549 : "but this is not a valid directory.",
1550 : pszBaseDir);
1551 3 : CPLFree(pszBaseDir);
1552 3 : return nullptr;
1553 : }
1554 :
1555 26 : CPLFree(pszBaseDir);
1556 26 : pszBaseDir = nullptr;
1557 :
1558 26 : if (VSIMkdir(pszFilenameIn, 0755) != 0)
1559 : {
1560 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unable to create directory %s.",
1561 : pszFilenameIn);
1562 0 : return nullptr;
1563 : }
1564 :
1565 : /* -------------------------------------------------------------------- */
1566 : /* Create the header file. */
1567 : /* -------------------------------------------------------------------- */
1568 26 : CPLErr CEHeaderCreated = SaveHKVAttribFile(pszFilenameIn, nXSize, nYSize,
1569 : nBandsIn, eType, FALSE, 0.0);
1570 :
1571 26 : if (CEHeaderCreated != CE_None)
1572 0 : return nullptr;
1573 :
1574 : /* -------------------------------------------------------------------- */
1575 : /* Create the blob file. */
1576 : /* -------------------------------------------------------------------- */
1577 :
1578 : const std::string osFilename =
1579 52 : CPLFormFilenameSafe(pszFilenameIn, "image_data", nullptr);
1580 26 : FILE *fp = VSIFOpen(osFilename.c_str(), "wb");
1581 26 : if (fp == nullptr)
1582 : {
1583 0 : CPLError(CE_Failure, CPLE_OpenFailed, "Couldn't create %s.\n",
1584 : osFilename.c_str());
1585 0 : return nullptr;
1586 : }
1587 :
1588 26 : bool bOK = VSIFWrite(reinterpret_cast<void *>(const_cast<char *>("")), 1, 1,
1589 26 : fp) == 1;
1590 26 : if (VSIFClose(fp) != 0)
1591 0 : bOK &= false;
1592 :
1593 26 : if (!bOK)
1594 0 : return nullptr;
1595 : /* -------------------------------------------------------------------- */
1596 : /* Open the dataset normally. */
1597 : /* -------------------------------------------------------------------- */
1598 26 : return GDALDataset::FromHandle(GDALOpen(pszFilenameIn, GA_Update));
1599 : }
1600 :
1601 : /************************************************************************/
1602 : /* Delete() */
1603 : /* */
1604 : /* An HKV Blob dataset consists of a bunch of files in a */
1605 : /* directory. Try to delete all the files, then the */
1606 : /* directory. */
1607 : /************************************************************************/
1608 :
1609 1 : CPLErr HKVDataset::Delete(const char *pszName)
1610 :
1611 : {
1612 : VSIStatBuf sStat;
1613 1 : if (CPLStat(pszName, &sStat) != 0 || !VSI_ISDIR(sStat.st_mode))
1614 : {
1615 0 : CPLError(CE_Failure, CPLE_AppDefined,
1616 : "%s does not appear to be an HKV Dataset, as it is not "
1617 : "a path to a directory.",
1618 : pszName);
1619 0 : return CE_Failure;
1620 : }
1621 :
1622 1 : char **papszFiles = VSIReadDir(pszName);
1623 6 : for (int i = 0; i < CSLCount(papszFiles); i++)
1624 : {
1625 5 : if (EQUAL(papszFiles[i], ".") || EQUAL(papszFiles[i], ".."))
1626 2 : continue;
1627 :
1628 : const std::string osTarget =
1629 3 : CPLFormFilenameSafe(pszName, papszFiles[i], nullptr);
1630 3 : if (VSIUnlink(osTarget.c_str()) != 0)
1631 : {
1632 0 : CPLError(CE_Failure, CPLE_AppDefined,
1633 : "Unable to delete file %s,"
1634 : "HKVDataset Delete(%s) failed.",
1635 : osTarget.c_str(), pszName);
1636 0 : CSLDestroy(papszFiles);
1637 0 : return CE_Failure;
1638 : }
1639 : }
1640 :
1641 1 : CSLDestroy(papszFiles);
1642 :
1643 1 : if (VSIRmdir(pszName) != 0)
1644 : {
1645 0 : CPLError(CE_Failure, CPLE_AppDefined,
1646 : "Unable to delete directory %s,"
1647 : "HKVDataset Delete() failed.",
1648 : pszName);
1649 0 : return CE_Failure;
1650 : }
1651 :
1652 1 : return CE_None;
1653 : }
1654 :
1655 : /************************************************************************/
1656 : /* CreateCopy() */
1657 : /************************************************************************/
1658 :
1659 20 : GDALDataset *HKVDataset::CreateCopy(const char *pszFilename,
1660 : GDALDataset *poSrcDS,
1661 : CPL_UNUSED int bStrict, char **papszOptions,
1662 : GDALProgressFunc pfnProgress,
1663 : void *pProgressData)
1664 : {
1665 20 : int nBands = poSrcDS->GetRasterCount();
1666 20 : if (nBands == 0)
1667 : {
1668 1 : CPLError(CE_Failure, CPLE_NotSupported,
1669 : "HKV driver does not support source dataset with zero band.");
1670 1 : return nullptr;
1671 : }
1672 :
1673 19 : GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
1674 :
1675 19 : if (!pfnProgress(0.0, nullptr, pProgressData))
1676 0 : return nullptr;
1677 :
1678 : /* check that other bands match type- sets type */
1679 : /* to unknown if they differ. */
1680 29 : for (int iBand = 1; iBand < poSrcDS->GetRasterCount(); iBand++)
1681 : {
1682 10 : GDALRasterBand *poBand = poSrcDS->GetRasterBand(iBand + 1);
1683 10 : eType = GDALDataTypeUnion(eType, poBand->GetRasterDataType());
1684 : }
1685 :
1686 19 : HKVDataset *poDS = reinterpret_cast<HKVDataset *>(Create(
1687 : pszFilename, poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(),
1688 : poSrcDS->GetRasterCount(), eType, papszOptions));
1689 :
1690 : /* Check that Create worked- return Null if it didn't */
1691 19 : if (poDS == nullptr)
1692 8 : return nullptr;
1693 :
1694 : /* -------------------------------------------------------------------- */
1695 : /* Copy the image data. */
1696 : /* -------------------------------------------------------------------- */
1697 11 : const int nXSize = poDS->GetRasterXSize();
1698 11 : const int nYSize = poDS->GetRasterYSize();
1699 :
1700 : int nBlockXSize, nBlockYSize;
1701 11 : poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
1702 :
1703 11 : const int nBlockTotal = ((nXSize + nBlockXSize - 1) / nBlockXSize) *
1704 11 : ((nYSize + nBlockYSize - 1) / nBlockYSize) *
1705 11 : poSrcDS->GetRasterCount();
1706 :
1707 11 : int nBlocksDone = 0;
1708 32 : for (int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++)
1709 : {
1710 21 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
1711 21 : GDALRasterBand *poDstBand = poDS->GetRasterBand(iBand + 1);
1712 :
1713 : /* Get nodata value, if relevant */
1714 21 : int pbSuccess = FALSE;
1715 21 : double dfSrcNoDataValue = poSrcBand->GetNoDataValue(&pbSuccess);
1716 21 : if (pbSuccess)
1717 0 : poDS->SetNoDataValue(dfSrcNoDataValue);
1718 :
1719 63 : void *pData = CPLMalloc(nBlockXSize * nBlockYSize *
1720 21 : GDALGetDataTypeSize(eType) / 8);
1721 :
1722 241 : for (int iYOffset = 0; iYOffset < nYSize; iYOffset += nBlockYSize)
1723 : {
1724 440 : for (int iXOffset = 0; iXOffset < nXSize; iXOffset += nBlockXSize)
1725 : {
1726 220 : if (!pfnProgress((nBlocksDone++) /
1727 220 : static_cast<float>(nBlockTotal),
1728 : nullptr, pProgressData))
1729 : {
1730 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
1731 0 : delete poDS;
1732 0 : CPLFree(pData);
1733 :
1734 : GDALDriver *poHKVDriver = reinterpret_cast<GDALDriver *>(
1735 0 : GDALGetDriverByName("MFF2"));
1736 0 : poHKVDriver->Delete(pszFilename);
1737 0 : return nullptr;
1738 : }
1739 :
1740 220 : const int nTBXSize = std::min(nBlockXSize, nXSize - iXOffset);
1741 220 : const int nTBYSize = std::min(nBlockYSize, nYSize - iYOffset);
1742 :
1743 220 : CPLErr eErr = poSrcBand->RasterIO(
1744 : GF_Read, iXOffset, iYOffset, nTBXSize, nTBYSize, pData,
1745 : nTBXSize, nTBYSize, eType, 0, 0, nullptr);
1746 220 : if (eErr != CE_None)
1747 : {
1748 0 : delete poDS;
1749 0 : CPLFree(pData);
1750 0 : return nullptr;
1751 : }
1752 :
1753 220 : eErr = poDstBand->RasterIO(GF_Write, iXOffset, iYOffset,
1754 : nTBXSize, nTBYSize, pData, nTBXSize,
1755 : nTBYSize, eType, 0, 0, nullptr);
1756 :
1757 220 : if (eErr != CE_None)
1758 : {
1759 0 : delete poDS;
1760 0 : CPLFree(pData);
1761 0 : return nullptr;
1762 : }
1763 : }
1764 : }
1765 :
1766 21 : CPLFree(pData);
1767 : }
1768 :
1769 : /* -------------------------------------------------------------------- */
1770 : /* Copy georeferencing information, if enough is available. */
1771 : /* Only copy geotransform-style info (won't work for slant range). */
1772 : /* -------------------------------------------------------------------- */
1773 :
1774 : double *tempGeoTransform =
1775 11 : static_cast<double *>(CPLMalloc(6 * sizeof(double)));
1776 :
1777 22 : if ((poSrcDS->GetGeoTransform(tempGeoTransform) == CE_None) &&
1778 11 : (tempGeoTransform[0] != 0.0 || tempGeoTransform[1] != 1.0 ||
1779 0 : tempGeoTransform[2] != 0.0 || tempGeoTransform[3] != 0.0 ||
1780 0 : tempGeoTransform[4] != 0.0 || std::abs(tempGeoTransform[5]) != 1.0))
1781 : {
1782 11 : auto poSrcSRS = poSrcDS->GetSpatialRef();
1783 11 : if (poSrcSRS)
1784 : {
1785 11 : poDS->SetSpatialRef(poSrcSRS);
1786 11 : poDS->m_oGCPSRS = *poSrcSRS;
1787 : }
1788 11 : poDS->SetGeoTransform(tempGeoTransform);
1789 :
1790 11 : CPLFree(tempGeoTransform);
1791 :
1792 : // georef file will be saved automatically when dataset is deleted
1793 : // because SetProjection sets a flag to indicate it is necessary.
1794 : }
1795 : else
1796 : {
1797 0 : CPLFree(tempGeoTransform);
1798 : }
1799 :
1800 : // Make sure image data gets flushed.
1801 32 : for (int iBand = 0; iBand < poDS->GetRasterCount(); iBand++)
1802 : {
1803 : RawRasterBand *poDstBand =
1804 21 : reinterpret_cast<RawRasterBand *>(poDS->GetRasterBand(iBand + 1));
1805 21 : poDstBand->FlushCache(false);
1806 : }
1807 :
1808 11 : if (!pfnProgress(1.0, nullptr, pProgressData))
1809 : {
1810 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
1811 0 : delete poDS;
1812 :
1813 : GDALDriver *poHKVDriver =
1814 0 : reinterpret_cast<GDALDriver *>(GDALGetDriverByName("MFF2"));
1815 0 : poHKVDriver->Delete(pszFilename);
1816 0 : return nullptr;
1817 : }
1818 :
1819 11 : poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
1820 :
1821 11 : return poDS;
1822 : }
1823 :
1824 : /************************************************************************/
1825 : /* GDALRegister_HKV() */
1826 : /************************************************************************/
1827 :
1828 1682 : void GDALRegister_HKV()
1829 :
1830 : {
1831 1682 : if (GDALGetDriverByName("MFF2") != nullptr)
1832 301 : return;
1833 :
1834 1381 : GDALDriver *poDriver = new GDALDriver();
1835 :
1836 1381 : poDriver->SetDescription("MFF2");
1837 1381 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1838 1381 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Vexcel MFF2 (HKV) Raster");
1839 1381 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/mff2.html");
1840 1381 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
1841 : "Byte Int16 UInt16 Int32 UInt32 CInt16 "
1842 1381 : "CInt32 Float32 Float64 CFloat32 CFloat64");
1843 :
1844 1381 : poDriver->pfnOpen = HKVDataset::Open;
1845 1381 : poDriver->pfnCreate = HKVDataset::Create;
1846 1381 : poDriver->pfnDelete = HKVDataset::Delete;
1847 1381 : poDriver->pfnCreateCopy = HKVDataset::CreateCopy;
1848 :
1849 1381 : GetGDALDriverManager()->RegisterDriver(poDriver);
1850 : }
|