Bug in grid indexing.
This commit is contained in:
parent
74a588046a
commit
82833748f4
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
src/main.rs
26
src/main.rs
@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/model.rs
13
src/model.rs
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user