hassium_utils/
noise_map_generator.rs1use crate::grid_2d::Grid2d;
2use noise::{NoiseFn, OpenSimplex, Seedable};
3use std::ops::Range;
4
5#[derive(Clone)]
6pub struct NoiseMapGenerator {
7 seed: u32,
8 chunk_size: usize,
9 zoom: f64,
10 generator: OpenSimplex,
11}
12
13impl NoiseMapGenerator {
14 pub fn new(seed: u32, chunk_size: usize, zoom: f64) -> Self {
15 Self {
16 seed,
17 chunk_size: chunk_size.max(1),
18 zoom,
19 generator: OpenSimplex::new().set_seed(seed),
20 }
21 }
22
23 pub fn seed(&self) -> u32 {
24 self.seed
25 }
26
27 pub fn chunk_size(&self) -> usize {
28 self.chunk_size
29 }
30
31 pub fn zoom(&self) -> f64 {
32 self.zoom
33 }
34
35 pub fn sample_raw(&self, x: f64, y: f64, z: f64) -> f64 {
36 self.generator.get([x, y, z]) + 1.0 * 0.5
37 }
38
39 pub fn sample(
40 &self,
41 coord: (isize, isize),
42 (col, row): (usize, usize),
43 margin: usize,
44 depth: f64,
45 ) -> f64 {
46 let col = col % (self.chunk_size + margin * 2);
47 let row = row % (self.chunk_size + margin * 2);
48 let x = self.zoom * (coord.0 as f64 * self.chunk_size as f64 + col as f64 - margin as f64)
49 / self.chunk_size as f64;
50 let y = self.zoom * (coord.1 as f64 * self.chunk_size as f64 + row as f64 - margin as f64)
51 / self.chunk_size as f64;
52 self.sample_raw(x, y, depth)
53 }
54
55 #[inline]
56 pub fn build_chunk(&self, coord: (isize, isize), margin: usize) -> Grid2d<f64> {
57 self.build_chunk_with_depth(coord, margin, 0.0)
58 }
59
60 pub fn build_chunk_with_depth(
61 &self,
62 coord: (isize, isize),
63 margin: usize,
64 depth: f64,
65 ) -> Grid2d<f64> {
66 let mut cells = Vec::with_capacity(self.chunk_size * self.chunk_size);
67 let mcs = self.chunk_size + margin * 2;
68 for row in 0..mcs {
69 for col in 0..mcs {
70 cells.push(self.sample(coord, (col, row), margin, depth));
71 }
72 }
73 Grid2d::with_cells(mcs, cells)
74 }
75
76 #[inline]
77 pub fn build_chunks(&self, coord: Range<(isize, isize)>) -> Grid2d<f64> {
78 self.build_chunks_with_depth(coord, 0.0)
79 }
80
81 pub fn build_chunks_with_depth(&self, coord: Range<(isize, isize)>, depth: f64) -> Grid2d<f64> {
82 let xs = (coord.end.0 - coord.start.0) as usize;
83 let ys = (coord.end.1 - coord.start.1) as usize;
84 let mut cells = Vec::with_capacity(self.chunk_size * self.chunk_size * xs * ys);
85 for row in 0..(self.chunk_size * ys) {
86 for col in 0..(self.chunk_size * xs) {
87 let xc = coord.start.0 + (col / self.chunk_size) as isize;
88 let yc = coord.start.1 + (row / self.chunk_size) as isize;
89 cells.push(self.sample(
90 (xc, yc),
91 (col % self.chunk_size, row % self.chunk_size),
92 0,
93 depth,
94 ));
95 }
96 }
97 Grid2d::with_cells(self.chunk_size * xs, cells)
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn test_print_ascii() {
107 let gen = NoiseMapGenerator::new(0, 8, 4.0);
108
109 fn print_chunk(chunk: Grid2d<f64>) {
110 for row in 0..chunk.rows() {
111 let cells = chunk
112 .get_row_cells(row)
113 .unwrap()
114 .into_iter()
115 .map(|f| if f >= 0.5 { '#' } else { ' ' })
116 .collect::<String>();
117 println!("|{}|", cells);
118 }
119 }
120
121 let chunk = gen.build_chunk((0, 0), 1);
123 print_chunk(chunk.clone());
124 println!("");
125 print_chunk(chunk.get_part((1, 1)..(9, 9)));
126 }
127}