Bug in grid indexing.

This commit is contained in:
mindv0rtex 2021-03-01 11:29:32 -05:00
parent 74a588046a
commit 82833748f4
3 changed files with 34 additions and 14 deletions

View File

@ -18,7 +18,7 @@ impl Grid {
/// Create a new grid filled with random floats in the [0.0..1.0) range. /// Create a new grid filled with random floats in the [0.0..1.0) range.
pub fn new(width: usize, height: usize) -> Self { pub fn new(width: usize, height: usize) -> Self {
if !width.is_power_of_two() || !height.is_power_of_two() { if !width.is_power_of_two() || !height.is_power_of_two() {
panic!("Grid dimensitions must be a power of two."); panic!("Grid dimensions must be a power of two.");
} }
let rng = rand::thread_rng(); let rng = rand::thread_rng();
let range = Uniform::from(0.0..1.0); let range = Uniform::from(0.0..1.0);
@ -35,8 +35,9 @@ impl Grid {
/// Truncate x and y and return a corresponding index into the data slice. /// Truncate x and y and return a corresponding index into the data slice.
fn index(&self, x: f32, y: f32) -> usize { fn index(&self, x: f32, y: f32) -> usize {
let i = (x as usize + self.width) & (self.width - 1); // x/y can come in negative, hence we shift them by width/height.
let j = (y as usize + self.height) & (self.height - 1); let i = (x + self.width as f32) as usize & (self.width - 1);
let j = (y + self.height as f32) as usize & (self.height - 1);
j * self.width + i j * self.width + i
} }

View File

@ -1,9 +1,27 @@
use indicatif::{ProgressBar, ProgressStyle};
use physarum::model; use physarum::model;
fn main() { fn main() {
let mut model = model::Model::new(128, 128, 4096, 1); let n_iterations = 400;
println!("{:#?}", model); let pb = ProgressBar::new(n_iterations);
pb.set_style(
ProgressStyle::default_bar()
.template(
"{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})",
)
.progress_chars("#>-"),
);
let (width, height) = (1024, 1024);
let n_particles = 1 << 22;
let diffusivity = 1;
let mut model = model::Model::new(width, height, n_particles, diffusivity);
println!("Model configuration: {:#?}", model.config);
for i in 0..n_iterations {
model.step(); model.step();
model.step(); pb.set_position(i);
model.save_to_image(); }
pb.finish_with_message("Finished!");
model.save_to_image("out.png");
} }

View File

@ -2,6 +2,7 @@ use crate::grid::Grid;
use rand::{seq::SliceRandom, Rng}; use rand::{seq::SliceRandom, Rng};
use rayon::prelude::*; use rayon::prelude::*;
use std::f32::consts::TAU;
/// A single Physarum agent. The x and y positions are continuous, hence we use floating point /// A single Physarum agent. The x and y positions are continuous, hence we use floating point
/// numbers instead of integers. /// numbers instead of integers.
@ -19,7 +20,7 @@ impl Agent {
Agent { Agent {
x: x * width as f32, x: x * width as f32,
y: y * height as f32, y: y * height as f32,
angle: angle * std::f32::consts::TAU, angle: angle * TAU,
} }
} }
@ -34,7 +35,7 @@ impl Agent {
) { ) {
use crate::util::wrap; use crate::util::wrap;
let delta_angle = rotation_angle * direction; let delta_angle = rotation_angle * direction;
self.angle = wrap(self.angle + delta_angle, std::f32::consts::TAU); self.angle = wrap(self.angle + delta_angle, TAU);
self.x = wrap(self.x + step_distance * self.angle.cos(), width as f32); self.x = wrap(self.x + step_distance * self.angle.cos(), width as f32);
self.y = wrap(self.y + step_distance * self.angle.sin(), height as f32); self.y = wrap(self.y + step_distance * self.angle.sin(), height as f32);
} }
@ -43,7 +44,7 @@ impl Agent {
/// A model configuration. We make it into a separate type, because we will eventually have multiple /// A model configuration. We make it into a separate type, because we will eventually have multiple
/// configurations in one model. /// configurations in one model.
#[derive(Debug)] #[derive(Debug)]
struct PopulationConfig { pub struct PopulationConfig {
sensor_distance: f32, sensor_distance: f32,
step_distance: f32, step_distance: f32,
decay_factor: f32, decay_factor: f32,
@ -95,7 +96,7 @@ pub struct Model {
// Simulation parameters. // Simulation parameters.
diffusivity: usize, diffusivity: usize,
config: PopulationConfig, pub config: PopulationConfig,
iteration: i32, iteration: i32,
width: usize, width: usize,
@ -178,7 +179,7 @@ impl Model {
} }
/// Output the current trail layer as a grayscale image. /// Output the current trail layer as a grayscale image.
pub fn save_to_image(&self) { pub fn save_to_image(&self, name: &str) {
let mut img = image::GrayImage::new(self.width as u32, self.height as u32); let mut img = image::GrayImage::new(self.width as u32, self.height as u32);
let max_value = self.grid.quantile(0.999); let max_value = self.grid.quantile(0.999);
@ -188,6 +189,6 @@ impl Model {
let c = (value / max_value).clamp(0.0, 1.0) * 255.0; let c = (value / max_value).clamp(0.0, 1.0) * 255.0;
img.put_pixel(x, y, image::Luma([c as u8])); img.put_pixel(x, y, image::Luma([c as u8]));
} }
img.save("out.png").unwrap(); img.save(name).unwrap();
} }
} }