TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
41 / 48
85.4%
Branches:
38 / 42
90.5%
Functions:
8 / 9
88.9%

python/src/materials.cpp
Line Branch Exec Source
1 #include "bindings.h"
2 #include "common.h"
3 #include "objects.h"
4
5 #include "terraingen/materials/materials.h"
6
7 #include <array>
8 #include <optional>
9 #include <vector>
10
11 namespace nb = nanobind;
12 using namespace nb::literals;
13
14 namespace terraingen::python {
15
16 namespace {
17
18 /// `photometry` as a list of `HapkeParameters` or None, one per `MaterialClass`.
19 1 std::vector<std::optional<HapkeParameters>> ToList(const MaterialPhotometry& photometry) {
20
1/1
✓ Branch 3 taken 1 time.
3 return {photometry.begin(), photometry.end()};
21 }
22
23 /// `classes` as `MaterialPhotometry`.
24 /// @throws std::invalid_argument for a list of the wrong length.
25 3 MaterialPhotometry FromList(const std::vector<std::optional<HapkeParameters>>& classes) {
26
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (classes.size() != kMaterialClasses) {
27
0/1
✗ Branch 2 not taken.
✗ throw std::invalid_argument("Photometry needs one entry (or None) per material class");
28 }
29 3 MaterialPhotometry photometry{};
30 3 std::copy(classes.begin(), classes.end(), photometry.begin());
31 3 return photometry;
32 }
33
34 } // namespace
35
36 44 void BindMaterials(nb::module_& m) {
37 auto options = nb::class_<MaterialOptions>(
38 m, "MaterialOptions",
39 "How a material map is made: bedrock where the ground beneath the material layers is bare "
40 "(`exposure`, None "
41 44 "for none), and dust in patches covering about `dust_cover` of the surface.");
42
1/1
✓ Branch 1 taken 44 times.
44 BindKwargsInit<MaterialOptions>(options);
43 44 options.def_rw("exposure", &MaterialOptions::exposure)
44 44 .def_rw("dust_cover", &MaterialOptions::dustCover)
45 44 .def_rw("dust_patch", &MaterialOptions::dustPatch)
46 .def_rw("seed", &MaterialOptions::seed);
47
2/2
✓ Branch 1 taken 44 times.
✓ Branch 4 taken 44 times.
44 m.def("validate_material_options", &ValidateMaterialOptions, "options"_a,
48 "Raises ValueError for invalid options.");
49
1/1
✓ Branch 1 taken 44 times.
44 m.def(
50 "materials_at",
51 ✗ [](const PyTerrain& terrain, const MaterialOptions& material, double x, double y,
52 double spacing) {
53
2/2
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
1 const MaterialShares shares = MaterialsAt(terrain.Get(), material, x, y, spacing);
54
1/1
✓ Branch 3 taken 1 time.
2 return std::vector<double>(shares.begin(), shares.end());
55 },
56
5/5
✓ Branch 1 taken 44 times.
✓ Branch 4 taken 44 times.
✓ Branch 7 taken 44 times.
✓ Branch 10 taken 44 times.
✓ Branch 13 taken 44 times.
44 "terrain"_a, "options"_a, "x"_a, "y"_a, "spacing"_a,
57 "The share of each MaterialClass at (x, y), in class order: soil, then bedrock where the "
58 "ground beneath the first material layer is bare, dust in patches, and each material "
59 "layer's "
60 "cover in order.");
61
1/1
✓ Branch 1 taken 44 times.
44 m.def(
62 "evaluate_materials",
63 ✗ [](const PyTerrain& terrain, const MaterialOptions& material, const RasterGrid& grid,
64 double spacing, unsigned threads) {
65
1/1
✓ Branch 1 taken 2 times.
4 return EvaluateMaterials(terrain.Get(), material, grid,
66
1/1
✓ Branch 3 taken 2 times.
6 EvaluationOptions{spacing, threads});
67 },
68
5/5
✓ Branch 1 taken 44 times.
✓ Branch 4 taken 44 times.
✓ Branch 7 taken 44 times.
✓ Branch 10 taken 44 times.
✓ Branch 13 taken 44 times.
176 "terrain"_a, "options"_a, "grid"_a, "spacing"_a = 0.0, "threads"_a = 0,
69 44 nb::call_guard<nb::gil_scoped_release>(),
70 "One raster per MaterialClass over `grid`: each cell's share of that class.");
71
72 auto hapke = nb::class_<HapkeParameters>(
73 m, "HapkeParameters",
74 "Hapke parameters: single-scattering `albedo` w, two-term Henyey-Greenstein `b` and `c`, "
75 44 "and macroscopic `roughness` theta-bar in degrees.");
76
1/1
✓ Branch 1 taken 44 times.
44 BindKwargsInit<HapkeParameters>(hapke);
77 44 hapke.def_rw("albedo", &HapkeParameters::albedo)
78 44 .def_rw("b", &HapkeParameters::b)
79 44 .def_rw("c", &HapkeParameters::c)
80 44 .def_rw("roughness", &HapkeParameters::roughness)
81 ✗ .def("__eq__", [](const HapkeParameters& a, const HapkeParameters& b) { return a == b; });
82
1/1
✓ Branch 1 taken 44 times.
44 m.def(
83
2/2
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
1 "mars_pancam_photometry", [] { return ToList(MarsPancamPhotometry()); },
84 "Hapke parameters of Martian soil, sand, dust, bedrock and rock at 753 nm from Pancam "
85 "(Johnson et "
86 "al. 2006a, b, as tabulated by Fernando et al. 2013, and Opportunity's Eagle crater "
87 "outcrop "
88 "for bedrock), one per MaterialClass.");
89
1/1
✓ Branch 1 taken 44 times.
44 m.def(
90 "mix_photometry",
91 ✗ [](const std::vector<double>& shares,
92 const std::vector<std::optional<HapkeParameters>>& photometry) {
93
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (shares.size() != kMaterialClasses) {
94
0/1
✗ Branch 2 not taken.
✗ throw std::invalid_argument("Mixing needs one share per material class");
95 }
96 2 MaterialShares mixed{};
97
1/1
✓ Branch 3 taken 2 times.
2 std::copy(shares.begin(), shares.end(), mixed.begin());
98
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 1 time.
2 return MixPhotometry(mixed, FromList(photometry));
99 },
100
2/2
✓ Branch 1 taken 44 times.
✓ Branch 4 taken 44 times.
44 "shares"_a, "photometry"_a,
101 "The share-weighted mean Hapke parameters of a mix of materials.");
102
1/1
✓ Branch 1 taken 44 times.
44 m.def(
103 "evaluate_photometry",
104 ✗ [](const std::vector<Raster<float>>& materials,
105 const std::vector<std::optional<HapkeParameters>>& photometry) {
106
2/2
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
1 return EvaluatePhotometry(materials, FromList(photometry));
107 },
108
2/2
✓ Branch 1 taken 44 times.
✓ Branch 4 taken 44 times.
44 "materials"_a, "photometry"_a,
109 "Rasters of the albedo, b, c and roughness that material rasters mix to.");
110 44 }
111
112 } // namespace terraingen::python
113