This commit is contained in:
Simon Gardling 2021-03-31 10:24:56 -04:00
parent bec6340607
commit 32bfd1b27e
9 changed files with 66 additions and 54 deletions

View File

@ -1,4 +1,3 @@
unstable_features = true
imports_granularity = "Crate"
wrap_comments = true
comment_width = 100
wrap_comments = false

View File

@ -10,7 +10,7 @@ impl Clone for Blur {
fn clone(&self) -> Blur {
return Blur {
row_buffer: self.row_buffer.clone(),
}
};
}
}

View File

@ -25,7 +25,7 @@ impl Clone for PopulationConfig {
rotation_angle: self.rotation_angle,
decay_factor: self.decay_factor,
deposition_amount: self.deposition_amount,
}
};
}
}
@ -93,13 +93,13 @@ pub struct Grid {
impl Clone for Grid {
fn clone(&self) -> Grid {
return Grid {
config: self.config.clone(),
width: self.width.clone(),
height: self.height.clone(),
data: self.data.clone(),
buf: self.buf.clone(),
config: self.config.clone(),
width: self.width.clone(),
height: self.height.clone(),
data: self.data.clone(),
buf: self.buf.clone(),
blur: self.blur.clone(),
}
};
}
}

View File

@ -1,8 +1,4 @@
use crate::{
grid::{Grid},
palette::{Palette},
};
use crate::{grid::Grid, palette::Palette};
// Class for storing data that will be used to create images
pub struct ImgData {
@ -17,16 +13,16 @@ impl Clone for ImgData {
grids: self.grids.clone(),
palette: self.palette.clone(),
iteration: self.iteration.clone(),
}
};
}
}
impl ImgData {
pub fn new(in_grids: Vec<Grid>, in_palette: Palette, in_iteration: i32) -> Self {
ImgData {
grids: in_grids,
grids: in_grids,
palette: in_palette,
iteration: in_iteration,
}
}
}
}

View File

@ -1,7 +1,7 @@
mod blur;
mod grid;
mod imgdata; // for storing image data
mod math;
pub mod model;
mod palette;
mod util;
mod imgdata; // for storing image data
mod math; // for math things
mod util; // for math things

View File

@ -17,18 +17,16 @@ fn main() {
// `n_populations` is the # of types of agents
let n_populations = 1;
// let n_populations = 1 + rng.gen_range(1..4); // make # of populations between 2 and 5
let mut model = model::Model::new(width, height, n_particles, n_populations, diffusivity); // Create the model
model.print_configurations(); // Print config for model
model.run(n_iterations); // Actually run the model
// export saved image data
println!("Rendering all saved image data....");
model.render_all_imgdata();
model.flush_image_data();
println!("Done!");
}
}

View File

@ -36,4 +36,4 @@ pub fn cos(mut x: f32) -> f32 {
#[inline(always)]
pub fn sin(x: f32) -> f32 {
return cos(x - std::f32::consts::FRAC_PI_2);
}
}

View File

