Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Hierarchical Data Format Release 5 (HDF5)
4 : * Purpose: Read S102 bathymetric datasets.
5 : * Author: Even Rouault <even dot rouault at spatialys dot com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2023, Even Rouault <even dot rouault at spatialys dot com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_port.h"
14 : #include "hdf5dataset.h"
15 : #include "hdf5drivercore.h"
16 : #include "gh5_convenience.h"
17 : #include "rat.h"
18 : #include "s100.h"
19 :
20 : #include "gdal_priv.h"
21 : #include "gdal_proxy.h"
22 : #include "gdal_rat.h"
23 :
24 : #include <cmath>
25 : #include <limits>
26 :
27 : /************************************************************************/
28 : /* S102Dataset */
29 : /************************************************************************/
30 :
31 44 : class S102Dataset final : public S100BaseDataset
32 : {
33 : bool OpenQuality(GDALOpenInfo *poOpenInfo,
34 : const std::shared_ptr<GDALGroup> &poRootGroup);
35 :
36 : public:
37 22 : explicit S102Dataset(const std::string &osFilename)
38 22 : : S100BaseDataset(osFilename)
39 : {
40 22 : }
41 :
42 : ~S102Dataset() override;
43 :
44 : static GDALDataset *Open(GDALOpenInfo *);
45 : };
46 :
47 : S102Dataset::~S102Dataset() = default;
48 :
49 : /************************************************************************/
50 : /* S102RasterBand */
51 : /************************************************************************/
52 :
53 : class S102RasterBand : public GDALProxyRasterBand
54 : {
55 : friend class S102Dataset;
56 : std::unique_ptr<GDALDataset> m_poDS{};
57 : GDALRasterBand *m_poUnderlyingBand = nullptr;
58 : double m_dfMinimum = std::numeric_limits<double>::quiet_NaN();
59 : double m_dfMaximum = std::numeric_limits<double>::quiet_NaN();
60 :
61 : CPL_DISALLOW_COPY_ASSIGN(S102RasterBand)
62 :
63 : public:
64 31 : explicit S102RasterBand(std::unique_ptr<GDALDataset> &&poDSIn)
65 62 : : m_poDS(std::move(poDSIn)),
66 31 : m_poUnderlyingBand(m_poDS->GetRasterBand(1))
67 : {
68 31 : eDataType = m_poUnderlyingBand->GetRasterDataType();
69 31 : m_poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
70 31 : }
71 :
72 : GDALRasterBand *
73 : RefUnderlyingRasterBand(bool /*bForceOpen*/ = true) const override;
74 :
75 8 : double GetMinimum(int *pbSuccess = nullptr) override
76 : {
77 8 : if (pbSuccess)
78 8 : *pbSuccess = !std::isnan(m_dfMinimum);
79 8 : return m_dfMinimum;
80 : }
81 :
82 8 : double GetMaximum(int *pbSuccess = nullptr) override
83 : {
84 8 : if (pbSuccess)
85 8 : *pbSuccess = !std::isnan(m_dfMaximum);
86 8 : return m_dfMaximum;
87 : }
88 :
89 4 : const char *GetUnitType() override
90 : {
91 4 : return "metre";
92 : }
93 : };
94 :
95 : GDALRasterBand *
96 23 : S102RasterBand::RefUnderlyingRasterBand(bool /*bForceOpen*/) const
97 : {
98 23 : return m_poUnderlyingBand;
99 : }
100 :
101 : /************************************************************************/
102 : /* S102GeoreferencedMetadataRasterBand */
103 : /************************************************************************/
104 :
105 : class S102GeoreferencedMetadataRasterBand : public GDALProxyRasterBand
106 : {
107 : friend class S102Dataset;
108 :
109 : std::unique_ptr<GDALDataset> m_poDS{};
110 : GDALRasterBand *m_poUnderlyingBand = nullptr;
111 : std::unique_ptr<GDALRasterAttributeTable> m_poRAT{};
112 :
113 : CPL_DISALLOW_COPY_ASSIGN(S102GeoreferencedMetadataRasterBand)
114 :
115 : public:
116 4 : explicit S102GeoreferencedMetadataRasterBand(
117 : std::unique_ptr<GDALDataset> &&poDSIn,
118 : std::unique_ptr<GDALRasterAttributeTable> &&poRAT)
119 8 : : m_poDS(std::move(poDSIn)),
120 4 : m_poUnderlyingBand(m_poDS->GetRasterBand(1)),
121 8 : m_poRAT(std::move(poRAT))
122 : {
123 4 : eDataType = m_poUnderlyingBand->GetRasterDataType();
124 4 : m_poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
125 4 : }
126 :
127 : GDALRasterBand *
128 : RefUnderlyingRasterBand(bool /*bForceOpen*/ = true) const override;
129 :
130 2 : GDALRasterAttributeTable *GetDefaultRAT() override
131 : {
132 2 : return m_poRAT.get();
133 : }
134 : };
135 :
136 6 : GDALRasterBand *S102GeoreferencedMetadataRasterBand::RefUnderlyingRasterBand(
137 : bool /*bForceOpen*/) const
138 : {
139 6 : return m_poUnderlyingBand;
140 : }
141 :
142 : /************************************************************************/
143 : /* Open() */
144 : /************************************************************************/
145 :
146 26 : GDALDataset *S102Dataset::Open(GDALOpenInfo *poOpenInfo)
147 :
148 : {
149 : // Confirm that this appears to be a S102 file.
150 26 : if (!S102DatasetIdentify(poOpenInfo))
151 0 : return nullptr;
152 :
153 : HDF5_GLOBAL_LOCK();
154 :
155 26 : if (poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER)
156 : {
157 2 : return HDF5Dataset::OpenMultiDim(poOpenInfo);
158 : }
159 :
160 : // Confirm the requested access is supported.
161 24 : if (poOpenInfo->eAccess == GA_Update)
162 : {
163 0 : ReportUpdateNotSupportedByDriver("S102");
164 0 : return nullptr;
165 : }
166 :
167 48 : std::string osFilename(poOpenInfo->pszFilename);
168 24 : bool bIsSubdataset = false;
169 24 : bool bIsQuality = false;
170 24 : if (STARTS_WITH(poOpenInfo->pszFilename, "S102:"))
171 : {
172 : const CPLStringList aosTokens(
173 11 : CSLTokenizeString2(poOpenInfo->pszFilename, ":",
174 11 : CSLT_HONOURSTRINGS | CSLT_PRESERVEESCAPES));
175 :
176 11 : if (aosTokens.size() == 2)
177 : {
178 1 : osFilename = aosTokens[1];
179 : }
180 10 : else if (aosTokens.size() == 3)
181 : {
182 10 : bIsSubdataset = true;
183 10 : osFilename = aosTokens[1];
184 10 : if (EQUAL(aosTokens[2], "BathymetryCoverage"))
185 : {
186 : // Default dataset
187 : }
188 12 : else if (EQUAL(aosTokens[2], "QualityOfSurvey") || // < v3
189 4 : EQUAL(aosTokens[2], "QualityOfBathymetryCoverage")) // v3
190 : {
191 6 : bIsQuality = true;
192 : }
193 : else
194 : {
195 2 : CPLError(CE_Failure, CPLE_NotSupported,
196 : "Unsupported subdataset component: '%s'. Expected "
197 : "'QualityOfSurvey'",
198 : aosTokens[2]);
199 2 : return nullptr;
200 : }
201 : }
202 : else
203 : {
204 0 : return nullptr;
205 : }
206 : }
207 :
208 44 : auto poDS = std::make_unique<S102Dataset>(osFilename);
209 22 : if (!poDS->Init())
210 0 : return nullptr;
211 :
212 22 : const auto &poRootGroup = poDS->m_poRootGroup;
213 : auto poBathymetryCoverage01 = poRootGroup->OpenGroupFromFullname(
214 66 : "/BathymetryCoverage/BathymetryCoverage.01");
215 22 : if (!poBathymetryCoverage01)
216 : {
217 0 : CPLError(CE_Failure, CPLE_AppDefined,
218 : "S102: Cannot find /BathymetryCoverage/BathymetryCoverage.01");
219 0 : return nullptr;
220 : }
221 :
222 22 : const bool bNorthUp = CPLTestBool(
223 22 : CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "NORTH_UP", "YES"));
224 :
225 22 : if (bIsQuality)
226 : {
227 6 : if (!poDS->OpenQuality(poOpenInfo, poRootGroup))
228 2 : return nullptr;
229 :
230 : // Setup/check for pam .aux.xml.
231 4 : poDS->SetDescription(osFilename.c_str());
232 4 : poDS->TryLoadXML();
233 :
234 : // Setup overviews.
235 4 : poDS->oOvManager.Initialize(poDS.get(), osFilename.c_str());
236 :
237 4 : return poDS.release();
238 : }
239 :
240 : // Compute geotransform
241 32 : poDS->m_bHasGT =
242 16 : S100GetGeoTransform(poBathymetryCoverage01.get(), poDS->m_gt, bNorthUp);
243 :
244 48 : auto poGroup001 = poBathymetryCoverage01->OpenGroup("Group_001");
245 16 : if (!poGroup001)
246 : {
247 0 : CPLError(CE_Failure, CPLE_AppDefined,
248 : "S102: Cannot find "
249 : "/BathymetryCoverage/BathymetryCoverage.01/Group_001");
250 0 : return nullptr;
251 : }
252 48 : auto poValuesArray = poGroup001->OpenMDArray("values");
253 16 : if (!poValuesArray || poValuesArray->GetDimensionCount() != 2)
254 : {
255 0 : CPLError(CE_Failure, CPLE_AppDefined,
256 : "S102: Cannot find "
257 : "/BathymetryCoverage/BathymetryCoverage.01/Group_001/values");
258 0 : return nullptr;
259 : }
260 16 : const auto &oType = poValuesArray->GetDataType();
261 16 : if (oType.GetClass() != GEDTC_COMPOUND)
262 : {
263 0 : CPLError(CE_Failure, CPLE_AppDefined,
264 : "S102: Wrong type for "
265 : "/BathymetryCoverage/BathymetryCoverage.01/Group_001/values");
266 0 : return nullptr;
267 : }
268 16 : const auto &oComponents = oType.GetComponents();
269 16 : if (oComponents.size() == 0 || oComponents[0]->GetName() != "depth")
270 : {
271 0 : CPLError(CE_Failure, CPLE_AppDefined,
272 : "S102: Wrong type for "
273 : "/BathymetryCoverage/BathymetryCoverage.01/Group_001/values");
274 0 : return nullptr;
275 : }
276 :
277 16 : if (bNorthUp)
278 15 : poValuesArray = poValuesArray->GetView("[::-1,...]");
279 :
280 48 : auto poDepth = poValuesArray->GetView("[\"depth\"]");
281 :
282 : // Mandatory in v2.2
283 16 : bool bCSIsElevation = false;
284 48 : auto poVerticalCS = poRootGroup->GetAttribute("verticalCS");
285 16 : if (poVerticalCS && poVerticalCS->GetDataType().GetClass() == GEDTC_NUMERIC)
286 : {
287 6 : const auto nVal = poVerticalCS->ReadAsInt();
288 6 : if (nVal == 6498) // Depth metre
289 : {
290 : // nothing to do
291 : }
292 0 : else if (nVal == 6499) // Height metre
293 : {
294 0 : bCSIsElevation = true;
295 : }
296 : else
297 : {
298 0 : CPLError(CE_Warning, CPLE_NotSupported, "Unsupported verticalCS=%d",
299 : nVal);
300 : }
301 : }
302 :
303 : const bool bUseElevation =
304 16 : EQUAL(CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
305 : "DEPTH_OR_ELEVATION", "DEPTH"),
306 : "ELEVATION");
307 31 : const bool bInvertDepth = (bUseElevation && !bCSIsElevation) ||
308 15 : (!bUseElevation && bCSIsElevation);
309 16 : const double dfDepthNoData = poDepth->GetNoDataValueAsDouble();
310 33 : auto poDepthDS = [&poDepth, bInvertDepth, dfDepthNoData]()
311 : {
312 16 : if (bInvertDepth)
313 : {
314 1 : auto poInverted = poDepth->GetUnscaled(-1, 0, dfDepthNoData);
315 : return std::unique_ptr<GDALDataset>(
316 1 : poInverted->AsClassicDataset(1, 0));
317 : }
318 : else
319 : {
320 : return std::unique_ptr<GDALDataset>(
321 15 : poDepth->AsClassicDataset(1, 0));
322 : }
323 32 : }();
324 :
325 16 : poDS->nRasterXSize = poDepthDS->GetRasterXSize();
326 16 : poDS->nRasterYSize = poDepthDS->GetRasterYSize();
327 :
328 : // Create depth (or elevation) band
329 16 : auto poDepthBand = new S102RasterBand(std::move(poDepthDS));
330 16 : poDepthBand->SetDescription(bUseElevation ? "elevation" : "depth");
331 :
332 48 : auto poMinimumDepth = poGroup001->GetAttribute("minimumDepth");
333 32 : if (poMinimumDepth &&
334 32 : poMinimumDepth->GetDataType().GetClass() == GEDTC_NUMERIC)
335 : {
336 16 : const double dfVal = poMinimumDepth->ReadAsDouble();
337 16 : if (dfVal != dfDepthNoData)
338 : {
339 13 : if (bInvertDepth)
340 1 : poDepthBand->m_dfMaximum = -dfVal;
341 : else
342 12 : poDepthBand->m_dfMinimum = dfVal;
343 : }
344 : }
345 :
346 48 : auto poMaximumDepth = poGroup001->GetAttribute("maximumDepth");
347 32 : if (poMaximumDepth &&
348 32 : poMaximumDepth->GetDataType().GetClass() == GEDTC_NUMERIC)
349 : {
350 16 : const double dfVal = poMaximumDepth->ReadAsDouble();
351 16 : if (dfVal != dfDepthNoData)
352 : {
353 16 : if (bInvertDepth)
354 1 : poDepthBand->m_dfMinimum = -dfVal;
355 : else
356 15 : poDepthBand->m_dfMaximum = dfVal;
357 : }
358 : }
359 :
360 16 : poDS->SetBand(1, poDepthBand);
361 :
362 : const bool bHasUncertainty =
363 16 : oComponents.size() >= 2 && oComponents[1]->GetName() == "uncertainty";
364 16 : if (bHasUncertainty)
365 : {
366 : // Create uncertainty band
367 45 : auto poUncertainty = poValuesArray->GetView("[\"uncertainty\"]");
368 : const double dfUncertaintyNoData =
369 15 : poUncertainty->GetNoDataValueAsDouble();
370 : auto poUncertaintyDS =
371 30 : std::unique_ptr<GDALDataset>(poUncertainty->AsClassicDataset(1, 0));
372 :
373 15 : auto poUncertaintyBand = new S102RasterBand(std::move(poUncertaintyDS));
374 15 : poUncertaintyBand->SetDescription("uncertainty");
375 :
376 : auto poMinimumUncertainty =
377 45 : poGroup001->GetAttribute("minimumUncertainty");
378 30 : if (poMinimumUncertainty &&
379 30 : poMinimumUncertainty->GetDataType().GetClass() == GEDTC_NUMERIC)
380 : {
381 15 : const double dfVal = poMinimumUncertainty->ReadAsDouble();
382 15 : if (dfVal != dfUncertaintyNoData)
383 : {
384 15 : poUncertaintyBand->m_dfMinimum = dfVal;
385 : }
386 : }
387 :
388 : auto poMaximumUncertainty =
389 45 : poGroup001->GetAttribute("maximumUncertainty");
390 30 : if (poMaximumUncertainty &&
391 30 : poMaximumUncertainty->GetDataType().GetClass() == GEDTC_NUMERIC)
392 : {
393 15 : const double dfVal = poMaximumUncertainty->ReadAsDouble();
394 15 : if (dfVal != dfUncertaintyNoData)
395 : {
396 15 : poUncertaintyBand->m_dfMaximum = dfVal;
397 : }
398 : }
399 :
400 15 : poDS->SetBand(2, poUncertaintyBand);
401 : }
402 :
403 16 : poDS->GDALDataset::SetMetadataItem(GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT);
404 :
405 48 : auto poGroupQuality = poRootGroup->OpenGroup("QualityOfSurvey");
406 16 : const bool bIsNamedQualityOfSurvey = poGroupQuality != nullptr;
407 16 : if (!bIsNamedQualityOfSurvey)
408 : {
409 : // S102 v3 now uses QualityOfBathymetryCoverage instead of QualityOfSurvey
410 14 : poGroupQuality = poRootGroup->OpenGroup("QualityOfBathymetryCoverage");
411 : }
412 16 : if (!bIsSubdataset && poGroupQuality)
413 : {
414 3 : const char *pszNameOfQualityGroup = bIsNamedQualityOfSurvey
415 3 : ? "QualityOfSurvey"
416 : : "QualityOfBathymetryCoverage";
417 3 : auto poGroupQuality01 = poGroupQuality->OpenGroup(
418 9 : CPLSPrintf("%s.01", pszNameOfQualityGroup));
419 3 : if (poGroupQuality01)
420 : {
421 3 : poDS->GDALDataset::SetMetadataItem(
422 : "SUBDATASET_1_NAME",
423 : CPLSPrintf("S102:\"%s\":BathymetryCoverage",
424 : osFilename.c_str()),
425 : "SUBDATASETS");
426 3 : poDS->GDALDataset::SetMetadataItem(
427 : "SUBDATASET_1_DESC", "Bathymetric gridded data", "SUBDATASETS");
428 :
429 3 : poDS->GDALDataset::SetMetadataItem(
430 : "SUBDATASET_2_NAME",
431 : CPLSPrintf("S102:\"%s\":%s", osFilename.c_str(),
432 : pszNameOfQualityGroup),
433 : "SUBDATASETS");
434 3 : poDS->GDALDataset::SetMetadataItem(
435 : "SUBDATASET_2_DESC",
436 : CPLSPrintf("Georeferenced metadata %s", pszNameOfQualityGroup),
437 : "SUBDATASETS");
438 : }
439 : }
440 :
441 : // Setup/check for pam .aux.xml.
442 16 : poDS->SetDescription(osFilename.c_str());
443 16 : poDS->TryLoadXML();
444 :
445 : // Setup overviews.
446 16 : poDS->oOvManager.Initialize(poDS.get(), osFilename.c_str());
447 :
448 16 : return poDS.release();
449 : }
450 :
451 : /************************************************************************/
452 : /* OpenQuality() */
453 : /************************************************************************/
454 :
455 6 : bool S102Dataset::OpenQuality(GDALOpenInfo *poOpenInfo,
456 : const std::shared_ptr<GDALGroup> &poRootGroup)
457 : {
458 6 : const bool bNorthUp = CPLTestBool(
459 6 : CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "NORTH_UP", "YES"));
460 :
461 6 : const char *pszNameOfQualityGroup = "QualityOfSurvey";
462 18 : auto poGroupQuality = poRootGroup->OpenGroup(pszNameOfQualityGroup);
463 6 : if (!poGroupQuality)
464 : {
465 4 : pszNameOfQualityGroup = "QualityOfBathymetryCoverage";
466 4 : poGroupQuality = poRootGroup->OpenGroup(pszNameOfQualityGroup);
467 4 : if (!poGroupQuality)
468 : {
469 2 : CPLError(CE_Failure, CPLE_AppDefined,
470 : "Cannot find group /QualityOfSurvey or "
471 : "/QualityOfBathymetryCoverage");
472 2 : return false;
473 : }
474 : }
475 :
476 : const std::string osQuality01Name =
477 12 : std::string(pszNameOfQualityGroup).append(".01");
478 8 : const std::string osQuality01FullName = std::string("/")
479 4 : .append(pszNameOfQualityGroup)
480 4 : .append("/")
481 8 : .append(osQuality01Name);
482 8 : auto poGroupQuality01 = poGroupQuality->OpenGroup(osQuality01Name);
483 4 : if (!poGroupQuality01)
484 : {
485 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find group %s",
486 : osQuality01FullName.c_str());
487 0 : return false;
488 : }
489 :
490 8 : if (auto poStartSequence = poGroupQuality01->GetAttribute("startSequence"))
491 : {
492 0 : const char *pszStartSequence = poStartSequence->ReadAsString();
493 0 : if (pszStartSequence && !EQUAL(pszStartSequence, "0,0"))
494 : {
495 0 : CPLError(CE_Failure, CPLE_AppDefined,
496 : "startSequence (=%s) != 0,0 is not supported",
497 : pszStartSequence);
498 0 : return false;
499 : }
500 : }
501 :
502 : // Compute geotransform
503 4 : m_bHasGT = S100GetGeoTransform(poGroupQuality01.get(), m_gt, bNorthUp);
504 :
505 12 : auto poGroup001 = poGroupQuality01->OpenGroup("Group_001");
506 4 : if (!poGroup001)
507 : {
508 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find group %s/Group_001",
509 : osQuality01FullName.c_str());
510 0 : return false;
511 : }
512 :
513 12 : auto poValuesArray = poGroup001->OpenMDArray("values");
514 4 : if (!poValuesArray)
515 : {
516 0 : CPLError(CE_Failure, CPLE_AppDefined,
517 : "Cannot find array "
518 : "%s/Group_001/values",
519 : osQuality01FullName.c_str());
520 0 : return false;
521 : }
522 :
523 : {
524 4 : const auto &oType = poValuesArray->GetDataType();
525 6 : if (oType.GetClass() == GEDTC_NUMERIC &&
526 2 : oType.GetNumericDataType() == GDT_UInt32)
527 : {
528 : // ok
529 : }
530 4 : else if (oType.GetClass() == GEDTC_COMPOUND &&
531 4 : oType.GetComponents().size() == 1 &&
532 2 : oType.GetComponents()[0]->GetType().GetClass() ==
533 4 : GEDTC_NUMERIC &&
534 2 : oType.GetComponents()[0]->GetType().GetNumericDataType() ==
535 : GDT_UInt32)
536 : {
537 : // seen in a S102 v3 product (102DE00CA22_UNC_MD.H5), although
538 : // I believe this is non-conformant.
539 :
540 : // Escape potentials single-quote and double-quote with back-slash
541 2 : CPLString osEscapedCompName(oType.GetComponents()[0]->GetName());
542 4 : osEscapedCompName.replaceAll("\\", "\\\\")
543 4 : .replaceAll("'", "\\'")
544 2 : .replaceAll("\"", "\\\"");
545 :
546 : // Gets a view with that single component extracted.
547 4 : poValuesArray = poValuesArray->GetView(
548 4 : std::string("['").append(osEscapedCompName).append("']"));
549 2 : if (!poValuesArray)
550 0 : return false;
551 : }
552 : else
553 : {
554 0 : CPLError(CE_Failure, CPLE_NotSupported,
555 : "Unsupported data type for %s",
556 0 : poValuesArray->GetFullName().c_str());
557 0 : return false;
558 : }
559 : }
560 :
561 4 : if (poValuesArray->GetDimensionCount() != 2)
562 : {
563 0 : CPLError(CE_Failure, CPLE_NotSupported,
564 : "Unsupported number of dimensions for %s",
565 0 : poValuesArray->GetFullName().c_str());
566 0 : return false;
567 : }
568 :
569 : auto poFeatureAttributeTable =
570 12 : poGroupQuality->OpenMDArray("featureAttributeTable");
571 4 : if (!poFeatureAttributeTable)
572 : {
573 0 : CPLError(CE_Failure, CPLE_AppDefined,
574 : "Cannot find array /%s/featureAttributeTable",
575 : pszNameOfQualityGroup);
576 0 : return false;
577 : }
578 :
579 : {
580 4 : const auto &oType = poFeatureAttributeTable->GetDataType();
581 4 : if (oType.GetClass() != GEDTC_COMPOUND)
582 : {
583 0 : CPLError(CE_Failure, CPLE_NotSupported,
584 : "Unsupported data type for %s",
585 0 : poFeatureAttributeTable->GetFullName().c_str());
586 0 : return false;
587 : }
588 :
589 4 : const auto &poComponents = oType.GetComponents();
590 4 : if (poComponents.size() >= 1 && poComponents[0]->GetName() != "id")
591 : {
592 0 : CPLError(CE_Failure, CPLE_AppDefined,
593 : "Missing 'id' component in %s",
594 0 : poFeatureAttributeTable->GetFullName().c_str());
595 0 : return false;
596 : }
597 : }
598 :
599 4 : if (bNorthUp)
600 2 : poValuesArray = poValuesArray->GetView("[::-1,...]");
601 :
602 : auto poDS =
603 8 : std::unique_ptr<GDALDataset>(poValuesArray->AsClassicDataset(1, 0));
604 4 : if (!poDS)
605 0 : return false;
606 :
607 4 : nRasterXSize = poDS->GetRasterXSize();
608 4 : nRasterYSize = poDS->GetRasterYSize();
609 :
610 : auto poRAT =
611 8 : HDF5CreateRAT(poFeatureAttributeTable, /* bFirstColIsMinMax = */ true);
612 : auto poBand = std::make_unique<S102GeoreferencedMetadataRasterBand>(
613 4 : std::move(poDS), std::move(poRAT));
614 4 : SetBand(1, poBand.release());
615 :
616 4 : return true;
617 : }
618 :
619 : /************************************************************************/
620 : /* S102DatasetDriverUnload() */
621 : /************************************************************************/
622 :
623 6 : static void S102DatasetDriverUnload(GDALDriver *)
624 : {
625 6 : HDF5UnloadFileDriver();
626 6 : }
627 :
628 : /************************************************************************/
629 : /* GDALRegister_S102() */
630 : /************************************************************************/
631 11 : void GDALRegister_S102()
632 :
633 : {
634 11 : if (!GDAL_CHECK_VERSION("S102"))
635 0 : return;
636 :
637 11 : if (GDALGetDriverByName(S102_DRIVER_NAME) != nullptr)
638 0 : return;
639 :
640 11 : GDALDriver *poDriver = new GDALDriver();
641 :
642 11 : S102DriverSetCommonMetadata(poDriver);
643 11 : poDriver->pfnOpen = S102Dataset::Open;
644 11 : poDriver->pfnUnloadDriver = S102DatasetDriverUnload;
645 :
646 11 : GetGDALDriverManager()->RegisterDriver(poDriver);
647 : }
|