use crate::{math::interpolate, noise_fns::NoiseFn, utils::noise_map::NoiseMap};
pub struct NoiseFnWrapper<SourceFn, const DIM: usize>
where
SourceFn: Fn([f64; DIM]) -> f64,
{
source_fn: SourceFn,
}
impl<F, const DIM: usize> NoiseFn<f64, DIM> for NoiseFnWrapper<F, DIM>
where
F: Fn([f64; DIM]) -> f64,
{
fn get(&self, point: [f64; DIM]) -> f64 {
(self.source_fn)(point)
}
}
pub trait NoiseMapBuilder<SourceModule> {
fn set_size(self, width: usize, height: usize) -> Self;
fn set_source_module(self, source_module: SourceModule) -> Self;
fn size(&self) -> (usize, usize);
fn build(&self) -> NoiseMap;
}
pub struct CylinderMapBuilder<SourceModule>
where
SourceModule: NoiseFn<f64, 3>,
{
angle_bounds: (f64, f64),
height_bounds: (f64, f64),
size: (usize, usize),
source_module: SourceModule,
}
impl<SourceModule> CylinderMapBuilder<SourceModule>
where
SourceModule: NoiseFn<f64, 3>,
{
pub fn new(source_module: SourceModule) -> Self {
CylinderMapBuilder {
angle_bounds: (-90.0, 90.0),
height_bounds: (-1.0, 1.0),
size: (100, 100),
source_module,
}
}
pub fn set_angle_bounds(self, lower_bound: f64, upper_bound: f64) -> Self {
let angle_bounds = if lower_bound >= upper_bound {
(upper_bound, lower_bound)
} else {
(lower_bound, upper_bound)
};
CylinderMapBuilder {
angle_bounds,
..self
}
}
pub fn set_height_bounds(self, lower_bound: f64, upper_bound: f64) -> Self {
let height_bounds = if lower_bound >= upper_bound {
(upper_bound, lower_bound)
} else {
(lower_bound, upper_bound)
};
CylinderMapBuilder {
height_bounds,
..self
}
}
pub fn angle_bounds(&self) -> (f64, f64) {
self.angle_bounds
}
pub fn height_bounds(&self) -> (f64, f64) {
self.height_bounds
}
}
impl<SourceModule> NoiseMapBuilder<SourceModule> for CylinderMapBuilder<SourceModule>
where
SourceModule: NoiseFn<f64, 3>,
{
fn set_size(self, width: usize, height: usize) -> Self {
CylinderMapBuilder {
size: (width, height),
..self
}
}
fn set_source_module(self, source_module: SourceModule) -> Self {
CylinderMapBuilder {
source_module,
..self
}
}
fn size(&self) -> (usize, usize) {
self.size
}
fn build(&self) -> NoiseMap {
let mut result_map = NoiseMap::new(self.size.0, self.size.1);
let (width, height) = self.size;
let angle_extent = self.angle_bounds.1 - self.angle_bounds.0;
let height_extent = self.height_bounds.1 - self.height_bounds.0;
let x_step = angle_extent / width as f64;
let y_step = height_extent / height as f64;
for y in 0..height {
let current_height = self.height_bounds.0 + y_step * y as f64;
for x in 0..width {
let current_angle = self.angle_bounds.0 + x_step * x as f64;
let point_x = current_angle.to_radians().cos();
let point_z = current_angle.to_radians().sin();
let value = self.source_module.get([point_x, current_height, point_z]);
result_map[(x, y)] = value;
}
}
result_map
}
}
pub struct PlaneMapBuilder<SourceModule, const DIM: usize>
where
SourceModule: NoiseFn<f64, DIM>,
{
is_seamless: bool,
x_bounds: (f64, f64),
y_bounds: (f64, f64),
size: (usize, usize),
source_module: SourceModule,
}
impl<SourceModule, const DIM: usize> PlaneMapBuilder<SourceModule, DIM>
where
SourceModule: NoiseFn<f64, DIM>,
{
pub fn new(source_module: SourceModule) -> Self {
PlaneMapBuilder {
is_seamless: false,
x_bounds: (-1.0, 1.0),
y_bounds: (-1.0, 1.0),
size: (100, 100),
source_module,
}
}
pub fn set_is_seamless(self, is_seamless: bool) -> Self {
PlaneMapBuilder {
is_seamless,
..self
}
}
pub fn set_x_bounds(self, lower_x_bound: f64, upper_x_bound: f64) -> Self {
PlaneMapBuilder {
x_bounds: (lower_x_bound, upper_x_bound),
..self
}
}
pub fn set_y_bounds(self, lower_y_bound: f64, upper_y_bound: f64) -> Self {
PlaneMapBuilder {
y_bounds: (lower_y_bound, upper_y_bound),
..self
}
}
pub fn x_bounds(&self) -> (f64, f64) {
self.x_bounds
}
pub fn y_bounds(&self) -> (f64, f64) {
self.y_bounds
}
}
impl<SourceModule> NoiseMapBuilder<SourceModule> for PlaneMapBuilder<SourceModule, 3>
where
SourceModule: NoiseFn<f64, 3>,
{
fn set_size(self, width: usize, height: usize) -> Self {
PlaneMapBuilder {
size: (width, height),
..self
}
}
fn set_source_module(self, source_module: SourceModule) -> Self {
PlaneMapBuilder {
source_module,
..self
}
}
fn size(&self) -> (usize, usize) {
self.size
}
fn build(&self) -> NoiseMap {
let (width, height) = self.size;
let mut result_map = NoiseMap::new(width, height);
let x_extent = self.x_bounds.1 - self.x_bounds.0;
let y_extent = self.y_bounds.1 - self.y_bounds.0;
let x_step = x_extent / width as f64;
let y_step = y_extent / height as f64;
for y in 0..height {
let current_y = self.y_bounds.0 + y_step * y as f64;
for x in 0..width {
let current_x = self.x_bounds.0 + x_step * x as f64;
let final_value = if self.is_seamless {
let sw_value = self.source_module.get([current_x, current_y, 0.0]);
let se_value = self
.source_module
.get([current_x + x_extent, current_y, 0.0]);
let nw_value = self
.source_module
.get([current_x, current_y + y_extent, 0.0]);
let ne_value =
self.source_module
.get([current_x + x_extent, current_y + y_extent, 0.0]);
let x_blend = 1.0 - ((current_x - self.x_bounds.0) / x_extent);
let y_blend = 1.0 - ((current_y - self.y_bounds.0) / y_extent);
let y0 = interpolate::linear(sw_value, se_value, x_blend);
let y1 = interpolate::linear(nw_value, ne_value, x_blend);
interpolate::linear(y0, y1, y_blend)
} else {
self.source_module.get([current_x, current_y, 0.0])
};
result_map[(x, y)] = final_value;
}
}
result_map
}
}
impl<SourceFn, const DIM: usize> PlaneMapBuilder<NoiseFnWrapper<SourceFn, DIM>, DIM>
where
SourceFn: Fn([f64; DIM]) -> f64,
{
pub fn new_fn(source_fn: SourceFn) -> Self {
PlaneMapBuilder {
is_seamless: false,
x_bounds: (-1.0, 1.0),
y_bounds: (-1.0, 1.0),
size: (100, 100),
source_module: NoiseFnWrapper { source_fn },
}
}
pub fn set_size(self, width: usize, height: usize) -> Self {
PlaneMapBuilder {
size: (width, height),
..self
}
}
}
impl<SourceFn> PlaneMapBuilder<NoiseFnWrapper<SourceFn, 2>, 2>
where
SourceFn: Fn([f64; 2]) -> f64,
{
pub fn build(&self) -> NoiseMap {
let (width, height) = self.size;
let mut result_map = NoiseMap::new(width, height);
let x_extent = self.x_bounds.1 - self.x_bounds.0;
let y_extent = self.y_bounds.1 - self.y_bounds.0;
let x_step = x_extent / width as f64;
let y_step = y_extent / height as f64;
for y in 0..height {
let current_y = self.y_bounds.0 + y_step * y as f64;
for x in 0..width {
let current_x = self.x_bounds.0 + x_step * x as f64;
let final_value = if self.is_seamless {
let sw_value = self.source_module.get([current_x, current_y]);
let se_value = self.source_module.get([current_x + x_extent, current_y]);
let nw_value = self.source_module.get([current_x, current_y + y_extent]);
let ne_value = self
.source_module
.get([current_x + x_extent, current_y + y_extent]);
let x_blend = 1.0 - ((current_x - self.x_bounds.0) / x_extent);
let y_blend = 1.0 - ((current_y - self.y_bounds.0) / y_extent);
let y0 = interpolate::linear(sw_value, se_value, x_blend);
let y1 = interpolate::linear(nw_value, ne_value, x_blend);
interpolate::linear(y0, y1, y_blend)
} else {
self.source_module.get([current_x, current_y])
};
result_map[(x, y)] = final_value;
}
}
result_map
}
}
impl<SourceFn> PlaneMapBuilder<NoiseFnWrapper<SourceFn, 3>, 3>
where
SourceFn: Fn([f64; 3]) -> f64,
{
pub fn build(&self) -> NoiseMap {
let (width, height) = self.size;
let mut result_map = NoiseMap::new(width, height);
let x_extent = self.x_bounds.1 - self.x_bounds.0;
let y_extent = self.y_bounds.1 - self.y_bounds.0;
let x_step = x_extent / width as f64;
let y_step = y_extent / height as f64;
for y in 0..height {
let current_y = self.y_bounds.0 + y_step * y as f64;
for x in 0..width {
let current_x = self.x_bounds.0 + x_step * x as f64;
let final_value = if self.is_seamless {
let sw_value = self.source_module.get([current_x, current_y, 0.0]);
let se_value = self
.source_module
.get([current_x + x_extent, current_y, 0.0]);
let nw_value = self
.source_module
.get([current_x, current_y + y_extent, 0.0]);
let ne_value =
self.source_module
.get([current_x + x_extent, current_y + y_extent, 0.0]);
let x_blend = 1.0 - ((current_x - self.x_bounds.0) / x_extent);
let y_blend = 1.0 - ((current_y - self.y_bounds.0) / y_extent);
let y0 = interpolate::linear(sw_value, se_value, x_blend);
let y1 = interpolate::linear(nw_value, ne_value, x_blend);
interpolate::linear(y0, y1, y_blend)
} else {
self.source_module.get([current_x, current_y, 0.0])
};
result_map[(x, y)] = final_value;
}
}
result_map
}
}
impl<SourceFn> PlaneMapBuilder<NoiseFnWrapper<SourceFn, 4>, 4>
where
SourceFn: Fn([f64; 4]) -> f64,
{
pub fn build(&self) -> NoiseMap {
let (width, height) = self.size;
let mut result_map = NoiseMap::new(width, height);
let x_extent = self.x_bounds.1 - self.x_bounds.0;
let y_extent = self.y_bounds.1 - self.y_bounds.0;
let x_step = x_extent / width as f64;
let y_step = y_extent / height as f64;
for y in 0..height {
let current_y = self.y_bounds.0 + y_step * y as f64;
for x in 0..width {
let current_x = self.x_bounds.0 + x_step * x as f64;
let final_value = if self.is_seamless {
let sw_value = self.source_module.get([current_x, current_y, 0.0, 0.5]);
let se_value =
self.source_module
.get([current_x + x_extent, current_y, 0.0, 0.5]);
let nw_value =
self.source_module
.get([current_x, current_y + y_extent, 0.0, 0.5]);
let ne_value = self.source_module.get([
current_x + x_extent,
current_y + y_extent,
0.0,
0.5,
]);
let x_blend = 1.0 - ((current_x - self.x_bounds.0) / x_extent);
let y_blend = 1.0 - ((current_y - self.y_bounds.0) / y_extent);
let y0 = interpolate::linear(sw_value, se_value, x_blend);
let y1 = interpolate::linear(nw_value, ne_value, x_blend);
interpolate::linear(y0, y1, y_blend)
} else {
self.source_module.get([current_x, current_y, 0.0, 0.5])
};
result_map[(x, y)] = final_value;
}
}
result_map
}
}
pub struct SphereMapBuilder<SourceModule>
where
SourceModule: NoiseFn<f64, 3>,
{
latitude_bounds: (f64, f64),
longitude_bounds: (f64, f64),
size: (usize, usize),
source_module: SourceModule,
}
impl<SourceModule> SphereMapBuilder<SourceModule>
where
SourceModule: NoiseFn<f64, 3>,
{
pub fn new(source_module: SourceModule) -> Self {
SphereMapBuilder {
latitude_bounds: (-1.0, 1.0),
longitude_bounds: (-1.0, 1.0),
size: (100, 100),
source_module,
}
}
pub fn set_latitude_bounds(self, min_lat_bound: f64, max_lat_bound: f64) -> Self {
SphereMapBuilder {
latitude_bounds: (min_lat_bound, max_lat_bound),
..self
}
}
pub fn set_longitude_bounds(self, min_lon_bound: f64, max_lon_bound: f64) -> Self {
SphereMapBuilder {
longitude_bounds: (min_lon_bound, max_lon_bound),
..self
}
}
pub fn set_bounds(
self,
min_lat_bound: f64,
max_lat_bound: f64,
min_lon_bound: f64,
max_lon_bound: f64,
) -> Self {
SphereMapBuilder {
latitude_bounds: (min_lat_bound, max_lat_bound),
longitude_bounds: (min_lon_bound, max_lon_bound),
..self
}
}
pub fn latitude_bounds(&self) -> (f64, f64) {
self.latitude_bounds
}
pub fn longitude_bounds(&self) -> (f64, f64) {
self.longitude_bounds
}
}
impl<SourceModule> NoiseMapBuilder<SourceModule> for SphereMapBuilder<SourceModule>
where
SourceModule: NoiseFn<f64, 3>,
{
fn set_size(self, width: usize, height: usize) -> Self {
SphereMapBuilder {
size: (width, height),
..self
}
}
fn set_source_module(self, source_module: SourceModule) -> Self {
SphereMapBuilder {
source_module,
..self
}
}
fn size(&self) -> (usize, usize) {
self.size
}
fn build(&self) -> NoiseMap {
let (width, height) = self.size;
let mut result_map = NoiseMap::new(width, height);
let lon_extent = self.longitude_bounds.1 - self.longitude_bounds.0;
let lat_extent = self.latitude_bounds.1 - self.latitude_bounds.0;
let x_step = lon_extent / width as f64;
let y_step = lat_extent / height as f64;
for y in 0..height {
let current_lat = self.latitude_bounds.0 + y_step * y as f64;
for x in 0..width {
let current_lon = self.longitude_bounds.0 + x_step * x as f64;
let point = lat_lon_to_xyz(current_lat, current_lon);
result_map[(x, y)] = self.source_module.get(point);
}
}
result_map
}
}
fn lat_lon_to_xyz(lat: f64, lon: f64) -> [f64; 3] {
let r = lat.to_radians().cos();
let x = r * lon.to_radians().cos();
let y = lat.to_radians().sin();
let z = r * lon.to_radians().sin();
[x, y, z]
}