diff --git a/Cargo.toml b/Cargo.toml index f7877f7..8749e67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ nalgebra = "0.13" float-cmp = "0.2" itertools = "0.7" serde = { version = "1.0", optional = true } -clippy = {version = "0.0.180", optional = true} +clippy = {version = "0.0.186", optional = true} [dev-dependencies] kiss3d = "0.12" diff --git a/README.md b/README.md index 19d12fa..6c0848b 100644 --- a/README.md +++ b/README.md @@ -75,9 +75,9 @@ The reason this library was initially written was to optimise the layout of infl - 0.1.2 (Unreleased) - - Small performance improvements. + - Small performance improvements via algebraic simplifications and minimising vector allocations. - Add [itertools](https://github.com/bluss/rust-itertools) to simplify pair collection using `.collect_tuple()`. - - Added `statistics_emerald` as a benchmarking target. + - Added [sphere_pack](benches/sphere_pack.rs) benchmarking target using [criterion](https://github.com/japaric/criterion.rs). - 0.1.1 diff --git a/src/lib.rs b/src/lib.rs index 483170f..18eeb9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,7 +77,8 @@ use nalgebra::core::{Matrix, Matrix3}; use rand::Rng; use rand::distributions::IndependentSample; use itertools::Itertools; -use shapes::Sphere; +use shapes::{Cuboid, Sphere}; +//use std::collections::LinkedList; use float_cmp::ApproxEqRatio; use errors::SphericalCowError as Error; @@ -131,7 +132,9 @@ impl PackedVolume { /// Calculates the volume fraction ν = Vs/V: the volume of all spheres packed into a container /// divided by the volume of said container. /// - /// The higest possible volume fraction for any random radii distribution is currently unknown to + /// The [Kepler Conjecture](http://mathworld.wolfram.com/KeplerConjecture.html) suggests that the + /// densest possible volume fraction for equal sized spheres is ~74.05%. However, the higest possible + /// volume fraction for any random radii distribution is currently unknown to /// mathematicians. The algorithm implemented herin obtains 59.29% in a cube with side lengths of /// 90 with sphere radii between 0.01 and 0.02, compared with a long standing and well known /// [geometric compression algorithm](10.1016/j.powtec.2005.04.055) which achieved 52.89%. @@ -442,6 +445,86 @@ fn identify_f( Ok(()) } +/// A bounding box is a cuboid which has the same extents as the maximum extents of +/// an enclosed object. +trait BoundingBox { + /// Returns a cuboid containing the current object. + fn bb(&self) -> Result; + /// The bottom, left, back coordinate of the `BoundingBox`. + fn bb_lower_bound(&self) -> Point3; + /// The top, right, front coordinate of the `BoundingBox`. + fn bb_upper_bound(&self) -> Point3; +} + +impl BoundingBox for Sphere { + /// Returns a cuboid containing the current sphere. + fn bb(&self) -> Result { + // A spheres radius is equal to all of the cuboids half extents + let bounding_box = Cuboid::new(self.radius, self.radius, self.radius)?; + Ok(bounding_box) + } + + /// The bottom, left, back coordinate of the Sphere's `BoundingBox`. + fn bb_lower_bound(&self) -> Point3 { + Point3::new(self.center.x-self.radius,self.center.y-self.radius,self.center.z-self.radius) + } + + /// The top, right, front coordinate of the Sphere's `BoundingBox`. + fn bb_upper_bound(&self) -> Point3 { + Point3::new(self.center.x+self.radius,self.center.y+self.radius,self.center.z+self.radius) + } +} + +/// WIP. Will replace the `set_v` neighbour O(n^2) lookup with an O(n) method. +fn dcell(_set_v: &mut Vec, spheres: &[Sphere]) { + // Using vectors instead of linked lists for now, to see if that's possible or not. + let nx = (5-0)/1; + let ny = (5-0)/1; + let mut x_lists: Vec> = Vec::with_capacity(nx); + for _ in 0..nx { + x_lists.push(Vec::new()); + } + let mut y_lists: Vec> = Vec::with_capacity(ny); + for _ in 0..ny { + y_lists.push(Vec::new()); + } + for sphere in spheres.iter() { + let lower = sphere.bb_lower_bound(); + let ix = ((lower.x-0.)/1.) as usize; + let iy = ((lower.y-0.)/1.) as usize; + x_lists[ix].push(&sphere); + y_lists[iy].push(&sphere); + println!("ix {}, iy {}", ix + 1, iy + 1); + } + println!("{:?}", x_lists); + println!("{:?}", y_lists); +} + +#[test] +fn dcell_2d() { + let mut spheres = Vec::new(); + spheres.push(Sphere::new(Point3::new(3.7, 3.0, 0.), 0.7).unwrap()); + spheres.push(Sphere::new(Point3::new(1.5, 2.8, 0.), 0.3).unwrap()); + spheres.push(Sphere::new(Point3::new(1.4, 4.1, 0.), 0.7).unwrap()); + spheres.push(Sphere::new(Point3::new(3.1, 1.6, 0.), 0.2).unwrap()); + spheres.push(Sphere::new(Point3::new(2.7, 2.7, 0.), 0.6).unwrap()); + spheres.push(Sphere::new(Point3::new(3.7, 0.3, 0.), 0.7).unwrap()); + spheres.push(Sphere::new(Point3::new(1.8, 1.8, 0.), 0.7).unwrap()); + spheres.push(Sphere::new(Point3::new(0.3, 3.1, 0.), 0.7).unwrap()); + spheres.push(Sphere::new(Point3::new(3.7, 4.8, 0.), 0.2).unwrap()); + spheres.push(Sphere::new(Point3::new(2.0, 3.4, 0.), 0.4).unwrap()); + spheres.push(Sphere::new(Point3::new(4.2, 4.1, 0.), 0.4).unwrap()); + spheres.push(Sphere::new(Point3::new(2.5, 1.0, 0.), 0.4).unwrap()); + spheres.push(Sphere::new(Point3::new(0.5, 0.8, 0.), 0.5).unwrap()); + spheres.push(Sphere::new(Point3::new(3.6, 2.2, 0.), 0.5).unwrap()); + spheres.push(Sphere::new(Point3::new(0.2, 4.6, 0.), 0.6).unwrap()); + + let mut set_v = Vec::new(); + dcell(&mut set_v, &spheres); + + assert!(false); +} + #[test] fn init_spheres_err() { let container = Sphere::new(Point3::origin(), 0.1).unwrap();