TerrainGen coverage


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

albedo/albedo.h
Line Branch Exec Source
1 /// @file
2 /// @brief The albedo source and layer interfaces, albedo compositions and their evaluation.
3 #pragma once
4
5 #include "terraingen/layers/ground.h"
6 #include "terraingen/raster/grid.h"
7 #include "terraingen/raster/raster.h"
8 #include "terraingen/util/surface.h"
9
10 #include <array>
11 #include <cstddef>
12 #include <functional>
13 #include <memory>
14 #include <vector>
15
16 namespace terraingen {
17
18 /// The most bands an albedo has: three for red, green and blue.
19 inline constexpr std::size_t kMaxAlbedoBands = 3;
20
21 /// An albedo at one point: the first `Bands()` values are used, the rest are 0.
22 using AlbedoSample = std::array<float, kMaxAlbedoBands>;
23
24 /// How an albedo is evaluated.
25 struct AlbedoContext {
26 /// Sample spacing in metres, positive and finite: detail that cannot be resolved at it is left
27 /// out.
28 double spacing = 1.0;
29 /// Threads a grid may be split over; 0 for every hardware thread. The result does not depend
30 /// on it.
31 unsigned threads = 1;
32 /// The terrain's heights, for layers shaped by the ground; null leaves it flat. It must outlive
33 /// the evaluation.
34 const Ground* ground = nullptr;
35 };
36
37 /// Checks an evaluation context.
38 /// @throws std::invalid_argument if `context.spacing` is not positive and finite.
39 void ValidateAlbedoContext(const AlbedoContext& context);
40
41 /// Where an albedo starts: a map from orbit, a synthetic colour, or a source of your own.
42 /// Values are reflectances (normal albedo, or reflectance at a wavelength), one per band.
43 ///
44 /// Sources must be deterministic and thread safe, and `Fill` must give every cell the bits
45 /// `ValueAt` gives at its centre, so tiles agree with the whole.
46 class AlbedoSource {
47 public:
48 111 virtual ~AlbedoSource() = default;
49
50 /// The number of bands: 1 for a single band, or 3 for red, green and blue.
51 virtual std::size_t Bands() const = 0;
52
53 /// The albedo at world point (`x`, `y`); NaN in every band where the source has no data.
54 virtual AlbedoSample ValueAt(double x, double y, const AlbedoContext& context) const = 0;
55
56 /// Sets every cell of each band to `ValueAt` at its centre; the default does exactly
57 /// that, cell by cell, on `context.threads` threads.
58 /// @param bands `Bands()` rasters on one grid.
59 virtual void Fill(std::vector<Raster<float>>& bands, const AlbedoContext& context) const;
60 };
61
62 /// A change to an albedo: bright ejecta around fresh craters, or a layer of your own.
63 ///
64 /// Layers must be deterministic and thread safe, and `Apply` must give every cell the bits
65 /// `ApplyAt` gives at its centre.
66 class AlbedoLayer {
67 public:
68 466 virtual ~AlbedoLayer() = default;
69
70 /// Applies the layer in place to `value`, the albedo at world point (`x`, `y`); NaN stays NaN.
71 /// @param bands Bands of `value` in use.
72 virtual void ApplyAt(AlbedoSample& value, std::size_t bands, double x, double y,
73 const AlbedoContext& context) const = 0;
74
75 /// Applies the layer in place to every cell of `bands` (one raster per band on one grid); the
76 /// default calls `ApplyAt` at each cell centre on `context.threads` threads.
77 virtual void Apply(std::vector<Raster<float>>& bands, const AlbedoContext& context) const;
78 };
79
80 /// An albedo as a composition: values from `source`, then each of `layers` in order.
81 struct Albedo {
82 std::shared_ptr<const AlbedoSource> source; ///< Where values start; required.
83 std::vector<std::shared_ptr<const AlbedoLayer>> layers; ///< Applied in order; none null.
84 /// Sets how a grid's cell size turns into a spacing in metres.
85 Surface surface{};
86 };
87
88 /// Evaluates `albedo` over `grid`: one raster per band, with no-data NaN.
89 /// @param context `spacing` in metres, raised to the grid's spacing on the albedo's surface
90 /// (`RasterGrid::Spacing`) when smaller or 0.
91 /// @throws std::invalid_argument if `albedo` has no source, holds a null layer, the source has a
92 /// band count other than 1 or 3, `grid` is empty, or the spacing is negative or not finite.
93 std::vector<Raster<float>> EvaluateAlbedo(const Albedo& albedo, const RasterGrid& grid,
94 AlbedoContext context);
95
96 /// The albedo at world point (`x`, `y`): the cell centred there of `EvaluateAlbedo` over a grid
97 /// of `context.spacing`, to the same bits.
98 /// @throws std::invalid_argument as `EvaluateAlbedo`.
99 AlbedoSample EvaluateAlbedoAt(const Albedo& albedo, double x, double y,
100 const AlbedoContext& context);
101
102 /// Visits the albedo at one cell centre: `visit(value, x, y)` may change `value`.
103 using AlbedoCellVisitor = std::function<void(AlbedoSample& value, double x, double y)>;
104
105 /// Calls `visit` for the albedo at every cell centre, writing back what it leaves in
106 /// `value`: the cell loop shared by `AlbedoSource::Fill` and `AlbedoLayer::Apply`.
107 /// @param bands The bands, one raster per band on one grid.
108 /// @param threads Threads to split the rows over; 0 for every hardware thread.
109 void ForEachAlbedoCell(std::vector<Raster<float>>& bands, unsigned threads,
110 const AlbedoCellVisitor& visit);
111
112 /// `ForEachAlbedoCell` in blocks of rows, for visitors that prepare per block, such as a
113 /// list of the features near it.
114 /// @param threads Threads to split the blocks over; 0 for every hardware thread.
115 /// @param blockRows Rows per block; positive.
116 /// @param visitorFor `visitorFor(rowBegin, rowEnd)` returns the visitor of the cells of rows
117 /// [`rowBegin`, `rowEnd`), called once per block on the thread that visits it.
118 void ForEachAlbedoBlock(
119 std::vector<Raster<float>>& bands, unsigned threads, std::size_t blockRows,
120 const std::function<AlbedoCellVisitor(std::size_t rowBegin, std::size_t rowEnd)>& visitorFor);
121
122 } // namespace terraingen
123