noise/noise_fns/selectors/
select.rs1use crate::{
2 math::{interpolate, s_curve::cubic::Cubic},
3 noise_fns::NoiseFn,
4};
5use core::marker::PhantomData;
6
7#[derive(Clone, Debug)]
10pub struct Select<T, Source1, Source2, Control, const DIM: usize>
11where
12 Source1: NoiseFn<T, DIM>,
13 Source2: NoiseFn<T, DIM>,
14 Control: NoiseFn<T, DIM>,
15{
16 pub source1: Source1,
18
19 pub source2: Source2,
21
22 pub control: Control,
27
28 pub bounds: (f64, f64),
30
31 pub falloff: f64,
33
34 phantom: PhantomData<T>,
35}
36
37impl<T, Source1, Source2, Control, const DIM: usize> Select<T, Source1, Source2, Control, DIM>
38where
39 Source1: NoiseFn<T, DIM>,
40 Source2: NoiseFn<T, DIM>,
41 Control: NoiseFn<T, DIM>,
42{
43 pub fn new(source1: Source1, source2: Source2, control: Control) -> Self {
44 Select {
45 source1,
46 source2,
47 control,
48 bounds: (0.0, 1.0),
49 falloff: 0.0,
50 phantom: PhantomData,
51 }
52 }
53
54 pub fn set_bounds(self, lower_bound: f64, upper_bound: f64) -> Self {
55 Select {
56 bounds: (lower_bound, upper_bound),
57 ..self
58 }
59 }
60
61 pub fn set_falloff(self, falloff: f64) -> Self {
62 Select { falloff, ..self }
63 }
64}
65
66impl<T, Source1, Source2, Control, const DIM: usize> NoiseFn<T, DIM>
67 for Select<T, Source1, Source2, Control, DIM>
68where
69 T: Copy,
70 Source1: NoiseFn<T, DIM>,
71 Source2: NoiseFn<T, DIM>,
72 Control: NoiseFn<T, DIM>,
73{
74 fn get(&self, point: [T; DIM]) -> f64 {
75 let control_value = self.control.get(point);
76 let (lower, upper) = self.bounds;
77
78 if self.falloff > 0.0 {
79 match () {
80 _ if control_value < (lower - self.falloff) => self.source1.get(point),
81 _ if control_value < (lower + self.falloff) => {
82 let lower_curve = lower - self.falloff;
83 let upper_curve = lower + self.falloff;
84 let alpha =
85 ((control_value - lower_curve) / (upper_curve - lower_curve)).map_cubic();
86
87 interpolate::linear(self.source1.get(point), self.source2.get(point), alpha)
88 }
89 _ if control_value < (upper - self.falloff) => self.source2.get(point),
90 _ if control_value < (upper + self.falloff) => {
91 let lower_curve = upper - self.falloff;
92 let upper_curve = upper + self.falloff;
93 let alpha =
94 ((control_value - lower_curve) / (upper_curve - lower_curve)).map_cubic();
95
96 interpolate::linear(self.source2.get(point), self.source1.get(point), alpha)
97 }
98 _ => self.source1.get(point),
99 }
100 } else if control_value < lower || control_value > upper {
101 self.source1.get(point)
102 } else {
103 self.source2.get(point)
104 }
105 }
106}