use nannou::prelude::*; use rayon::prelude::*; mod recording; fn main() { nannou::app(model) .size(1440, 1440) .update(update) .simple_window(view) .run(); } #[derive(Clone)] struct Body { pos: DVec2, vel: DVec2, mass: i64, } struct Model { bodies: Vec, } fn model(_app: &App) -> Model { let mut bodies = Vec::new(); const MASS_SUN: i64 = 150000000000000000; bodies.push(Body { pos: (0.0, 0.0).into(), vel: (0.0, 0.0).into(), mass: MASS_SUN, }); const G: f64 = 6.67408e-11; const COPIES: i32 = 1; let d_theta: f64 = (360.0 / COPIES as f64).to_radians(); for i in 0..COPIES { let theta = i as f64 * d_theta; for i in 10..250 { let r = 5.0 * i as f64; let m = 10000000 / i; bodies.push(Body { pos: (r * theta.cos(), r * theta.sin()).into(), vel: (0.0, (G * MASS_SUN as f64 / r).sqrt()).into(), mass: m, }); } } Model { bodies } } fn update(app: &App, model: &mut Model, _update: Update) { const G: f64 = 6.67408e-11; let bodies = model.bodies.clone(); let delta_t = recording::delta_t(&app); model .bodies .par_iter_mut() .enumerate() .for_each(|(i, body)| { let mut acc: DVec2 = (0.0, 0.0).into(); bodies.iter().enumerate().for_each(|(j, other_body)| { if i == j { return; } let delta = other_body.pos - body.pos; let dist_sq = body.pos.distance_squared(other_body.pos); if dist_sq < 1.0 { return; } let acceleration = G * other_body.mass as f64 / dist_sq; acc += delta * acceleration / dist_sq.sqrt(); }); body.vel += acc * delta_t; body.pos += body.vel * delta_t; }); } fn view(app: &App, model: &Model, frame: Frame) { // let t = app.duration.since_start.as_secs_f64(); let draw = app.draw().scale(2.0); draw.background().color(BLACK); for body in model.bodies.iter() { let diameter = (body.mass as f32).log10(); // should be proportional to cuberoot but this is so we can actually see the small ones draw.ellipse().w_h(diameter, diameter).xy(body.pos.as_f32()); } draw.to_frame(app, &frame).unwrap(); recording::record(app, &frame); }