Compare commits
10 commits
a4408e624c
...
4b1933f3f8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b1933f3f8 | ||
|
|
fb06e9cb9e | ||
|
|
05abba5afe | ||
|
|
493af1e71c | ||
|
|
1eaa48d511 | ||
|
|
2feaed6fd5 | ||
|
|
de5f28b4f7 | ||
|
|
57e28360a0 | ||
|
|
8c713df698 | ||
|
|
2c457ae91f |
5 changed files with 197 additions and 88 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
|
@ -4,21 +4,21 @@ version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.4.0"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.9.0"
|
version = "2.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.20"
|
version = "1.2.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
|
checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
@ -34,9 +34,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.172"
|
version = "0.2.174"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libflac-sys"
|
name = "libflac-sys"
|
||||||
|
|
|
||||||
26
src/link.rs
26
src/link.rs
|
|
@ -1,29 +1,31 @@
|
||||||
|
use crate::math;
|
||||||
use crate::particle::Particle;
|
use crate::particle::Particle;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct Link {
|
pub struct Link {
|
||||||
p1: Rc<RefCell<Particle>>,
|
p1: Rc<RefCell<Particle>>,
|
||||||
p2: Rc<RefCell<Particle>>,
|
p2: Rc<RefCell<Particle>>,
|
||||||
length: f32
|
length: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Link {
|
impl Link {
|
||||||
pub fn new(p1: Rc<RefCell<Particle>>, p2: Rc<RefCell<Particle>>, length: f32) -> Self {
|
pub fn new(p1: Rc<RefCell<Particle>>, p2: Rc<RefCell<Particle>>, length: f32) -> Self {
|
||||||
Link {
|
Link { p1, p2, length }
|
||||||
p1: p1,
|
|
||||||
p2: p2,
|
|
||||||
length: length
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn solve(&mut self) {
|
pub fn solve(&mut self) {
|
||||||
let vec = self.p2.borrow().pos - self.p1.borrow().pos;
|
let vec = self.p2.borrow().pos - self.p1.borrow().pos;
|
||||||
let vec_len = (vec.x*vec.x + vec.y*vec.y).sqrt();
|
let vec_len = math::vec_len(vec);
|
||||||
let vec_norm = vec/vec_len;
|
|
||||||
let vec_scaled = vec_norm * (self.length-vec_len) * 9.;
|
|
||||||
|
|
||||||
self.p1.borrow_mut().apply_force(-vec_scaled);
|
if vec_len > self.length {
|
||||||
self.p2.borrow_mut().apply_force(vec_scaled);
|
let vec_norm = vec / vec_len;
|
||||||
|
|
||||||
|
let displacement = self.length - vec_len;
|
||||||
|
let vec_scaled = vec_norm * displacement / 2.;
|
||||||
|
|
||||||
|
self.p1.borrow_mut().apply_vel(-vec_scaled);
|
||||||
|
self.p2.borrow_mut().apply_vel(vec_scaled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
197
src/main.rs
197
src/main.rs
|
|
@ -1,9 +1,11 @@
|
||||||
use sfml::graphics::*;
|
|
||||||
use sfml::window::*;
|
|
||||||
use sfml::SfResult;
|
use sfml::SfResult;
|
||||||
use sfml::system::{Vector2f, Clock};
|
use sfml::graphics::*;
|
||||||
use std::rc::Rc;
|
use sfml::system::{Clock, Vector2f};
|
||||||
|
use sfml::window::*;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
mod math;
|
||||||
|
|
||||||
mod particle;
|
mod particle;
|
||||||
use particle::Particle;
|
use particle::Particle;
|
||||||
|
|
@ -11,67 +13,148 @@ use particle::Particle;
|
||||||
mod link;
|
mod link;
|
||||||
use link::Link;
|
use link::Link;
|
||||||
|
|
||||||
//const GRAVITY: f32 = 100.;
|
const WIN_WIDTH: u32 = 800;
|
||||||
|
const WIN_HEIGHT: u32 = 600;
|
||||||
|
|
||||||
fn populate_particles(mut particles: Vec<Rc<RefCell<Particle>>>, num: u32) {
|
const GRAVITY: Vector2f = Vector2f::new(0., 1500.);
|
||||||
for i in 0..=num {
|
|
||||||
particles.push(Rc::new(RefCell::new(Particle::new(Vector2f::new(100. * i as f32, 300.)))));
|
const SUBSTEP_COUNT: u32 = 16;
|
||||||
|
|
||||||
|
fn populate_particles(particles: &mut Vec<Rc<RefCell<Particle>>>, num: u32, cols: u32) {
|
||||||
|
for i in 0..num {
|
||||||
|
const OFFSET: u32 = 10;
|
||||||
|
let x_pos = (/* WIN_WIDTH/2 - cols/2*OFFSET */120 + OFFSET * (i % cols)) as f32;
|
||||||
|
let y_pos = (/* WIN_HEIGHT/2 - (num/cols)/2*OFFSET */40 + OFFSET * (i / cols)) as f32;
|
||||||
|
let immovable = i == 0 || i == cols - 1 || i == (cols / 2);
|
||||||
|
let particle = Particle::new((x_pos, y_pos), immovable);
|
||||||
|
particles.push(Rc::new(RefCell::new(particle)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn populate_links(links: Vec<Link>, particles: Vec<Rc<RefCell<Particle>>>) {
|
fn populate_circles(circles: &mut Vec<CircleShape>, num: u32, rad: f32, pts: usize) {
|
||||||
|
for _ in 0..num {
|
||||||
|
let mut circle = CircleShape::new(rad, pts);
|
||||||
|
circle.set_origin((rad, rad));
|
||||||
|
circles.push(circle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_forces(particles: Vec<Rc<RefCell<Particle>>>) {
|
fn populate_links(
|
||||||
|
links: &mut Vec<Link>,
|
||||||
|
particles: &[Rc<RefCell<Particle>>],
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
) {
|
||||||
|
for y in 0..height {
|
||||||
|
for x in 0..width {
|
||||||
|
let i = y * width + x;
|
||||||
|
|
||||||
|
if x < width - 1 {
|
||||||
|
let right = i + 1;
|
||||||
|
let dist = math::vec_len(particles[i].borrow().pos - particles[right].borrow().pos);
|
||||||
|
let link = Link::new(Rc::clone(&particles[i]), Rc::clone(&particles[right]), dist);
|
||||||
|
links.push(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
if y < height - 1 {
|
||||||
|
let below = i + width;
|
||||||
|
let dist = math::vec_len(particles[i].borrow().pos - particles[below].borrow().pos);
|
||||||
|
let link = Link::new(Rc::clone(&particles[i]), Rc::clone(&particles[below]), dist);
|
||||||
|
links.push(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*fn populate_lines(lines: &mut Vec<RectangleShape>, circles: &Vec<CircleShape>, num: u32) {
|
||||||
|
for i in 0..num {
|
||||||
|
let rect = RectangleShape::with_size(Vector2f::new(100., 100.));
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
fn apply_forces(particles: &Vec<Rc<RefCell<Particle>>>) {
|
||||||
for particle in particles {
|
for particle in particles {
|
||||||
|
let velocity = particle.borrow().vel;
|
||||||
let mut borrowed = particle.borrow_mut();
|
let mut borrowed = particle.borrow_mut();
|
||||||
// borrowed.apply_force(Vector2f::new(0., GRAVITY));
|
borrowed.apply_force(GRAVITY);
|
||||||
borrowed.apply_force(Vector2f::new(1., 1.));
|
borrowed.apply_force(-(velocity * 0.5));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_particles(particles: Vec<Rc<RefCell<Particle>>>, dt: f32) {
|
fn update_particles(particles: &Vec<Rc<RefCell<Particle>>>, dt: f32) {
|
||||||
for particle in particles { particle.borrow_mut().update(dt); }
|
for particle in particles {
|
||||||
|
particle.borrow_mut().update(dt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn solve_links(links: Vec<Link>) {
|
fn solve_links(links: &mut Vec<Link>) {
|
||||||
for mut link in links { link.solve(); }
|
for link in links {
|
||||||
|
link.solve();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_positions(circles: Vec<CircleShape>) {
|
fn update_particle_derivatives(particles: &Vec<Rc<RefCell<Particle>>>, dt: f32) {
|
||||||
|
for particle in particles {
|
||||||
|
particle.borrow_mut().update_derivatives(dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_positions(circles: &mut Vec<CircleShape>, particles: &[Rc<RefCell<Particle>>]) {
|
||||||
|
for (index, circle) in circles.iter_mut().enumerate() {
|
||||||
|
circle.set_position(particles[index].borrow().pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_all(
|
||||||
|
window: &mut RenderWindow,
|
||||||
|
circles: &Vec<CircleShape>, /* lines: &Vec<RectangleShape> */
|
||||||
|
) {
|
||||||
|
for circle in circles {
|
||||||
|
window.draw(circle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for line in lines {
|
||||||
|
// window.draw(line);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> SfResult<()> {
|
fn main() -> SfResult<()> {
|
||||||
let mut window = RenderWindow::new(
|
let mut window = RenderWindow::new(
|
||||||
(800, 600),
|
(WIN_WIDTH, WIN_HEIGHT),
|
||||||
"Verlet",
|
"Verlet",
|
||||||
Style::CLOSE,
|
Style::CLOSE,
|
||||||
&Default::default()
|
&Default::default(),
|
||||||
)?;
|
)?;
|
||||||
window.set_framerate_limit(60);
|
window.set_framerate_limit(60);
|
||||||
|
|
||||||
let mut clock = Clock::start()?;
|
let mut clock = Clock::start()?;
|
||||||
|
|
||||||
|
let mouse_pos_prev = window.mouse_position();
|
||||||
|
let mut mouse_coords_prev = window.map_pixel_to_coords_current_view(mouse_pos_prev);
|
||||||
|
|
||||||
|
let particle_count: u32 = 2000;
|
||||||
|
let column_count: u32 = 50;
|
||||||
|
let row_count: u32 = particle_count / column_count;
|
||||||
|
|
||||||
let mut particles: Vec<Rc<RefCell<Particle>>> = vec![];
|
let mut particles: Vec<Rc<RefCell<Particle>>> = vec![];
|
||||||
populate_particles(particles, 3);
|
populate_particles(&mut particles, particle_count, column_count);
|
||||||
let particle1 = Rc::new(RefCell::new(Particle::new(Vector2f::new(200., 300.))));
|
|
||||||
let particle2 = Rc::new(RefCell::new(Particle::new(Vector2f::new(300., 300.))));
|
|
||||||
let particle3 = Rc::new(RefCell::new(Particle::new(Vector2f::new(400., 300.))));
|
|
||||||
|
|
||||||
let mut link1 = Link::new(Rc::clone(&particle1), Rc::clone(&particle2), 100.);
|
let mut links: Vec<Link> = vec![];
|
||||||
let mut link2 = Link::new(Rc::clone(&particle2), Rc::clone(&particle3), 100.);
|
populate_links(
|
||||||
let mut link3 = Link::new(Rc::clone(&particle1), Rc::clone(&particle3), 200.);
|
&mut links,
|
||||||
|
&particles,
|
||||||
|
column_count as usize,
|
||||||
|
row_count as usize,
|
||||||
|
);
|
||||||
|
// let mut link3 = Link::new(Rc::clone(&(particles[0])), Rc::clone(&(particles[2])), 200.);
|
||||||
|
|
||||||
let radius = 32.;
|
let radius: f32 = 1.;
|
||||||
let mut circle1 = CircleShape::new(radius, 100);
|
let point_count: usize = 100;
|
||||||
let mut circle2 = CircleShape::new(radius, 100);
|
let mut circles: Vec<CircleShape> = vec![];
|
||||||
let mut circle3 = CircleShape::new(radius, 100);
|
populate_circles(&mut circles, particle_count, radius, point_count);
|
||||||
circle1.set_origin((radius, radius));
|
|
||||||
circle2.set_origin((radius, radius));
|
// let mut lines: Vec<RectangleShape> = vec![];
|
||||||
circle3.set_origin((radius, radius));
|
// populate_lines(&mut lines, &circles, particle_count);
|
||||||
|
|
||||||
while window.is_open() {
|
while window.is_open() {
|
||||||
while let Some(event) = window.poll_event() {
|
while let Some(event) = window.poll_event() {
|
||||||
|
|
@ -81,33 +164,37 @@ fn main() -> SfResult<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mouse_pos = window.mouse_position();
|
||||||
|
let mouse_coords = window.map_pixel_to_coords_current_view(mouse_pos);
|
||||||
|
let mouse_vel = mouse_coords - mouse_coords_prev;
|
||||||
|
mouse_coords_prev = mouse_coords;
|
||||||
|
|
||||||
if mouse::Button::is_pressed(mouse::Button::Left) {
|
if mouse::Button::is_pressed(mouse::Button::Left) {
|
||||||
let mouse_pos = window.mouse_position();
|
for particle in &particles {
|
||||||
let mouse_coords = window.map_pixel_to_coords_current_view(mouse_pos);
|
let p_pos = particle.borrow().pos;
|
||||||
let p_pos = particle1.borrow().pos;
|
let dist_vec = mouse_coords - p_pos;
|
||||||
particle2.borrow_mut().apply_force(mouse_coords - p_pos);
|
let dist = math::vec_len(dist_vec);
|
||||||
|
if dist < 40. {
|
||||||
|
particle.borrow_mut().apply_force(mouse_vel * 800.);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let dt = clock.restart().as_seconds();
|
let dt = clock.restart().as_seconds();
|
||||||
|
let substep_dt = dt / SUBSTEP_COUNT as f32;
|
||||||
|
|
||||||
//particle.apply_force(Vector2f::new(0., GRAVITY));
|
//for _ in 0..SUBSTEP_COUNT {
|
||||||
|
apply_forces(&particles);
|
||||||
particle1.borrow_mut().update(dt);
|
update_particles(&particles, dt);
|
||||||
particle2.borrow_mut().update(dt);
|
for _ in 0..SUBSTEP_COUNT {
|
||||||
particle3.borrow_mut().update(dt);
|
solve_links(&mut links);
|
||||||
|
}
|
||||||
link1.solve();
|
update_particle_derivatives(&particles, dt);
|
||||||
link2.solve();
|
update_positions(&mut circles, &particles);
|
||||||
link3.solve();
|
//}
|
||||||
|
|
||||||
circle1.set_position(particle1.borrow().pos);
|
|
||||||
circle2.set_position(particle2.borrow().pos);
|
|
||||||
circle3.set_position(particle3.borrow().pos);
|
|
||||||
|
|
||||||
window.clear(Color::BLACK);
|
window.clear(Color::BLACK);
|
||||||
window.draw(&circle1);
|
draw_all(&mut window, &circles /* &lines */);
|
||||||
window.draw(&circle2);
|
|
||||||
window.draw(&circle3);
|
|
||||||
window.display();
|
window.display();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
5
src/math.rs
Normal file
5
src/math.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
use sfml::system::Vector2f;
|
||||||
|
|
||||||
|
pub fn vec_len(vec: Vector2f) -> f32 {
|
||||||
|
(vec.x * vec.x + vec.y * vec.y).sqrt()
|
||||||
|
}
|
||||||
|
|
@ -3,28 +3,43 @@ use sfml::system::Vector2f;
|
||||||
pub struct Particle {
|
pub struct Particle {
|
||||||
pub pos: Vector2f,
|
pub pos: Vector2f,
|
||||||
prev_pos: Vector2f,
|
prev_pos: Vector2f,
|
||||||
accel: Vector2f
|
pub vel: Vector2f,
|
||||||
|
accel: Vector2f,
|
||||||
|
|
||||||
|
immovable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Particle {
|
impl Particle {
|
||||||
pub fn new(pos: Vector2f) -> Self {
|
pub fn new<P: Into<Vector2f>>(pos: P, immovable: bool) -> Self {
|
||||||
|
let pos = pos.into();
|
||||||
Particle {
|
Particle {
|
||||||
pos: pos,
|
pos,
|
||||||
prev_pos: pos,
|
prev_pos: pos,
|
||||||
accel: Vector2f::default()
|
vel: Vector2f::default(),
|
||||||
|
accel: Vector2f::default(),
|
||||||
|
|
||||||
|
immovable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_force(&mut self, force: Vector2f) {
|
pub fn apply_force<F: Into<Vector2f>>(&mut self, force: F) {
|
||||||
self.accel += force;
|
self.accel += force.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, dt: f32) {
|
pub fn update(&mut self, dt: f32) {
|
||||||
let vel = (self.pos - self.prev_pos) * 0.99;
|
if self.immovable {return}
|
||||||
let new_pos = self.pos + vel + self.accel * (dt * dt);
|
|
||||||
|
|
||||||
self.prev_pos = self.pos;
|
self.prev_pos = self.pos;
|
||||||
self.pos = new_pos;
|
self.vel += self.accel * dt;
|
||||||
|
self.pos += self.vel * dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_derivatives(&mut self, dt: f32) {
|
||||||
|
self.vel = (self.pos - self.prev_pos) / dt;
|
||||||
self.accel = Vector2f::default();
|
self.accel = Vector2f::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn apply_vel(&mut self, vel: Vector2f) {
|
||||||
|
if self.immovable {return}
|
||||||
|
self.pos += vel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue