Corentin Chauvin-Hameau – 2019-2020
Coverage Path Planning for an underwater robot surveying a marine farm
perlin_noise.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  *
4  * \brief Definition of 2D perlin noise generator
5  * \author Corentin Chauvin-Hameau
6  * \date 2019
7  */
8 
9 #include "perlin_noise.hpp"
10 #include <random>
11 #include <cmath>
12 #include <vector>
13 #include <algorithm>
14 #include <iostream>
15 
16 namespace mfcpp {
17 
18 
20  x(0), y(0)
21 {
22 
23 }
24 
25 
27  x(_x), y(_y)
28 {
29 
30 }
31 
32 
34 {
35  x = a.x;
36  y = a.y;
37 }
38 
39 
41 {
42  return x*x + y*y;
43 }
44 
45 
47 {
48  return std::sqrt(x*x + y*y);
49 }
50 
51 
52 /*
53  * Function definitions of PerlinNoiseGenerator
54  */
55 
57 {
58  height_ = 1;
59  width_ = 1;
60  n_height_ = 1;
61  n_width_ = 1;
62 
63  init_random(0);
64 }
65 
66 
68  unsigned int n_height, unsigned int n_width, unsigned long int seed)
69 {
70  height_ = height;
71  width_ = width;
72  n_height_ = n_height;
73  n_width_ = n_width;
74  gradients_.resize(n_height+1, std::vector<Vec2d>(n_width+1, Vec2d()));
75 
76  init_random(seed);
77 }
78 
79 
81 {
82 
83 }
84 
85 
86 void PerlinNoiseGenerator::configure(float height, float width,
87  unsigned int n_height, unsigned int n_width, unsigned long int seed)
88 {
89  height_ = height;
90  width_ = width;
91  n_height_ = n_height;
92  n_width_ = n_width;
93  gradients_.resize(n_height+1, std::vector<Vec2d>(n_width+1, Vec2d()));
94 
95  init_random(seed);
96 }
97 
98 
100 {
101  std::uniform_real_distribution<double> distribution(-1, 1);
102  std::mt19937 random_generator;
103 
104  if (randomise_seed_)
105  random_generator = std::mt19937(random_device_());
106  else
107  random_generator = std::mt19937(seed_);
108 
109  hash_gradients_.resize(256, Vec2d());
110 
111  for (int i = 0; i < 256; i++) {
112  Vec2d v;
113 
114  do {
115  v.x = distribution(random_generator);
116  v.y = distribution(random_generator);
117  } while (v.norm2() > 1.0 && v.norm2() == 0.0);
118 
119  float norm = v.norm();
120  v.x /= norm;
121  v.y /= norm;
122 
123  hash_gradients_[i] = v;
124  }
125 }
126 
127 
128 void PerlinNoiseGenerator::generate(unsigned long int seed)
129 {
130  // Generate permutations
131  std::vector<unsigned int> permut(256);
132  for (int i = 0; i < 256; i++) {
133  permut[i] = i;
134  }
135 
136  if (seed == 0)
137  srand(time(0));
138  else
139  srand(seed);
140 
141  std::random_shuffle(permut.begin(), permut.end());
142 
143  // Assign gradients to each node
144  for (unsigned int i = 0; i <= n_height_; i++) {
145  for (unsigned int j = 0; j <= n_width_; j++) {
146  gradients_[i][j] = hash_gradients_[permut[(i + permut[j]) & 255]];
147  }
148  }
149 }
150 
151 
152 double PerlinNoiseGenerator::evaluate(float x, float y) const
153 {
154  if (x < 0 || y < 0 || x > height_ || y > width_) {
155  std::cout << "[PerlinNoiseGenerator] Error: specified coordinates not valid\n";
156  }
157 
158  // Find the cell corresponding to the coordinates
159  unsigned int i0 = x / height_ * n_height_;
160  unsigned int j0 = y / width_ * n_width_;
161  unsigned int i1 = i0 + 1;
162  unsigned int j1 = j0 + 1;
163  float x0 = float(i0)/float(n_height_)*height_;
164  float y0 = float(j0)/float(n_width_)*width_;
165 
166  // Compute the dot products between the distance to the nodes and the gradients
167  // d0 | d2 | -> y/j
168  // ------- V
169  // d1 | d3 x/i
170  float d0 = dot_dist_grad(i0, j0, x, y);
171  float d1 = dot_dist_grad(i1, j0, x, y);
172  float d2 = dot_dist_grad(i0, j1, x, y);
173  float d3 = dot_dist_grad(i1, j1, x, y);
174 
175  // Interpolate the dot products
176  float t_x = (x - x0) / (height_/n_height_);
177  float t_y = (y - y0) / (width_/n_width_);
178 
179  float int1 = interpolate(d0, d1, fade(t_x));
180  float int2 = interpolate(d2, d3, fade(t_x));
181  float output = interpolate(int1, int2, fade(t_y));
182 
183  // Bring output from [-1, 1] to [0, 1]
184  if (output < -1) output = -1;
185  if (output > 1) output = 1;
186  output = output/2 + 0.5;
187 
188  return output;
189 }
190 
191 
192 void PerlinNoiseGenerator::init_random(unsigned long int seed)
193 {
194  if (seed == 0) {
195  srand(time(0));
196  randomise_seed_ = true;
197  } else {
198  seed_ = seed;
199  randomise_seed_ = false;
200  }
201 }
202 
203 
205 {
206  return u.x*v.x + u.y*v.y;
207 }
208 
209 
210 float PerlinNoiseGenerator::dot_dist_grad(unsigned int i, unsigned int j,
211  float x, float y) const
212 {
213  float x_node = float(i) / float(n_height_) * height_;
214  float y_node = float(j) / float(n_width_) * width_;
215 
216  return dot_product(Vec2d(x-x_node, y-y_node), gradients_[i][j]);
217 }
218 
219 
220 float PerlinNoiseGenerator::interpolate(float a, float b, float t) const
221 {
222  return (1-t)*a + t*b;
223 }
224 
225 
226 } // namespace mfcpp
float norm2()
Computes the square of the euclidean norm of the vector.
float fade(float t) const
Sixth order polynomial to smooth the noise.
Definition: common.hpp:23
Declaration of 2D perlin noise generator.
std::vector< std::vector< Vec2d > > gradients_
Gradients evaluated at nodes of the grid.
float dot_product(Vec2d u, Vec2d v) const
Computes the dot product between two vectors.
void init_random(unsigned long int seed)
Initialises random generation.
float height_
Height of the 2D space in which to generate the noise.
float width_
Width of the 2D space in which to generate the noise.
float interpolate(float a, float b, float t) const
Linear interpolation between two values.
void configure(float height, float width, unsigned int n_height, unsigned int n_width, unsigned long int seed=0)
Configures the generator.
unsigned int n_height_
Size of the discretised grid in the first dimension.
bool randomise_seed_
Whether to randomise seeding for random numbers.
float y
Second coordinate.
std::random_device random_device_
Seed initialiser for generation of random numbers.
void generate(unsigned long int seed=0)
Populates the grid with random gradients from the hash list.
unsigned int n_width_
Size of the discretised grid in the second dimension.
Two dimensional vector.
unsigned long int seed_
Seed for random numbers when no random seeding.
void randomise_gradients()
Fills the hash list with random gradients.
std::vector< Vec2d > hash_gradients_
Hash list of random gradients.
float dot_dist_grad(unsigned int i, unsigned int j, float x, float y) const
Compute the dot product of the distance vector to the node an the gradient at this node...
PerlinNoiseGenerator()
Default constructor.
float norm()
Computes the euclidean norm of the vector.
double evaluate(float x, float y) const
Evaluates the perlin noise at a given position.