Refactor Position thing (again, we love hitting compiler bugs), and add P2 rendering

This commit is contained in:
Joshua Coles 2023-03-18 18:22:41 +00:00
parent 2b20df273b
commit 596b2a509f
12 changed files with 100 additions and 66 deletions

1
Cargo.lock generated
View File

@ -4000,6 +4000,7 @@ dependencies = [
"nalgebra 0.32.2", "nalgebra 0.32.2",
"nd_array", "nd_array",
"num-integer", "num-integer",
"num-traits",
"parquet", "parquet",
"polars", "polars",
"rand", "rand",

View File

@ -65,6 +65,7 @@ rayon = "1.7.0"
walkdir = "2.3.3" walkdir = "2.3.3"
parquet = { version = "35.0.0", features = ["serde"] } parquet = { version = "35.0.0", features = ["serde"] }
colorous = "1.0.10" colorous = "1.0.10"
num-traits = "0.2.15"
[build-dependencies] [build-dependencies]
cbindgen = "0.24.3" cbindgen = "0.24.3"

BIN
dla-eg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

View File

@ -8,13 +8,13 @@ pub mod model;
pub mod spaces; pub mod spaces;
pub trait Position: Add<Output=Self> + Serialize + Clone { pub trait Position: Add<Output=Self> + Serialize + Clone {
// const DIM: usize; const DIM: usize;
type Cartesian; // type Cartesian;
fn zero() -> Self; fn zero() -> Self;
fn abs(&self) -> f32; fn abs(&self) -> f32;
fn from_cartesian(cartesian: Self::Cartesian) -> Self; fn from_cartesian(cartesian: &[f32]) -> Self;
fn to_cartesian(&self) -> Self::Cartesian; fn to_cartesian(&self) -> Vec<f32>;
} }
pub trait GriddedPosition: Position { pub trait GriddedPosition: Position {

View File

@ -2,15 +2,15 @@ use std::f32::consts::PI;
use std::ops::Add; use std::ops::Add;
use kiddo::distance::squared_euclidean; use kiddo::distance::squared_euclidean;
use rand::Rng; use rand::Rng;
use serde::Serialize; use serde::{Serialize, Deserialize};
use crate::system::sticker::Sticker; use crate::system::sticker::Sticker;
use crate::system::{Position, Storage}; use crate::system::{Position, Storage};
use crate::system::walker::Walker; use crate::system::walker::Walker;
#[derive(Serialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct P2 { pub struct P2 {
x: f32, pub x: f32,
y: f32, pub y: f32,
} }
impl P2 { impl P2 {
@ -47,7 +47,7 @@ pub struct ContinuousStorage {
} }
impl Position for P2 { impl Position for P2 {
type Cartesian = [f32; 2]; const DIM: usize = 2;
fn zero() -> Self { fn zero() -> Self {
P2 { x: 0f32, y: 0f32 } P2 { x: 0f32, y: 0f32 }
@ -57,12 +57,12 @@ impl Position for P2 {
(self.x.powi(2) + self.y.powi(2)).powf(0.5) (self.x.powi(2) + self.y.powi(2)).powf(0.5)
} }
fn from_cartesian(cartesian: Self::Cartesian) -> Self { fn from_cartesian(cartesian: &[f32]) -> Self {
P2 { x: cartesian[0], y: cartesian[1] } P2 { x: cartesian[0], y: cartesian[1] }
} }
fn to_cartesian(&self) -> Self::Cartesian { fn to_cartesian(&self) -> Vec<f32> {
[self.x, self.y] vec![self.x, self.y]
} }
} }

View File

@ -51,7 +51,7 @@ pub struct ContinuousStorage {
} }
impl Position for P3 { impl Position for P3 {
type Cartesian = [f32; 3]; const DIM: usize = 3;
fn zero() -> Self { fn zero() -> Self {
P3 { x: 0f32, y: 0f32, z: 0f32 } P3 { x: 0f32, y: 0f32, z: 0f32 }
@ -61,12 +61,12 @@ impl Position for P3 {
(self.x.powi(2) + self.y.powi(2) + self.z.powi(2)).powf(0.5) (self.x.powi(2) + self.y.powi(2) + self.z.powi(2)).powf(0.5)
} }
fn from_cartesian(cartesian: Self::Cartesian) -> Self { fn from_cartesian(cartesian: &[f32]) -> Self {
P3 { x: cartesian[0], y: cartesian[1], z: cartesian[3] } P3 { x: cartesian[0], y: cartesian[1], z: cartesian[3] }
} }
fn to_cartesian(&self) -> Self::Cartesian { fn to_cartesian(&self) -> Vec<f32> {
[self.x, self.y, self.z] vec![self.x, self.y, self.z]
} }
} }

View File

@ -1,5 +1,6 @@
use std::ops::Add; use std::ops::Add;
use num_integer::Roots; use num_integer::Roots;
use num_traits::Pow;
use crate::system::{GriddedPosition, Position}; use crate::system::{GriddedPosition, Position};
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
@ -40,8 +41,7 @@ impl GriddedPosition for HexPosition {
} }
impl Position for HexPosition { impl Position for HexPosition {
// const DIM: usize = 2; const DIM: usize = 2;
type Cartesian = [f32; 2];
fn zero() -> Self { fn zero() -> Self {
HexPosition { q: 0, r: 0 } HexPosition { q: 0, r: 0 }
@ -51,17 +51,18 @@ impl Position for HexPosition {
((self.q.pow(2) + self.r.pow(2) + self.q * self.r) as f32).sqrt() ((self.q.pow(2) + self.r.pow(2) + self.q * self.r) as f32).sqrt()
} }
fn from_cartesian(cartesian: Self::Cartesian) -> Self { fn from_cartesian(cartesian: &[f32]) -> Self {
let q = (1.0f32 / 3.0f32).sqrt() * cartesian[0] - 1.0 / 3.0 * cartesian[1]; let q = (1.0f32 / 3.0f32).sqrt() * cartesian[0] - 1.0 / 3.0 * cartesian[1];
let r = 2.0 / 3.0 * cartesian[1]; let r = 2.0 / 3.0 * cartesian[1];
Self { q: q as i32, r: r as i32 } Self { q: q as i32, r: r as i32 }
} }
fn to_cartesian(&self) -> Self::Cartesian { fn to_cartesian(&self) -> Vec<f32> {
let q = self.q as f32; let q = self.q as f32;
let r = self.r as f32; let r = self.r as f32;
[
vec![
3f32.sqrt() * q + 3f32.sqrt() / 2f32 * r, 3f32.sqrt() * q + 3f32.sqrt() / 2f32 * r,
(3. / 2.) * r (3. / 2.) * r
] ]

View File

@ -28,7 +28,7 @@ impl Add for Grid2D {
} }
impl Position for Grid2D { impl Position for Grid2D {
type Cartesian = [f32; 2]; const DIM: usize = 2;
fn zero() -> Self { fn zero() -> Self {
Grid2D { x: 0, y: 0 } Grid2D { x: 0, y: 0 }
@ -38,15 +38,15 @@ impl Position for Grid2D {
(((self.x * self.x) + (self.y * self.y)) as f32).powf(0.5) (((self.x * self.x) + (self.y * self.y)) as f32).powf(0.5)
} }
fn from_cartesian(cartesian: Self::Cartesian) -> Self { fn from_cartesian(cartesian: &[f32]) -> Self {
Grid2D { Grid2D {
x: cartesian[0] as i32, x: cartesian[0] as i32,
y: cartesian[1] as i32, y: cartesian[1] as i32,
} }
} }
fn to_cartesian(&self) -> Self::Cartesian { fn to_cartesian(&self) -> Vec<f32> {
[self.x as f32, self.y as f32] vec![self.x as f32, self.y as f32]
} }
} }
@ -113,17 +113,17 @@ impl Add for Grid3D {
#[test] #[test]
fn grid3_add_test() { fn grid3_add_test() {
assert_eq!( assert_eq!(
Grid3D::from_cartesian([0f32, 0f32, 0f32]) + Grid3D::from_cartesian([0f32, 1f32, 0f32]), Grid3D::from_cartesian(&[0f32, 0f32, 0f32]) + Grid3D::from_cartesian(&[0f32, 1f32, 0f32]),
Grid3D::from_cartesian([0f32, 1f32, 0f32]) Grid3D::from_cartesian(&[0f32, 1f32, 0f32])
); );
assert_eq!( assert_eq!(
Grid3D::from_cartesian([5.0, 3.0, 1.0]) + Grid3D::from_cartesian([-2.0, 5.0, 100.0]), Grid3D::from_cartesian(&[5.0, 3.0, 1.0]) + Grid3D::from_cartesian(&[-2.0, 5.0, 100.0]),
Grid3D::from_cartesian([3.0, 8.0, 101.0]) Grid3D::from_cartesian(&[3.0, 8.0, 101.0])
); );
} }
impl Position for Grid3D { impl Position for Grid3D {
type Cartesian = [f32; 3]; const DIM: usize = 3;
fn zero() -> Self { fn zero() -> Self {
Grid3D { x: 0, y: 0, z: 0 } Grid3D { x: 0, y: 0, z: 0 }
@ -133,7 +133,7 @@ impl Position for Grid3D {
(((self.x * self.x) + (self.y * self.y) + (self.z * self.z)) as f32).powf(0.5) (((self.x * self.x) + (self.y * self.y) + (self.z * self.z)) as f32).powf(0.5)
} }
fn from_cartesian(cartesian: Self::Cartesian) -> Self { fn from_cartesian(cartesian: &[f32]) -> Self {
Self { Self {
x: cartesian[0] as i32, x: cartesian[0] as i32,
y: cartesian[1] as i32, y: cartesian[1] as i32,
@ -141,8 +141,8 @@ impl Position for Grid3D {
} }
} }
fn to_cartesian(&self) -> Self::Cartesian { fn to_cartesian(&self) -> Vec<f32> {
[self.x as f32, self.y as f32, self.z as f32] vec![self.x as f32, self.y as f32, self.z as f32]
} }
} }

View File

@ -17,7 +17,7 @@ impl Spawner<Grid2D> for UniformSpawner {
let theta = rng.gen_range(0f32..1.0) * 2.0 * PI; let theta = rng.gen_range(0f32..1.0) * 2.0 * PI;
let (x, y) = (radius * theta.cos(), radius * theta.sin()); let (x, y) = (radius * theta.cos(), radius * theta.sin());
Grid2D::from_cartesian([x, y]) Grid2D::from_cartesian(&[x, y])
} }
} }
@ -26,7 +26,7 @@ impl Spawner<HexPosition> for UniformSpawner {
let theta = rng.gen_range(0f32..1.0) * 2.0 * PI; let theta = rng.gen_range(0f32..1.0) * 2.0 * PI;
let (x, y) = (radius * theta.cos(), radius * theta.sin()); let (x, y) = (radius * theta.cos(), radius * theta.sin());
HexPosition::from_cartesian([x, y]) HexPosition::from_cartesian(&[x, y])
} }
} }
@ -41,7 +41,7 @@ impl Spawner<Grid3D> for UniformSpawner {
radius * theta.cos() radius * theta.cos()
); );
Grid3D::from_cartesian([x, y, z]) Grid3D::from_cartesian(&[x, y, z])
} }
} }

