Sen API
Sen Libraries
Loading...
Searching...
No Matches
gradient_noise.h
Go to the documentation of this file.
1// === gradient_noise.h ================================================================================================
2// Sen Infrastructure
3// Released under the Apache License v2.0 (SPDX-License-Identifier Apache-2.0).
4// See the LICENSE.txt file for more information.
5// © Airbus SAS, Airbus Helicopters, and Airbus Defence and Space SAU/GmbH/SAS.
6// =====================================================================================================================
7
8#ifndef SEN_CORE_BASE_GRADIENT_NOISE_H
9#define SEN_CORE_BASE_GRADIENT_NOISE_H
10
13
14#include <array>
15#include <mutex>
16#include <random>
17
18namespace sen
19{
20
21namespace impl
22{
23template <typename T>
24[[nodiscard]] inline T makeRandomSeed();
25} // namespace impl
26
29template <typename FloatType, std::size_t dimensionCount>
30class GradientNoise final
31{
32 SEN_MOVE_ONLY(GradientNoise)
33
34public:
35 using EngineType = std::default_random_engine;
36 using DistType = std::uniform_real_distribution<FloatType>;
37 using SeedType = EngineType::result_type;
38
40 static constexpr unsigned int discardCount = 1;
41
42public:
43 explicit GradientNoise(): seed_(impl::makeRandomSeed<FloatType>()) {}
44
45 ~GradientNoise() = default;
46
47public:
49 void seed(SeedType val = EngineType::default_seed) { seed_ = val; }
50
52 FloatType operator()(std::array<FloatType, dimensionCount> position);
53
54private:
55 SeedType seed_;
56};
57
58//----------------------------------------------------------------------------------------------------------------------
59// Inline implementation
60//----------------------------------------------------------------------------------------------------------------------
61
62namespace impl
63{
64
65template <typename T>
66[[nodiscard]] constexpr T cubicInterpolation(T y0, T y1, T y2, T y3, T mu) noexcept
67{
68 const auto a0 = y3 - y2 - y0 + y1;
69 const auto a1 = y0 - y1 - a0;
70 const auto a2 = y2 - y0;
71 const auto a3 = y1;
72 const auto mu2 = mu * mu;
73 return a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3;
74}
75
76template <const unsigned int exponent>
77[[nodiscard]] constexpr int ipowExp(int base)
78{
79 return (exponent & 1U ? base : 1) * ipowExp<exponent / 2>(base * base);
80}
81
82[[nodiscard]] constexpr int ipow(int base, unsigned int exponent)
83{
84 if (exponent == 0 && base == 0)
85 {
86 throwRuntimeError("0^0 is undefined");
87 }
88
89 if (base == 2)
90 {
91 return static_cast<int>(1U << exponent);
92 }
93
94 int result = 1;
95 int term = base;
96 while (exponent != 0U)
97 {
98 if ((exponent & 1U) != 0U)
99 {
100 result *= term;
101 }
102 term *= term;
103 exponent /= 2;
104 }
105 return result;
106}
107
108template <typename T>
109[[nodiscard]] inline T makeRandomSeed()
110{
111 static std::random_device rd;
112 static std::mt19937 gen(rd());
113 static std::mutex globalRandomGeneratorMutex;
114
115 const std::lock_guard lock(globalRandomGeneratorMutex);
116 if constexpr (std::is_floating_point_v<T>)
117 {
118 std::uniform_real_distribution<T> distribution;
119 return distribution(gen);
120 }
121
122 if constexpr (std::is_integral_v<T>)
123 {
124 std::uniform_int_distribution<T> distribution;
125 return distribution(gen);
126 }
127}
128
129} // namespace impl
130
131template <typename FloatType, std::size_t dimensionCount>
132inline FloatType GradientNoise<FloatType, dimensionCount>::operator()(std::array<FloatType, dimensionCount> position)
133{
134 std::array<SeedType, dimensionCount> unitPosition;
135 std::array<FloatType, dimensionCount> offsetPosition = position;
136
137 for (std::size_t dimension = 0; dimension < dimensionCount; dimension++)
138 {
139 // The unit position is the same as the position, but it's the integer floor of all axis positions
140 unitPosition.at(dimension) = static_cast<int>(floor(position.at(dimension)));
141
142 // The offset position is the position within the node 'cell'
143 offsetPosition.at(dimension) -= unitPosition.at(dimension);
144 }
145
146 // The pseudo-random nodes to be interpolated
147 std::array<FloatType, impl::ipow(4, dimensionCount)> nodes;
148
149 for (std::size_t node = 0; node < nodes.size(); node++)
150 {
151 std::array<SeedType, dimensionCount + 1> nodePosition;
152 nodePosition[dimensionCount] = seed_ * 2; // Use the private seed as an extra dimension
153
154 for (std::size_t dimension = 0; dimension < dimensionCount; dimension++)
155 {
156 // Get the n-dimensional position of the node
157 nodePosition.at(dimension) =
158 (node / static_cast<int>(pow(4, static_cast<double>(dimension)))) % 4 + unitPosition.at(dimension);
159 }
160
161 std::seed_seq seq(nodePosition.begin(), nodePosition.end()); // Make a seed sequence from the node position
162 std::array<SeedType, 1> nodeSeed {};
163 seq.generate(nodeSeed.begin(), nodeSeed.end());
164
165 EngineType engine(nodeSeed[0]);
166 engine.discard(discardCount); // Escape from zero-land
167 nodes.at(node) = DistType(-1.0, 1.0)(engine); // Get node value
168 }
169
170 for (std::size_t dimension = 0; dimension < dimensionCount; dimension++)
171 {
172 const auto interpolatedNodeCount = (nodes.size() / 4) / static_cast<int>(pow(4, static_cast<double>(dimension)));
173
174 for (std::size_t interpolatedNode = 0; interpolatedNode < interpolatedNodeCount; interpolatedNode++)
175 {
176 // The node that will be overwritten with the interpolated node (every fourth node is overwritten)
177 const auto node = interpolatedNode * 4;
178
179 // Overwrite every 4th node with an interpolation of the 3 preceding nodes including the overwritten node
180 nodes.at(interpolatedNode) = ::sen::impl::cubicInterpolation(
181 nodes.at(node), nodes.at(node + 1), nodes.at(node + 2), nodes.at(node + 3), offsetPosition.at(dimension));
182 }
183 }
184
185 return nodes[0]; // The final noise value
186}
187
188} // namespace sen
189
190#endif // SEN_CORE_BASE_GRADIENT_NOISE_H
The following macros implement a replacement of assert that is connected to the overall fault handlin...
Here we define a set of template meta-programming helpers to let the compiler take some decisions bas...
std::default_random_engine EngineType
Definition gradient_noise.h:35
static constexpr unsigned int discardCount
The number of random numbers discarded after a new engine seed.
Definition gradient_noise.h:40
GradientNoise()
Definition gradient_noise.h:43
~GradientNoise()=default
EngineType::result_type SeedType
Definition gradient_noise.h:37
void seed(SeedType val=EngineType::default_seed)
Seed the gradient noise.
Definition gradient_noise.h:49
FloatType operator()(std::array< FloatType, dimensionCount > position)
Return a noise value from an n-dimensional position.
Definition gradient_noise.h:132
std::uniform_real_distribution< FloatType > DistType
Definition gradient_noise.h:36
void throwRuntimeError(const std::string &err)
Throws std::exception that attempts to collect the stack trace. We also wrap it to avoid including st...
Definition assert.h:17