/src/bag/api/bag_surfacecorrections.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | #include "bag_dataset.h" |
3 | | #include "bag_private.h" |
4 | | #include "bag_simplelayer.h" |
5 | | #include "bag_surfacecorrections.h" |
6 | | #include "bag_surfacecorrectionsdescriptor.h" |
7 | | |
8 | | #include <array> |
9 | | #include <cmath> |
10 | | #include <cstring> // memset |
11 | | #include <memory> |
12 | | #include <H5Cpp.h> |
13 | | |
14 | | |
15 | | namespace BAG { |
16 | | |
17 | | //! The maximum length of the list of datums. |
18 | | constexpr uint16_t kMaxDatumsLength = 256; |
19 | | //! The radius to use while searching for nearest neighbours. |
20 | | constexpr int32_t kSearchRadius = 3; |
21 | | |
22 | | namespace { |
23 | | |
24 | | //! Get the HDF5 CompType specified by the surface corrections descriptor. |
25 | | /*! |
26 | | \param descriptor |
27 | | The surface corrections descriptor. |
28 | | |
29 | | \return |
30 | | The HDF5 CompType as specified by the descriptor. |
31 | | */ |
32 | | ::H5::CompType getCompoundType( |
33 | | const SurfaceCorrectionsDescriptor& descriptor) |
34 | 0 | { |
35 | 0 | const ::H5::CompType h5memDataType{ |
36 | 0 | static_cast<size_t>(descriptor.getElementSize())}; |
37 | |
|
38 | 0 | size_t offset = 0; |
39 | |
|
40 | 0 | if (descriptor.getSurfaceType() == BAG_SURFACE_IRREGULARLY_SPACED) |
41 | 0 | { |
42 | 0 | h5memDataType.insertMember("x", offset, ::H5::PredType::NATIVE_DOUBLE); |
43 | 0 | offset += sizeof(double); |
44 | |
|
45 | 0 | h5memDataType.insertMember("y", offset, ::H5::PredType::NATIVE_DOUBLE); |
46 | 0 | offset += sizeof(double); |
47 | 0 | } |
48 | |
|
49 | 0 | const std::array<hsize_t, kRank> zDims{1, descriptor.getNumCorrectors()}; |
50 | 0 | ::H5::ArrayType h5zDataType{::H5::PredType::NATIVE_FLOAT, kRank, zDims.data()}; |
51 | |
|
52 | 0 | h5memDataType.insertMember("z", offset, h5zDataType); |
53 | |
|
54 | 0 | return h5memDataType; |
55 | 0 | } |
56 | | |
57 | | } // namespace |
58 | | |
59 | | //! Constructor. |
60 | | /*! |
61 | | \param dataset |
62 | | The BAG Dataset this layer belongs to. |
63 | | \param descriptor |
64 | | The descriptor of this layer. |
65 | | \param pH5dataSet |
66 | | The HDF5 DataSet that stores this interleaved layer. |
67 | | */ |
68 | | SurfaceCorrections::SurfaceCorrections( |
69 | | Dataset& dataset, |
70 | | SurfaceCorrectionsDescriptor& descriptor, |
71 | | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> pH5dataSet) |
72 | 26 | : Layer(dataset, descriptor) |
73 | 26 | , m_pH5dataSet(std::move(pH5dataSet)) |
74 | 26 | { |
75 | 26 | } |
76 | | |
77 | | //! Create a surface corrections layer. |
78 | | /*! |
79 | | \param dataset |
80 | | The BAG Dataset this layer belongs to. |
81 | | \param type |
82 | | The type of surface correction topography. |
83 | | \param numCorrectors |
84 | | The number of correctors provided. |
85 | | Valid range is 1-10. |
86 | | \param chunkSize |
87 | | The chunk size the HDF5 DataSet will use. |
88 | | \param compressionLevel |
89 | | The compression level the HDF5 DataSet will use. |
90 | | |
91 | | \return |
92 | | The new surface corrections layer. |
93 | | */ |
94 | | std::shared_ptr<SurfaceCorrections> SurfaceCorrections::create( |
95 | | Dataset& dataset, |
96 | | BAG_SURFACE_CORRECTION_TOPOGRAPHY type, |
97 | | uint8_t numCorrectors, |
98 | | uint64_t chunkSize, |
99 | | int compressionLevel) |
100 | 0 | { |
101 | 0 | auto descriptor = SurfaceCorrectionsDescriptor::create(dataset, type, |
102 | 0 | numCorrectors, chunkSize, compressionLevel); |
103 | |
|
104 | 0 | auto h5dataSet = SurfaceCorrections::createH5dataSet(dataset, *descriptor); |
105 | |
|
106 | 0 | return std::make_shared<SurfaceCorrections>(dataset, |
107 | 0 | *descriptor, std::move(h5dataSet)); |
108 | 0 | } |
109 | | |
110 | | //! Open an existing surface corrections layer. |
111 | | /*! |
112 | | \param dataset |
113 | | The BAG Dataset this layer belongs to. |
114 | | \param descriptor |
115 | | The descriptor of this layer. |
116 | | |
117 | | \return |
118 | | The new surface corrections layer. |
119 | | */ |
120 | | std::shared_ptr<SurfaceCorrections> SurfaceCorrections::open( |
121 | | Dataset& dataset, |
122 | | SurfaceCorrectionsDescriptor& descriptor) |
123 | 26 | { |
124 | 26 | const auto& h5file = dataset.getH5file(); |
125 | 26 | auto h5dataSet = std::unique_ptr<::H5::DataSet, DeleteH5dataSet>( |
126 | 26 | new ::H5::DataSet{h5file.openDataSet(descriptor.getInternalPath())}, |
127 | 26 | DeleteH5dataSet{}); |
128 | | |
129 | 26 | return std::make_shared<SurfaceCorrections>(dataset, |
130 | 26 | descriptor, std::move(h5dataSet)); |
131 | 26 | } |
132 | | |
133 | | |
134 | | //! Create the HDF5 DataSet. |
135 | | /*! |
136 | | \param dataset |
137 | | The BAG Dataset this layer belongs to. |
138 | | \param descriptor |
139 | | The descriptor of this layer. |
140 | | |
141 | | \return |
142 | | The new HDF5 DataSet. |
143 | | */ |
144 | | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> |
145 | | SurfaceCorrections::createH5dataSet( |
146 | | const Dataset& dataset, |
147 | | const SurfaceCorrectionsDescriptor& descriptor) |
148 | 0 | { |
149 | 0 | std::array<hsize_t, kRank> fileDims{0, 0}; |
150 | 0 | const std::array<hsize_t, kRank> kMaxFileDims{H5S_UNLIMITED, H5S_UNLIMITED}; |
151 | 0 | const ::H5::DataSpace h5fileDataSpace{kRank, fileDims.data(), kMaxFileDims.data()}; |
152 | | |
153 | | // Use chunk size and compression level from the descriptor. |
154 | 0 | const auto compressionLevel = descriptor.getCompressionLevel(); |
155 | | |
156 | | // Create the creation property list. |
157 | 0 | const ::H5::DSetCreatPropList h5createPropList{}; |
158 | |
|
159 | 0 | const auto chunkSize = descriptor.getChunkSize(); |
160 | 0 | if (chunkSize > 0) |
161 | 0 | { |
162 | 0 | const std::array<hsize_t, kRank> chunkDims{chunkSize, chunkSize}; |
163 | 0 | h5createPropList.setChunk(kRank, chunkDims.data()); |
164 | |
|
165 | 0 | if (compressionLevel > 0 && compressionLevel <= kMaxCompressionLevel) |
166 | 0 | h5createPropList.setDeflate(compressionLevel); |
167 | 0 | } |
168 | 0 | else if (compressionLevel > 0) |
169 | 0 | throw CompressionNeedsChunkingSet{}; |
170 | 0 | else |
171 | 0 | throw LayerRequiresChunkingSet{}; |
172 | | |
173 | 0 | h5createPropList.setFillTime(H5D_FILL_TIME_ALLOC); |
174 | |
|
175 | 0 | const auto h5memDataType = getCompoundType(descriptor); |
176 | | |
177 | | // Create the DataSet using the above. |
178 | 0 | const auto& h5file = dataset.getH5file(); |
179 | |
|
180 | 0 | const auto h5dataSet = h5file.createDataSet(VERT_DATUM_CORR_PATH, |
181 | 0 | h5memDataType, h5fileDataSpace, h5createPropList); |
182 | | |
183 | | // Create any attributes. |
184 | 0 | const ::H5::DataSpace kScalarDataSpace{}; |
185 | 0 | auto att = h5dataSet.createAttribute(VERT_DATUM_CORR_SURFACE_TYPE, |
186 | 0 | ::H5::PredType::NATIVE_UINT8, kScalarDataSpace); |
187 | |
|
188 | 0 | const auto surfaceType = descriptor.getSurfaceType(); |
189 | 0 | const auto tmpSurfaceType = static_cast<uint8_t>(surfaceType); |
190 | 0 | att.write(::H5::PredType::NATIVE_UINT8, &tmpSurfaceType); |
191 | |
|
192 | 0 | constexpr hsize_t xmlLength = 0; |
193 | 0 | constexpr hsize_t kMaxSize = kMaxDatumsLength; |
194 | 0 | const ::H5::DataSpace kVerticalDatumDataSpace{1, &xmlLength, &kMaxSize}; |
195 | |
|
196 | 0 | att = h5dataSet.createAttribute(VERT_DATUM_CORR_VERTICAL_DATUM, |
197 | 0 | ::H5::PredType::C_S1, kVerticalDatumDataSpace); |
198 | | |
199 | | // Create any optional attributes. |
200 | 0 | if (surfaceType == BAG_SURFACE_GRID_EXTENTS) |
201 | 0 | { |
202 | 0 | constexpr double junk = 0.; |
203 | |
|
204 | 0 | att = h5dataSet.createAttribute(VERT_DATUM_CORR_SWX, |
205 | 0 | ::H5::PredType::NATIVE_DOUBLE, kScalarDataSpace); |
206 | 0 | att.write(::H5::PredType::NATIVE_DOUBLE, &junk); |
207 | |
|
208 | 0 | att = h5dataSet.createAttribute(VERT_DATUM_CORR_SWY, |
209 | 0 | ::H5::PredType::NATIVE_DOUBLE, kScalarDataSpace); |
210 | 0 | att.write(::H5::PredType::NATIVE_DOUBLE, &junk); |
211 | |
|
212 | 0 | att = h5dataSet.createAttribute(VERT_DATUM_CORR_NSX, |
213 | 0 | ::H5::PredType::NATIVE_DOUBLE, kScalarDataSpace); |
214 | 0 | att.write(::H5::PredType::NATIVE_DOUBLE, &junk); |
215 | |
|
216 | 0 | att = h5dataSet.createAttribute(VERT_DATUM_CORR_NSY, |
217 | 0 | ::H5::PredType::NATIVE_DOUBLE, kScalarDataSpace); |
218 | 0 | att.write(::H5::PredType::NATIVE_DOUBLE, &junk); |
219 | 0 | } |
220 | |
|
221 | 0 | return std::unique_ptr<::H5::DataSet, DeleteH5dataSet>( |
222 | 0 | new ::H5::DataSet{h5dataSet}, DeleteH5dataSet{}); |
223 | 0 | } |
224 | | |
225 | | //! Retrieve the HDF5 DataSet. |
226 | | const ::H5::DataSet& SurfaceCorrections::getH5dataSet() const & noexcept |
227 | 0 | { |
228 | 0 | return *m_pH5dataSet; |
229 | 0 | } |
230 | | |
231 | | //! Retrieve the layer's descriptor. Note: this shadows BAG::Layer.getDescriptor() |
232 | | /*! |
233 | | \return |
234 | | The layer's descriptor. |
235 | | Will never be nullptr. |
236 | | */ |
237 | | std::shared_ptr<SurfaceCorrectionsDescriptor> SurfaceCorrections::getDescriptor() & noexcept |
238 | 0 | { |
239 | 0 | return std::dynamic_pointer_cast<SurfaceCorrectionsDescriptor>(Layer::getDescriptor()); |
240 | 0 | } |
241 | | |
242 | | //! Retrieve the layer's descriptor. Note: this shadows BAG::Layer.getDescriptor() |
243 | | /*! |
244 | | \return |
245 | | The layer's descriptor. |
246 | | Will never be nullptr. |
247 | | */ |
248 | 0 | std::shared_ptr<const SurfaceCorrectionsDescriptor> SurfaceCorrections::getDescriptor() const & noexcept { |
249 | 0 | return std::dynamic_pointer_cast<const SurfaceCorrectionsDescriptor>(Layer::getDescriptor()); |
250 | 0 | } |
251 | | |
252 | | //! Read a corrected region from a simple layer using the specified corrector. |
253 | | /*! |
254 | | \param rowStart |
255 | | The starting row. |
256 | | \param columnStart |
257 | | The starting column. |
258 | | \param rowEnd |
259 | | The ending row (inclusive). |
260 | | \param columnEnd |
261 | | The ending column (inclusive). |
262 | | \param corrector |
263 | | The corrector to use when applying a correction. |
264 | | Valid values are 1-10. |
265 | | \param layer |
266 | | The simple layer to correct. |
267 | | |
268 | | \return |
269 | | The corrected date from the simple layer using the specified corrector. |
270 | | */ |
271 | | UInt8Array SurfaceCorrections::readCorrected( |
272 | | uint32_t rowStart, |
273 | | uint32_t columnStart, |
274 | | uint32_t rowEnd, |
275 | | uint32_t columnEnd, |
276 | | uint8_t corrector, |
277 | | const SimpleLayer& layer) const |
278 | 0 | { |
279 | 0 | auto pDescriptor = |
280 | 0 | std::dynamic_pointer_cast<const SurfaceCorrectionsDescriptor>( |
281 | 0 | this->getDescriptor()); |
282 | 0 | if (!pDescriptor) |
283 | 0 | throw InvalidDescriptor{}; |
284 | | |
285 | 0 | auto weakDataset = this->getDataset(); |
286 | 0 | if (weakDataset.expired()) |
287 | 0 | throw DatasetNotFound{}; |
288 | | |
289 | 0 | auto dataset = weakDataset.lock(); |
290 | |
|
291 | 0 | uint32_t ncols = 0, nrows = 0; |
292 | 0 | std::tie(ncols, nrows) = dataset->getDescriptor().getDims(); |
293 | |
|
294 | 0 | if (columnEnd >= ncols || rowEnd >= nrows || rowStart > rowEnd |
295 | 0 | || columnStart > columnEnd) |
296 | 0 | throw InvalidReadSize{}; |
297 | | |
298 | 0 | UInt8Array data{(columnEnd - columnStart + 1) * (rowEnd - rowStart + 1) |
299 | 0 | * sizeof(float)}; |
300 | |
|
301 | 0 | for (uint32_t f=0, i=0; i<nrows; ++i) |
302 | 0 | { |
303 | 0 | if (i >= rowStart && i <= rowEnd) |
304 | 0 | { |
305 | | //! By row at a time, fill the whole buffer |
306 | 0 | auto sepData = this->readCorrectedRow(i, columnStart, columnEnd, |
307 | 0 | corrector, layer); |
308 | | |
309 | | //! For each column in the transfer set |
310 | 0 | for (uint32_t j=0; j<columnEnd-columnStart + 1; ++j) |
311 | 0 | data[(columnEnd - columnStart + 1) * f + j] = sepData[j]; |
312 | |
|
313 | 0 | f++; |
314 | 0 | } |
315 | 0 | } |
316 | |
|
317 | 0 | return data; |
318 | 0 | } |
319 | | |
320 | | //! Read a corrected row from a simple layer using the specified corrector. |
321 | | /*! |
322 | | \param row |
323 | | The row. |
324 | | \param columnStart |
325 | | The starting column. |
326 | | \param columnEnd |
327 | | The ending column (inclusive). |
328 | | \param corrector |
329 | | The corrector to use when applying a correction. |
330 | | Valid values are 1-10. |
331 | | \param layer |
332 | | The simple layer to correct. |
333 | | |
334 | | \return |
335 | | The corrected date from the simple layer using the specified corrector. |
336 | | */ |
337 | | UInt8Array SurfaceCorrections::readCorrectedRow( |
338 | | uint32_t row, |
339 | | uint32_t columnStart, |
340 | | uint32_t columnEnd, |
341 | | uint8_t corrector, |
342 | | const SimpleLayer& layer) const |
343 | 0 | { |
344 | 0 | auto pDescriptor = |
345 | 0 | std::dynamic_pointer_cast<const SurfaceCorrectionsDescriptor>( |
346 | 0 | this->getDescriptor()); |
347 | 0 | if (!pDescriptor) |
348 | 0 | throw InvalidDescriptor{}; |
349 | | |
350 | 0 | const auto surfaceType = pDescriptor->getSurfaceType(); // aka topography |
351 | |
|
352 | 0 | if (surfaceType != BAG_SURFACE_GRID_EXTENTS) |
353 | 0 | throw UnsupportedSurfaceType{}; |
354 | | |
355 | 0 | if (corrector < 1 || corrector > pDescriptor->getNumCorrectors()) |
356 | 0 | throw InvalidCorrector{}; |
357 | | |
358 | 0 | --corrector; // This is 0 based when used. |
359 | |
|
360 | 0 | auto originalRow = layer.read(row, row, columnStart, columnEnd); |
361 | 0 | auto* data = reinterpret_cast<float*>(originalRow.data()); |
362 | | |
363 | | // Obtain cell resolution and SW origin (0,1,1,0). |
364 | 0 | double swCornerX = 0., swCornerY = 0.; |
365 | 0 | std::tie(swCornerX, swCornerY) = pDescriptor->getOrigin(); |
366 | |
|
367 | 0 | double nodeSpacingX = 0., nodeSpacingY = 0.; |
368 | 0 | std::tie(nodeSpacingX, nodeSpacingY) = pDescriptor->getSpacing(); |
369 | |
|
370 | 0 | const auto resratio = nodeSpacingX / nodeSpacingY; |
371 | |
|
372 | 0 | uint32_t ncols = 0, nrows = 0; |
373 | 0 | std::tie(nrows, ncols) = pDescriptor->getDims(); |
374 | |
|
375 | 0 | std::array<int32_t, 2> lastP{-1, -1}; |
376 | |
|
377 | 0 | auto weakDataset = this->getDataset(); |
378 | 0 | if (weakDataset.expired()) |
379 | 0 | throw DatasetNotFound{}; |
380 | | |
381 | 0 | auto dataset = weakDataset.lock(); |
382 | |
|
383 | 0 | double swCornerXsimple = 0., swCornerYsimple = 0.; |
384 | 0 | std::tie(swCornerXsimple, swCornerYsimple) = |
385 | 0 | dataset->getDescriptor().getOrigin(); |
386 | |
|
387 | 0 | double nodeSpacingXsimple = 0., nodeSpacingYsimple = 0.; |
388 | 0 | std::tie(nodeSpacingXsimple, nodeSpacingYsimple) = |
389 | 0 | dataset->getDescriptor().getGridSpacing(); |
390 | |
|
391 | 0 | using std::floor; using std::fabs; using std::ceil; |
392 | | |
393 | | // Compute an SEP for each cell in the row. |
394 | 0 | for (auto j=columnStart; j<=columnEnd; ++j) |
395 | 0 | { |
396 | 0 | const uint32_t rowIndex = j - columnStart; |
397 | |
|
398 | 0 | if (data[rowIndex] == BAG_NULL_GENERIC || |
399 | 0 | data[rowIndex] == BAG_NULL_ELEVATION || |
400 | 0 | data[rowIndex] == BAG_NULL_UNCERTAINTY) |
401 | 0 | continue; |
402 | | |
403 | 0 | std::array<uint32_t, 2> rowRange{0, 0}; |
404 | 0 | std::array<uint32_t, 2> colRange{0, 0}; |
405 | | |
406 | | //! Determine the X and Y values of given cell. |
407 | 0 | const double nodeX = swCornerXsimple + j * nodeSpacingXsimple; |
408 | 0 | const double nodeY = swCornerYsimple + row * nodeSpacingYsimple; |
409 | |
|
410 | | #if 0 // Dead code (see logic above); saved from C code for now. |
411 | | if (surfaceType == BAG_SURFACE_IRREGULARLY_SPACED) |
412 | | { |
413 | | if (lastP[0] == -1 || lastP[1] == -1) |
414 | | { |
415 | | colRange[0] = 0; |
416 | | colRange[1] = ncols -1; |
417 | | rowRange[0] = 0; |
418 | | rowRange[1] = nrows -1; |
419 | | } |
420 | | else |
421 | | { |
422 | | colRange[0] = lastP[0] - kSearchRadius; |
423 | | colRange[1] = lastP[0] + kSearchRadius; |
424 | | rowRange[0] = lastP[1] - kSearchRadius; |
425 | | rowRange[1] = lastP[1] + kSearchRadius; |
426 | | } |
427 | | } |
428 | | else |
429 | | #endif |
430 | 0 | if (surfaceType == BAG_SURFACE_GRID_EXTENTS) |
431 | 0 | { |
432 | | //! A simple calculation for 4 nearest corrector nodes. |
433 | 0 | colRange[0] = static_cast<uint32_t>(fabs(floor((swCornerX - nodeX) / nodeSpacingX))); |
434 | 0 | colRange[1] = static_cast<uint32_t>(fabs(ceil((swCornerX - nodeX) / nodeSpacingX))); |
435 | 0 | rowRange[0] = static_cast<uint32_t>(fabs(floor((swCornerY - nodeY) / nodeSpacingY))); |
436 | 0 | rowRange[1] = static_cast<uint32_t>(fabs(ceil((swCornerY - nodeY) / nodeSpacingY))); |
437 | 0 | } |
438 | | |
439 | | //! Enforce dataset limits. |
440 | 0 | if (colRange[0] > colRange[1]) |
441 | 0 | std::swap(colRange[0], colRange[1]); |
442 | |
|
443 | 0 | if (colRange[0] >= ncols) |
444 | 0 | colRange[0] = ncols -1; |
445 | |
|
446 | 0 | if (colRange[1] >= ncols) |
447 | 0 | colRange[1] = ncols -1; |
448 | |
|
449 | 0 | if (rowRange[0] > rowRange[1]) |
450 | 0 | std::swap(rowRange[0], rowRange[1]); |
451 | |
|
452 | 0 | if (rowRange[0] >= nrows) |
453 | 0 | rowRange[0] = nrows -1; |
454 | |
|
455 | 0 | if (rowRange[1] >= nrows) |
456 | 0 | rowRange[1] = nrows -1; |
457 | |
|
458 | 0 | if (colRange[1] == colRange[0]) |
459 | 0 | { |
460 | 0 | if (colRange[0] > 0) |
461 | 0 | --colRange[0]; |
462 | |
|
463 | 0 | if ((colRange[1] + 1) < ncols) |
464 | 0 | ++colRange[1]; |
465 | 0 | } |
466 | 0 | if (rowRange[1] == rowRange[0]) |
467 | 0 | { |
468 | |
|
469 | 0 | if (rowRange[0] > 0) |
470 | 0 | --rowRange[0]; |
471 | |
|
472 | 0 | if ((rowRange[1] + 1) < nrows) |
473 | 0 | ++rowRange[1]; |
474 | 0 | } |
475 | | |
476 | | //std::cerr << "INDX: " << rowIndex << " Row: " << row << " RC: " << rowRange[0] << " / "<< rowRange[1] << '\n'; |
477 | |
|
478 | 0 | bool isZeroDistance = false; |
479 | 0 | double sum_sep = 0.0; |
480 | 0 | double sum = 0.0; |
481 | 0 | double leastDistSq = std::numeric_limits<double>::max(); |
482 | | |
483 | | // Look through the SEPs and calculate the weighted average between them and this position. |
484 | 0 | for (auto q=rowRange[0]; !isZeroDistance && q <= rowRange[1]; ++q) |
485 | 0 | { |
486 | | // The SEP should be accessed, up to entire row of all columns of Surface_Correction. |
487 | 0 | const auto buffer = this->read(q, q, colRange[0], colRange[1]); |
488 | 0 | const auto* readbuf = reinterpret_cast<const BagVerticalDatumCorrectionsGridded*>(buffer.data()); |
489 | 0 | const auto y1 = swCornerY + q * nodeSpacingY; |
490 | |
|
491 | 0 | for (auto u=colRange[0]; u<=colRange[1]; ++u) |
492 | 0 | { |
493 | 0 | const auto* vertCorr = readbuf + (u - colRange[0]); |
494 | |
|
495 | 0 | const auto z1 = vertCorr->z[corrector]; |
496 | 0 | const auto x1 = swCornerX + u * nodeSpacingX; |
497 | |
|
498 | 0 | double distSq = 0.; |
499 | |
|
500 | 0 | if (nodeX == x1 && nodeY == y1) |
501 | 0 | { |
502 | 0 | isZeroDistance = true; |
503 | 0 | distSq = 1.0; |
504 | 0 | data[rowIndex] += z1; |
505 | |
|
506 | 0 | break; |
507 | 0 | } |
508 | | |
509 | | // Calculate distance weight between nodeX/nodeY and y1/x1 |
510 | 0 | distSq = std::pow(fabs(static_cast<double>(nodeX - x1)), 2.0) + |
511 | 0 | std::pow(resratio * fabs(static_cast<double>(nodeY - y1)), 2.0); |
512 | | |
513 | |
|
514 | 0 | if (leastDistSq > distSq) |
515 | 0 | { |
516 | 0 | leastDistSq = distSq; |
517 | 0 | lastP[0] = u; |
518 | 0 | lastP[1] = q; |
519 | 0 | } |
520 | | |
521 | | // Inverse distance calculation |
522 | 0 | sum_sep += z1 / distSq; |
523 | 0 | sum += 1.0 / distSq; |
524 | 0 | } |
525 | 0 | } |
526 | | |
527 | | //std::cerr << "sum sum " << sum_sep << " / " << sum << " = " << sum_sep / sum << " : " << data[rowIndex] << '\n'; |
528 | |
|
529 | 0 | if (!isZeroDistance) |
530 | 0 | { |
531 | | // is not a constant SEP with one point? |
532 | 0 | if (sum_sep != 0.0 && sum != 0.0) |
533 | 0 | data[rowIndex] += static_cast<float>(sum_sep / sum); |
534 | 0 | else |
535 | 0 | data[rowIndex] = BAG_NULL_GENERIC; |
536 | 0 | } |
537 | |
|
538 | 0 | } |
539 | |
|
540 | 0 | return originalRow; |
541 | 0 | } |
542 | | |
543 | | //! \copydoc Layer::read |
544 | | UInt8Array SurfaceCorrections::readProxy( |
545 | | uint32_t rowStart, |
546 | | uint32_t columnStart, |
547 | | uint32_t rowEnd, |
548 | | uint32_t columnEnd) const |
549 | 0 | { |
550 | | // Query the file for the specified rows and columns. |
551 | 0 | const auto h5fileDataSpace = m_pH5dataSet->getSpace(); |
552 | |
|
553 | 0 | const auto rows = (rowEnd - rowStart) + 1; |
554 | 0 | const auto columns = (columnEnd - columnStart) + 1; |
555 | 0 | const std::array<hsize_t, kRank> count{rows, columns}; |
556 | 0 | const std::array<hsize_t, kRank> offset{rowStart, columnStart}; |
557 | |
|
558 | 0 | h5fileDataSpace.selectHyperslab(H5S_SELECT_SET, count.data(), offset.data()); |
559 | |
|
560 | 0 | auto pDescriptor = |
561 | 0 | std::dynamic_pointer_cast<const SurfaceCorrectionsDescriptor>( |
562 | 0 | this->getDescriptor()); |
563 | 0 | if (!pDescriptor) |
564 | 0 | throw InvalidLayerDescriptor{}; |
565 | | |
566 | 0 | const auto bufferSize = pDescriptor->getReadBufferSize(rows, columns); |
567 | 0 | UInt8Array buffer{bufferSize}; |
568 | |
|
569 | 0 | const ::H5::DataSpace h5memSpace{kRank, count.data(), count.data()}; |
570 | |
|
571 | 0 | const auto h5memDataType = getCompoundType(*pDescriptor); |
572 | |
|
573 | 0 | m_pH5dataSet->read(buffer.data(), h5memDataType, h5memSpace, h5fileDataSpace); |
574 | |
|
575 | 0 | return buffer; |
576 | 0 | } |
577 | | |
578 | | //! \copydoc Layer::writeAttributes |
579 | | void SurfaceCorrections::writeAttributesProxy() const |
580 | 0 | { |
581 | 0 | auto pDescriptor = |
582 | 0 | std::dynamic_pointer_cast<const SurfaceCorrectionsDescriptor>( |
583 | 0 | this->getDescriptor()); |
584 | 0 | if (!pDescriptor) |
585 | 0 | throw InvalidDescriptor{}; |
586 | | |
587 | | // Write any attributes, from the layer descriptor. |
588 | | // surface type |
589 | 0 | auto att = m_pH5dataSet->openAttribute(VERT_DATUM_CORR_SURFACE_TYPE); |
590 | 0 | const auto surfaceType = pDescriptor->getSurfaceType(); |
591 | 0 | const auto tmpSurfaceType = static_cast<uint8_t>(surfaceType); |
592 | 0 | att.write(::H5::PredType::NATIVE_UINT8, &tmpSurfaceType); |
593 | | |
594 | | // vertical datums |
595 | 0 | auto tmpDatums = pDescriptor->getVerticalDatums(); |
596 | 0 | if (tmpDatums.size() > kMaxDatumsLength) |
597 | 0 | tmpDatums.resize(kMaxDatumsLength); |
598 | |
|
599 | 0 | att = m_pH5dataSet->openAttribute(VERT_DATUM_CORR_VERTICAL_DATUM); |
600 | 0 | att.write(::H5::PredType::C_S1, tmpDatums); |
601 | | |
602 | | // Write any optional attributes. |
603 | 0 | if (surfaceType == BAG_SURFACE_GRID_EXTENTS) |
604 | 0 | { |
605 | | // sw corner x |
606 | 0 | att = m_pH5dataSet->openAttribute(VERT_DATUM_CORR_SWX); |
607 | 0 | const auto origin = pDescriptor->getOrigin(); |
608 | 0 | att.write(::H5::PredType::NATIVE_DOUBLE, &std::get<0>(origin)); |
609 | | |
610 | | // sw corner y |
611 | 0 | att = m_pH5dataSet->openAttribute(VERT_DATUM_CORR_SWY); |
612 | 0 | att.write(::H5::PredType::NATIVE_DOUBLE, &std::get<1>(origin)); |
613 | | |
614 | | // node spacing x |
615 | 0 | const auto spacing = pDescriptor->getSpacing(); |
616 | 0 | att = m_pH5dataSet->openAttribute(VERT_DATUM_CORR_NSX); |
617 | 0 | att.write(::H5::PredType::NATIVE_DOUBLE, &std::get<0>(spacing)); |
618 | | |
619 | | // node spacing y |
620 | 0 | att = m_pH5dataSet->openAttribute(VERT_DATUM_CORR_NSY); |
621 | 0 | att.write(::H5::PredType::NATIVE_DOUBLE, &std::get<1>(spacing)); |
622 | 0 | } |
623 | 0 | } |
624 | | |
625 | | //! \copydoc Layer::write |
626 | | void SurfaceCorrections::writeProxy( |
627 | | uint32_t rowStart, |
628 | | uint32_t columnStart, |
629 | | uint32_t rowEnd, |
630 | | uint32_t columnEnd, |
631 | | const uint8_t* buffer) |
632 | 0 | { |
633 | 0 | auto pDescriptor = std::dynamic_pointer_cast<SurfaceCorrectionsDescriptor>( |
634 | 0 | this->getDescriptor()); |
635 | 0 | if (!pDescriptor) |
636 | 0 | throw InvalidDescriptor{}; |
637 | | |
638 | 0 | const auto rows = (rowEnd - rowStart) + 1; |
639 | 0 | const auto columns = (columnEnd - columnStart) + 1; |
640 | 0 | const std::array<hsize_t, kRank> count{rows, columns}; |
641 | 0 | const std::array<hsize_t, kRank> offset{rowStart, columnStart}; |
642 | 0 | const ::H5::DataSpace h5memDataSpace{kRank, count.data(), count.data()}; |
643 | |
|
644 | 0 | ::H5::DataSpace h5fileDataSpace = m_pH5dataSet->getSpace(); |
645 | | |
646 | | // Expand the file data space if needed. |
647 | 0 | std::array<hsize_t, kRank> fileDims{}; |
648 | 0 | std::array<hsize_t, kRank> maxFileDims{}; |
649 | 0 | h5fileDataSpace.getSimpleExtentDims(fileDims.data(), maxFileDims.data()); |
650 | |
|
651 | 0 | if ((fileDims[0] < (rowEnd + 1)) || |
652 | 0 | (fileDims[1] < (columnEnd + 1))) |
653 | 0 | { |
654 | 0 | const std::array<hsize_t, kRank> newDims{ |
655 | 0 | std::max<hsize_t>(fileDims[0], rowEnd + 1), |
656 | 0 | std::max<hsize_t>(fileDims[1], columnEnd + 1)}; |
657 | |
|
658 | 0 | m_pH5dataSet->extend(newDims.data()); |
659 | |
|
660 | 0 | h5fileDataSpace = m_pH5dataSet->getSpace(); |
661 | | |
662 | | // Update the dataset's dimensions. |
663 | 0 | if (this->getDataset().expired()) |
664 | 0 | throw DatasetNotFound{}; |
665 | | |
666 | 0 | auto pDataset = this->getDataset().lock(); |
667 | 0 | pDataset->getDescriptor().setDims(static_cast<uint32_t>(newDims[0]), |
668 | 0 | static_cast<uint32_t>(newDims[1])); |
669 | 0 | } |
670 | | |
671 | 0 | h5fileDataSpace.selectHyperslab(H5S_SELECT_SET, count.data(), offset.data()); |
672 | |
|
673 | 0 | const auto h5memDataType = getCompoundType(*pDescriptor); |
674 | |
|
675 | 0 | m_pH5dataSet->write(buffer, h5memDataType, h5memDataSpace, h5fileDataSpace); |
676 | | |
677 | | // Update descriptor. |
678 | 0 | const auto h5Space = m_pH5dataSet->getSpace(); |
679 | |
|
680 | 0 | std::array<hsize_t, kRank> dims{}; |
681 | 0 | h5Space.getSimpleExtentDims(dims.data()); |
682 | |
|
683 | 0 | pDescriptor->setDims(static_cast<uint32_t>(dims[0]), |
684 | 0 | static_cast<uint32_t>(dims[1])); |
685 | 0 | } |
686 | | |
687 | | } //namespace BAG |
688 | | |