| Line |
Branch |
Exec |
Source |
| 1 |
|
|
/// @file |
| 2 |
|
|
/// @brief Resampling and interpolation of rasters: nearest, bilinear and cubic. |
| 3 |
|
|
#pragma once |
| 4 |
|
|
|
| 5 |
|
|
#include "terraingen/raster/grid.h" |
| 6 |
|
|
#include "terraingen/raster/raster.h" |
| 7 |
|
|
|
| 8 |
|
|
#include <cmath> |
| 9 |
|
|
#include <cstddef> |
| 10 |
|
|
#include <limits> |
| 11 |
|
|
#include <optional> |
| 12 |
|
|
|
| 13 |
|
|
namespace terraingen { |
| 14 |
|
|
|
| 15 |
|
|
/// How `Resample` interpolates between source cells. |
| 16 |
|
|
enum class ResampleMethod { |
| 17 |
|
|
Nearest, ///< The value of the nearest cell centre. |
| 18 |
|
|
Bilinear, ///< Linear in each axis over the four surrounding cells. |
| 19 |
|
|
Cubic, ///< Keys cubic convolution (a = -0.5) over the sixteen surrounding cells. |
| 20 |
|
|
}; |
| 21 |
|
|
|
| 22 |
|
|
/// A raster resampled to square cells over the same extent, origin and axis directions, on the |
| 23 |
|
|
/// `ResampledGrid`, keeping `raster`'s no-data value (NaN cells without one). |
| 24 |
|
|
/// |
| 25 |
|
|
/// Each output cell centre is interpolated in the source, with samples beyond the edge taken from |
| 26 |
|
|
/// the nearest edge cell. An output cell is no-data where any contributing cell is. |
| 27 |
|
|
/// @param raster The source raster; not empty and not rotated. |
| 28 |
|
|
/// @param pixelSize The new cell side in world units; positive and finite. |
| 29 |
|
|
/// @throws std::invalid_argument for an empty or rotated raster, a non-positive or non-finite |
| 30 |
|
|
/// `pixelSize`, or a result wider or taller than 2^31 cells. |
| 31 |
|
|
Raster<float> Resample(const Raster<float>& raster, double pixelSize, ResampleMethod method); |
| 32 |
|
|
|
| 33 |
|
|
/// A raster interpolated at world position (`x`, `y`), as `Resample` interpolates; NaN outside |
| 34 |
|
|
/// the raster's extent or where a contributing cell is no-data. |
| 35 |
|
|
/// @param raster The raster; not empty and not rotated. |
| 36 |
|
|
/// @throws std::invalid_argument for an empty or rotated raster. |
| 37 |
|
|
/// @throws std::domain_error if the raster's transform is not invertible. |
| 38 |
|
|
float SampleRaster(const Raster<float>& raster, double x, double y, ResampleMethod method); |
| 39 |
|
|
|
| 40 |
|
|
/// A raster resampled onto a non-empty grid, each cell `SampleRaster` at its centre. |
| 41 |
|
|
/// |
| 42 |
|
|
/// Cells giving NaN hold `raster`'s no-data value, or NaN, which then becomes the no-data value |
| 43 |
|
|
/// (`FilledNoData`). |
| 44 |
|
|
/// @param raster The source raster; not empty and not rotated. |
| 45 |
|
|
/// @throws std::invalid_argument for an empty or rotated raster, or an empty grid. |
| 46 |
|
|
/// @throws std::domain_error if the raster's transform is not invertible. |
| 47 |
|
|
Raster<float> ResampleTo(const Raster<float>& raster, const RasterGrid& grid, |
| 48 |
|
|
ResampleMethod method); |
| 49 |
|
|
|
| 50 |
|
|
/// The no-data value of a raster filled from a source with no-data value `noData`, whose |
| 51 |
|
|
/// missing cells hold `noData` or, without one, NaN: `noData` if set; otherwise NaN if a cell |
| 52 |
|
|
/// was `missing`, else none. |
| 53 |
|
|
std::optional<float> FilledNoData(std::optional<float> noData, bool missing); |
| 54 |
|
|
|
| 55 |
|
|
/// Sets each cell of `target` to `sample` at the cell's centre; cells where it gives NaN |
| 56 |
|
|
/// hold `noData`, or NaN without one, and `target` gets `FilledNoData`. |
| 57 |
|
|
/// @tparam Sample Callable as `float(double x, double y)` with world coordinates; returns NaN |
| 58 |
|
|
/// where missing. |
| 59 |
|
|
template <typename Sample> |
| 60 |
|
7 |
void SampleAtCentres(Raster<float>& target, std::optional<float> noData, Sample&& sample) { |
| 61 |
|
7 |
const float fill = noData.value_or(std::numeric_limits<float>::quiet_NaN()); |
| 62 |
|
7 |
bool missing = false; |
| 63 |
8/8
void terraingen::SampleAtCentres<SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#1}&&):
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
void terraingen::SampleAtCentres<SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#2}>(terraingen::Raster<float>&, std::optional<float>, SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#2}&&):
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
void terraingen::SampleAtCentres<terraingen::GeoTiffSource::FillBySampling(terraingen::Raster<float>&) const::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, terraingen::GeoTiffSource::FillBySampling(terraingen::Raster<float>&) const::{lambda(double, double)#1}&&):
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 3 times.
void terraingen::SampleAtCentres<terraingen::ResampleTo(terraingen::Raster<float> const&, terraingen::RasterGrid const&, terraingen::ResampleMethod)::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, terraingen::ResampleTo(terraingen::Raster<float> const&, terraingen::RasterGrid const&, terraingen::ResampleMethod)::{lambda(double, double)#1}&&):
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 2 times.
|
36 |
for (std::size_t row = 0; row < target.Height(); ++row) { |
| 64 |
8/8
void terraingen::SampleAtCentres<SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#1}&&):
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2 times.
void terraingen::SampleAtCentres<SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#2}>(terraingen::Raster<float>&, std::optional<float>, SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#2}&&):
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2 times.
void terraingen::SampleAtCentres<terraingen::GeoTiffSource::FillBySampling(terraingen::Raster<float>&) const::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, terraingen::GeoTiffSource::FillBySampling(terraingen::Raster<float>&) const::{lambda(double, double)#1}&&):
✓ Branch 1 taken 97 times.
✓ Branch 2 taken 15 times.
void terraingen::SampleAtCentres<terraingen::ResampleTo(terraingen::Raster<float> const&, terraingen::RasterGrid const&, terraingen::ResampleMethod)::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, terraingen::ResampleTo(terraingen::Raster<float> const&, terraingen::RasterGrid const&, terraingen::ResampleMethod)::{lambda(double, double)#1}&&):
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 10 times.
|
190 |
for (std::size_t col = 0; col < target.Width(); ++col) { |
| 65 |
|
161 |
const Vec2d centre = target.CellCenter(col, row); |
| 66 |
2/2
void terraingen::SampleAtCentres<terraingen::GeoTiffSource::FillBySampling(terraingen::Raster<float>&) const::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, terraingen::GeoTiffSource::FillBySampling(terraingen::Raster<float>&) const::{lambda(double, double)#1}&&):
✓ Branch 1 taken 97 times.
void terraingen::SampleAtCentres<terraingen::ResampleTo(terraingen::Raster<float> const&, terraingen::RasterGrid const&, terraingen::ResampleMethod)::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, terraingen::ResampleTo(terraingen::Raster<float> const&, terraingen::RasterGrid const&, terraingen::ResampleMethod)::{lambda(double, double)#1}&&):
✓ Branch 1 taken 52 times.
|
161 |
const float value = sample(centre.x, centre.y); |
| 67 |
14/16
void terraingen::SampleAtCentres<SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#1}&&):
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 2 times.
void terraingen::SampleAtCentres<SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#2}>(terraingen::Raster<float>&, std::optional<float>, SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#2}&&):
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
void terraingen::SampleAtCentres<terraingen::GeoTiffSource::FillBySampling(terraingen::Raster<float>&) const::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, terraingen::GeoTiffSource::FillBySampling(terraingen::Raster<float>&) const::{lambda(double, double)#1}&&):
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 24 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 72 times.
void terraingen::SampleAtCentres<terraingen::ResampleTo(terraingen::Raster<float> const&, terraingen::RasterGrid const&, terraingen::ResampleMethod)::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, terraingen::ResampleTo(terraingen::Raster<float> const&, terraingen::RasterGrid const&, terraingen::ResampleMethod)::{lambda(double, double)#1}&&):
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 35 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 16 times.
|
161 |
missing = missing || std::isnan(value); |
| 68 |
7/8
void terraingen::SampleAtCentres<SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#1}&&):
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
void terraingen::SampleAtCentres<SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#2}>(terraingen::Raster<float>&, std::optional<float>, SampleAtCentres_CallsTheSamplerAtEachCellCentre_Test::TestBody()::{lambda(double, double)#2}&&):
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
void terraingen::SampleAtCentres<terraingen::GeoTiffSource::FillBySampling(terraingen::Raster<float>&) const::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, terraingen::GeoTiffSource::FillBySampling(terraingen::Raster<float>&) const::{lambda(double, double)#1}&&):
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 88 times.
void terraingen::SampleAtCentres<terraingen::ResampleTo(terraingen::Raster<float> const&, terraingen::RasterGrid const&, terraingen::ResampleMethod)::{lambda(double, double)#1}>(terraingen::Raster<float>&, std::optional<float>, terraingen::ResampleTo(terraingen::Raster<float> const&, terraingen::RasterGrid const&, terraingen::ResampleMethod)::{lambda(double, double)#1}&&):
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 32 times.
|
161 |
target(col, row) = std::isnan(value) ? fill : value; |
| 69 |
|
|
} |
| 70 |
|
|
} |
| 71 |
|
7 |
target.SetNoData(FilledNoData(noData, missing)); |
| 72 |
|
7 |
} |
| 73 |
|
|
|
| 74 |
|
|
} // namespace terraingen |
| 75 |
|
|
|