View File

@ -5,7 +5,7 @@ use polars::io::RowCount;
use rayon::prelude::*; use rayon::prelude::*;
use walkdir::WalkDir; use walkdir::WalkDir;
pub fn main(cli: &DataAnalysisCli) { pub(crate) fn main(cli: &DataAnalysisCli) {
let a: Vec<_> = WalkDir::new(&cli.sp_dir) let a: Vec<_> = WalkDir::new(&cli.sp_dir)
.into_iter() .into_iter()
.par_bridge() .par_bridge()

View File

@ -9,12 +9,16 @@ use crate::system::model::HistoryLine;
use crate::system::spaces::square_grid::Grid2D; use crate::system::spaces::square_grid::Grid2D;
use clap::Parser; use clap::Parser;
use colorous::Color; use colorous::Color;
use itertools::Itertools;
use num_traits::real::Real;
use num_traits::Signed;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::Deserialize; use serde::Deserialize;
use svg::Node; use svg::Node;
use svg::node::element::Rectangle; use svg::node::element::{Circle, Rectangle};
use crate::RenderCli; use crate::{RenderCli, Space};
use crate::system::Position; use crate::system::{GriddedPosition, Position};
use crate::system::spaces::continuous_2d::P2;
use crate::system::spaces::hexagonal::HexPosition; use crate::system::spaces::hexagonal::HexPosition;
use crate::tools::read; use crate::tools::read;
@ -26,68 +30,93 @@ struct Args {
} }
trait ToSvg { trait ToSvg {
fn to_svg(&self, size: i32, colour: Color) -> Box<dyn Node>; fn to_svg(&self, colour: Color) -> Box<dyn Node>;
} }
impl ToSvg for Grid2D { impl ToSvg for Grid2D {
fn to_svg(&self, size: i32, colour: Color) -> Box<dyn Node> { fn to_svg(&self, colour: Color) -> Box<dyn Node> {
Box::new(Rectangle::new() Box::new(Rectangle::new()
.set("fill", format!("rgb({}, {}, {})", colour.r, colour.g, colour.b)) .set("fill", format!("rgb({}, {}, {})", colour.r, colour.g, colour.b))
.set("width", size) .set("width", 1)
.set("height", size) .set("height", 1)
.set("x", self.x * size) .set("x", self.x)
.set("y", self.y * size)) .set("y", self.y))
}
}
impl ToSvg for P2 {
fn to_svg(&self, colour: Color) -> Box<dyn Node> {
Box::new(Circle::new()
.set("fill", format!("rgb({}, {}, {})", colour.r, colour.g, colour.b))
.set("r", 1)
.set("cx", self.x)
.set("cy", self.y))
} }
} }
impl ToSvg for HexPosition { impl ToSvg for HexPosition {
fn to_svg(&self, size: i32, colour: Color) -> Box<dyn Node> { fn to_svg(&self, colour: Color) -> Box<dyn Node> {
let points = [ let points = [
[25.045, 128.0], [256.0, 0.0], [486.955, 128.0], [486.955, 384.0], [256.0, 512.0], [25.045, 384.0] [25.045, 128.0], [256.0, 0.0], [486.955, 128.0], [486.955, 384.0], [256.0, 512.0], [25.045, 384.0]
]; ];
let size = size as f32;
let b = points.map(|x| [ let b = points.map(|x| [
(x[0] / 512.0) * (size), (x[0] / 512.0),
(x[1] / 512.0) * (size)] (x[1] / 512.0)]
); );
let c = b.map(|p| format!("{},{}", p[0], p[1])).join(" "); let c = b.map(|p| format!("{},{}", p[0], p[1])).join(" ");
let [x, y] = self.to_cartesian(); let cartesian = self.to_cartesian();
Box::new(Rectangle::new() Box::new(Rectangle::new()
.set("fill", format!("rgb({}, {}, {})", colour.r, colour.g, colour.b)) .set("fill", format!("rgb({}, {}, {})", colour.r, colour.g, colour.b))
.set("x", x * size) .set("x", cartesian[0])
.set("y", y * size)) .set("y", cartesian[1]))
} }
} }
pub(crate) fn main(args: &RenderCli) { pub fn compute_max_size<P: GriddedPosition>(positions: &[P]) -> f32 {
let positions: Vec<Grid2D> = read::<Grid2D>(&args.path, args.format); let mut positions = positions.iter().map(P::to_cartesian);
let mut maximums: Vec<f32> = positions.next().unwrap();
let size: i32 = args.image_size as i32; for cartesian in positions {
let max_x = positions.iter().max_by(|a, b| a.x.abs().cmp(&b.x.abs())).unwrap().x.abs(); for i in 0..maximums.len() {
let max_y = positions.iter().max_by(|a, b| a.y.abs().cmp(&b.y.abs())).unwrap().y.abs(); maximums[i] = maximums[i].abs().max(cartesian[i].abs());
let max_size = max_x.max(max_y) * size; }
}
maximums.into_iter()
.fold(0f32, |r, c| r.abs().max(c.abs()))
}
fn render<P: Position>(args: &RenderCli) where P: DeserializeOwned + ToSvg {
let positions = read::<Grid2D>(&args.path, args.format);
let max_size = compute_max_size(&positions);
let mut svg = svg::Document::new() let mut svg = svg::Document::new()
.set("width", max_size * size) .set("width", max_size)
.set("height", max_size * size) .set("height", max_size)
.set("viewBox", format!("{} {} {} {}", -max_size, -max_size, max_size * 2, max_size * 2)); .set("viewBox", format!("{} {} {} {}", -max_size, -max_size, max_size * 2.0, max_size * 2.0));
svg.append(Rectangle::new() svg.append(Rectangle::new()
.set("fill", "white") .set("fill", "white")
.set("width", max_size * 2) .set("width", max_size * 2.0)
.set("height", max_size * 2) .set("height", max_size * 2.0)
.set("x", -max_size) .set("x", -max_size)
.set("y", -max_size) .set("y", -max_size)
); );
for (n, position) in positions.iter().enumerate() { for (n, position) in positions.iter().enumerate() {
let colour = if args.colour { colorous::VIRIDIS.eval_rational(n, positions.len()) } else { Color::default() }; let colour = if args.colour { colorous::VIRIDIS.eval_rational(n, positions.len()) } else { Color::default() };
svg.append(position.to_svg(size, colour)); svg.append(position.to_svg(colour));
} }
svg::write(File::create(&args.output).unwrap(), &svg).unwrap(); svg::write(File::create(&args.output).unwrap(), &svg).unwrap();
} }
pub(crate) fn main(args: &RenderCli) {
match args.space {
Space::Grid2D => render::<Grid2D>(args),
Space::Continuous2D => render::<P2>(args),
}
}

View File

@ -1,5 +1,6 @@
#![feature(generic_const_exprs)] #![feature(generic_const_exprs)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(array_zip)]
use std::fs::File; use std::fs::File;
use std::ops::{Index, Mul}; use std::ops::{Index, Mul};
@ -33,6 +34,7 @@ enum ToolsCli {
#[derive(clap::ValueEnum, Clone, Debug, Copy)] #[derive(clap::ValueEnum, Clone, Debug, Copy)]
enum Space { enum Space {
Grid2D, Grid2D,
Continuous2D
} }
#[derive(Debug, Args)] #[derive(Debug, Args)]