Created
June 25, 2020 09:55
-
-
Save timClicks/c61c8e5c2f22625ef0ea917aa421f7a0 to your computer and use it in GitHub Desktop.
Implementating Circle Packing in Rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "circle-packing" | |
version = "0.1.0" | |
authors = ["Tim McNamara <[email protected]>"] | |
edition = "2018" | |
[dependencies] | |
nannou = "0.14" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// See these two great guides! | |
/// | |
/// https://generativeartistry.com/tutorials/circle-packing/ | |
/// https://guide.nannou.cc/tutorials/draw/drawing-2d-shapes.html | |
use nannou::prelude::*; | |
use nannou::color::{WHITESMOKE, POWDERBLUE}; | |
const LINE_WIDTH: f32 = 2.0; | |
const MIN_RADIUS: f32 = 2.0; | |
const MAX_RADIUS: f32 = 385.0; | |
const N_CIRCLES: usize = 3000; | |
const CREATE_CIRCLE_ATTEMPTS: usize = 500; | |
struct Model; | |
struct Circle { | |
x: f32, | |
y: f32, | |
radius: f32, | |
} | |
impl Circle { | |
fn collides(&self, other: &Circle) -> bool { | |
let a = self.radius + other.radius; | |
let x = self.x - other.x; | |
let y = self.y - other.y; | |
if a >= ((x*x) + (y*y)).sqrt() { | |
true | |
} else { | |
false | |
} | |
} | |
fn any_collision(&self, others: &Vec<Circle>) -> bool { | |
for other in others { | |
if self.collides(other) { | |
return true; | |
} | |
} | |
false | |
} | |
} | |
fn main() { | |
nannou::app(model).run(); | |
} | |
fn model(app: &App) -> Model { | |
app.set_loop_mode(LoopMode::loop_once()); | |
let _window = app | |
.new_window() | |
.view(view) | |
.build() | |
.unwrap(); | |
Model | |
} | |
fn view(app: &App, _model: &Model, frame: Frame) { | |
let window = app.window_rect(); | |
let draw = app.draw(); | |
draw.background() | |
.color(POWDERBLUE); | |
let mut circles = Vec::<Circle>::with_capacity(N_CIRCLES); | |
for _ in 0..=N_CIRCLES { | |
for _attempt in 0..=CREATE_CIRCLE_ATTEMPTS { | |
let x = random_range(window.left(), window.right()); | |
let y = random_range(window.top(), window.bottom()); | |
let radius = random_range(MIN_RADIUS, MAX_RADIUS); | |
let c = Circle { | |
x: x, | |
y: y, | |
radius: radius, | |
}; | |
if c.any_collision(&circles) { | |
continue; | |
} | |
circles.push(c); | |
break; | |
} | |
} | |
for c in circles { | |
let line_points = (0..=360).map(|i| { | |
// Convert each degree to radians. | |
let radian = deg_to_rad(i as f32); | |
// Get the sine of the radian to find the x co-ordinate of this point of the circle | |
// and multiply it by the radius. | |
let x_ = c.x + radian.sin() * c.radius; | |
// Do the same with cosine to find the y co-ordinate. | |
let y_ = c.y + radian.cos() * c.radius; | |
// Construct and return a point object with a color. | |
(pt2(x_, y_), WHITESMOKE) | |
}); | |
draw.polyline() | |
.weight(LINE_WIDTH) | |
.points_colored(line_points) | |
; | |
} | |
draw.to_frame(app, &frame).unwrap(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment