diff --git a/src/tools/boxcount.rs b/src/tools/boxcount.rs index b43b2f0..865f3bd 100644 --- a/src/tools/boxcount.rs +++ b/src/tools/boxcount.rs @@ -4,6 +4,7 @@ use bevy::tasks::ParallelSlice; use crate::system::spaces::square_grid::{Grid2D, Grid3D}; use itertools::{Itertools, MinMaxResult}; use clap::Parser; +use serde::Serialize; use crate::BoxCountCli; use crate::cli::cli::OutputFormat; use crate::system::{GriddedPosition, Position}; @@ -15,30 +16,30 @@ fn bb(data: &Vec) -> ((i32, i32), (i32, i32)) { .iter().minmax_by(|a, b| a.x.cmp(&b.x)); let y = data - .iter().minmax_by(|a, b| a.x.cmp(&b.x)); + .iter().minmax_by(|a, b| a.y.cmp(&b.y)); match (x, y) { (MinMaxResult::MinMax(min_x, max_x), MinMaxResult::MinMax(min_y, max_y)) => { ((min_x.x, min_y.y), (max_x.x, max_y.y)) - }, + } _ => panic!("Cannot determine bounding box") } } -fn box_count_2d(data: &Vec, box_number: u32) -> usize { - let n = data.len(); - let ((x_min, x_max), (y_min, y_max)) = bb(data); - +fn box_count_2d(data: &Vec, box_number: u32) -> (f64, usize) { + let ((x_min, y_min), (x_max, y_max)) = bb(data); let x_range = (x_max - x_min) as f64; let y_range = (y_max - y_min) as f64; let w: f64 = x_range / (box_number as f64); - data.iter() - .map(|Grid2D { x, y }| [((x - x_min) as f64 / w) as u32, ((y - y_min) as f64 / w) as u32]) + let boxes_occupied = data.iter() + .map(|Grid2D { x, y }| [((x - x_min) as f64 / w) as i32, ((y - y_min) as f64 / w) as i32]) .unique() - .count() + .count(); + + (w, boxes_occupied) } fn box_count_3d(data: &Vec, size: u32) -> usize { @@ -110,6 +111,25 @@ fn box_count_nd(data: &Vec<[f32; N]>, size: u32) -> usize { .count(); } -pub fn main(cli: &BoxCountCli) { - let particles = read(&cli.path, cli.format); +#[derive(Serialize)] +struct FDRow { + w: f64, + n_occupied: usize, +} + +pub(crate) fn main(cli: &BoxCountCli) { + let particles: Vec = read(&cli.path, cli.format); + let n_particles = dbg!(particles.len()); + let box_side_counts = 1..500; + + let mut writer = csv::Writer::from_path(&cli.output) + .expect("Unable to create csv"); + + box_side_counts + .map(|box_side_count| box_count_2d(&particles, box_side_count)) + // .filter(|(w, n_occupied)| *n_occupied < n_particles) // Remove saturated values + .map(|(w, n_occupied)| FDRow { w, n_occupied }) + .for_each(|row| writer.serialize(row).expect("Failed to write row")); + + writer.flush().unwrap(); } diff --git a/src/tools/mod.rs b/src/tools/mod.rs index b44669b..34a2ec7 100644 --- a/src/tools/mod.rs +++ b/src/tools/mod.rs @@ -1,3 +1,4 @@ +use std::fs::File; use std::path::Path; use serde::de::DeserializeOwned; use crate::cli::cli::OutputFormat; diff --git a/src/tools/render.rs b/src/tools/render.rs index f8b5486..bf9df85 100644 --- a/src/tools/render.rs +++ b/src/tools/render.rs @@ -12,8 +12,10 @@ use serde::de::DeserializeOwned; use serde::Deserialize; use svg::Node; use svg::node::element::Rectangle; +use crate::RenderCli; use crate::system::Position; use crate::system::spaces::hexagonal::HexPosition; +use crate::tools::read; #[derive(Debug, Parser)] struct Args { @@ -60,30 +62,10 @@ impl ToSvg for HexPosition { } } -fn read_json(args: &Args) -> Vec where T: DeserializeOwned { - serde_json::from_reader::<_, Vec>>(File::open(&args.path).expect("Failed to open file")) - .expect("Failed to read json") - .iter() - .map(|l| (l.position.clone())) - .collect::>() -} +pub(crate) fn main(args: &RenderCli) { + let positions: Vec = read::(&args.path, args.format); -fn read_csv(args: &Args) -> Vec where T: DeserializeOwned { - csv::Reader::from_path(&args.path).expect("Failed to read positions csv").deserialize::() - .collect::, _>>() - .unwrap() -} - -fn main() { - let args = Args::parse(); - dbg!(&args); - - let positions: Vec = match args.format { - OutputFormat::FullDataJson => read_json::(&args), - OutputFormat::Positions => read_csv::(&args), - }; - - let size: i32 = 800; + let size: i32 = args.image_size as i32; let max_x = positions.iter().max_by(|a, b| a.x.abs().cmp(&b.x.abs())).unwrap().x.abs(); let max_y = positions.iter().max_by(|a, b| a.y.abs().cmp(&b.y.abs())).unwrap().y.abs(); let max_size = max_x.max(max_y) * size; @@ -105,5 +87,5 @@ fn main() { svg.append(position.to_svg(size)); } - svg::write(File::create(args.output).unwrap(), &svg).unwrap(); + svg::write(File::create(&args.output).unwrap(), &svg).unwrap(); } diff --git a/src/tools_cli.rs b/src/tools_cli.rs index 2b84683..1417d47 100644 --- a/src/tools_cli.rs +++ b/src/tools_cli.rs @@ -2,7 +2,7 @@ #![feature(let_chains)] use std::fs::File; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use anyhow::Context; use crate::cli::cli::OutputFormat; use crate::system::model::HistoryLine; @@ -25,9 +25,24 @@ enum ToolsCli { BoxCount(BoxCountCli) } +#[derive(clap::ValueEnum, Clone, Debug, Copy)] +enum Space { + Grid2D, +} + #[derive(Debug, Args)] struct RenderCli { + #[arg(value_enum, short, long, default_value_t = OutputFormat::Positions)] + format: OutputFormat, + #[arg(value_enum, short, long, default_value_t = Space::Grid2D)] + space: Space, + + path: PathBuf, + output: PathBuf, + + #[arg(short, long, default_value_t = 800)] + image_size: u32, } #[derive(Debug, Args)] @@ -35,6 +50,7 @@ struct BoxCountCli { #[arg(value_enum, short, long, default_value_t = OutputFormat::Positions)] format: OutputFormat, path: PathBuf, + output: PathBuf, } fn main() { @@ -42,7 +58,7 @@ fn main() { dbg!(&args); match args { - ToolsCli::Render(_) => {} + ToolsCli::Render(cli) => tools::render::main(&cli), ToolsCli::BoxCount(cli) => tools::boxcount::main(&cli), } }