orbital mechanics :D
parent
fc8f7775ba
commit
6bb5d90d54
|
@ -1 +1,5 @@
|
||||||
/target
|
/target
|
||||||
|
|
||||||
|
# ffmpeg -framerate 60 -i recordings/%05d.png -pix_fmt yuv420p recording.mp4
|
||||||
|
/recordings
|
||||||
|
/recording.mp4
|
||||||
|
|
|
@ -2240,6 +2240,7 @@ name = "sketch-gravity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nannou",
|
"nannou",
|
||||||
|
"once_cell",
|
||||||
"rayon",
|
"rayon",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -7,4 +7,5 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nannou = "0.17.1"
|
nannou = "0.17.1"
|
||||||
|
once_cell = "1.8.0"
|
||||||
rayon = "1.5.1"
|
rayon = "1.5.1"
|
||||||
|
|
52
src/main.rs
52
src/main.rs
|
@ -1,14 +1,21 @@
|
||||||
use nannou::prelude::*;
|
use nannou::prelude::*;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
|
||||||
|
mod recording;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
nannou::app(model).update(update).simple_window(view).run();
|
nannou::app(model)
|
||||||
|
.size(1440, 1440)
|
||||||
|
.update(update)
|
||||||
|
.simple_window(view)
|
||||||
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Body {
|
struct Body {
|
||||||
pos: DVec2,
|
pos: DVec2,
|
||||||
vel: DVec2,
|
vel: DVec2,
|
||||||
|
mass: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Model {
|
struct Model {
|
||||||
|
@ -18,17 +25,33 @@ struct Model {
|
||||||
fn model(_app: &App) -> Model {
|
fn model(_app: &App) -> Model {
|
||||||
let mut bodies = Vec::new();
|
let mut bodies = Vec::new();
|
||||||
|
|
||||||
let mut theta = 0.0;
|
const MASS_SUN: i64 = 150000000000000000;
|
||||||
for r in 0..512 {
|
|
||||||
let r = r as f64;
|
bodies.push(Body {
|
||||||
let r = 10.0 * r.sqrt();
|
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 {
|
bodies.push(Body {
|
||||||
pos: (r * theta.cos(), r * theta.sin()).into(),
|
pos: (r * theta.cos(), r * theta.sin()).into(),
|
||||||
vel: (0.0, 0.0).into(),
|
vel: (0.0, (G * MASS_SUN as f64 / r).sqrt()).into(),
|
||||||
|
mass: m,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
theta += 1.94161103873;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Model { bodies }
|
Model { bodies }
|
||||||
|
@ -38,7 +61,7 @@ fn update(app: &App, model: &mut Model, _update: Update) {
|
||||||
const G: f64 = 6.67408e-11;
|
const G: f64 = 6.67408e-11;
|
||||||
|
|
||||||
let bodies = model.bodies.clone();
|
let bodies = model.bodies.clone();
|
||||||
let delta_t = app.duration.since_prev_update.as_secs_f64();
|
let delta_t = recording::delta_t(&app);
|
||||||
|
|
||||||
model
|
model
|
||||||
.bodies
|
.bodies
|
||||||
|
@ -59,10 +82,9 @@ fn update(app: &App, model: &mut Model, _update: Update) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let force = G * /* × mass_a × mass_b = */ 1e14 / dist_sq;
|
let acceleration = G * other_body.mass as f64 / dist_sq;
|
||||||
|
|
||||||
acc += delta * force / dist_sq.sqrt();
|
acc += delta * acceleration / dist_sq.sqrt();
|
||||||
acc -= 0.5 * delta / (dist_sq * 0.5);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
body.vel += acc * delta_t;
|
body.vel += acc * delta_t;
|
||||||
|
@ -73,12 +95,14 @@ fn update(app: &App, model: &mut Model, _update: Update) {
|
||||||
fn view(app: &App, model: &Model, frame: Frame) {
|
fn view(app: &App, model: &Model, frame: Frame) {
|
||||||
// let t = app.duration.since_start.as_secs_f64();
|
// let t = app.duration.since_start.as_secs_f64();
|
||||||
|
|
||||||
let draw = app.draw();
|
let draw = app.draw().scale(2.0);
|
||||||
draw.background().color(BLACK);
|
draw.background().color(BLACK);
|
||||||
|
|
||||||
for body in model.bodies.iter() {
|
for body in model.bodies.iter() {
|
||||||
draw.ellipse().w_h(10.0, 10.0).xy(body.pos.as_f32());
|
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();
|
draw.to_frame(app, &frame).unwrap();
|
||||||
|
recording::record(app, &frame);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
use nannou::prelude::*;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
|
static RECORDING: Lazy<bool> = Lazy::new(|| {
|
||||||
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
args.iter().any(|s| s == "--record")
|
||||||
|
});
|
||||||
|
|
||||||
|
pub fn record(app: &App, frame: &Frame) {
|
||||||
|
if !*RECORDING {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// save frame
|
||||||
|
let path = app
|
||||||
|
.project_path()
|
||||||
|
.expect("failed to locate `project_path`")
|
||||||
|
// Capture all frames to a directory called `/<path_to_nannou>/nannou/simple_capture`.
|
||||||
|
.join("recordings")
|
||||||
|
// Name each file after the number of the frame.
|
||||||
|
.join(format!("{:05}", frame.nth()))
|
||||||
|
// The extension will be PNG. We also support tiff, bmp, gif, jpeg, webp and some others.
|
||||||
|
.with_extension("png");
|
||||||
|
println!("frame: {} {:.05}", frame.nth(), frame.nth() as f32 / 60.0);
|
||||||
|
app.main_window().capture_frame(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delta_t(app: &App) -> f64 {
|
||||||
|
if *RECORDING {
|
||||||
|
1.0 / 60.0
|
||||||
|
} else {
|
||||||
|
app.duration.since_prev_update.as_secs_f64()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue