Adjusted code so asteroids should correctly follow geodesics.

This commit is contained in:
2025-09-08 17:36:01 -05:00
parent e974c95970
commit 658ca2c12b

View File

@@ -552,7 +552,8 @@ fn bivector_exponential(bivector: &CGA) -> CGA {
} }
struct Asteroid { struct Asteroid {
circle: CGA, com_rotor: CGA,
verts: Vec::<CGA>,
vel: CGA, vel: CGA,
} }
@@ -569,28 +570,106 @@ fn circle_from_coords(x: f64, y: f64, r: f64) -> CGA {
impl Asteroid { impl Asteroid {
fn new() -> Asteroid { fn new() -> Asteroid {
let v = 0.; let vec = 0.8*CGA::e1() + 0.0*CGA::e2();
let vec_sqr = (&vec*&vec)[SCALAR];
let scale = 1. / (1.-vec_sqr).sqrt();
let com_rotor = scale * (CGA::new(1., SCALAR) + CGA::e5()*vec);
let tx_gen = CGA::e15();
let ty_gen = CGA::e25();
let v1_gen = -0.2*&tx_gen;
let v2_gen = 0.2*&tx_gen;
let v3_gen = 0.2*&ty_gen;
let v1_rot = bivector_exponential(&v1_gen);
let v2_rot = bivector_exponential(&v2_gen);
let v3_rot = bivector_exponential(&v3_gen);
let origin = gen_hyperbolic_point(&CGA::zero());
let v1 = &v1_rot * &origin * &v1_rot.Reverse();
let v2 = &v2_rot * &origin * &v2_rot.Reverse();
let v3 = &v3_rot * &origin * &v3_rot.Reverse();
let verts = vec![v1, v2, v3];
let v = 1.;
let (v_x, v_y) = (v * 1.0_f64.cos(), v*1.0_f64.sin()); let (v_x, v_y) = (v * 1.0_f64.cos(), v*1.0_f64.sin());
let vel = v_x*CGA::e15() + v_y*CGA::e25(); let vel = v_x*CGA::e1() + v_y*CGA::e2();
let circle = circle_from_coords(0.5, 0., 0.4); Asteroid { com_rotor, vel, verts }
Asteroid { circle, vel }
} }
/*
fn _new_from_coords(x: f64, y: f64, r: f64, vel: CGA) -> Asteroid { fn _new_from_coords(x: f64, y: f64, r: f64, vel: CGA) -> Asteroid {
let circle = circle_from_coords(x, y, r); let (circle, verts) = circle_from_coords(x, y, r);
Asteroid { circle, vel } Asteroid { circle, vel, verts }
} }
*/
fn update(&mut self, dt_s: f64) { fn update(&mut self, dt_s: f64, boundary: &CGA) {
let vel = &self.vel; let vel = &self.vel*CGA::e5();
let delta = vel * dt_s; let delta = &vel * dt_s;
let delta = self.fixed_to_world(&delta);//&self.com_rotor * delta * &self.com_rotor.Reverse();
let vel_rotor = bivector_exponential(&delta); let vel_rotor = bivector_exponential(&delta);
let circle = &vel_rotor*&self.circle*&vel_rotor.Reverse(); //let vel_rotor = &self.com_rotor.Reverse() * vel_rotor * &self.com_rotor;
self.circle = circle; let new_pos = &vel_rotor * &self.com_rotor;
let p1 = &new_pos * &self.verts[0] * &new_pos.Reverse();
let p2 = &new_pos * &self.verts[1] * &new_pos.Reverse();
let p3 = &new_pos * &self.verts[2] * &new_pos.Reverse();
let circle = p1 ^ p2 ^ p3;
let intersect = circle_intersection(&circle, boundary);
match intersect {
CircleIntersection::None => { self.com_rotor = new_pos; }
CircleIntersection::TwoPoints(_,_) => {
self.reflect_off_boundary();
}
}
} }
fn draw(&self, context: &CanvasRenderingContext2d) { fn draw(&self, context: &CanvasRenderingContext2d) {
draw_line(context, &self.circle); let p1 = self.fixed_to_world(&self.verts[0]);
let p2 = self.fixed_to_world(&self.verts[1]);
let p3 = self.fixed_to_world(&self.verts[2]);
draw_point(context, &p1);
draw_point(context, &p2);
draw_point(context, &p3);
let circle = &p1 ^ &p2 ^ &p3;
draw_line(context, &circle);
//Construct and draw line pointing straight ahead, to help orient the player.
let origin = gen_hyperbolic_point(&CGA::zero());
let com = self.fixed_to_world(&origin);
let delta_gen = self.fixed_to_world(&(&self.vel*CGA::e5()));
let dot = delta_gen | &com;
let line = CGA::e4() ^ com ^ dot;
draw_line(context, &line);
}
fn fixed_to_world(&self, vec: &CGA) -> CGA {
&self.com_rotor*vec*&self.com_rotor.Reverse()
}
fn get_circle(&self) -> CGA {
let p1 = self.fixed_to_world(&self.verts[0]);
let p2 = self.fixed_to_world(&self.verts[1]);
let p3 = self.fixed_to_world(&self.verts[2]);
p1 ^ p2 ^ p3
}
fn reflect_off_boundary(&mut self) {
let origin = gen_hyperbolic_point(&CGA::zero());
let mut pos = self.fixed_to_world(&origin);
pos[E4] = 0.;
pos[E5] = 0.;
let norm = pos.norm();
pos = pos * (1./ norm);
let norm_old = self.vel.norm();
let vel = self.fixed_to_world(&self.vel);
let dot = &vel | &pos;
let vel_para_radial = dot * &pos;
let vel_perp_radial = &vel - &vel_para_radial;
let vel_tick = vel_perp_radial - vel_para_radial;
let mut vel_fixed = &self.com_rotor.Reverse()*vel_tick*&self.com_rotor;
vel_fixed[E4] = 0.;
vel_fixed[E5] = 0.;
let norm = vel_fixed.norm();
vel_fixed = (1. / norm)*vel_fixed;
vel_fixed = norm_old * vel_fixed;
self.vel = vel_fixed;
} }
} }
@@ -675,7 +754,8 @@ impl Game {
self.context.set_stroke_style_str(RED); self.context.set_stroke_style_str(RED);
for asteroid in &self.asteroids { for asteroid in &self.asteroids {
if self.ship.intersects_circle(&asteroid.circle) { let circle = asteroid.get_circle();
if self.ship.intersects_circle(&circle) {
intersects = true; intersects = true;
} }
asteroid.draw(&self.context); asteroid.draw(&self.context);
@@ -699,7 +779,7 @@ impl Game {
self.dt = dt_m; self.dt = dt_m;
for asteroid in &mut self.asteroids { for asteroid in &mut self.asteroids {
asteroid.update(dt_s); asteroid.update(dt_s, &self.boundary);
} }
self.ship.update(dt_s, &self.keys, &self.boundary); self.ship.update(dt_s, &self.keys, &self.boundary);