@ -1,19 +1,16 @@
use crate::{
grid::{combine, Grid, PopulationConfig},
palette::{random_palette, Palette},
imgdata::ImgData,
palette::{random_palette, Palette},
util::wrap,
};
use indicatif::{ParallelProgressIterator, ProgressBar, ProgressStyle};
use itertools::multizip;
use rand::{seq::SliceRandom, Rng};
use rand_distr::{Distribution, Normal};
use rayon::prelude::*;
use itertools::multizip;
use std::f32::consts::TAU;
use std::time::{Instant};
use rayon::iter::ParallelIterator;
use indicatif::{ParallelProgressIterator, ProgressBar, ProgressStyle};
use std::path::Path;
use rayon::{iter::ParallelIterator, prelude::*};
use std::{f32::consts::TAU, path::Path, time::Instant};
// A single Physarum agent. The x and y positions are continuous, hence we use floating point numbers instead of integers.
#[derive(Debug)]
@ -39,7 +36,7 @@ impl Agent {
}
#[inline]
pub fn tick(&mut self, grid: &Grid) {
pub fn tick(&mut self, grid: &Grid) {
let (width, height) = (grid.width, grid.height);
let PopulationConfig {
sensor_distance,
@ -51,7 +48,7 @@ impl Agent {
let xc = self.x + fastapprox::faster::cos(self.angle) * sensor_distance;
let yc = self.y + fastapprox::faster::sin(self.angle) * sensor_distance;
let agent_add_sens = self.angle + sensor_angle;
let agent_sub_sens = self.angle - sensor_angle;
@ -68,7 +65,7 @@ impl Agent {
// Rotate and move logic
let mut rng = rand::thread_rng();
let mut direction: f32 = 0.0;
if (center > left) && (center > right) {
direction = 0.0;
} else if (center < left) && (center < right) {
@ -82,8 +79,14 @@ impl Agent {
let delta_angle = rotation_angle * direction;
self.angle = wrap(self.angle + delta_angle, TAU);
self.x = wrap(self.x + step_distance * fastapprox::faster::cos(self.angle), width as f32);
self.y = wrap(self.y + step_distance * fastapprox::faster::sin(self.angle), height as f32);
self.x = wrap(
self.x + step_distance * fastapprox::faster::cos(self.angle),
width as f32,
);
self.y = wrap(
self.y + step_distance * fastapprox::faster::sin(self.angle),
height as f32,
);
}
}
@ -95,17 +98,20 @@ impl Clone for Agent {
angle: self.angle,
population_id: self.population_id,
i: self.i,
}
};
}
}
impl PartialEq for Agent {
fn eq(&self, other: &Self) -> bool {
return self.x == other.x && self.y == other.y && self.angle == other.angle && self.population_id == other.population_id && self.i == other.i;
return self.x == other.x
&& self.y == other.y
&& self.angle == other.angle
&& self.population_id == other.population_id
&& self.i == other.i;
}
}
// Top-level simulation class.
pub struct Model {
// Physarum agents.
@ -188,7 +194,6 @@ impl Model {
}
}
// Simulates `steps` # of steps
#[inline]
pub fn run(&mut self, steps: usize) {
@ -206,7 +211,9 @@ impl Model {
let mut time_per_agent_list: Vec<f64> = Vec::new();
let mut time_per_step_list: Vec<f64> = Vec::new();
for i in 0..steps {
if debug {println!("Starting tick for all agents...")};
if debug {
println!("Starting tick for all agents...")
};
// Combine grids
let grids = &mut self.grids;
@ -237,16 +244,26 @@ impl Model {
time_per_agent_list.push(ms_per_agent);
time_per_step_list.push(agents_tick_elapsed);
if debug {println!("Finished tick for all agents. took {}ms\nTime per agent: {}ms\n", agents_tick_elapsed, ms_per_agent)};
if debug {
println!(
"Finished tick for all agents. took {}ms\nTime per agent: {}ms\n",
agents_tick_elapsed, ms_per_agent
)
};
self.iteration += 1;
pb.set_position(i as u64);
}
pb.finish();
let avg_per_step: f64 = time_per_step_list.iter().sum::<f64>() as f64 / time_per_step_list.len() as f64;
let avg_per_agent: f64 = time_per_agent_list.iter().sum::<f64>() as f64 / time_per_agent_list.len() as f64;
println!("Average time per step: {}ms\nAverage time per agent: {}ms", avg_per_step, avg_per_agent);
let avg_per_step: f64 =
time_per_step_list.iter().sum::<f64>() as f64 / time_per_step_list.len() as f64;
let avg_per_agent: f64 =
time_per_agent_list.iter().sum::<f64>() as f64 / time_per_agent_list.len() as f64;
println!(
"Average time per step: {}ms\nAverage time per agent: {}ms",
avg_per_step, avg_per_agent
);
}
fn save_image_data(&mut self) {
@ -260,7 +277,6 @@ impl Model {
return;
}
}
}
pub fn flush_image_data(&mut self) {
@ -285,7 +301,9 @@ impl Model {
pb.finish();
*/
(&self.img_data_vec).par_iter().progress_with(pb)
(&self.img_data_vec)
.par_iter()
.progress_with(pb)
.for_each(|img| {
Self::save_to_image(img.to_owned());
});
@ -306,7 +324,8 @@ impl Model {
let i = y * width + x;
let (mut r, mut g, mut b) = (0.0_f32, 0.0_f32, 0.0_f32);
for (grid, max_value, color) in
multizip((&imgdata.grids, &max_values, &imgdata.palette.colors)) {
multizip((&imgdata.grids, &max_values, &imgdata.palette.colors))
{
let mut t = (grid.data()[i] / max_value).clamp(0.0, 1.0);
t = t.powf(1.0 / 2.2); // gamma correction
r += color.0[0] as f32 * t;
@ -320,7 +339,7 @@ impl Model {
}
}
img.save(format!("./tmp/out_{}.png", imgdata.iteration).as_str()).unwrap();
img.save(format!("./tmp/out_{}.png", imgdata.iteration).as_str())
.unwrap();
}
}

View File

@ -1,4 +1,4 @@
#[inline(always)]
pub fn wrap(x: f32, max: f32) -> f32 {
return x - max * ((x > max) as i32 as f32 - (x < 0.0_f32) as i32 as f32);
}
}