/src/bag/api/bag_dataset.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | #include "bag_attributeinfo.h" |
3 | | #include "bag_georefmetadatalayer.h" |
4 | | #include "bag_georefmetadatalayerdescriptor.h" |
5 | | #include "bag_dataset.h" |
6 | | #include "bag_exceptions.h" |
7 | | #include "bag_interleavedlegacylayer.h" |
8 | | #include "bag_interleavedlegacylayerdescriptor.h" |
9 | | #include "bag_metadataprofiles.h" |
10 | | #include "bag_metadata_export.h" |
11 | | #include "bag_private.h" |
12 | | #include "bag_simplelayer.h" |
13 | | #include "bag_simplelayerdescriptor.h" |
14 | | #include "bag_surfacecorrections.h" |
15 | | #include "bag_surfacecorrectionsdescriptor.h" |
16 | | #include "bag_version.h" |
17 | | #include "bag_vrmetadata.h" |
18 | | #include "bag_vrmetadatadescriptor.h" |
19 | | #include "bag_vrnode.h" |
20 | | #include "bag_vrnodedescriptor.h" |
21 | | #include "bag_vrrefinements.h" |
22 | | #include "bag_vrrefinementsdescriptor.h" |
23 | | |
24 | | #include <iostream> |
25 | | #include <algorithm> |
26 | | #include <array> |
27 | | #include <cctype> |
28 | | #include <H5Cpp.h> |
29 | | #include <H5Exception.h> |
30 | | #include <map> |
31 | | #include <memory> |
32 | | #include <regex> |
33 | | #include <string> |
34 | | #include <memory> |
35 | | #include <csignal> |
36 | | |
37 | | |
38 | | namespace BAG { |
39 | | |
40 | | using std::cerr; |
41 | | |
42 | | namespace { |
43 | | |
44 | | //! Find a layer by type and case-insensitive name. |
45 | | /*! |
46 | | \param layers |
47 | | The layers to search. |
48 | | \param type |
49 | | The type of layer to find. |
50 | | \param name |
51 | | The case-insensitive name of the layer to find. |
52 | | This is optional unless looking for a georeferenced metadata layer. |
53 | | |
54 | | \return |
55 | | The found layer. |
56 | | nullptr if not found. |
57 | | */ |
58 | | std::shared_ptr<Layer> getLayer( |
59 | | const std::vector<std::shared_ptr<Layer>>& layers, |
60 | | LayerType type, |
61 | | const std::string& name = {}) |
62 | 63 | { |
63 | 63 | if (type == Georef_Metadata && name.empty()) |
64 | 0 | throw NameRequired{}; |
65 | | |
66 | 63 | std::string nameLower{name}; |
67 | 63 | std::transform(begin(nameLower), end(nameLower), begin(nameLower), |
68 | 63 | [](char c) noexcept { |
69 | 0 | return static_cast<char>(std::tolower(c)); |
70 | 0 | }); |
71 | | |
72 | 63 | std::shared_ptr<Layer> foundLayer = nullptr; |
73 | 69 | for (auto layer : layers) { |
74 | 69 | auto pDescriptor = layer->getDescriptor(); |
75 | 69 | if (type == pDescriptor->getLayerType()) { |
76 | 0 | if (nameLower.empty()) { |
77 | 0 | foundLayer = layer; |
78 | 0 | break; |
79 | 0 | } |
80 | 0 | std::string foundNameLower{pDescriptor->getName()}; |
81 | 0 | std::transform(begin(foundNameLower), end(foundNameLower), begin(foundNameLower), |
82 | 0 | [](char c) noexcept { |
83 | 0 | return static_cast<char>(std::tolower(c)); |
84 | 0 | }); |
85 | 0 | if (foundNameLower == nameLower) { |
86 | 0 | foundLayer = layer; |
87 | 0 | break; |
88 | 0 | } |
89 | 0 | } |
90 | 69 | } |
91 | | |
92 | 63 | if (foundLayer == nullptr) return {}; |
93 | | |
94 | 0 | return std::shared_ptr<Layer>(foundLayer); |
95 | 63 | } |
96 | | |
97 | | //! Get the numerical version. |
98 | | /*! |
99 | | Expecting "major" (2) or "major.minor" (2.0) or "major.minor.patch" (2.0.0), |
100 | | which will be turned into a number such that: |
101 | | |
102 | | major * 1,000,000 + minor * 1,000 + patch is returned. |
103 | | |
104 | | \param versionStr |
105 | | The version as a string. Eg., "2.1.4". |
106 | | |
107 | | \return |
108 | | The numerical representation of the version. |
109 | | 0 if the version string cannot be parsed. |
110 | | */ |
111 | | uint32_t getNumericalVersion( |
112 | | const std::string& versionStr) |
113 | 242 | { |
114 | 242 | const std::regex expression{R"(\.)"}; // match any period |
115 | | |
116 | 242 | auto b = std::sregex_token_iterator{begin(versionStr), end(versionStr), |
117 | 242 | expression, -1}; |
118 | 242 | const auto e = std::sregex_token_iterator{}; |
119 | | |
120 | | |
121 | 242 | uint32_t version = 0; |
122 | 242 | uint32_t multiplier = 1'000'000; |
123 | | |
124 | 777 | for (auto iter = b; iter != e; ++iter) |
125 | 589 | { |
126 | 589 | try |
127 | 589 | { |
128 | 589 | version += std::stoul(*iter) * multiplier; |
129 | 589 | } |
130 | 589 | catch(...) |
131 | 589 | { |
132 | 54 | return 0; |
133 | 54 | } |
134 | | |
135 | 535 | multiplier /= 1000; |
136 | 535 | } |
137 | | |
138 | 188 | return version; |
139 | 242 | } |
140 | | |
141 | | //! A type alias to use SFINAE to check if a type is not a std::string. |
142 | | template <typename T> |
143 | | using IsNotString = std::enable_if_t<!std::is_same<T, std::string>::value>; |
144 | | |
145 | | //! Helper to read a non-string attribute from an HDF5 DataSet. |
146 | | /*! |
147 | | \param h5file |
148 | | The HDF5 file to read. |
149 | | \param dataSetName |
150 | | The name of the HDF5 DataSet. |
151 | | \param attributeName |
152 | | The name of the attribute. |
153 | | |
154 | | \return |
155 | | The attribute value. |
156 | | */ |
157 | | template <typename T, typename = IsNotString<T>> |
158 | | T readAttributeFromDataSet( |
159 | | const ::H5::H5File& h5file, |
160 | | const std::string& dataSetName, |
161 | | const std::string& attributeName) |
162 | 358 | { |
163 | 358 | const ::H5::DataSet h5DataSet = h5file.openDataSet(dataSetName); |
164 | 358 | const ::H5::Attribute attribute = h5DataSet.openAttribute(attributeName); |
165 | | |
166 | 358 | T value{}; |
167 | 358 | attribute.read(attribute.getDataType(), &value); |
168 | | |
169 | 358 | return value; |
170 | 358 | } |
171 | | |
172 | | //! Helper to read a string attribute from an HDF5 DataSet. |
173 | | /*! |
174 | | \param h5file |
175 | | The HDF5 file to read. |
176 | | \param dataSetName |
177 | | The name of the HDF5 DataSet. |
178 | | \param attributeName |
179 | | The name of the attribute. |
180 | | |
181 | | \return |
182 | | The attribute value as a string. |
183 | | */ |
184 | | std::string readStringAttributeFromDataSet( |
185 | | const ::H5::H5File& h5file, |
186 | | const std::string& dataSetName, |
187 | | const std::string& attributeName) |
188 | 0 | { |
189 | 0 | const ::H5::DataSet h5DataSet = h5file.openDataSet(dataSetName); |
190 | 0 | const ::H5::Attribute attribute = h5DataSet.openAttribute(attributeName); |
191 | 0 |
|
192 | 0 | std::string value; |
193 | 0 | attribute.read(attribute.getDataType(), value); |
194 | 0 |
|
195 | 0 | return value; |
196 | 0 | } |
197 | | |
198 | | //! Helper to read a non-string attribute from an HDF5 Group. |
199 | | /*! |
200 | | \param h5file |
201 | | The HDF5 file to read. |
202 | | \param groupName |
203 | | The name of the HDF5 Group. |
204 | | \param attributeName |
205 | | The name of the attribute. |
206 | | |
207 | | \return |
208 | | The attribute value. |
209 | | */ |
210 | | template <typename T, typename = IsNotString<T>> |
211 | | T readAttributeFromGroup( |
212 | | const ::H5::H5File& h5file, |
213 | | const std::string& groupName, |
214 | | const std::string& attributeName) |
215 | | { |
216 | | const ::H5::Group h5group = h5file.openGroup(groupName); |
217 | | const ::H5::Attribute attribute = h5group.openAttribute(attributeName); |
218 | | |
219 | | T value{}; |
220 | | attribute.read(attribute.getDataType(), &value); |
221 | | |
222 | | return value; |
223 | | } |
224 | | |
225 | | //! Helper to read a string attribute from an HDF5 Group. |
226 | | /*! |
227 | | \param h5file |
228 | | The HDF5 file to read. |
229 | | \param groupName |
230 | | The name of the HDF5 Group. |
231 | | \param attributeName |
232 | | The name of the attribute. |
233 | | |
234 | | \return |
235 | | The attribute value as a string. |
236 | | */ |
237 | | std::string readStringAttributeFromGroup( |
238 | | const ::H5::H5File& h5file, |
239 | | const std::string& groupName, |
240 | | const std::string& attributeName) |
241 | 242 | { |
242 | 242 | const ::H5::Group h5group = h5file.openGroup(groupName); |
243 | 242 | const ::H5::Attribute attribute = h5group.openAttribute(attributeName); |
244 | | |
245 | 242 | std::string value; |
246 | 242 | attribute.read(attribute.getDataType(), value); |
247 | | |
248 | 242 | return value; |
249 | 242 | } |
250 | | |
251 | | } // namespace |
252 | | |
253 | | //! Open an existing BAG. |
254 | | /*! |
255 | | \param fileName |
256 | | The name of the BAG. |
257 | | \param openMode |
258 | | The mode to open the BAG with. |
259 | | |
260 | | \return |
261 | | The BAG Dataset. |
262 | | */ |
263 | | std::shared_ptr<Dataset> Dataset::open( |
264 | | const std::string& fileName, |
265 | | OpenMode openMode) |
266 | 332 | { |
267 | 332 | #ifdef NDEBUG |
268 | 332 | ::H5::Exception::dontPrint(); |
269 | 332 | #endif |
270 | | |
271 | 332 | std::shared_ptr<Dataset> pDataset{new Dataset}; |
272 | 332 | try |
273 | 332 | { |
274 | 332 | pDataset->readDataset(fileName, openMode); |
275 | 332 | } catch (H5::FileIException &fileExcept) |
276 | 332 | { |
277 | 130 | std::cerr << "\nUnable to open BAG file: " << fileName << " due to error: " << fileExcept.getCDetailMsg(); |
278 | 130 | return nullptr; |
279 | 130 | } |
280 | | |
281 | 202 | return pDataset; |
282 | 332 | } |
283 | | |
284 | | //! Create a BAG. |
285 | | /*! |
286 | | \param fileName |
287 | | The name of the BAG. |
288 | | \param metadata |
289 | | The metadata describing the BAG. |
290 | | This parameter will be moved, and not usable after. |
291 | | \param chunkSize |
292 | | The chunk size the HDF5 DataSet will use. |
293 | | \param compressionLevel |
294 | | The compression level the HDF5 DataSet will use. |
295 | | |
296 | | \return |
297 | | The BAG Dataset. |
298 | | */ |
299 | | std::shared_ptr<Dataset> Dataset::create( |
300 | | const std::string& fileName, |
301 | | Metadata&& metadata, |
302 | | uint64_t chunkSize, |
303 | | int compressionLevel) |
304 | 0 | { |
305 | 0 | std::shared_ptr<Dataset> pDataset{new Dataset}; |
306 | 0 | pDataset->createDataset(fileName, std::move(metadata), chunkSize, |
307 | 0 | compressionLevel); |
308 | |
|
309 | 0 | return pDataset; |
310 | 0 | } |
311 | | |
312 | | //! Close a BAG dataset. Closes the underlying HDF5 file. |
313 | 202 | void Dataset::close() { |
314 | 202 | if (m_pH5file) { |
315 | 202 | m_pH5file->close(); |
316 | 202 | m_pH5file.reset(nullptr); |
317 | 202 | } |
318 | 202 | } |
319 | | |
320 | | |
321 | | //! Add a layer to this dataset. |
322 | | /*! |
323 | | \param newLayer |
324 | | The new layer. |
325 | | |
326 | | \return |
327 | | A reference to the new layer. |
328 | | */ |
329 | | Layer& Dataset::addLayer( |
330 | | std::shared_ptr<Layer> newLayer) & |
331 | 239 | { |
332 | 239 | m_layers.push_back(std::move(newLayer)); |
333 | | |
334 | 239 | const auto& layer = m_layers.back(); |
335 | | |
336 | 239 | m_descriptor.addLayerDescriptor(*layer->getDescriptor()); |
337 | | |
338 | 239 | return *layer; |
339 | 239 | } |
340 | | |
341 | | //! Create a georeferenced metadata layer. |
342 | | /*! |
343 | | \param keyType |
344 | | The type of key the georeferenced metadata layer will use. |
345 | | Valid values are: DT_UINT8, DT_UINT16, DT_UINT32 or DT_UINT64 |
346 | | \param name |
347 | | The name of the simple layer this georeferenced metadata layer has metadata for. |
348 | | \param definition |
349 | | The list of fields defining a record of the georeferenced metadata layer. |
350 | | \param chunkSize |
351 | | The chunk size the HDF5 DataSet will use. |
352 | | \param compressionLevel |
353 | | The compression level the HDF5 DataSet will use. |
354 | | |
355 | | \return |
356 | | The new georeferenced metadata layer. |
357 | | */ |
358 | | GeorefMetadataLayer& Dataset::createGeorefMetadataLayer( |
359 | | DataType keyType, |
360 | | GeorefMetadataProfile profile, |
361 | | const std::string& name, |
362 | | const RecordDefinition& definition, |
363 | | uint64_t chunkSize, |
364 | | int compressionLevel) & |
365 | 0 | { |
366 | 0 | if (m_descriptor.isReadOnly()) |
367 | 0 | throw ReadOnlyError{}; |
368 | | |
369 | 0 | std::string nameLower{name}; |
370 | 0 | std::transform(begin(nameLower), end(nameLower), begin(nameLower), |
371 | 0 | [](char c) noexcept { |
372 | 0 | return static_cast<char>(std::tolower(c)); |
373 | 0 | }); |
374 | | |
375 | | // Make sure a corresponding simple layer exists. |
376 | 0 | const bool simpleLayerExists = std::any_of(cbegin(m_layers), cend(m_layers), |
377 | 0 | [&nameLower](const std::shared_ptr<Layer>& layer) { |
378 | 0 | auto pDescriptor = layer->getDescriptor(); |
379 | |
|
380 | 0 | const auto layerType = pDescriptor->getLayerType(); |
381 | | |
382 | | // Skip non-simple layers. |
383 | 0 | if (layerType == Georef_Metadata || layerType == VarRes_Metadata || |
384 | 0 | layerType == VarRes_Refinement || layerType == VarRes_Node) |
385 | 0 | return false; |
386 | | |
387 | 0 | std::string simpleNameLower{pDescriptor->getName()}; |
388 | 0 | std::transform(begin(simpleNameLower), end(simpleNameLower), begin(simpleNameLower), |
389 | 0 | [](char c) noexcept { |
390 | 0 | return static_cast<char>(std::tolower(c)); |
391 | 0 | }); |
392 | |
|
393 | 0 | return simpleNameLower == nameLower; |
394 | 0 | }); |
395 | 0 | if (!simpleLayerExists) |
396 | 0 | throw LayerNotFound{}; |
397 | | |
398 | | // Make sure the georeferenced metadata layer does not already exist. |
399 | 0 | if (this->getGeorefMetadataLayer(name)) |
400 | 0 | throw LayerExists{}; |
401 | | |
402 | | // Create the group if it does not exist. |
403 | 0 | const auto id = H5Gopen2(m_pH5file->getId(), GEOREF_METADATA_PATH, H5P_DEFAULT); |
404 | 0 | if (id == -1) |
405 | 0 | m_pH5file->createGroup(GEOREF_METADATA_PATH); |
406 | 0 | else |
407 | 0 | H5Gclose(id); |
408 | |
|
409 | 0 | return dynamic_cast<GeorefMetadataLayer&>(this->addLayer(GeorefMetadataLayer::create( |
410 | 0 | keyType, name, profile, *this, definition, chunkSize, compressionLevel))); |
411 | 0 | } |
412 | | |
413 | | //! Convenience method for creating a georeferenced metadata layer with a known metadata profile. |
414 | | //! Will use the RecordDefinition appropriate to the known profile. |
415 | | /*! |
416 | | \param profile |
417 | | The metadata profile to assign to the georeferenced metadata layer. |
418 | | \param name |
419 | | The name of the simple layer this georeferenced metadata layer has metadata for. |
420 | | \param chunkSize |
421 | | The chunk size the HDF5 DataSet will use. |
422 | | \param compressionLevel |
423 | | The compression level the HDF5 DataSet will use. |
424 | | \param keyType |
425 | | The type of key the georeferenced metadata layer will use. |
426 | | Valid values are: DT_UINT8, DT_UINT16, DT_UINT32 or DT_UINT64 |
427 | | Default value: DT_UINT16 |
428 | | |
429 | | \return |
430 | | The new georeferenced metadata layer. |
431 | | |
432 | | \throws |
433 | | UknownMetadataProfile if profile is not a known metadata profile |
434 | | */ |
435 | | GeorefMetadataLayer& Dataset::createGeorefMetadataLayer( |
436 | | GeorefMetadataProfile profile, |
437 | | const std::string& name, |
438 | | uint64_t chunkSize, |
439 | | int compressionLevel, |
440 | | DataType keyType) & |
441 | 0 | { |
442 | 0 | BAG::RecordDefinition definition = METADATA_DEFINITION_UNKNOWN; |
443 | |
|
444 | 0 | try { |
445 | 0 | definition = kGeorefMetadataProfileMapKnownRecordDefinition.at(profile); |
446 | 0 | } catch (const std::out_of_range&) { |
447 | 0 | throw UknownMetadataProfile{kGeorefMetadataProfileMapString.at(profile)}; |
448 | 0 | } |
449 | | |
450 | 0 | return createGeorefMetadataLayer(keyType, profile, |
451 | 0 | name, definition, chunkSize, compressionLevel); |
452 | 0 | } |
453 | | |
454 | | //! Create a new Dataset. |
455 | | /*! |
456 | | \param fileName |
457 | | The name of the new BAG. |
458 | | \param metadata |
459 | | The metadata to be used by the BAG. |
460 | | \param chunkSize |
461 | | The chunk size the HDF5 DataSet will use. |
462 | | \param compressionLevel |
463 | | The compression level the HDF5 DataSet will use. |
464 | | */ |
465 | | void Dataset::createDataset( |
466 | | const std::string& fileName, |
467 | | Metadata&& metadata, |
468 | | uint64_t chunkSize, |
469 | | int compressionLevel) |
470 | 0 | { |
471 | 0 | #ifdef NDEBUG |
472 | 0 | ::H5::Exception::dontPrint(); |
473 | 0 | #endif |
474 | |
|
475 | 0 | m_pH5file = std::unique_ptr<::H5::H5File, DeleteH5File>(new ::H5::H5File{ |
476 | 0 | fileName.c_str(), H5F_ACC_EXCL}, DeleteH5File{}); |
477 | | |
478 | | // Group: BAG_root |
479 | 0 | { |
480 | 0 | auto h5bagGroup = m_pH5file->createGroup(ROOT_PATH); |
481 | |
|
482 | 0 | const auto versionAttType = ::H5::StrType{0, BAG_VERSION_LENGTH}; |
483 | 0 | const ::H5::DataSpace versionAttDataSpace{}; |
484 | 0 | auto versionAtt = h5bagGroup.createAttribute(BAG_VERSION_NAME, |
485 | 0 | versionAttType, versionAttDataSpace); |
486 | |
|
487 | 0 | versionAtt.write(versionAttType, BAG_VERSION); |
488 | 0 | } |
489 | | |
490 | | // Metadata |
491 | 0 | metadata.createH5dataSet(*this); |
492 | 0 | metadata.write(); |
493 | 0 | m_pMetadata = std::make_unique<Metadata>(std::move(metadata)); |
494 | |
|
495 | 0 | m_descriptor = Descriptor{*m_pMetadata}; |
496 | 0 | m_descriptor.setReadOnly(false); |
497 | 0 | m_descriptor.setVersion(BAG_VERSION); |
498 | | |
499 | | // TrackingList |
500 | 0 | m_pTrackingList = std::unique_ptr<TrackingList>(new TrackingList{*this, |
501 | 0 | compressionLevel}); |
502 | | |
503 | | // Mandatory Layers |
504 | | // Elevation |
505 | 0 | this->addLayer(SimpleLayer::create(*this, Elevation, chunkSize, |
506 | 0 | compressionLevel)); |
507 | | |
508 | | // Uncertainty |
509 | 0 | this->addLayer(SimpleLayer::create(*this, Uncertainty, chunkSize, |
510 | 0 | compressionLevel)); |
511 | 0 | } |
512 | | |
513 | | //! Create an optional simple layer. |
514 | | /*! |
515 | | \param type |
516 | | The type of layer to create. |
517 | | The layer cannot currently exist. |
518 | | \param chunkSize |
519 | | The chunk size the HDF5 DataSet will use. |
520 | | \param compressionLevel |
521 | | The compression level the HDF5 DataSet will use. |
522 | | |
523 | | \return |
524 | | The new layer. |
525 | | */ |
526 | | Layer& Dataset::createSimpleLayer( |
527 | | LayerType type, |
528 | | uint64_t chunkSize, |
529 | | int compressionLevel) & |
530 | 0 | { |
531 | 0 | if (m_descriptor.isReadOnly()) |
532 | 0 | throw ReadOnlyError{}; |
533 | | |
534 | | // Make sure it doesn't already exist. |
535 | 0 | if (BAG::getLayer(m_layers, type)) |
536 | 0 | throw LayerExists{}; |
537 | | |
538 | 0 | switch (type) |
539 | 0 | { |
540 | 0 | case Elevation: //[[fallthrough]]; |
541 | 0 | case Uncertainty: //[[fallthrough]]; |
542 | 0 | case Hypothesis_Strength: //[[fallthrough]]; |
543 | 0 | case Num_Hypotheses: //[[fallthrough]]; |
544 | 0 | case Shoal_Elevation: //[[fallthrough]]; |
545 | 0 | case Std_Dev: //[[fallthrough]]; |
546 | 0 | case Num_Soundings: //[[fallthrough]]; |
547 | 0 | case Average_Elevation: //[[fallthrough]]; |
548 | 0 | case Nominal_Elevation: |
549 | 0 | return this->addLayer(SimpleLayer::create(*this, type, chunkSize, |
550 | 0 | compressionLevel)); |
551 | 0 | case Surface_Correction: //[[fallthrough]]; |
552 | 0 | case Georef_Metadata: //[[fallthrough]]; |
553 | 0 | default: |
554 | 0 | throw UnsupportedLayerType{}; |
555 | 0 | } |
556 | 0 | } |
557 | | |
558 | | //! Create optional surface corrections layer. |
559 | | /*! |
560 | | \param type |
561 | | The type of topography. |
562 | | Gridded (BAG_SURFACE_GRID_EXTENTS) or sparse (BAG_SURFACE_IRREGULARLY_SPACED). |
563 | | \param numCorrectors |
564 | | The number of correctors to use (1-10). |
565 | | \param chunkSize |
566 | | The chunk size the HDF5 DataSet will use. |
567 | | \param compressionLevel |
568 | | The compression level the HDF5 DataSet will use. |
569 | | |
570 | | \return |
571 | | The new surface corrections layer. |
572 | | */ |
573 | | SurfaceCorrections& Dataset::createSurfaceCorrections( |
574 | | BAG_SURFACE_CORRECTION_TOPOGRAPHY type, |
575 | | uint8_t numCorrectors, |
576 | | uint64_t chunkSize, |
577 | | int compressionLevel) & |
578 | 0 | { |
579 | 0 | if (m_descriptor.isReadOnly()) |
580 | 0 | throw ReadOnlyError{}; |
581 | | |
582 | | // Make sure surface corrections do not already exist. |
583 | 0 | if (this->getSurfaceCorrections()) |
584 | 0 | throw LayerExists{}; |
585 | | |
586 | 0 | return dynamic_cast<SurfaceCorrections&>(this->addLayer( |
587 | 0 | SurfaceCorrections::create(*this, type, numCorrectors, chunkSize, |
588 | 0 | compressionLevel))); |
589 | 0 | } |
590 | | |
591 | | //! Create optional variable resolution layers. |
592 | | /*! |
593 | | \param chunkSize |
594 | | The chunk size the HDF5 DataSet will use. |
595 | | \param compressionLevel |
596 | | The compression level the HDF5 DataSet will use. |
597 | | */ |
598 | | void Dataset::createVR( |
599 | | uint64_t chunkSize, |
600 | | int compressionLevel, |
601 | | bool createNode) |
602 | 0 | { |
603 | 0 | if (m_descriptor.isReadOnly()) |
604 | 0 | throw ReadOnlyError{}; |
605 | | |
606 | | // Make sure VR layers do not already exist. |
607 | 0 | if (this->getVRMetadata()) |
608 | 0 | throw LayerExists{}; |
609 | | |
610 | | //TODO Consider a try/catch to undo partial creation. |
611 | | |
612 | 0 | m_pVRTrackingList = std::make_unique<VRTrackingList>( |
613 | 0 | *this, compressionLevel); |
614 | |
|
615 | 0 | this->addLayer(VRMetadata::create(*this, chunkSize, compressionLevel)); |
616 | 0 | this->addLayer(VRRefinements::create(*this, chunkSize, compressionLevel)); |
617 | |
|
618 | 0 | if (createNode) |
619 | 0 | this->addLayer(VRNode::create(*this, chunkSize, compressionLevel)); |
620 | 0 | } |
621 | | |
622 | | //! Convert a geographic location to grid position. |
623 | | /*! |
624 | | \param x |
625 | | The X of the geographic location. |
626 | | \param y |
627 | | The Y of the geographic location. |
628 | | |
629 | | \return |
630 | | The grid position (row, column). |
631 | | */ |
632 | | std::tuple<uint32_t, uint32_t> Dataset::geoToGrid( |
633 | | double x, |
634 | | double y) const noexcept |
635 | 0 | { |
636 | 0 | const auto row = static_cast<uint32_t>((x - m_pMetadata->llCornerX()) / |
637 | 0 | m_pMetadata->rowResolution()); |
638 | 0 | const auto column = static_cast<uint32_t>((y - m_pMetadata->llCornerY()) / |
639 | 0 | m_pMetadata->columnResolution()); |
640 | |
|
641 | 0 | return {row, column}; |
642 | 0 | } |
643 | | |
644 | | //! Retrieve an optional georeferenced metadata layer by name. |
645 | | /*! |
646 | | \param name |
647 | | The name of the simple layer the georeferenced metadata layer has metadata for. |
648 | | |
649 | | \return |
650 | | The specified georeferenced metadata layer, if it exists. nullptr otherwise |
651 | | */ |
652 | | std::shared_ptr<GeorefMetadataLayer> Dataset::getGeorefMetadataLayer( |
653 | | const std::string& name) & noexcept |
654 | 0 | { |
655 | 0 | return std::dynamic_pointer_cast<GeorefMetadataLayer>(BAG::getLayer(m_layers, Georef_Metadata, name)); |
656 | 0 | } |
657 | | |
658 | | //! Retrieve an optional georeferenced metadata layer by name. |
659 | | /*! |
660 | | \param name |
661 | | The name of the simple layer the georeferenced metadata layer has metadata for. |
662 | | |
663 | | \return |
664 | | x The specified georeferenced metadata layer, if it exists. nullptr otherwise |
665 | | */ |
666 | | std::shared_ptr<const GeorefMetadataLayer> Dataset::getGeorefMetadataLayer(const std::string& name) const & noexcept |
667 | 0 | { |
668 | 0 | return std::dynamic_pointer_cast<const GeorefMetadataLayer>(BAG::getLayer(m_layers, Georef_Metadata, name)); |
669 | 0 | } |
670 | | |
671 | | //! Retrieve all the georeferenced metadata layers. |
672 | | /*! |
673 | | \return |
674 | | All the georeferenced metadata layers. |
675 | | */ |
676 | | std::vector<std::shared_ptr<GeorefMetadataLayer>> Dataset::getGeorefMetadataLayers() & noexcept |
677 | 0 | { |
678 | 0 | std::vector<std::shared_ptr<GeorefMetadataLayer>> layers; |
679 | |
|
680 | 0 | for (const auto& layer : m_layers) |
681 | 0 | if (layer->getDescriptor()->getLayerType() == Georef_Metadata) { |
682 | 0 | layers.emplace_back(std::dynamic_pointer_cast<GeorefMetadataLayer>(layer)); |
683 | 0 | } |
684 | |
|
685 | 0 | return layers; |
686 | 0 | } |
687 | | |
688 | | //! Retrieve the dataset's descriptor. |
689 | | /*! |
690 | | \return |
691 | | The dataset's descriptor. |
692 | | */ |
693 | | Descriptor& Dataset::getDescriptor() & noexcept |
694 | 24 | { |
695 | 24 | return m_descriptor; |
696 | 24 | } |
697 | | |
698 | | //! Retrieve the dataset's descriptor. |
699 | | /*! |
700 | | \return |
701 | | The dataset's descriptor. |
702 | | */ |
703 | | const Descriptor& Dataset::getDescriptor() const & noexcept |
704 | 0 | { |
705 | 0 | return m_descriptor; |
706 | 0 | } |
707 | | |
708 | | //! Retrieve the HDF5 file that contains this BAG. |
709 | | /*! |
710 | | \return |
711 | | The HDF5 file that contains to this BAG. |
712 | | */ |
713 | | ::H5::H5File& Dataset::getH5file() const & noexcept |
714 | 1.06k | { |
715 | 1.06k | return *m_pH5file; |
716 | 1.06k | } |
717 | | |
718 | | //! Retrieve a layer by its unique id. |
719 | | /*! |
720 | | Retrieve a layer by its unique id. If it is not found, an InvalidLayerId |
721 | | exception is thrown. |
722 | | |
723 | | \param id |
724 | | The unique id of the layer. |
725 | | |
726 | | \return |
727 | | The layer specified by the id. |
728 | | */ |
729 | | Layer& Dataset::getLayer(uint32_t id) & |
730 | 0 | { |
731 | 0 | if (id >= m_layers.size()) |
732 | 0 | throw InvalidLayerId{}; |
733 | | |
734 | 0 | return *m_layers[id]; |
735 | 0 | } |
736 | | |
737 | | //! Retrieve a layer by its unique id. |
738 | | /*! |
739 | | Retrieve a layer by its unique id. If it is not found, an InvalidLayerId |
740 | | exception is thrown. |
741 | | |
742 | | \param id |
743 | | The unique id of the layer. |
744 | | |
745 | | \return |
746 | | The layer specified by the id. |
747 | | */ |
748 | | const Layer& Dataset::getLayer(uint32_t id) const & |
749 | 0 | { |
750 | 0 | if (id >= m_layers.size()) |
751 | 0 | throw InvalidLayerId{}; |
752 | | |
753 | 0 | return *m_layers[id]; |
754 | 0 | } |
755 | | |
756 | | //! Retrieve a layer based on type and case-insensitive name. |
757 | | /*! |
758 | | \param type |
759 | | The layer type. |
760 | | \param name |
761 | | The optional, case-insensitive name. |
762 | | If the layer type is Georef_Metadata, the name must be the simple layer it refers to. |
763 | | |
764 | | \return |
765 | | The specified layer. |
766 | | nullptr if no layer is found. |
767 | | */ |
768 | | std::shared_ptr<Layer> Dataset::getLayer( |
769 | | LayerType type, |
770 | | const std::string& name) & |
771 | 0 | { |
772 | 0 | return BAG::getLayer(m_layers, type, name); |
773 | 0 | } |
774 | | |
775 | | //! Retrieve a layer based on type and case-insensitive name. |
776 | | /*! |
777 | | \param type |
778 | | The layer type. |
779 | | \param name |
780 | | The optional, case-insensitive name. |
781 | | If the layer type is Georef_Metadata, the name must be the simple layer it refers to. |
782 | | */ |
783 | | std::shared_ptr<const Layer> Dataset::getLayer( |
784 | | LayerType type, |
785 | | const std::string& name) const & |
786 | 0 | { |
787 | 0 | return std::shared_ptr<const Layer>{BAG::getLayer(m_layers, type, name)}; |
788 | 0 | } |
789 | | |
790 | | //! Retrieve all the layers. |
791 | | /*! |
792 | | \return |
793 | | All the layers. |
794 | | */ |
795 | | std::vector<std::shared_ptr<const Layer>> Dataset::getLayers() const & |
796 | 24 | { |
797 | 24 | std::vector<std::shared_ptr<const Layer>> layers; |
798 | 24 | layers.reserve(m_layers.size()); |
799 | | |
800 | 24 | for (auto&& layer : m_layers) |
801 | 42 | layers.push_back(std::static_pointer_cast<const Layer>(layer)); |
802 | | |
803 | 24 | return layers; |
804 | 24 | } |
805 | | |
806 | | //! Retrieve the layer types. |
807 | | /*! |
808 | | \return |
809 | | The layer types. |
810 | | If multiple georeferenced metadata layers exist, Compound_Layer will only be present once. |
811 | | */ |
812 | | std::vector<LayerType> Dataset::getLayerTypes() const |
813 | 0 | { |
814 | 0 | std::vector<LayerType> types; |
815 | 0 | types.reserve(m_layers.size()); |
816 | |
|
817 | 0 | bool georefMetadataLayerAdded = false; |
818 | |
|
819 | 0 | for (auto&& layer : m_layers) |
820 | 0 | { |
821 | 0 | const auto type = layer->getDescriptor()->getLayerType(); |
822 | 0 | if (type == Georef_Metadata) |
823 | 0 | { |
824 | 0 | if (georefMetadataLayerAdded) |
825 | 0 | continue; |
826 | 0 | else |
827 | 0 | georefMetadataLayerAdded = true; |
828 | 0 | } |
829 | | |
830 | 0 | types.push_back(type); |
831 | 0 | } |
832 | |
|
833 | 0 | return types; |
834 | 0 | } |
835 | | |
836 | | //! Retrieve the metadta. |
837 | | /*! |
838 | | \return |
839 | | The metadata. |
840 | | */ |
841 | | const Metadata& Dataset::getMetadata() const & noexcept |
842 | 0 | { |
843 | 0 | return *m_pMetadata; |
844 | 0 | } |
845 | | |
846 | | //! Retrieve the minimum and maximum values of a simple layer. |
847 | | /*! |
848 | | \param type |
849 | | The type of simple layer. |
850 | | \param path |
851 | | The optional internal HDF5 path to use. |
852 | | |
853 | | \return |
854 | | A tuple of results. |
855 | | The first value in the tuple indicates whether a value was found or not. |
856 | | If the first value is true, the second value is the minimum, and the third value is the maximum. |
857 | | If the first value is false, the second and third values are undefined. |
858 | | */ |
859 | | std::tuple<bool, float, float> Dataset::getMinMax( |
860 | | LayerType type, |
861 | | const std::string& path) const |
862 | 179 | { |
863 | 179 | try |
864 | 179 | { |
865 | 179 | const auto info = getAttributeInfo(type); |
866 | 179 | const auto& thePath = path.empty() ? info.path : path; |
867 | | |
868 | 179 | return {true, |
869 | 179 | readAttributeFromDataSet<float>(*m_pH5file, thePath, info.minName), |
870 | 179 | readAttributeFromDataSet<float>(*m_pH5file, thePath, info.maxName)}; |
871 | 179 | } |
872 | 179 | catch(const UnsupportedSimpleLayerType&) |
873 | 179 | { |
874 | 0 | return {false, 0.f, 0.f}; // No min/max attributes. |
875 | 0 | } |
876 | 179 | } |
877 | | |
878 | | //! Retrieve the next unique layer id. |
879 | | /*! |
880 | | \return |
881 | | The next unique layer id. |
882 | | */ |
883 | | uint32_t Dataset::getNextId() const noexcept |
884 | 268 | { |
885 | 268 | return static_cast<uint32_t>(m_layers.size()); |
886 | 268 | } |
887 | | |
888 | | //! Retrieve the specified simple layer. |
889 | | /*! |
890 | | \param type |
891 | | The layer type. |
892 | | |
893 | | \return |
894 | | The specified simple l ayer. |
895 | | nullptr if the layer does not exist. |
896 | | */ |
897 | | std::shared_ptr<SimpleLayer> Dataset::getSimpleLayer(LayerType type) & noexcept |
898 | 0 | { |
899 | 0 | return std::dynamic_pointer_cast<SimpleLayer>(BAG::getLayer(m_layers, type)); |
900 | 0 | } |
901 | | |
902 | | //! Retrieve the specified simple layer. |
903 | | /*! |
904 | | \param type |
905 | | The layer type. |
906 | | |
907 | | \return |
908 | | The specified simple l ayer. |
909 | | nullptr if the layer does not exist. |
910 | | */ |
911 | | std::shared_ptr<const SimpleLayer> Dataset::getSimpleLayer(LayerType type) const & noexcept |
912 | 0 | { |
913 | 0 | return std::dynamic_pointer_cast<const SimpleLayer>(BAG::getLayer(m_layers, type)); |
914 | 0 | } |
915 | | |
916 | | //! Retrieve the optional surface corrections layer. |
917 | | /*! |
918 | | \return |
919 | | The optional surface corrections layer. |
920 | | */ |
921 | | std::shared_ptr<SurfaceCorrections> Dataset::getSurfaceCorrections() & noexcept |
922 | 0 | { |
923 | 0 | return std::dynamic_pointer_cast<SurfaceCorrections>(BAG::getLayer(m_layers, Surface_Correction)); |
924 | 0 | } |
925 | | |
926 | | //! Retrieve the optional surface corrections layer. |
927 | | /*! |
928 | | \return |
929 | | The optional surface corrections layer. |
930 | | */ |
931 | | std::shared_ptr<const SurfaceCorrections> Dataset::getSurfaceCorrections() const & noexcept |
932 | 0 | { |
933 | 0 | return std::dynamic_pointer_cast<const SurfaceCorrections>(BAG::getLayer(m_layers, Surface_Correction)); |
934 | 0 | } |
935 | | |
936 | | //! Retrieve the tracking list. |
937 | | /*! |
938 | | \return |
939 | | The tracking list. |
940 | | */ |
941 | | TrackingList& Dataset::getTrackingList() & noexcept |
942 | 24 | { |
943 | 24 | return *m_pTrackingList; |
944 | 24 | } |
945 | | |
946 | | //! Retrieve the tracking list. |
947 | | /*! |
948 | | \return |
949 | | The tracking list. |
950 | | */ |
951 | | const TrackingList& Dataset::getTrackingList() const & noexcept |
952 | 0 | { |
953 | 0 | return *m_pTrackingList; |
954 | 0 | } |
955 | | |
956 | | //! Retrieve the optional variable resolution metadata. |
957 | | /*! |
958 | | \return |
959 | | The optional variable resolution metadata. |
960 | | */ |
961 | | std::shared_ptr<VRMetadata> Dataset::getVRMetadata() & noexcept |
962 | 63 | { |
963 | 63 | return std::dynamic_pointer_cast<VRMetadata>(BAG::getLayer(m_layers, VarRes_Metadata)); |
964 | 63 | } |
965 | | |
966 | | //! Retrieve the optional variable resolution metadata. |
967 | | /*! |
968 | | \return |
969 | | The optional variable resolution metadata. |
970 | | */ |
971 | | std::shared_ptr<const VRMetadata> Dataset::getVRMetadata() const & noexcept |
972 | 0 | { |
973 | 0 | return std::dynamic_pointer_cast<const VRMetadata>(BAG::getLayer(m_layers, VarRes_Metadata)); |
974 | 0 | } |
975 | | |
976 | | //! Retrieve the optional variable resolution node group. |
977 | | /*! |
978 | | \return |
979 | | The optional variable resolution node group. |
980 | | */ |
981 | | std::shared_ptr<VRNode> Dataset::getVRNode() & noexcept |
982 | 0 | { |
983 | 0 | return std::dynamic_pointer_cast<VRNode>(BAG::getLayer(m_layers, VarRes_Node)); |
984 | 0 | } |
985 | | |
986 | | //! Retrieve the optional variable resolution node group. |
987 | | /*! |
988 | | \return |
989 | | The optional variable resolution node group. |
990 | | */ |
991 | | std::shared_ptr<const VRNode> Dataset::getVRNode() const & noexcept |
992 | 0 | { |
993 | 0 | return std::dynamic_pointer_cast<const VRNode>(BAG::getLayer(m_layers, VarRes_Node)); |
994 | 0 | } |
995 | | |
996 | | //! Retrieve the optional variable resolution refinements. |
997 | | /*! |
998 | | \return |
999 | | The optional variable resolution refinements. |
1000 | | */ |
1001 | | std::shared_ptr<VRRefinements> Dataset::getVRRefinements() & noexcept |
1002 | 0 | { |
1003 | 0 | return std::dynamic_pointer_cast<VRRefinements>(BAG::getLayer(m_layers, VarRes_Refinement)); |
1004 | 0 | } |
1005 | | |
1006 | | //! Retrieve the optional variable resolution refinements. |
1007 | | /*! |
1008 | | \return |
1009 | | The optional variable resolution refinements. |
1010 | | */ |
1011 | | std::shared_ptr<const VRRefinements> Dataset::getVRRefinements() const & noexcept |
1012 | 0 | { |
1013 | 0 | return std::dynamic_pointer_cast<const VRRefinements>(BAG::getLayer(m_layers, VarRes_Refinement)); |
1014 | 0 | } |
1015 | | |
1016 | | //! Retrieve the optional variable resolution tracking list. |
1017 | | /*! |
1018 | | \return |
1019 | | The optional variable resolution tracking list. |
1020 | | */ |
1021 | | std::shared_ptr<VRTrackingList> Dataset::getVRTrackingList() & noexcept |
1022 | 0 | { |
1023 | 0 | return std::shared_ptr<VRTrackingList>{m_pVRTrackingList}; |
1024 | 0 | } |
1025 | | |
1026 | | //! Retrieve the optional variable resolution tracking list. |
1027 | | /*! |
1028 | | \return |
1029 | | The optional variable resolution tracking list. |
1030 | | */ |
1031 | | std::shared_ptr<const VRTrackingList> Dataset::getVRTrackingList() const & noexcept |
1032 | 0 | { |
1033 | 0 | return std::static_pointer_cast<const VRTrackingList>(m_pVRTrackingList); |
1034 | 0 | } |
1035 | | |
1036 | | //! Convert a grid position to a geographic location. |
1037 | | /*! |
1038 | | \param row |
1039 | | The grid row. |
1040 | | \param column |
1041 | | The grid column. |
1042 | | |
1043 | | \return |
1044 | | The geographic position. |
1045 | | */ |
1046 | | std::tuple<double, double> Dataset::gridToGeo( |
1047 | | uint32_t row, |
1048 | | uint32_t column) const noexcept |
1049 | 48 | { |
1050 | 48 | const auto x = m_pMetadata->llCornerX() + |
1051 | 48 | (row * m_pMetadata->rowResolution()); |
1052 | | |
1053 | 48 | const auto y = m_pMetadata->llCornerY() + |
1054 | 48 | (column * m_pMetadata->columnResolution()); |
1055 | | |
1056 | 48 | return {x, y}; |
1057 | 48 | } |
1058 | | |
1059 | | |
1060 | 2.87k | hid_t DopenProtector2(hid_t loc_id, const char *name, hid_t dapl_id) { |
1061 | 2.87k | hid_t id = -1; |
1062 | 2.87k | try { |
1063 | 2.87k | id = H5Dopen2(loc_id, name, dapl_id); |
1064 | 2.87k | } catch (std::exception& e) { |
1065 | 0 | std::cerr << e.what(); |
1066 | 0 | id = -1; |
1067 | 0 | } |
1068 | 2.87k | return id; |
1069 | 2.87k | } |
1070 | | |
1071 | 119 | hid_t GopenProtector2(hid_t loc_id, const char *name, hid_t dapl_id) { |
1072 | 119 | hid_t id = -1; |
1073 | 119 | try { |
1074 | 119 | id = H5Gopen2(loc_id, name, dapl_id); |
1075 | 119 | } catch (std::exception& e) { |
1076 | 0 | std::cerr << e.what(); |
1077 | 0 | id = -1; |
1078 | 0 | } |
1079 | 119 | return id; |
1080 | 119 | } |
1081 | | |
1082 | 0 | void handleAbrt(int signum) { |
1083 | 0 | std::cerr << "\nUnrecoverable HDF5 Error \n"; |
1084 | 0 | exit(signum); |
1085 | 0 | } |
1086 | | |
1087 | | //! Read an existing BAG. |
1088 | | /*! |
1089 | | \param fileName |
1090 | | The name of the BAG. |
1091 | | \param openMode |
1092 | | The mode to open the BAG with. |
1093 | | */ |
1094 | | void Dataset::readDataset( |
1095 | | const std::string& fileName, |
1096 | | OpenMode openMode) |
1097 | 332 | { |
1098 | 332 | signal(SIGABRT, handleAbrt); |
1099 | 332 | m_pH5file = std::unique_ptr<::H5::H5File, DeleteH5File>(new ::H5::H5File{ |
1100 | 332 | fileName.c_str(), |
1101 | 332 | (openMode == BAG_OPEN_READONLY) ? H5F_ACC_RDONLY : H5F_ACC_RDWR}, |
1102 | 332 | DeleteH5File{}); |
1103 | | |
1104 | 332 | m_pMetadata = std::make_unique<Metadata>(*this); |
1105 | | |
1106 | 332 | m_descriptor = Descriptor{*m_pMetadata}; |
1107 | 332 | m_descriptor.setReadOnly(openMode == BAG_OPEN_READONLY); |
1108 | 332 | m_descriptor.setVersion(readStringAttributeFromGroup(*m_pH5file, |
1109 | 332 | ROOT_PATH, BAG_VERSION_NAME)); |
1110 | | |
1111 | 332 | const auto bagGroup = m_pH5file->openGroup(ROOT_PATH); |
1112 | | |
1113 | | // Look for the simple layers. |
1114 | 332 | for (auto layerType : {Elevation, Uncertainty, Hypothesis_Strength, |
1115 | 332 | Num_Hypotheses, Shoal_Elevation, Std_Dev, Num_Soundings, |
1116 | 332 | Average_Elevation, Nominal_Elevation}) |
1117 | 2.17k | { |
1118 | 2.17k | const std::string internalPath = Layer::getInternalPath(layerType); |
1119 | 2.17k | if (internalPath.empty()) |
1120 | 0 | continue; |
1121 | 2.17k | hid_t id = DopenProtector2(bagGroup.getLocId(), internalPath.c_str(), |
1122 | 2.17k | H5P_DEFAULT); |
1123 | 2.17k | if (id < 0) |
1124 | 1.99k | continue; |
1125 | | |
1126 | 179 | H5Dclose(id); |
1127 | | |
1128 | 179 | auto layerDesc = SimpleLayerDescriptor::open(*this, layerType); |
1129 | 179 | this->addLayer(SimpleLayer::open(*this, *layerDesc)); |
1130 | 179 | } |
1131 | | |
1132 | 332 | const auto bagVersion = getNumericalVersion(m_descriptor.getVersion()); |
1133 | | |
1134 | | // If the BAG is version 1.5+ ... |
1135 | 332 | if (bagVersion >= 1'005'000) |
1136 | 127 | { |
1137 | 127 | hid_t id = DopenProtector2(bagGroup.getLocId(), NODE_GROUP_PATH, H5P_DEFAULT); |
1138 | 127 | if (id >= 0) |
1139 | 0 | { |
1140 | 0 | H5Dclose(id); |
1141 | | |
1142 | | // Hypothesis_Strength |
1143 | 0 | auto layerDesc = InterleavedLegacyLayerDescriptor::open(*this, |
1144 | 0 | Hypothesis_Strength, NODE); |
1145 | 0 | this->addLayer(InterleavedLegacyLayer::open(*this, *layerDesc)); |
1146 | | |
1147 | | // Num_Hypotheses |
1148 | 0 | layerDesc = InterleavedLegacyLayerDescriptor::open(*this, Num_Hypotheses, |
1149 | 0 | NODE); |
1150 | 0 | this->addLayer(InterleavedLegacyLayer::open(*this, *layerDesc)); |
1151 | 0 | } |
1152 | 127 | id = DopenProtector2(bagGroup.getLocId(), ELEVATION_SOLUTION_GROUP_PATH, |
1153 | 127 | H5P_DEFAULT); |
1154 | 127 | if (id >= 0) |
1155 | 0 | { |
1156 | 0 | H5Dclose(id); |
1157 | | |
1158 | | // Shoal_Elevation |
1159 | 0 | auto layerDesc = InterleavedLegacyLayerDescriptor::open(*this, |
1160 | 0 | Shoal_Elevation, ELEVATION); |
1161 | |
|
1162 | 0 | this->addLayer(InterleavedLegacyLayer::open(*this, *layerDesc)); |
1163 | | |
1164 | | // Std_Dev |
1165 | 0 | layerDesc = InterleavedLegacyLayerDescriptor::open(*this, Std_Dev, |
1166 | 0 | ELEVATION); |
1167 | 0 | this->addLayer(InterleavedLegacyLayer::open(*this, *layerDesc)); |
1168 | | |
1169 | | // Num_Soundings |
1170 | 0 | layerDesc = InterleavedLegacyLayerDescriptor::open(*this, Num_Soundings, |
1171 | 0 | ELEVATION); |
1172 | 0 | this->addLayer(InterleavedLegacyLayer::open(*this, *layerDesc)); |
1173 | 0 | } |
1174 | 127 | } |
1175 | | |
1176 | | // Read optional VR |
1177 | 332 | hid_t id = DopenProtector2(bagGroup.getLocId(), VR_TRACKING_LIST_PATH, H5P_DEFAULT); |
1178 | 332 | if (id >= 0) |
1179 | 0 | { |
1180 | 0 | H5Dclose(id); |
1181 | |
|
1182 | 0 | m_pVRTrackingList = std::make_shared<VRTrackingList>(*this); |
1183 | |
|
1184 | 0 | { |
1185 | 0 | auto descriptor = VRMetadataDescriptor::open(*this); |
1186 | 0 | this->addLayer(VRMetadata::open(*this, *descriptor)); |
1187 | 0 | } |
1188 | |
|
1189 | 0 | { |
1190 | 0 | auto descriptor = VRRefinementsDescriptor::open(*this); |
1191 | 0 | this->addLayer(VRRefinements::open(*this, *descriptor)); |
1192 | 0 | } |
1193 | | |
1194 | | // optional VRNodeLayer |
1195 | 0 | id = DopenProtector2(bagGroup.getLocId(), VR_NODE_PATH, H5P_DEFAULT); |
1196 | 0 | if (id >= 0) |
1197 | 0 | { |
1198 | 0 | H5Dclose(id); |
1199 | |
|
1200 | 0 | auto descriptor = VRNodeDescriptor::open(*this); |
1201 | 0 | this->addLayer(VRNode::open(*this, *descriptor)); |
1202 | 0 | } |
1203 | 0 | } |
1204 | | |
1205 | 332 | m_pTrackingList = std::unique_ptr<TrackingList>(new TrackingList{*this}); |
1206 | | |
1207 | | // Read optional Surface Corrections |
1208 | 332 | id = DopenProtector2(bagGroup.getLocId(), VERT_DATUM_CORR_PATH, H5P_DEFAULT); |
1209 | 332 | if (id >= 0) |
1210 | 26 | { |
1211 | 26 | H5Dclose(id); |
1212 | | |
1213 | 26 | auto descriptor = SurfaceCorrectionsDescriptor::open(*this); |
1214 | 26 | this->addLayer(SurfaceCorrections::open(*this, *descriptor)); |
1215 | 26 | } |
1216 | | |
1217 | | // If the BAG is version 2.0+ ... |
1218 | 332 | if (bagVersion >= 2'000'000) |
1219 | 119 | { |
1220 | | // Add all existing GeorefMetadataLayers |
1221 | 119 | id = GopenProtector2(bagGroup.getLocId(), GEOREF_METADATA_PATH, H5P_DEFAULT); |
1222 | 119 | if (id >= 0) |
1223 | 86 | { |
1224 | 86 | H5Gclose(id); |
1225 | | |
1226 | | // Look for any subgroups of the GEOREF_METADATA_PATH group. |
1227 | 86 | const auto group = m_pH5file->openGroup(GEOREF_METADATA_PATH); |
1228 | 86 | const hsize_t numObjects = group.getNumObjs(); |
1229 | | |
1230 | 171 | for (auto i=0; i<numObjects; ++i) |
1231 | 85 | { |
1232 | 85 | try |
1233 | 85 | { |
1234 | 85 | const auto name = group.getObjnameByIdx(i); |
1235 | | |
1236 | 85 | auto descriptor = GeorefMetadataLayerDescriptor::open(*this, name); |
1237 | 85 | this->addLayer(GeorefMetadataLayer::open(*this, *descriptor)); |
1238 | 85 | } |
1239 | 85 | catch(...) |
1240 | 85 | {} |
1241 | 85 | } |
1242 | 86 | } |
1243 | 119 | } |
1244 | 332 | } |
1245 | | |
1246 | | //! Custom deleter to not expose the HDF5 dependency to the user. |
1247 | | /*! |
1248 | | \param ptr |
1249 | | The H5File to be deleted. |
1250 | | */ |
1251 | | void Dataset::DeleteH5File::operator()(::H5::H5File* ptr) noexcept |
1252 | 242 | { |
1253 | 242 | delete ptr; |
1254 | 242 | } |
1255 | | |
1256 | | } //namespace BAG |
1257 | | |