diff --git a/.gitignore b/.gitignore index 3acd3cc..16b3535 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target *.csv *.wav +*.png diff --git a/Cargo.lock b/Cargo.lock index a57e185..60f0e34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,18 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + [[package]] name = "autocfg" version = "1.5.1" @@ -26,6 +38,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + [[package]] name = "bytemuck" version = "1.25.2" @@ -68,13 +86,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "dpsim" -version = "0.1.0" -dependencies = [ - "macroquad", -] - [[package]] name = "equivalent" version = "1.0.3" @@ -144,7 +155,7 @@ dependencies = [ "byteorder", "color_quant", "num-traits", - "png", + "png 0.17.16", ] [[package]] @@ -159,6 +170,12 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + [[package]] name = "macroquad" version = "0.4.16" @@ -250,7 +267,20 @@ version = "0.17.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" dependencies = [ - "bitflags", + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide 0.8.9", +] + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.13.2", "crc32fast", "fdeflate", "flate2", @@ -269,6 +299,46 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + +[[package]] +name = "symplectic-double-pendulum" +version = "0.1.0" +dependencies = [ + "macroquad", + "tiny-skia", +] + +[[package]] +name = "tiny-skia" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47ffee5eaaf5527f630fb0e356b90ebdec84d5d18d937c5e440350f88c5a91ea" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png 0.18.1", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca365c3faccca67d06593c5980fa6c57687de727a03131735bb85f01fdeeb9" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + [[package]] name = "ttf-parser" version = "0.25.1" diff --git a/Cargo.toml b/Cargo.toml index 2cf6a48..fedd98f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,4 @@ edition = "2024" [dependencies] macroquad = "0.4.16" +tiny-skia = "0.12.0" diff --git a/README.md b/README.md index f32ed23..6efd97a 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,13 @@ the simulation can be ran with: cargo run --bin anim ``` +Alternatively you can generate a trace image of the path the outer bob +takes with: + +``` +cargo run --bin trace +``` + ## License Copyright © Camden Dixie O'Brien, available under the Komorebi 2.0.0 diff --git a/src/bin/trace.rs b/src/bin/trace.rs new file mode 100644 index 0000000..c5bd34c --- /dev/null +++ b/src/bin/trace.rs @@ -0,0 +1,58 @@ +use symplectic_double_pendulum::*; + +use tiny_skia::*; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 800; + +const MIN: f32 = -2.0; +const MAX: f32 = 2.0; +const MARGIN: f32 = 0.2; + +fn system_xy(q: &DoublePendulum) -> [f64; 2] { + [ + q.theta.sin() + (q.theta + q.phi).sin(), + q.theta.cos() + (q.theta + q.phi).cos() + ] +} + +fn canvas_xy(q: &DoublePendulum) -> [f32; 2] { + system_xy(q).map(|x| (x as f32 * (1.0 - MARGIN) - MIN) * WIDTH as f32 / (MAX - MIN)) +} + +fn main() { + let omega = 500.0; + let h = 1e-3; + let t = 20.0; + + let mut state = Augmented::from(State { + q: DoublePendulum { theta: std::f64::consts::PI, phi: 0.1 }, + p: DoublePendulum { theta: 0.0, phi: 0.0 }, + }, omega); + + let path = { + let mut pb = PathBuilder::new(); + + let [x, y] = canvas_xy(&state.average().q); + pb.move_to(x, y); + + let n = (t / h) as u32; + for _ in 0..n { + state.evolve(h); + let [x, y] = canvas_xy(&state.average().q); + pb.line_to(x, y); + } + + pb.finish().unwrap() + }; + + let mut paint = Paint::default(); + paint.set_color_rgba8(0, 0, 0, 0xff); + paint.anti_alias = true; + let mut stroke = Stroke::default(); + stroke.width = 4.0; + stroke.line_cap = LineCap::Round; + let mut pixmap = Pixmap::new(WIDTH, HEIGHT).unwrap(); + pixmap.stroke_path(&path, &paint, &stroke, Transform::identity(), None); + pixmap.save_png("trace.png").unwrap(); +}