Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Hierarchical Data Format Release 5 (HDF5)
4 : * Purpose: Implementation of HDF5 HDFEOS parser
5 : * Author: Even Rouault
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2023, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_error.h"
14 : #include "nasakeywordhandler.h"
15 :
16 : #include "hdf5eosparser.h"
17 :
18 : #include <cstring>
19 : #include <utility>
20 :
21 : /************************************************************************/
22 : /* HasHDFEOS() */
23 : /************************************************************************/
24 :
25 264 : bool HDF5EOSParser::HasHDFEOS(hid_t hRoot)
26 : {
27 264 : hsize_t numObjs = 0;
28 264 : H5Gget_num_objs(hRoot, &numObjs);
29 264 : bool bFound = false;
30 918 : for (hsize_t i = 0; i < numObjs; ++i)
31 : {
32 : char szName[128];
33 : ssize_t nLen =
34 684 : H5Gget_objname_by_idx(hRoot, i, szName, sizeof(szName) - 1);
35 684 : if (nLen > 0)
36 : {
37 684 : szName[nLen] = 0;
38 684 : if (strcmp(szName, "HDFEOS INFORMATION") == 0)
39 : {
40 30 : bFound = true;
41 30 : break;
42 : }
43 : }
44 : }
45 264 : if (!bFound)
46 234 : return false;
47 :
48 : H5G_stat_t oStatbuf;
49 30 : if (H5Gget_objinfo(hRoot, "HDFEOS INFORMATION", false, &oStatbuf) < 0)
50 0 : return false;
51 :
52 30 : auto hHDFEOSInformation = H5Gopen(hRoot, "HDFEOS INFORMATION");
53 30 : if (hHDFEOSInformation < 0)
54 : {
55 0 : return false;
56 : }
57 30 : H5Gclose(hHDFEOSInformation);
58 30 : return true;
59 : }
60 :
61 : /************************************************************************/
62 : /* Parse() */
63 : /************************************************************************/
64 :
65 30 : bool HDF5EOSParser::Parse(hid_t hRoot)
66 : {
67 30 : auto hHDFEOSInformation = H5Gopen(hRoot, "HDFEOS INFORMATION");
68 30 : if (hHDFEOSInformation < 0)
69 : {
70 0 : return false;
71 : }
72 :
73 30 : const hid_t hArrayId = H5Dopen(hHDFEOSInformation, "StructMetadata.0");
74 30 : if (hArrayId < 0)
75 : {
76 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find StructMetadata.0");
77 0 : H5Gclose(hHDFEOSInformation);
78 0 : return false;
79 : }
80 :
81 30 : const hid_t hAttrSpace = H5Dget_space(hArrayId);
82 30 : const hid_t hAttrTypeID = H5Dget_type(hArrayId);
83 : const hid_t hAttrNativeType =
84 30 : H5Tget_native_type(hAttrTypeID, H5T_DIR_DEFAULT);
85 :
86 : // Fetch StructMetadata.0 content in a std::string
87 60 : std::string osResult;
88 30 : if (H5Tget_class(hAttrNativeType) == H5T_STRING &&
89 60 : !H5Tis_variable_str(hAttrNativeType) &&
90 30 : H5Sget_simple_extent_ndims(hAttrSpace) == 0)
91 : {
92 30 : const auto nSize = H5Tget_size(hAttrNativeType);
93 30 : if (nSize > 10 * 1024 * 1024)
94 : {
95 0 : CPLError(CE_Failure, CPLE_AppDefined,
96 : "Too large HDFEOS INFORMATION.StructMetadata.0");
97 : }
98 : else
99 : {
100 30 : osResult.resize(nSize);
101 30 : H5Dread(hArrayId, hAttrNativeType, H5S_ALL, hAttrSpace, H5P_DEFAULT,
102 30 : &osResult[0]);
103 : }
104 : }
105 : else
106 : {
107 0 : CPLError(CE_Failure, CPLE_AppDefined,
108 : "HDFEOS INFORMATION.StructMetadata.0 not of type string");
109 : }
110 30 : H5Sclose(hAttrSpace);
111 30 : H5Tclose(hAttrNativeType);
112 30 : H5Tclose(hAttrTypeID);
113 :
114 30 : H5Dclose(hArrayId);
115 30 : H5Gclose(hHDFEOSInformation);
116 :
117 30 : if (osResult.empty())
118 0 : return false;
119 :
120 : // Parse StructMetadata.0 with NASAKeywordHandler
121 60 : NASAKeywordHandler oKWHandler;
122 : #ifdef DEBUG
123 30 : CPLDebug("HDF5EOS", "%s", osResult.c_str());
124 : #endif
125 30 : if (!oKWHandler.Parse(osResult.c_str()))
126 : {
127 0 : CPLError(CE_Failure, CPLE_AppDefined,
128 : "Cannot parse HDFEOS INFORMATION.StructMetadata.0 with "
129 : "NASAKeywordHandler");
130 0 : return false;
131 : }
132 :
133 60 : auto oJsonRoot = oKWHandler.GetJsonObject();
134 90 : auto oGridStructure = oJsonRoot.GetObj("GridStructure");
135 60 : auto oSwathStructure = oJsonRoot.GetObj("SwathStructure");
136 30 : bool bOK = false;
137 : // An empty
138 : // GROUP=GridStructure
139 : // END_GROUP=GridStructure
140 : // will generate 2 keys (_type and END_GROUP)
141 30 : if (oGridStructure.IsValid() && oGridStructure.GetChildren().size() > 2)
142 : {
143 15 : bOK = true;
144 15 : m_eDataModel = DataModel::GRID;
145 15 : ParseGridStructure(oGridStructure);
146 : }
147 30 : else if (oSwathStructure.IsValid() &&
148 30 : oSwathStructure.GetChildren().size() > 2)
149 : {
150 15 : bOK = true;
151 15 : m_eDataModel = DataModel::SWATH;
152 15 : ParseSwathStructure(oSwathStructure);
153 : }
154 :
155 30 : return bOK;
156 : }
157 :
158 : /************************************************************************/
159 : /* GetGTCPProjectionCode() */
160 : /************************************************************************/
161 :
162 15 : static int GetGTCPProjectionCode(const std::string &osProjection)
163 : {
164 15 : const char *const apszGCTPProjections[] = {
165 : "HE5_GCTP_GEO", "HE5_GCTP_UTM", "HE5_GCTP_SPCS",
166 : "HE5_GCTP_ALBERS", "HE5_GCTP_LAMCC", "HE5_GCTP_MERCAT",
167 : "HE5_GCTP_PS", "HE5_GCTP_POLYC", "HE5_GCTP_EQUIDC",
168 : "HE5_GCTP_TM", "HE5_GCTP_STEREO", "HE5_GCTP_LAMAZ",
169 : "HE5_GCTP_AZMEQD", "HE5_GCTP_GNOMON", "HE5_GCTP_ORTHO",
170 : "HE5_GCTP_GVNSP", "HE5_GCTP_SNSOID", "HE5_GCTP_EQRECT",
171 : "HE5_GCTP_MILLER", "HE5_GCTP_VGRINT", "HE5_GCTP_HOM",
172 : "HE5_GCTP_ROBIN", "HE5_GCTP_SOM", "HE5_GCTP_ALASKA",
173 : "HE5_GCTP_GOOD", "HE5_GCTP_MOLL", "HE5_GCTP_IMOLL",
174 : "HE5_GCTP_HAMMER", "HE5_GCTP_WAGIV", "HE5_GCTP_WAGVII",
175 : "HE5_GCTP_OBLEQA"};
176 : // HE5_GCTP_CEA, HE5_GCTP_BCEA, HE5_GCTP_ISINUS not taken
177 : // into account.
178 132 : for (int i = 0; i < static_cast<int>(CPL_ARRAYSIZE(apszGCTPProjections));
179 : ++i)
180 : {
181 132 : if (osProjection == apszGCTPProjections[i])
182 : {
183 15 : return i;
184 : }
185 : }
186 0 : return -1;
187 : }
188 :
189 : /************************************************************************/
190 : /* ParseGridStructure() */
191 : /************************************************************************/
192 :
193 15 : void HDF5EOSParser::ParseGridStructure(const CPLJSONObject &oGridStructure)
194 : {
195 60 : for (const auto &oGrid : oGridStructure.GetChildren())
196 : {
197 45 : if (oGrid.GetType() == CPLJSONObject::Type::Object)
198 : {
199 45 : const auto osGridName = oGrid.GetString("GridName");
200 45 : const auto oDataFields = oGrid.GetObj("DataField");
201 45 : const auto oDimensions = oGrid.GetObj("Dimension");
202 30 : std::map<std::string, int> oMapDimensionNameToSize;
203 30 : auto poGridMetadata = std::make_unique<GridMetadata>();
204 15 : poGridMetadata->osGridName = osGridName;
205 72 : for (const auto &oDimension : oDimensions.GetChildren())
206 : {
207 57 : if (oDimension.GetType() == CPLJSONObject::Type::Object)
208 : {
209 : std::string osDimensionName =
210 81 : oDimension.GetString("DimensionName");
211 27 : int nSize = oDimension.GetInteger("Size");
212 27 : oMapDimensionNameToSize[osDimensionName] = nSize;
213 54 : Dimension oDim;
214 27 : oDim.osName = std::move(osDimensionName);
215 27 : oDim.nSize = nSize;
216 27 : poGridMetadata->aoDimensions.push_back(std::move(oDim));
217 : }
218 : }
219 :
220 : // Happens for example for products following
221 : // AMSR-E/AMSR2 Unified L3 Daily 12.5 km Brightness Temperatures,
222 : // Sea Ice Concentration, Motion & Snow Depth Polar Grids
223 : // (https://nsidc.org/sites/default/files/au_si12-v001-userguide_1.pdf)
224 : // such as
225 : // https://n5eil01u.ecs.nsidc.org/AMSA/AU_SI12.001/2012.07.02/AMSR_U2_L3_SeaIce12km_B04_20120702.he5
226 15 : const int nXDim = oGrid.GetInteger("XDim", 0);
227 15 : const int nYDim = oGrid.GetInteger("YDim", 0);
228 15 : if (nXDim > 0 && nYDim > 0 &&
229 35 : !cpl::contains(oMapDimensionNameToSize, "XDim") &&
230 5 : !cpl::contains(oMapDimensionNameToSize, "YDim"))
231 : {
232 : // Check that we have at least one data field with DimList=(YDim,XDim)
233 : // property.
234 5 : bool bHasDimListYDimXDim = false;
235 15 : for (const auto &oDataField : oDataFields.GetChildren())
236 : {
237 10 : if (oDataField.GetType() == CPLJSONObject::Type::Object)
238 : {
239 10 : const auto oDimList = oDataField.GetArray("DimList");
240 5 : if (oDimList.Size() == 2 &&
241 15 : oDimList[0].ToString() == "YDim" &&
242 10 : oDimList[1].ToString() == "XDim")
243 : {
244 5 : bHasDimListYDimXDim = true;
245 5 : break;
246 : }
247 : }
248 : }
249 5 : if (bHasDimListYDimXDim)
250 : {
251 : {
252 10 : std::string osDimensionName("YDim");
253 5 : oMapDimensionNameToSize[osDimensionName] = nYDim;
254 10 : Dimension oDim;
255 5 : oDim.osName = std::move(osDimensionName);
256 5 : oDim.nSize = nYDim;
257 5 : poGridMetadata->aoDimensions.push_back(std::move(oDim));
258 : }
259 : {
260 10 : std::string osDimensionName("XDim");
261 5 : oMapDimensionNameToSize[osDimensionName] = nXDim;
262 10 : Dimension oDim;
263 5 : oDim.osName = std::move(osDimensionName);
264 5 : oDim.nSize = nXDim;
265 5 : poGridMetadata->aoDimensions.push_back(std::move(oDim));
266 : }
267 : }
268 : }
269 :
270 15 : poGridMetadata->osProjection = oGrid.GetString("Projection");
271 30 : poGridMetadata->nProjCode =
272 15 : GetGTCPProjectionCode(poGridMetadata->osProjection);
273 15 : poGridMetadata->osGridOrigin = oGrid.GetString("GridOrigin");
274 15 : poGridMetadata->nZone = oGrid.GetInteger("ZoneCode", -1);
275 15 : poGridMetadata->nSphereCode = oGrid.GetInteger("SphereCode", -1);
276 :
277 45 : const auto oProjParams = oGrid.GetArray("ProjParams");
278 106 : for (int j = 0; j < oProjParams.Size(); ++j)
279 91 : poGridMetadata->adfProjParams.push_back(
280 91 : oProjParams[j].ToDouble());
281 :
282 : const auto oUpperLeftPointMtrs =
283 45 : oGrid.GetArray("UpperLeftPointMtrs");
284 45 : for (int j = 0; j < oUpperLeftPointMtrs.Size(); ++j)
285 30 : poGridMetadata->adfUpperLeftPointMeters.push_back(
286 30 : oUpperLeftPointMtrs[j].ToDouble());
287 :
288 45 : const auto oLowerRightMtrs = oGrid.GetArray("LowerRightMtrs");
289 45 : for (int j = 0; j < oLowerRightMtrs.Size(); ++j)
290 30 : poGridMetadata->adfLowerRightPointMeters.push_back(
291 30 : oLowerRightMtrs[j].ToDouble());
292 :
293 15 : m_oMapGridNameToGridMetadata[osGridName] =
294 30 : std::move(poGridMetadata);
295 : const auto poGridMetadataRef =
296 15 : m_oMapGridNameToGridMetadata[osGridName].get();
297 :
298 60 : for (const auto &oDataField : oDataFields.GetChildren())
299 : {
300 45 : if (oDataField.GetType() == CPLJSONObject::Type::Object)
301 : {
302 : const auto osDataFieldName =
303 45 : oDataField.GetString("DataFieldName");
304 45 : const auto oDimList = oDataField.GetArray("DimList");
305 30 : GridDataFieldMetadata oDataFieldMetadata;
306 15 : bool bValid = oDimList.Size() > 0;
307 49 : for (int j = 0; j < oDimList.Size(); ++j)
308 : {
309 68 : std::string osDimensionName = oDimList[j].ToString();
310 : const auto oIter = oMapDimensionNameToSize.find(
311 34 : osDimensionName.c_str());
312 34 : if (oIter == oMapDimensionNameToSize.end())
313 : {
314 0 : bValid = false;
315 0 : break;
316 : }
317 68 : Dimension oDim;
318 34 : oDim.osName = std::move(osDimensionName);
319 34 : oDim.nSize = oIter->second;
320 34 : oDataFieldMetadata.aoDimensions.push_back(
321 34 : std::move(oDim));
322 : }
323 15 : if (bValid)
324 : {
325 15 : oDataFieldMetadata.poGridMetadata = poGridMetadataRef;
326 : m_oMapSubdatasetNameToGridDataFieldMetadata
327 30 : ["//HDFEOS/GRIDS/" + osGridName + "/Data_Fields/" +
328 30 : osDataFieldName] = std::move(oDataFieldMetadata);
329 : }
330 : }
331 : }
332 : }
333 : }
334 15 : }
335 :
336 : /************************************************************************/
337 : /* GetGridMetadata() */
338 : /************************************************************************/
339 :
340 9 : bool HDF5EOSParser::GetGridMetadata(const std::string &osGridName,
341 : GridMetadata &gridMetadataOut) const
342 : {
343 9 : const auto oIter = m_oMapGridNameToGridMetadata.find(osGridName);
344 9 : if (oIter == m_oMapGridNameToGridMetadata.end())
345 6 : return false;
346 3 : gridMetadataOut = *(oIter->second);
347 3 : return true;
348 : }
349 :
350 : /************************************************************************/
351 : /* GetGridDataFieldMetadata() */
352 : /************************************************************************/
353 :
354 12 : bool HDF5EOSParser::GetGridDataFieldMetadata(
355 : const char *pszSubdatasetName,
356 : GridDataFieldMetadata &gridDataFieldMetadataOut) const
357 : {
358 : const auto oIter =
359 12 : m_oMapSubdatasetNameToGridDataFieldMetadata.find(pszSubdatasetName);
360 12 : if (oIter == m_oMapSubdatasetNameToGridDataFieldMetadata.end())
361 3 : return false;
362 9 : gridDataFieldMetadataOut = oIter->second;
363 9 : return true;
364 : }
365 :
366 : /************************************************************************/
367 : /* ParseSwathStructure() */
368 : /************************************************************************/
369 :
370 15 : void HDF5EOSParser::ParseSwathStructure(const CPLJSONObject &oSwathStructure)
371 : {
372 60 : for (const auto &oSwath : oSwathStructure.GetChildren())
373 : {
374 45 : if (oSwath.GetType() == CPLJSONObject::Type::Object)
375 : {
376 45 : const auto osSwathName = oSwath.GetString("SwathName");
377 :
378 45 : const auto oDimensions = oSwath.GetObj("Dimension");
379 30 : std::map<std::string, int> oMapDimensionNameToSize;
380 30 : auto poSwathMetadata = std::make_unique<SwathMetadata>();
381 15 : poSwathMetadata->osSwathName = osSwathName;
382 126 : for (const auto &oDimension : oDimensions.GetChildren())
383 : {
384 111 : if (oDimension.GetType() == CPLJSONObject::Type::Object)
385 : {
386 : auto osDimensionName =
387 243 : oDimension.GetString("DimensionName");
388 81 : int nSize = oDimension.GetInteger("Size");
389 81 : oMapDimensionNameToSize[osDimensionName] = nSize;
390 162 : Dimension oDim;
391 81 : oDim.osName = std::move(osDimensionName);
392 81 : oDim.nSize = nSize;
393 81 : poSwathMetadata->aoDimensions.emplace_back(std::move(oDim));
394 : }
395 : }
396 :
397 15 : m_oMapSwathNameToSwathMetadata[osSwathName] =
398 30 : std::move(poSwathMetadata);
399 : const auto poSwathMetadataRef =
400 15 : m_oMapSwathNameToSwathMetadata[osSwathName].get();
401 :
402 : struct DimensionMap
403 : {
404 : std::string osGeoDimName{};
405 : std::string osDataDimName{};
406 : int nOffset = 0;
407 : int nIncrement = 1;
408 : };
409 :
410 30 : std::vector<DimensionMap> aoDimensionMaps;
411 30 : std::map<std::string, std::string> oMapDataDimensionToGeoDimension;
412 :
413 45 : const auto jsonDimensionMaps = oSwath.GetObj("DimensionMap");
414 57 : for (const auto &jsonDimensionMap : jsonDimensionMaps.GetChildren())
415 : {
416 42 : if (jsonDimensionMap.GetType() == CPLJSONObject::Type::Object)
417 : {
418 24 : DimensionMap oDimensionMap;
419 : oDimensionMap.osGeoDimName =
420 12 : jsonDimensionMap.GetString("GeoDimension");
421 : oDimensionMap.osDataDimName =
422 12 : jsonDimensionMap.GetString("DataDimension");
423 12 : oDimensionMap.nOffset =
424 12 : jsonDimensionMap.GetInteger("Offset", 0);
425 12 : oDimensionMap.nIncrement =
426 12 : jsonDimensionMap.GetInteger("Increment", 1);
427 : oMapDataDimensionToGeoDimension[oDimensionMap
428 12 : .osDataDimName] =
429 12 : oDimensionMap.osGeoDimName;
430 12 : aoDimensionMaps.emplace_back(oDimensionMap);
431 : }
432 : }
433 :
434 45 : const auto oGeoFields = oSwath.GetObj("GeoField");
435 30 : std::vector<Dimension> aoLongitudeDimensions;
436 30 : std::vector<Dimension> aoLatitudeDimensions;
437 90 : for (const auto &oGeoField : oGeoFields.GetChildren())
438 : {
439 75 : if (oGeoField.GetType() == CPLJSONObject::Type::Object)
440 : {
441 135 : auto osGeoFieldName = oGeoField.GetString("GeoFieldName");
442 135 : auto oDimList = oGeoField.GetArray("DimList");
443 45 : bool bValid = true;
444 90 : std::vector<Dimension> aoDimensions;
445 120 : for (int j = 0; j < oDimList.Size(); ++j)
446 : {
447 150 : const auto osDimensionName = oDimList[j].ToString();
448 : const auto oIter = oMapDimensionNameToSize.find(
449 75 : osDimensionName.c_str());
450 75 : if (oIter == oMapDimensionNameToSize.end())
451 : {
452 0 : bValid = false;
453 0 : break;
454 : }
455 150 : Dimension oDim;
456 75 : oDim.osName = osDimensionName;
457 75 : oDim.nSize = oIter->second;
458 75 : aoDimensions.push_back(std::move(oDim));
459 75 : if (oMapDataDimensionToGeoDimension.find(
460 75 : osDimensionName) ==
461 150 : oMapDataDimensionToGeoDimension.end())
462 : {
463 : // Create a fake dimension map for this dim
464 60 : DimensionMap oDimensionMap;
465 30 : oDimensionMap.osGeoDimName = osDimensionName;
466 30 : oDimensionMap.osDataDimName = osDimensionName;
467 30 : oDimensionMap.nOffset = 0;
468 30 : oDimensionMap.nIncrement = 1;
469 30 : oMapDataDimensionToGeoDimension[osDimensionName] =
470 30 : osDimensionName;
471 30 : aoDimensionMaps.emplace_back(oDimensionMap);
472 : }
473 : }
474 45 : if (bValid)
475 : {
476 90 : SwathGeolocationFieldMetadata oMetadata;
477 45 : oMetadata.poSwathMetadata = poSwathMetadataRef;
478 :
479 45 : if (osGeoFieldName == "Longitude")
480 15 : aoLongitudeDimensions = aoDimensions;
481 30 : else if (osGeoFieldName == "Latitude")
482 15 : aoLatitudeDimensions = aoDimensions;
483 :
484 45 : oMetadata.aoDimensions = std::move(aoDimensions);
485 :
486 : const std::string osSubdatasetName =
487 90 : "//HDFEOS/SWATHS/" + osSwathName +
488 90 : "/Geolocation_Fields/" + osGeoFieldName;
489 : m_oMapSubdatasetNameToSwathGeolocationFieldMetadata
490 45 : [osSubdatasetName] = std::move(oMetadata);
491 : }
492 : }
493 : }
494 :
495 45 : const auto oDataFields = oSwath.GetObj("DataField");
496 90 : for (const auto &oDataField : oDataFields.GetChildren())
497 : {
498 75 : if (oDataField.GetType() == CPLJSONObject::Type::Object)
499 : {
500 : const auto osDataFieldName =
501 135 : oDataField.GetString("DataFieldName");
502 135 : const auto oDimList = oDataField.GetArray("DimList");
503 90 : SwathDataFieldMetadata oMetadata;
504 45 : oMetadata.poSwathMetadata = poSwathMetadataRef;
505 45 : bool bValid = oDimList.Size() > 0;
506 126 : for (int j = 0; j < oDimList.Size(); ++j)
507 : {
508 162 : std::string osDimensionName = oDimList[j].ToString();
509 : const auto oIter = oMapDimensionNameToSize.find(
510 81 : osDimensionName.c_str());
511 81 : if (oIter == oMapDimensionNameToSize.end())
512 : {
513 0 : bValid = false;
514 0 : break;
515 : }
516 162 : Dimension oDim;
517 81 : oDim.osName = std::move(osDimensionName);
518 81 : oDim.nSize = oIter->second;
519 81 : oMetadata.aoDimensions.push_back(std::move(oDim));
520 : }
521 45 : if (bValid)
522 : {
523 66 : if (oMetadata.aoDimensions.size() >= 2 &&
524 66 : aoLongitudeDimensions.size() == 2 &&
525 21 : aoLongitudeDimensions == aoLatitudeDimensions)
526 : {
527 21 : int i = 0;
528 42 : std::string osDataXDimName;
529 42 : std::string osDataYDimName;
530 78 : for (const auto &oDimSwath : oMetadata.aoDimensions)
531 : {
532 : auto oIter =
533 : oMapDataDimensionToGeoDimension.find(
534 57 : oDimSwath.osName);
535 57 : if (oIter !=
536 114 : oMapDataDimensionToGeoDimension.end())
537 : {
538 42 : const auto &osGeoDimName = oIter->second;
539 42 : if (osGeoDimName ==
540 42 : aoLongitudeDimensions[0].osName)
541 : {
542 21 : osDataYDimName = oDimSwath.osName;
543 21 : oMetadata.iYDim = i;
544 : }
545 21 : else if (osGeoDimName ==
546 21 : aoLongitudeDimensions[1].osName)
547 : {
548 21 : osDataXDimName = oDimSwath.osName;
549 21 : oMetadata.iXDim = i;
550 : }
551 : }
552 : else
553 : {
554 15 : oMetadata.iOtherDim = i;
555 : }
556 57 : ++i;
557 : }
558 21 : if (oMetadata.iXDim >= 0 && oMetadata.iYDim >= 0)
559 : {
560 : oMetadata.osLongitudeSubdataset =
561 42 : "//HDFEOS/SWATHS/" + osSwathName +
562 21 : "/Geolocation_Fields/Longitude";
563 : oMetadata.osLatitudeSubdataset =
564 42 : "//HDFEOS/SWATHS/" + osSwathName +
565 21 : "/Geolocation_Fields/Latitude";
566 :
567 87 : for (const auto &oDimMap : aoDimensionMaps)
568 : {
569 66 : if (oDimMap.osDataDimName == osDataYDimName)
570 : {
571 21 : oMetadata.nLineOffset = oDimMap.nOffset;
572 21 : oMetadata.nLineStep =
573 21 : oDimMap.nIncrement;
574 : }
575 45 : else if (oDimMap.osDataDimName ==
576 : osDataXDimName)
577 : {
578 21 : oMetadata.nPixelOffset =
579 21 : oDimMap.nOffset;
580 21 : oMetadata.nPixelStep =
581 21 : oDimMap.nIncrement;
582 : }
583 : }
584 : }
585 : }
586 :
587 : m_oMapSubdatasetNameToSwathDataFieldMetadata
588 90 : ["//HDFEOS/SWATHS/" + osSwathName +
589 135 : "/Data_Fields/" + osDataFieldName] =
590 90 : std::move(oMetadata);
591 : }
592 : }
593 : }
594 : }
595 : }
596 15 : }
597 :
598 : /************************************************************************/
599 : /* GetSwathMetadata() */
600 : /************************************************************************/
601 :
602 3 : bool HDF5EOSParser::GetSwathMetadata(const std::string &osSwathName,
603 : SwathMetadata &swathMetadataOut) const
604 : {
605 3 : const auto oIter = m_oMapSwathNameToSwathMetadata.find(osSwathName);
606 3 : if (oIter == m_oMapSwathNameToSwathMetadata.end())
607 0 : return false;
608 3 : swathMetadataOut = *(oIter->second.get());
609 3 : return true;
610 : }
611 :
612 : /************************************************************************/
613 : /* GetSwathDataFieldMetadata() */
614 : /************************************************************************/
615 :
616 22 : bool HDF5EOSParser::GetSwathDataFieldMetadata(
617 : const char *pszSubdatasetName,
618 : SwathDataFieldMetadata &swathDataFieldMetadataOut) const
619 : {
620 : const auto oIter =
621 22 : m_oMapSubdatasetNameToSwathDataFieldMetadata.find(pszSubdatasetName);
622 22 : if (oIter == m_oMapSubdatasetNameToSwathDataFieldMetadata.end())
623 12 : return false;
624 10 : swathDataFieldMetadataOut = oIter->second;
625 10 : return true;
626 : }
627 :
628 : /************************************************************************/
629 : /* GetSwathGeolocationFieldMetadata() */
630 : /************************************************************************/
631 :
632 2 : bool HDF5EOSParser::GetSwathGeolocationFieldMetadata(
633 : const char *pszSubdatasetName,
634 : SwathGeolocationFieldMetadata &swathGeolocationFieldMetadataOut) const
635 : {
636 : const auto oIter = m_oMapSubdatasetNameToSwathGeolocationFieldMetadata.find(
637 2 : pszSubdatasetName);
638 2 : if (oIter == m_oMapSubdatasetNameToSwathGeolocationFieldMetadata.end())
639 0 : return false;
640 2 : swathGeolocationFieldMetadataOut = oIter->second;
641 2 : return true;
642 : }
643 :
644 : /************************************************************************/
645 : /* GetGeoTransform() */
646 : /************************************************************************/
647 :
648 9 : bool HDF5EOSParser::GridMetadata::GetGeoTransform(GDALGeoTransform >) const
649 : {
650 9 : if (nProjCode >= 0 &&
651 20 : (osGridOrigin == "HE5_HDFE_GD_UL" || osGridOrigin.empty()) &&
652 27 : adfUpperLeftPointMeters.size() == 2 &&
653 9 : adfLowerRightPointMeters.size() == 2)
654 : {
655 9 : int nRasterXSize = 0;
656 9 : int nRasterYSize = 0;
657 :
658 31 : for (const auto &oDim : aoDimensions)
659 : {
660 22 : if (oDim.osName == "XDim")
661 9 : nRasterXSize = oDim.nSize;
662 13 : else if (oDim.osName == "YDim")
663 9 : nRasterYSize = oDim.nSize;
664 : }
665 9 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
666 0 : return false;
667 9 : if (nProjCode == 0) // GEO
668 : {
669 2 : gt[0] = CPLPackedDMSToDec(adfUpperLeftPointMeters[0]);
670 2 : gt[1] = (CPLPackedDMSToDec(adfLowerRightPointMeters[0]) -
671 2 : CPLPackedDMSToDec(adfUpperLeftPointMeters[0])) /
672 : nRasterXSize;
673 2 : gt[2] = 0;
674 2 : gt[3] = CPLPackedDMSToDec(adfUpperLeftPointMeters[1]);
675 2 : gt[4] = 0;
676 4 : gt[5] = (CPLPackedDMSToDec(adfLowerRightPointMeters[1]) -
677 2 : CPLPackedDMSToDec(adfUpperLeftPointMeters[1])) /
678 : nRasterYSize;
679 : }
680 : else
681 : {
682 7 : gt[0] = adfUpperLeftPointMeters[0];
683 7 : gt[1] = (adfLowerRightPointMeters[0] - adfUpperLeftPointMeters[0]) /
684 : nRasterXSize;
685 7 : gt[2] = 0;
686 7 : gt[3] = adfUpperLeftPointMeters[1];
687 7 : gt[4] = 0;
688 7 : gt[5] = (adfLowerRightPointMeters[1] - adfUpperLeftPointMeters[1]) /
689 : nRasterYSize;
690 : }
691 9 : return true;
692 : }
693 0 : return false;
694 : }
695 :
696 : /************************************************************************/
697 : /* GetSRS() */
698 : /************************************************************************/
699 :
700 9 : std::unique_ptr<OGRSpatialReference> HDF5EOSParser::GridMetadata::GetSRS() const
701 : {
702 18 : std::vector<double> l_adfProjParams = adfProjParams;
703 9 : l_adfProjParams.resize(15);
704 18 : auto poSRS = std::make_unique<OGRSpatialReference>();
705 9 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
706 18 : if (poSRS->importFromUSGS(nProjCode, nZone, l_adfProjParams.data(),
707 18 : nSphereCode) == OGRERR_NONE)
708 : {
709 9 : return poSRS;
710 : }
711 0 : return nullptr;
712 : }
|