TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
12 / 12
100.0%
Branches:
-
-%
Functions:
7 / 7
100.0%

sources/field.h
Line Branch Exec Source
1 /// @file
2 /// @brief Scalar fields over a surface, such as density maps and catalog completeness limits.
3 #pragma once
4
5 #include "terraingen/raster/raster.h"
6 #include "terraingen/raster/resample.h"
7
8 #include <cstddef>
9 #include <filesystem>
10 #include <limits>
11 #include <memory>
12
13 namespace terraingen {
14
15 /// A scalar quantity over a surface, read at surface coordinates: metres on a plane, longitude
16 /// and latitude in degrees on a sphere. Values depend only on position, so tiles, point queries
17 /// and threads agree; implementations must be thread-safe.
18 class SurfaceField {
19 public:
20 70 virtual ~SurfaceField() = default;
21
22 /// The value at surface (x, y); NaN where the field has none.
23 virtual double ValueAt(double x, double y) const = 0;
24
25 /// The largest value the field takes anywhere, a bound for drawing features from it; NaN when
26 /// it has no values.
27 virtual double Max() const = 0;
28 };
29
30 /// The same value everywhere.
31 class ConstantField final : public SurfaceField {
32 public:
33 /// @param value Any value; NaN gives a field with none.
34 47 explicit ConstantField(double value) : value_(value) {}
35
36 2332973 double ValueAt(double /*x*/, double /*y*/) const override {
37 2332973 return value_;
38 }
39 43 double Max() const override {
40 43 return value_;
41 }
42
43 private:
44 double value_;
45 };
46
47 /// How a `RasterField` reads its raster.
48 struct RasterFieldOptions {
49 /// `Nearest`, or `Bilinear` over the valid cells around a point, weights renormalized, so a
50 /// no-data cell only removes itself; both stay within the range of the cells they read.
51 ResampleMethod method = ResampleMethod::Bilinear;
52 /// Multiplies every cell, such as 0.001 for a map stored in thousandths; positive.
53 double scale = 1.0;
54 /// The value where the raster has none: outside its extent, and where every cell read is
55 /// no-data or NaN. NaN leaves those points without a value.
56 double fallback = std::numeric_limits<double>::quiet_NaN();
57 /// The raster's x is longitude in degrees, repeating every 360: points outside its extent are
58 /// read 360 degrees east or west, so a map from 0 to 360 serves -180 to 180.
59 bool periodicLongitude = false;
60
61 bool operator==(const RasterFieldOptions&) const = default;
62 };
63
64 /// Checks raster field options.
65 /// @throws std::invalid_argument for a cubic method, or a scale that is not positive and finite.
66 void ValidateRasterFieldOptions(const RasterFieldOptions& options);
67
68 /// A field interpolated from a raster in the surface's coordinates.
69 class RasterField final : public SurfaceField {
70 public:
71 /// @throws std::invalid_argument for an empty or rotated raster, or invalid options.
72 explicit RasterField(Raster<float> raster, RasterFieldOptions options = {});
73
74 double ValueAt(double x, double y) const override;
75
76 /// The largest finite cell times the scale, or the fallback if larger.
77 9 double Max() const override {
78 9 return max_;
79 }
80
81 /// The raster read.
82 2 const Raster<float>& Values() const {
83 2 return raster_;
84 }
85
86 /// How it is read.
87 1 const RasterFieldOptions& Options() const {
88 1 return options_;
89 }
90
91 private:
92 /// The raster at (x, y) before scaling: its nearest cell, or the bilinear mean of the valid
93 /// cells around it; NaN outside its extent or where every cell read is invalid.
94 double Sample(double x, double y) const;
95
96 Raster<float> raster_;
97 RasterFieldOptions options_;
98 double max_ = std::numeric_limits<double>::quiet_NaN();
99 };
100
101 /// A field read from one band of a GeoTIFF in the surface's coordinates.
102 /// @param band The band, from 0.
103 /// @throws GeoTiffError if the file cannot be read.
104 /// @throws std::invalid_argument as `RasterField`.
105 std::shared_ptr<const RasterField> ReadRasterField(const std::filesystem::path& path,
106 RasterFieldOptions options = {},
107 std::size_t band = 0);
108
109 } // namespace terraingen
110