diff --git a/Cargo.lock b/Cargo.lock index 9a6ed36..96d42ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,21 +4,21 @@ version = 4 [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "cc" -version = "1.2.20" +version = "1.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" +checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" dependencies = [ "shlex", ] @@ -34,9 +34,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.172" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libflac-sys" diff --git a/src/link.rs b/src/link.rs index 342e6ee..75bf156 100644 --- a/src/link.rs +++ b/src/link.rs @@ -1,29 +1,31 @@ +use crate::math; use crate::particle::Particle; -use std::rc::Rc; use std::cell::RefCell; +use std::rc::Rc; pub struct Link { p1: Rc>, p2: Rc>, - length: f32 + length: f32, } impl Link { pub fn new(p1: Rc>, p2: Rc>, length: f32) -> Self { - Link { - p1: p1, - p2: p2, - length: length - } + Link { p1, p2, length } } pub fn solve(&mut self) { let vec = self.p2.borrow().pos - self.p1.borrow().pos; - let vec_len = (vec.x*vec.x + vec.y*vec.y).sqrt(); - let vec_norm = vec/vec_len; - let vec_scaled = vec_norm * (self.length-vec_len) * 9.; + let vec_len = math::vec_len(vec); - self.p1.borrow_mut().apply_force(-vec_scaled); - self.p2.borrow_mut().apply_force(vec_scaled); + if vec_len > self.length { + 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); + } } -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index 9675dae..80c3d40 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,11 @@ -use sfml::graphics::*; -use sfml::window::*; use sfml::SfResult; -use sfml::system::{Vector2f, Clock}; -use std::rc::Rc; +use sfml::graphics::*; +use sfml::system::{Clock, Vector2f}; +use sfml::window::*; use std::cell::RefCell; +use std::rc::Rc; + +mod math; mod particle; use particle::Particle; @@ -11,67 +13,148 @@ use particle::Particle; mod link; use link::Link; -//const GRAVITY: f32 = 100.; +const WIN_WIDTH: u32 = 800; +const WIN_HEIGHT: u32 = 600; -fn populate_particles(mut particles: Vec>>, num: u32) { - for i in 0..=num { - particles.push(Rc::new(RefCell::new(Particle::new(Vector2f::new(100. * i as f32, 300.))))); +const GRAVITY: Vector2f = Vector2f::new(0., 1500.); + +const SUBSTEP_COUNT: u32 = 16; + +fn populate_particles(particles: &mut Vec>>, 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, particles: Vec>>) { - +fn populate_circles(circles: &mut Vec, 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>>) { +fn populate_links( + links: &mut Vec, + particles: &[Rc>], + 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, circles: &Vec, num: u32) { + for i in 0..num { + let rect = RectangleShape::with_size(Vector2f::new(100., 100.)); + } +}*/ + +fn apply_forces(particles: &Vec>>) { for particle in particles { + let velocity = particle.borrow().vel; let mut borrowed = particle.borrow_mut(); - // borrowed.apply_force(Vector2f::new(0., GRAVITY)); - borrowed.apply_force(Vector2f::new(1., 1.)); - + borrowed.apply_force(GRAVITY); + borrowed.apply_force(-(velocity * 0.5)); } } -fn update_particles(particles: Vec>>, dt: f32) { - for particle in particles { particle.borrow_mut().update(dt); } +fn update_particles(particles: &Vec>>, dt: f32) { + for particle in particles { + particle.borrow_mut().update(dt); + } } -fn solve_links(links: Vec) { - for mut link in links { link.solve(); } +fn solve_links(links: &mut Vec) { + for link in links { + link.solve(); + } } -fn update_positions(circles: Vec) { +fn update_particle_derivatives(particles: &Vec>>, dt: f32) { + for particle in particles { + particle.borrow_mut().update_derivatives(dt); + } +} +fn update_positions(circles: &mut Vec, particles: &[Rc>]) { + for (index, circle) in circles.iter_mut().enumerate() { + circle.set_position(particles[index].borrow().pos); + } +} + +fn draw_all( + window: &mut RenderWindow, + circles: &Vec, /* lines: &Vec */ +) { + for circle in circles { + window.draw(circle); + } + + // for line in lines { + // window.draw(line); + // } } fn main() -> SfResult<()> { let mut window = RenderWindow::new( - (800, 600), + (WIN_WIDTH, WIN_HEIGHT), "Verlet", Style::CLOSE, - &Default::default() + &Default::default(), )?; window.set_framerate_limit(60); 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>> = vec![]; - populate_particles(particles, 3); - 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.)))); + populate_particles(&mut particles, particle_count, column_count); - let mut link1 = Link::new(Rc::clone(&particle1), Rc::clone(&particle2), 100.); - let mut link2 = Link::new(Rc::clone(&particle2), Rc::clone(&particle3), 100.); - let mut link3 = Link::new(Rc::clone(&particle1), Rc::clone(&particle3), 200.); + let mut links: Vec = vec![]; + populate_links( + &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 mut circle1 = CircleShape::new(radius, 100); - let mut circle2 = CircleShape::new(radius, 100); - let mut circle3 = CircleShape::new(radius, 100); - circle1.set_origin((radius, radius)); - circle2.set_origin((radius, radius)); - circle3.set_origin((radius, radius)); + let radius: f32 = 1.; + let point_count: usize = 100; + let mut circles: Vec = vec![]; + populate_circles(&mut circles, particle_count, radius, point_count); + + // let mut lines: Vec = vec![]; + // populate_lines(&mut lines, &circles, particle_count); while window.is_open() { while let Some(event) = window.poll_event() { @@ -81,35 +164,39 @@ 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) { - let mouse_pos = window.mouse_position(); - let mouse_coords = window.map_pixel_to_coords_current_view(mouse_pos); - let p_pos = particle1.borrow().pos; - particle2.borrow_mut().apply_force(mouse_coords - p_pos); + for particle in &particles { + let p_pos = particle.borrow().pos; + let dist_vec = 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 substep_dt = dt / SUBSTEP_COUNT as f32; - //particle.apply_force(Vector2f::new(0., GRAVITY)); - - particle1.borrow_mut().update(dt); - particle2.borrow_mut().update(dt); - particle3.borrow_mut().update(dt); - - link1.solve(); - link2.solve(); - link3.solve(); - - circle1.set_position(particle1.borrow().pos); - circle2.set_position(particle2.borrow().pos); - circle3.set_position(particle3.borrow().pos); + //for _ in 0..SUBSTEP_COUNT { + apply_forces(&particles); + update_particles(&particles, dt); + for _ in 0..SUBSTEP_COUNT { + solve_links(&mut links); + } + update_particle_derivatives(&particles, dt); + update_positions(&mut circles, &particles); + //} window.clear(Color::BLACK); - window.draw(&circle1); - window.draw(&circle2); - window.draw(&circle3); + draw_all(&mut window, &circles /* &lines */); window.display(); } Ok(()) -} \ No newline at end of file +} diff --git a/src/math.rs b/src/math.rs new file mode 100644 index 0000000..9150b0d --- /dev/null +++ b/src/math.rs @@ -0,0 +1,5 @@ +use sfml::system::Vector2f; + +pub fn vec_len(vec: Vector2f) -> f32 { + (vec.x * vec.x + vec.y * vec.y).sqrt() +} \ No newline at end of file diff --git a/src/particle.rs b/src/particle.rs index 0998294..5b39883 100644 --- a/src/particle.rs +++ b/src/particle.rs @@ -3,28 +3,43 @@ use sfml::system::Vector2f; pub struct Particle { pub pos: Vector2f, prev_pos: Vector2f, - accel: Vector2f + pub vel: Vector2f, + accel: Vector2f, + + immovable: bool, } impl Particle { - pub fn new(pos: Vector2f) -> Self { + pub fn new>(pos: P, immovable: bool) -> Self { + let pos = pos.into(); Particle { - pos: pos, + pos, prev_pos: pos, - accel: Vector2f::default() + vel: Vector2f::default(), + accel: Vector2f::default(), + + immovable, } } - pub fn apply_force(&mut self, force: Vector2f) { - self.accel += force; + pub fn apply_force>(&mut self, force: F) { + self.accel += force.into(); } pub fn update(&mut self, dt: f32) { - let vel = (self.pos - self.prev_pos) * 0.99; - let new_pos = self.pos + vel + self.accel * (dt * dt); - + if self.immovable {return} 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(); } -} \ No newline at end of file + + pub fn apply_vel(&mut self, vel: Vector2f) { + if self.immovable {return} + self.pos += vel; + } +}