1use crate::prelude::Vector;
4use num_traits::{
5 Float as FloatT, Num as NumT, NumAssignOps, NumAssignRef, NumCast, NumOps, NumRef,
6};
7use rand::{self, distributions::uniform::SampleUniform, Rng};
8use std::ops::{AddAssign, Range};
9
10use once_cell::sync::Lazy;
11pub use std::f64::consts::*;
13
14pub trait Num:
16 NumT + NumOps + NumAssignOps + NumAssignRef + Copy + Default + PartialOrd + PartialEq
17{
18}
19
20pub trait Float: Num + FloatT {}
22
23impl<T> Num for T where
24 T: NumT
25 + NumOps
26 + NumRef
27 + NumAssignOps
28 + NumAssignRef
29 + Copy
30 + Default
31 + PartialOrd
32 + PartialEq
33{
34}
35
36impl<T> Float for T where T: Num + FloatT {}
37
38const PERLIN_YWRAPB: usize = 4;
39const PERLIN_YWRAP: usize = 1 << PERLIN_YWRAPB;
40const PERLIN_ZWRAPB: usize = 8;
41const PERLIN_ZWRAP: usize = 1 << PERLIN_ZWRAPB;
42const PERLIN_SIZE: usize = 4095;
43
44static PERLIN: Lazy<Vec<f64>> = Lazy::new(|| {
45 let mut perlin = Vec::with_capacity(PERLIN_SIZE + 1);
46 for _ in 0..=PERLIN_SIZE {
47 perlin.push(random(1.0));
48 }
49 perlin
50});
51
52pub fn random_rng<T, R>(val: R) -> T
65where
66 T: SampleUniform + PartialOrd,
67 R: Into<Range<T>>,
68{
69 let val = val.into();
70 rand::thread_rng().gen_range(val)
71}
72
73pub fn random<T>(val: T) -> T
86where
87 T: Num + SampleUniform + PartialOrd,
88{
89 if val > T::zero() {
90 random_rng(T::zero()..val)
91 } else {
92 random_rng(val..T::zero())
93 }
94}
95
96pub fn noise<V, const N: usize>(vector: V) -> f64
113where
114 V: Into<Vector<f64, N>>,
115{
116 let v = vector.into();
117
118 let values = v.coords();
119 let x = values.first().unwrap_or(&0.0).abs();
120 let y = values.get(1).unwrap_or(&0.0).abs();
121 let z = values.get(2).unwrap_or(&0.0).abs();
122
123 let mut xi: usize = x.trunc() as usize;
124 let mut yi: usize = y.trunc() as usize;
125 let mut zi: usize = z.trunc() as usize;
126
127 let mut xf = x.fract();
128 let mut yf = y.fract();
129 let mut zf = z.fract();
130 let (mut rxf, mut ryf);
131
132 let mut noise_result = 0.0;
133 let mut ampl = 0.5;
134
135 let (mut n1, mut n2, mut n3);
136
137 let scaled_cosine = |i: f64| 0.5 * (1.0 - (i - PI).cos());
138
139 let perlin_octaves = 4; let perlin_amp_falloff = 0.5; for _ in 0..perlin_octaves {
142 let mut of = xi + (yi << PERLIN_YWRAPB) + (zi << PERLIN_ZWRAPB);
143
144 rxf = scaled_cosine(xf);
145 ryf = scaled_cosine(yf);
146
147 n1 = PERLIN[of & PERLIN_SIZE];
148 n1 += rxf * (PERLIN[(of + 1) & PERLIN_SIZE] - n1);
149 n2 = PERLIN[(of + PERLIN_YWRAP) & PERLIN_SIZE];
150 n2 += rxf * (PERLIN[(of + PERLIN_YWRAP + 1) & PERLIN_SIZE] - n2);
151 n1 += ryf * (n2 - n1);
152
153 of += PERLIN_ZWRAP;
154 n2 = PERLIN[of & PERLIN_SIZE];
155 n2 += rxf * (PERLIN[(of + 1) & PERLIN_SIZE] - n2);
156 n3 = PERLIN[(of + PERLIN_YWRAP) & PERLIN_SIZE];
157 n3 += rxf * (PERLIN[(of + PERLIN_YWRAP + 1) & PERLIN_SIZE] - n3);
158 n2 += ryf * (n3 - n2);
159
160 n1 += scaled_cosine(zf) * (n2 - n1);
161
162 noise_result += n1 * ampl;
163 ampl *= perlin_amp_falloff;
164 xi <<= 1;
165 xf *= 2.0;
166 yi <<= 1;
167 yf *= 2.0;
168 zi <<= 1;
169 zf *= 2.0;
170
171 if xf >= 1.0 {
172 xi += 1;
173 xf -= 1.0;
174 }
175 if yf >= 1.0 {
176 yi += 1;
177 yf -= 1.0;
178 }
179 if zf >= 1.0 {
180 zi += 1;
181 zf -= 1.0;
182 }
183 }
184 noise_result
185}
186
187#[macro_export]
207macro_rules! random {
208 () => {
209 $crate::math::random(1.0)
210 };
211 ($v:expr) => {
212 $crate::math::random($v)
213 };
214 ($s:expr, $e:expr$(,)?) => {
215 $crate::math::random_rng($s..$e)
216 };
217}
218
219#[macro_export]
236macro_rules! noise {
237 ($x:expr$(,)?) => {
238 $crate::math::noise([$x])
239 };
240 ($x:expr, $y:expr$(,)?) => {
241 $crate::math::noise([$x, $y])
242 };
243 ($x:expr, $y:expr, $z:expr$(,)?) => {
244 $crate::math::noise([$x, $y, $z])
245 };
246}
247
248pub fn map<T>(value: T, start1: T, end1: T, start2: T, end2: T) -> T
278where
279 T: NumCast + Into<f64> + PartialOrd + Copy,
280{
281 let default = end2;
282 let start1 = start1.into();
283 let end1 = end1.into();
284 let start2 = start2.into();
285 let end2 = end2.into();
286 let value = value.into();
287 let new_val = ((value - start1) / (end1 - start1)).mul_add(end2 - start2, start2);
288 NumCast::from(new_val.clamp(start2, end2)).unwrap_or(default)
289}
290
291pub fn lerp<T>(start: T, end: T, amount: T) -> T
305where
306 T: Num + Copy + PartialOrd,
307{
308 (T::one() - amount) * start + amount * end
309}
310
311pub fn lerp_map<T>(start1: T, end1: T, start2: T, end2: T) -> Vec<T>
333where
334 T: Num + NumCast + Copy + PartialOrd + AddAssign,
335{
336 if start1 == end1 {
337 vec![start2]
338 } else {
339 let size: usize = NumCast::from(end1 - start1).unwrap_or(4);
340 let mut values = Vec::with_capacity(size);
341 let a = (end2 - start2) / (end1 - start1);
342 let mut d = start2;
343 let mut i = start1;
344 while i <= end1 {
345 values.push(d);
346 d += a;
347 i += T::one();
348 }
349 values
350 }
351}