use ndarray::Array1;
use rand::{rngs::SmallRng, Rng, SeedableRng};
use std::{num::NonZeroUsize, ops::Range};
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MidpointDisplacement {
length: NonZeroUsize,
iteration: u32,
range: Range<f32>,
roughness: f32,
seed: u64,
}
impl Default for MidpointDisplacement {
fn default() -> Self {
unsafe {
Self {
length: NonZeroUsize::new_unchecked(4),
iteration: 2,
roughness: 1.1,
seed: 42,
range: Range { start: -1.0, end: 1.0 },
}
}
}
}
impl MidpointDisplacement {
pub fn get_length(&self) -> usize {
self.length.get()
}
pub fn get_map_length(&self) -> usize {
let step = 2usize.pow(self.iteration);
self.length.get() * step + 1
}
pub fn set_length(&mut self, length: usize) {
self.length = NonZeroUsize::new(length).unwrap();
}
pub fn with_length(mut self, length: usize) -> Self {
self.set_length(length);
self
}
pub fn get_iteration(&self) -> u32 {
self.iteration
}
pub fn set_iteration(&mut self, iteration: u32) {
self.iteration = iteration;
}
pub fn with_iteration(mut self, iteration: u32) -> Self {
self.set_iteration(iteration);
self
}
pub fn get_range(&self) -> Range<f32> {
self.range.clone()
}
pub fn set_range(&mut self, range: Range<f32>) {
self.range = range;
}
pub fn with_range(mut self, range: Range<f32>) -> Self {
self.set_range(range);
self
}
pub fn get_roughness(&self) -> f32 {
self.roughness
}
pub fn set_roughness(&mut self, roughness: f32) {
self.roughness = roughness;
}
pub fn with_roughness(mut self, roughness: f32) -> Self {
self.set_roughness(roughness);
self
}
pub fn get_seed(&self) -> u64 {
self.seed
}
pub fn set_seed(&mut self, seed: u64) {
self.seed = seed;
}
pub fn with_seed(mut self, seed: u64) -> Self {
self.set_seed(seed);
self
}
}
impl MidpointDisplacement {
pub fn generate(&self) -> Array1<f32> {
let mut rng = SmallRng::seed_from_u64(self.seed);
let mut step = 2usize.pow(self.iteration);
let length = self.get_map_length();
let mut grid = Array1::zeros((length,));
for x in (0..length).step_by(step) {
unsafe {
*grid.uget_mut(x) = rng.gen_range(self.range.clone());
}
}
for iteration in 0..self.iteration {
tracing::trace!("Iteration: {}, step: {} in {}", iteration + 1, step, length);
let half = step / 2;
for i in (half..length).step_by(step) {
unsafe {
let l = *grid.uget(i - half);
let r = *grid.uget(i + half);
*grid.uget_mut(i) = self.random_average(&mut rng, [l, r]);
}
}
step /= 2;
}
grid
}
fn random_average(&self, rng: &mut SmallRng, vs: [f32; 2]) -> f32 {
let mut avg = vs.iter().sum::<f32>() / 2.0;
if self.roughness != 1.0 {
let r_roughness = self.roughness.recip();
avg *= rng.gen_range(r_roughness..self.roughness);
}
avg
}
}