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",
"nd_array",
"num-integer",
"num-traits",
"parquet",
"polars",
"rand",

View File

@ -65,6 +65,7 @@ rayon = "1.7.0"
walkdir = "2.3.3"
parquet = { version = "35.0.0", features = ["serde"] }
colorous = "1.0.10"
num-traits = "0.2.15"
[build-dependencies]
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 trait Position: Add<Output=Self> + Serialize + Clone {
// const DIM: usize;
type Cartesian;
const DIM: usize;
// type Cartesian;
fn zero() -> Self;
fn abs(&self) -> f32;
fn from_cartesian(cartesian: Self::Cartesian) -> Self;
fn to_cartesian(&self) -> Self::Cartesian;
fn from_cartesian(cartesian: &[f32]) -> Self;
fn to_cartesian(&self) -> Vec<f32>;
}
pub trait GriddedPosition: Position {

View File

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

View File

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

View File

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

View File

@ -28,7 +28,7 @@ impl Add for Grid2D {
}
impl Position for Grid2D {
type Cartesian = [f32; 2];
const DIM: usize = 2;
fn zero() -> Self {
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)
}
fn from_cartesian(cartesian: Self::Cartesian) -> Self {
fn from_cartesian(cartesian: &[f32]) -> Self {
Grid2D {
x: cartesian[0] as i32,
y: cartesian[1] as i32,
}
}
fn to_cartesian(&self) -> Self::Cartesian {
[self.x as f32, self.y as f32]
fn to_cartesian(&self) -> Vec<f32> {
vec![self.x as f32, self.y as f32]
}
}
@ -113,17 +113,17 @@ impl Add for Grid3D {
#[test]
fn grid3_add_test() {
assert_eq!(
Grid3D::from_cartesian([0f32, 0f32, 0f32]) + Grid3D::from_cartesian([0f32, 1f32, 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])
);
assert_eq!(
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(&[5.0, 3.0, 1.0]) + Grid3D::from_cartesian(&[-2.0, 5.0, 100.0]),
Grid3D::from_cartesian(&[3.0, 8.0, 101.0])
);
}
impl Position for Grid3D {
type Cartesian = [f32; 3];
const DIM: usize = 3;
fn zero() -> Self {
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)
}
fn from_cartesian(cartesian: Self::Cartesian) -> Self {
fn from_cartesian(cartesian: &[f32]) -> Self {
Self {
x: cartesian[0] as i32,
y: cartesian[1] as i32,
@ -141,8 +141,8 @@ impl Position for Grid3D {
}
}
fn to_cartesian(&self) -> Self::Cartesian {
[self.x as f32, self.y as f32, self.z as f32]
fn to_cartesian(&self) -> Vec<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 (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 (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()
);
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 walkdir::WalkDir;
pub fn main(cli: &DataAnalysisCli) {
pub(crate) fn main(cli: &DataAnalysisCli) {
let a: Vec<_> = WalkDir::new(&cli.sp_dir)
.into_iter()
.par_bridge()

View File

@ -9,12 +9,16 @@ use crate::system::model::HistoryLine;
use crate::system::spaces::square_grid::Grid2D;
use clap::Parser;
use colorous::Color;
use itertools::Itertools;
use num_traits::real::Real;
use num_traits::Signed;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use svg::Node;
use svg::node::element::Rectangle;
use crate::RenderCli;
use crate::system::Position;
use svg::node::element::{Circle, Rectangle};
use crate::{RenderCli, Space};
use crate::system::{GriddedPosition, Position};
use crate::system::spaces::continuous_2d::P2;
use crate::system::spaces::hexagonal::HexPosition;
use crate::tools::read;
@ -26,68 +30,93 @@ struct Args {
}
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 {
fn to_svg(&self, size: i32, colour: Color) -> Box<dyn Node> {
fn to_svg(&self, colour: Color) -> Box<dyn Node> {
Box::new(Rectangle::new()
.set("fill", format!("rgb({}, {}, {})", colour.r, colour.g, colour.b))
.set("width", size)
.set("height", size)
.set("x", self.x * size)
.set("y", self.y * size))
.set("width", 1)
.set("height", 1)
.set("x", self.x)
.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 {
fn to_svg(&self, size: i32, colour: Color) -> Box<dyn Node> {
fn to_svg(&self, colour: Color) -> Box<dyn Node> {
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]
];
let size = size as f32;
let b = points.map(|x| [
(x[0] / 512.0) * (size),
(x[1] / 512.0) * (size)]
(x[0] / 512.0),
(x[1] / 512.0)]
);
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()
.set("fill", format!("rgb({}, {}, {})", colour.r, colour.g, colour.b))
.set("x", x * size)
.set("y", y * size))
.set("x", cartesian[0])
.set("y", cartesian[1]))
}
}
pub(crate) fn main(args: &RenderCli) {
let positions: Vec<Grid2D> = read::<Grid2D>(&args.path, args.format);
pub fn compute_max_size<P: GriddedPosition>(positions: &[P]) -> f32 {
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;
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;
for cartesian in positions {
for i in 0..maximums.len() {
maximums[i] = maximums[i].abs().max(cartesian[i].abs());
}
}
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()
.set("width", max_size * size)
.set("height", max_size * size)
.set("viewBox", format!("{} {} {} {}", -max_size, -max_size, max_size * 2, max_size * 2));
.set("width", max_size)
.set("height", max_size)
.set("viewBox", format!("{} {} {} {}", -max_size, -max_size, max_size * 2.0, max_size * 2.0));
svg.append(Rectangle::new()
.set("fill", "white")
.set("width", max_size * 2)
.set("height", max_size * 2)
.set("width", max_size * 2.0)
.set("height", max_size * 2.0)
.set("x", -max_size)
.set("y", -max_size)
);
for (n, position) in positions.iter().enumerate() {
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();
}
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(let_chains)]
#![feature(array_zip)]
use std::fs::File;
use std::ops::{Index, Mul};
@ -33,6 +34,7 @@ enum ToolsCli {
#[derive(clap::ValueEnum, Clone, Debug, Copy)]
enum Space {
Grid2D,
Continuous2D
}
#[derive(Debug, Args)]