Compare commits
No commits in common. "192017d14e7878a930f999e71aec65e9a99dde66" and "9fe0337c9d35d4b15a27f038ac8e0d7246b944bf" have entirely different histories.
192017d14e
...
9fe0337c9d
2625
Cargo.lock
generated
2625
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
12
Cargo.toml
12
Cargo.toml
@ -5,10 +5,19 @@ edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
name = "dla"
|
||||
crate-type = ["staticlib"]
|
||||
path = "src/clib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "model"
|
||||
path = "src/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "ui"
|
||||
path = "src/ui.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "tools"
|
||||
path = "src/tools_cli.rs"
|
||||
@ -27,6 +36,7 @@ opt-level = 3
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.1.8", features = ["derive"] }
|
||||
bevy = { version = "0.10.0" }
|
||||
nd_array = "0.1.0"
|
||||
num-integer = "0.1.45"
|
||||
rand = { version = "0.8.5", features = ["default", "small_rng"] }
|
||||
@ -34,7 +44,7 @@ csv = "1.1"
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
serde_json = "1.0.93"
|
||||
kd-tree = { version = "0.5.1", features = ["nalgebra"] }
|
||||
nalgebra = { version = "0.32.2", features = ["serde-serialize"] }
|
||||
nalgebra = "0.32.2"
|
||||
kiddo = "0.2.5"
|
||||
anyhow = "1.0.69"
|
||||
itertools = "0.10.5"
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
# DLA Generic Model
|
||||
|
||||
A generic pluggable model for diffusion limited aggregation. Produces two executables,
|
||||
|
||||
- `./target/release/model`, built from `./src/main.rs`
|
||||
- `./target/release/tools`, built from `./src/tools_cli.rs`
|
||||
|
||||
Build with `cargo build --release`. Requires a working rust installation.
|
||||
16
build.rs
Normal file
16
build.rs
Normal file
@ -0,0 +1,16 @@
|
||||
extern crate cbindgen;
|
||||
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
use cbindgen::{Config, Builder};
|
||||
|
||||
fn main() {
|
||||
let crate_env = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
let crate_path = Path::new(&crate_env);
|
||||
let config = Config::from_root_or_default(crate_path);
|
||||
Builder::new().with_crate(crate_path.to_str().unwrap())
|
||||
.with_config(config)
|
||||
.generate()
|
||||
.expect("Cannot generate header file!")
|
||||
.write_to_file("libdla.h");
|
||||
}
|
||||
BIN
dla-eg.png
Normal file
BIN
dla-eg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
11
libdla.h
Normal file
11
libdla.h
Normal file
@ -0,0 +1,11 @@
|
||||
#include <cstdarg>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <ostream>
|
||||
#include <new>
|
||||
|
||||
extern "C" {
|
||||
|
||||
bool dla_rust_disabled();
|
||||
|
||||
} // extern "C"
|
||||
4
src/clib.rs
Normal file
4
src/clib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#[no_mangle]
|
||||
pub extern "C" fn dla_rust_disabled() -> bool {
|
||||
true
|
||||
}
|
||||
@ -7,4 +7,3 @@ pub mod hexagonal;
|
||||
|
||||
pub mod continuous_3d;
|
||||
pub mod continuous_2d;
|
||||
pub mod nalg;
|
||||
|
||||
@ -1,148 +0,0 @@
|
||||
use std::ops::Add;
|
||||
use itertools::Itertools;
|
||||
use nalgebra::{EuclideanNorm, LpNorm, Matrix, Norm, OMatrix, SVector};
|
||||
use num_traits::Pow;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::system::{GriddedPosition, Position, Storage};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct Gridded<const D: usize>(SVector<i32, D>);
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct Continuous<const D: usize>(SVector<f32, D>);
|
||||
|
||||
impl<const D: usize> Add for Continuous<D> {
|
||||
type Output = Continuous<D>;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Continuous(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const D: usize> Position for Continuous<D> {
|
||||
const DIM: usize = 0;
|
||||
|
||||
fn zero() -> Self {
|
||||
Continuous(SVector::<f32, D>::zeros())
|
||||
}
|
||||
|
||||
fn abs(&self) -> f32 {
|
||||
self.0.norm()
|
||||
}
|
||||
|
||||
fn from_cartesian(cartesian: &[f32]) -> Self {
|
||||
Continuous(SVector::<f32, D>::from_fn(|i, _| cartesian[i]))
|
||||
}
|
||||
|
||||
fn to_cartesian(&self) -> Vec<f32> {
|
||||
self.0.as_slice().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const D: usize> Add for Gridded<D> {
|
||||
type Output = Gridded<D>;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Gridded(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const D: usize> Position for Gridded<D> {
|
||||
const DIM: usize = 0;
|
||||
|
||||
fn zero() -> Self {
|
||||
Gridded(SVector::<i32, D>::zeros())
|
||||
}
|
||||
|
||||
fn abs(&self) -> f32 {
|
||||
(self.0.fold(0, |r, c| r + c.pow(2)) as f32).sqrt()
|
||||
}
|
||||
|
||||
fn from_cartesian(cartesian: &[f32]) -> Self {
|
||||
Gridded(SVector::<i32, D>::from_fn(|i, _| cartesian[i] as i32))
|
||||
}
|
||||
|
||||
fn to_cartesian(&self) -> Vec<f32> {
|
||||
self.0.as_slice()
|
||||
.iter()
|
||||
.map(|a| *a as f32)
|
||||
.collect_vec()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KDSpace<const N: usize>(pub(crate) kiddo::KdTree<f32, (), N>);
|
||||
|
||||
impl<const D: usize> Storage<Gridded<D>> for KDSpace<D> {
|
||||
fn is_occupied(&self, position: &Gridded<D>) -> bool {
|
||||
let a = self.0.best_n_within(
|
||||
&position.0.data.0[0].map(|i| i as f32),
|
||||
0f32,
|
||||
1,
|
||||
&|a, b| {
|
||||
LpNorm(1).metric_distance(
|
||||
&SVector::<f32, D>::from_row_slice(a),
|
||||
&SVector::<f32, D>::from_row_slice(b),
|
||||
)
|
||||
},
|
||||
).unwrap();
|
||||
|
||||
!a.is_empty()
|
||||
}
|
||||
|
||||
fn deposit(&mut self, position: &Gridded<D>) {
|
||||
self.0.add(&position.0.data.0[0].map(|i| i as f32), ())
|
||||
.expect("Failed to write to space")
|
||||
}
|
||||
}
|
||||
|
||||
impl<const D: usize> Storage<Continuous<D>> for KDSpace<D> {
|
||||
fn is_occupied(&self, position: &Continuous<D>) -> bool {
|
||||
let a = self.0.best_n_within(
|
||||
&position.0.data.0[0],
|
||||
0f32,
|
||||
1,
|
||||
&|a, b| {
|
||||
EuclideanNorm.metric_distance(
|
||||
&SVector::<f32, D>::from_row_slice(a),
|
||||
&SVector::<f32, D>::from_row_slice(b),
|
||||
)
|
||||
},
|
||||
).unwrap();
|
||||
|
||||
!a.is_empty()
|
||||
}
|
||||
|
||||
fn deposit(&mut self, position: &Continuous<D>) {
|
||||
self.0.add(&position.0.data.0[0], ())
|
||||
.expect("Failed to write to space")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VectorStorage {
|
||||
backing: Vec<bool>,
|
||||
grid_size: usize,
|
||||
}
|
||||
|
||||
impl<const D: usize> Storage<Gridded<D>> for VectorStorage {
|
||||
fn is_occupied(&self, position: &Gridded<D>) -> bool {
|
||||
let mut index: usize = 0;
|
||||
|
||||
for i in 0..D {
|
||||
index += (position.0[i] + (self.grid_size as i32 / 2)) as usize * self.grid_size * i;
|
||||
}
|
||||
|
||||
return self.backing[index];
|
||||
}
|
||||
|
||||
fn deposit(&mut self, position: &Gridded<D>) {
|
||||
let mut index: usize = 0;
|
||||
|
||||
for i in 0..D {
|
||||
index += (position.0[i] + (self.grid_size as i32 / 2)) as usize * self.grid_size * i;
|
||||
}
|
||||
|
||||
self.backing[index] = true;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
use std::hash::Hash;
|
||||
use bevy::render::render_resource::encase::private::RuntimeSizedArray;
|
||||
use itertools::Itertools;
|
||||
use rand::distributions::Slice;
|
||||
use rand::prelude::Rng;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use std::fs::File;
|
||||
use std::os::unix::fs::symlink;
|
||||
use bevy::tasks::ParallelSlice;
|
||||
use crate::system::spaces::square_grid::{Grid2D, Grid3D};
|
||||
use itertools::{Itertools, MinMaxResult};
|
||||
use clap::Parser;
|
||||
|
||||
@ -96,8 +96,8 @@ fn render<P: Position>(args: &RenderCli) where P: DeserializeOwned + ToSvg {
|
||||
let max_size = compute_max_size(&positions) + 10.0;
|
||||
|
||||
let mut svg = svg::Document::new()
|
||||
.set("width", args.image_size)
|
||||
.set("height", args.image_size)
|
||||
.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()
|
||||
|
||||
108
src/ui.rs
Normal file
108
src/ui.rs
Normal file
@ -0,0 +1,108 @@
|
||||
//! A simplified implementation of the classic game "Breakout".
|
||||
|
||||
use bevy::{
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
// These constants are defined in `Transform` units.
|
||||
// Using the default 2D camera they correspond 1:1 with screen pixels.
|
||||
const GAP_BETWEEN_PADDLE_AND_FLOOR: f32 = 60.0;
|
||||
|
||||
const LEFT_WALL: f32 = -450.;
|
||||
const RIGHT_WALL: f32 = 450.;
|
||||
// y coordinates
|
||||
const BOTTOM_WALL: f32 = -300.;
|
||||
const TOP_WALL: f32 = 300.;
|
||||
|
||||
const PARTICLE_SIZE: Vec2 = Vec2::new(10., 10.);
|
||||
|
||||
// These values are exact
|
||||
const GAP_BETWEEN_PADDLE_AND_BRICKS: f32 = 270.0;
|
||||
const GAP_BETWEEN_BRICKS: f32 = 5.0;
|
||||
// These values are lower bounds, as the number of bricks is computed
|
||||
const GAP_BETWEEN_BRICKS_AND_CEILING: f32 = 20.0;
|
||||
const GAP_BETWEEN_BRICKS_AND_SIDES: f32 = 20.0;
|
||||
|
||||
const BACKGROUND_COLOR: Color = Color::rgb(0.9, 0.9, 0.9);
|
||||
const BRICK_COLOR: Color = Color::rgb(0.5, 0.5, 1.0);
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.insert_resource(ClearColor(BACKGROUND_COLOR))
|
||||
.add_startup_system(setup)
|
||||
.add_system(bevy::window::close_on_esc)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
struct Brick;
|
||||
|
||||
// Add the game's entities to our world
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
) {
|
||||
// Camera
|
||||
commands.spawn(Camera2dBundle::default());
|
||||
|
||||
// Paddle
|
||||
let paddle_y = BOTTOM_WALL + GAP_BETWEEN_PADDLE_AND_FLOOR;
|
||||
|
||||
// Bricks
|
||||
// Negative scales result in flipped sprites / meshes,
|
||||
// which is definitely not what we want here
|
||||
assert!(PARTICLE_SIZE.x > 0.0);
|
||||
assert!(PARTICLE_SIZE.y > 0.0);
|
||||
|
||||
let total_width_of_bricks = (RIGHT_WALL - LEFT_WALL) - 2. * GAP_BETWEEN_BRICKS_AND_SIDES;
|
||||
let bottom_edge_of_bricks = paddle_y + GAP_BETWEEN_PADDLE_AND_BRICKS;
|
||||
let total_height_of_bricks = TOP_WALL - bottom_edge_of_bricks - GAP_BETWEEN_BRICKS_AND_CEILING;
|
||||
|
||||
assert!(total_width_of_bricks > 0.0);
|
||||
assert!(total_height_of_bricks > 0.0);
|
||||
|
||||
// Given the space available, compute how many rows and columns of bricks we can fit
|
||||
let n_columns = (total_width_of_bricks / (PARTICLE_SIZE.x + GAP_BETWEEN_BRICKS)).floor() as usize;
|
||||
let n_rows = (total_height_of_bricks / (PARTICLE_SIZE.y + GAP_BETWEEN_BRICKS)).floor() as usize;
|
||||
let n_vertical_gaps = n_columns - 1;
|
||||
|
||||
// Because we need to round the number of columns,
|
||||
// the space on the top and sides of the bricks only captures a lower bound, not an exact value
|
||||
let center_of_bricks = (LEFT_WALL + RIGHT_WALL) / 2.0;
|
||||
let left_edge_of_bricks = center_of_bricks
|
||||
// Space taken up by the bricks
|
||||
- (n_columns as f32 / 2.0 * PARTICLE_SIZE.x)
|
||||
// Space taken up by the gaps
|
||||
- n_vertical_gaps as f32 / 2.0 * GAP_BETWEEN_BRICKS;
|
||||
|
||||
// In Bevy, the `translation` of an entity describes the center point,
|
||||
// not its bottom-left corner
|
||||
let offset_x = left_edge_of_bricks + PARTICLE_SIZE.x / 2.;
|
||||
let offset_y = bottom_edge_of_bricks + PARTICLE_SIZE.y / 2.;
|
||||
|
||||
for row in 0..n_rows {
|
||||
for column in 0..n_columns {
|
||||
let brick_position = Vec2::new(
|
||||
offset_x + column as f32 * (PARTICLE_SIZE.x + GAP_BETWEEN_BRICKS),
|
||||
offset_y + row as f32 * (PARTICLE_SIZE.y + GAP_BETWEEN_BRICKS),
|
||||
);
|
||||
|
||||
// brick
|
||||
commands.spawn((
|
||||
SpriteBundle {
|
||||
sprite: Sprite {
|
||||
color: BRICK_COLOR,
|
||||
..default()
|
||||
},
|
||||
transform: Transform {
|
||||
translation: brick_position.extend(0.0),
|
||||
scale: Vec3::new(PARTICLE_SIZE.x, PARTICLE_SIZE.y, 1.0),
|
||||
..default()
|
||||
},
|
||||
..default()
|
||||
},
|
||||
Brick,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user