Mercurial > lbo > hg > collisions
changeset 1:aaff243d027c
Essentially works
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sun, 15 Nov 2020 18:18:31 +0100 |
parents | 3de93b2549e8 |
children | c9c0a2509f23 |
files | src/main.rs |
diffstat | 1 files changed, 128 insertions(+), 53 deletions(-) [+] |
line wrap: on
line diff
--- a/src/main.rs Sun Nov 15 15:16:43 2020 +0100 +++ b/src/main.rs Sun Nov 15 18:18:31 2020 +0100 @@ -53,6 +53,7 @@ struct Event { typ: EventType, when: usize, + coll: usize, } impl PartialOrd for Event { @@ -87,11 +88,9 @@ } impl Particle { - fn draw(&self) { - unimplemented!() - } fn mov(&mut self, dt: usize) { self.pos = self.pos + self.vel * dt as f32 * TIME_UNIT; + assert!(self.pos.0 > -0.1 && self.pos.1 > -0.1); } fn timetohit(&self, dt: usize, other: &Particle, limit: usize) -> Option<usize> { let mut mypos = self.pos; @@ -99,7 +98,7 @@ let mindistsq = self.rad * self.rad + other.rad * other.rad; let mut i = 0; - while (otherpos - mypos).normsq() < mindistsq && i * dt < limit { + while (otherpos - mypos).normsq() > mindistsq && i * dt < limit { mypos = mypos + self.vel * dt as f32 * TIME_UNIT; otherpos = otherpos + other.vel * dt as f32 * TIME_UNIT; i += 1; @@ -113,22 +112,31 @@ } fn timetohit_horiz_wall(&self, y: BaseNum) -> Option<usize> { - if (self.pos.1 > y && self.vel.1 > 0.) || (self.pos.1 < y && self.vel.1 < 0.) { + let vert_dist = y - self.pos.1; + let timetohit = (vert_dist / self.vel.1) / TIME_UNIT; + if y == 0. { + } + if timetohit > 0. { + Some(timetohit as usize) + } else { None - } else { - Some((((y - self.pos.1).abs() / self.vel.1) / TIME_UNIT as BaseNum) as usize) } } fn timetohit_vert_wall(&self, x: BaseNum) -> Option<usize> { - if (self.pos.0 > x && self.vel.0 > 0.) || (self.pos.0 < x && self.vel.0 < 0.) { + let horiz_dist = x - self.pos.0; + let timetohit = (horiz_dist / self.vel.0) / TIME_UNIT; + if timetohit > 0. { + Some(timetohit as usize) + } else { None - } else { - Some((((x - self.pos.0).abs() / self.vel.0) / TIME_UNIT as BaseNum) as usize) } } fn bounce_off(&mut self, other: &mut Particle) { let conn = self.pos - other.pos; - assert!(conn.normsq() <= (self.rad * self.rad + other.rad * other.rad)); + if (conn.normsq() > (self.rad * self.rad + other.rad * other.rad)) { + println!("BUG? {} > {}", conn.normsq(), self.rad * self.rad + other.rad * other.rad); + } + //assert!(conn.normsq() <= (self.rad * self.rad + other.rad * other.rad)); // Determine orthogonal bounce plane. let connu = conn.unit(); @@ -149,34 +157,19 @@ self.vel = connu * v1_bounce_after + bounceplane * v1_orth; other.vel = connu * v2_bounce_after + bounceplane * v2_orth; + assert!(self.pos.0 > 0. && self.pos.1 > 0.); + self.coll += 1; } fn bounce_horiz_wall(&mut self) { - self.vel.1 = -self.vel.1 + self.vel.1 = -self.vel.1; + self.coll += 1; } fn bounce_vert_wall(&mut self) { - self.vel.0 = -self.vel.0 + self.vel.0 = -self.vel.0; + self.coll += 1; } } -fn test_generate_data() { - let dt = 0.01; - // 2x2 box. - let mut p1 = Particle { - pos: Vector(0., 0.), - vel: Vector(1., 1.), - rad: 0.1, - mass: 1., - coll: 0, - }; - let mut p2 = Particle { - pos: Vector(1., 1.), - vel: Vector(-0.9, -0.9), - ..p1 - }; - - for i in 0..1000 {} -} - struct System { parts: Vec<Particle>, pq: BinaryHeap<Reverse<Event>>, @@ -192,8 +185,8 @@ .map(|_| Particle { pos: Vector(rng.gen_range(0., dim), rng.gen_range(0., dim)), vel: Vector(rng.gen_range(0., dim), rng.gen_range(0., dim)), - mass: rng.gen_range(0., 1.), - rad: rng.gen_range(0., dim / 100.), + mass: rng.gen_range(0., 10.), + rad: rng.gen_range(0., dim / 25.), coll: 0, }) .collect::<Vec<Particle>>(); @@ -216,7 +209,10 @@ fn particle_for_mut(&mut self, ph: ParticleHandle) -> &mut Particle { &mut self.parts[ph.0] } - fn for_all_particles<F>(&mut self, f: F) where F: std::ops::Fn(&mut Particle) { + fn for_all_particles<F>(&mut self, f: F) + where + F: std::ops::Fn(&mut Particle), + { for p in self.parts.iter_mut() { f(p); } @@ -224,71 +220,150 @@ fn predict_collisions(&mut self, p: ParticleHandle, limit: usize) { for (i, other) in self.parts.iter().enumerate() { + if i == p.0 { + continue; + } if let Some(tth) = self.particle_for(p).timetohit(self.dt, other, limit) { self.pq.push(Reverse(Event { typ: EventType::PP(p, self.handle_for(i)), - when: (tth / self.dt) as usize, + when: self.t + tth, + coll: self.particle_for(p).coll, })); } } - let particle = self.particle_for(p); - let (dtx, dty) = ( - particle.timetohit_vert_wall(self.dim), - particle.timetohit_horiz_wall(self.dim), - ); - if let Some(dtx) = dtx { + let particle = self.particle_for(p).clone(); + if let Some(dtx) = particle.timetohit_vert_wall(0.) { if dtx <= limit { self.pq.push(Reverse(Event { typ: EventType::VertWall(p), when: self.t + dtx, + coll: particle.coll, })); } } - if let Some(dty) = dty { + if let Some(dtx) = particle.timetohit_vert_wall(self.dim) { + if dtx <= limit { + self.pq.push(Reverse(Event { + typ: EventType::VertWall(p), + when: self.t + dtx, + coll: particle.coll, + })); + } + } + if let Some(dty) = particle.timetohit_horiz_wall(0.) { if dty <= limit { self.pq.push(Reverse(Event { typ: EventType::HorizWall(p), when: self.t + dty, + coll: particle.coll, + })); + } + } + if let Some(dty) = particle.timetohit_horiz_wall(self.dim) { + if dty <= limit { + self.pq.push(Reverse(Event { + typ: EventType::HorizWall(p), + when: self.t + dty, + coll: particle.coll, })); } } } - fn simulate(&mut self, limit: usize, redrawHz: usize) { + fn simulate( + &mut self, + limit: usize, + redrawHz: usize, + maxsteps: usize, + mut render: Option<Box<dyn FnMut(&Vec<Particle>)>>, + ) { for i in 0..self.parts.len() { self.predict_collisions(self.handle_for(i), limit); } - self.pq.push(Reverse(Event { typ: EventType::Redraw, when: (1./(redrawHz*self.dt) as f32) as usize })); + self.pq.push(Reverse(Event { + typ: EventType::Redraw, + when: (1. / (redrawHz as f32 * TIME_UNIT)) as usize, + coll: 0, + })); - while !self.pq.is_empty() { + let mut i = 0; + while !self.pq.is_empty() && i < maxsteps { if let Some(next) = self.pq.pop() { let next = next.0; - let dt = next.when; - let t = self.t + dt; + if next.when <= self.t { + continue; + } + + // Still valid? + match next.typ { + EventType::HorizWall(p) | EventType::VertWall(p) | EventType::PP(p, _) => { + if self.particle_for(p).coll > next.coll { + continue; + } + }, + _ => {} + } + + let dt = next.when - self.t; + self.t = next.when; self.for_all_particles(|p| p.mov(dt)); + // Render on every collision. + if let Some(ref mut render_cb) = render { + render_cb(&self.parts); + } + match next.typ { - EventType::Redraw => {}, + EventType::Redraw => { + //self.pq.push(Reverse(Event { + // typ: EventType::Redraw, + // when: self.t + (1. / (TIME_UNIT * redrawHz as f32)) as usize, + // coll: 0, + //})); + } EventType::HorizWall(p) => { self.particle_for_mut(p).bounce_horiz_wall(); self.predict_collisions(p, limit); - }, + } EventType::VertWall(p) => { self.particle_for_mut(p).bounce_vert_wall(); self.predict_collisions(p, limit); - }, + } EventType::PP(p1, p2) => { let mut pm1 = self.parts[p1.0].clone(); let mut pm2 = self.parts[p2.0].clone(); pm1.bounce_off(&mut pm2); self.parts[p1.0] = pm1; self.parts[p2.0] = pm2; - }, + self.predict_collisions(p1, limit); + self.predict_collisions(p2, limit); + } } } + i += 1; } } } +fn render_3_particles() { + use std::io::Write; + + let mut sys = System::new(10., 1e4 as usize, 50); + let mut destfile = std::fs::OpenOptions::new() + .write(true) + .create(true) + .open("render.csv") + .unwrap(); + let render_cb = Box::new(move |parts: &Vec<Particle>| { + for p in parts.iter() { + write!(destfile, "{:.2}, {:.2}, ", p.pos.0, p.pos.1); + } + write!(destfile, "\n"); + }); + + // limit, redrawhz, steps + sys.simulate(10e6 as usize, 10, 100000, Some(render_cb)); +} + fn main() { - println!("Hello, world!"); + render_3_particles(); }