Added some utility functions and intersection testing.

This commit is contained in:
2025-08-25 15:51:57 -05:00
parent 3d84fff063
commit 6d5b9456ea

View File

@@ -47,9 +47,9 @@ const BLUE: &str = "#0000ff";
const SCALAR: usize = 0; const SCALAR: usize = 0;
const E1: usize = 1; const E1: usize = 1;
const E2: usize = 2; const E2: usize = 2;
//const E3: usize = 3; const E3: usize = 3;
//const E4: usize = 4; const E4: usize = 4;
//const E5: usize = 5; const E5: usize = 5;
const E12: usize = 6; const E12: usize = 6;
const E13: usize = 7; const E13: usize = 7;
const E14: usize = 8; const E14: usize = 8;
@@ -60,22 +60,22 @@ const E25: usize = 12;
const E34: usize = 13; const E34: usize = 13;
const E35: usize = 14; const E35: usize = 14;
const E45: usize = 15; const E45: usize = 15;
//const E123: usize = 16; const E123: usize = 16;
//const E124: usize = 17; const E124: usize = 17;
//const E125: usize = 18; const E125: usize = 18;
//const E134: usize = 19; const E134: usize = 19;
//const E135: usize = 20; const E135: usize = 20;
//const E145: usize = 21; const E145: usize = 21;
//const E234: usize = 22; const E234: usize = 22;
//const E235: usize = 23; const E235: usize = 23;
//const E245: usize = 24; const E245: usize = 24;
//const E345: usize = 25; const E345: usize = 25;
//const E1234: usize = 26; const E1234: usize = 26;
//const E1235: usize = 27; const E1235: usize = 27;
//const E1245: usize = 28; const E1245: usize = 28;
//const E1345: usize = 29; const E1345: usize = 29;
//const E2345: usize = 30; const E2345: usize = 30;
//const E12345: usize = 31; const E12345: usize = 31;
const DRAG: f64 = 1.; const DRAG: f64 = 1.;
const ACCEL_STR: f64 = 1.; const ACCEL_STR: f64 = 1.;
@@ -352,6 +352,92 @@ fn _get_hyperbolic_translation(vec: &CGA) -> CGA {
t t
} }
enum CircleIntersection {
Two_Points(CGA, CGA),
One_Point(CGA),
None,
}
/*fn get_circle_intersection(circle_1: &CGA, circle_2: &CGA) -> CircleIntersection {
if !circle_intersection(circle_1, circle_2) {
return CircleIntersection::None;
}
let n = CGA::e4() + CGA::e5();
}*/
fn circle_intersection(circle_1: &CGA, circle_2: &CGA) -> bool {
let circle_1 = grade_selection(circle_1, 4);
let circle_2 = grade_selection(circle_2, 4);
let meet = circle_1 & circle_2;
let sqr = &meet * &meet;
let mag = magnitude(&sqr);
if mag < ERROR {
true
} else {
false
}
}
fn line_intersection(line_1: &CGA, line_2: &CGA) -> bool {
let line_1 = grade_selection(line_1, 4);
let line_2 = grade_selection(line_2, 4);
let meet = line_1 & line_2;
let mag = magnitude(&meet);
if mag < ERROR {
true
} else {
false
}
}
fn get_line_intersection(line_1: &CGA, line_2: &CGA) -> Option<CGA> {
if !line_intersection(line_1, line_2) {
return None;
}
let n = CGA::e4() + CGA::e5();
let x = CGA::up(0., 0., 0.); //Pick an arbitrary point
let l_1_tick = line_2 * line_1 * line_2; //reflect line_1 by line_2
let l_1_2tick = line_1 - l_1_tick; //bisector of line_1 and its reflection
let x_tick = &l_1_2tick * &x * & l_1_2tick; //reflection of x in the bisector
let x_2tick = 0.5*x + 0.5*&x_tick; //midpoint, on the bisector
let x_3tick = line_2*&x_2tick*line_2; //Reflection of midpoint in line_2
let p_tick = 0.5*&x_2tick + 0.5 * x_3tick; //Intersection point of lines, but with extra n component.
let dot = &p_tick | &n;
let dot_sqr = dot[SCALAR]*dot[SCALAR];
let p = -1.*&p_tick*&n*&p_tick*(0.5/dot_sqr); //Get the point with the correct n component.
Some(p)
}
fn grade_selection(multi: &CGA, grade: usize) -> CGA {
match grade {
0 => { CGA::new(multi[SCALAR], SCALAR) },
1 => { multi[E1]*CGA::e1() + multi[E2]*CGA::e2() + multi[E3]*CGA::e3() + multi[E4]*CGA::e4() + multi[E5]*CGA::e5() },
2 => { multi[E12]*CGA::e12() + multi[E13]*CGA::e13() + multi[E14]*CGA::e14() + multi[E15]*CGA::e15()
+ multi[E23]*CGA::e23() + multi[E24]*CGA::e24() + multi[E25]*CGA::e25()
+ multi[E34]*CGA::e34() + multi[E35]*CGA::e35() + multi[E45]*CGA::e45() },
3 => { multi[E123]*CGA::e123() + multi[E124]*CGA::e124() + multi[E125]*CGA::e125() + multi[E134]*CGA::e134()
+ multi[E135]*CGA::e135() + multi[E145]*CGA::e145() + multi[E234]*CGA::e234() + multi[E235]*CGA::e235()
+ multi[E245]*CGA::e245() + multi[E345]*CGA::e345() },
4 => { multi[E1234]*CGA::e1234() + multi[E1235]*CGA::e1235() + multi[E1245]*CGA::e1245() + multi[E1345]*CGA::e1345()
+ multi[E2345]*CGA::e2345() },
5 => { multi[E12345]*CGA::e12345() }
_ => { CGA::zero() }
}
}
fn magnitude(multi: &CGA) -> f64 {
multi[SCALAR]*multi[SCALAR]
+ multi[E1]*multi[E1] + multi[E2]*multi[E2] + multi[E3]*multi[E3] + multi[E4]*multi[E4] + multi[E5]*multi[E5]
+ multi[E12]*multi[E12] + multi[E13]*multi[E13] + multi[E14]*multi[E14] + multi[E15]*multi[E15]
+ multi[E23]*multi[E23] + multi[E24]*multi[E24] + multi[E25]*multi[E25]
+ multi[E34]*multi[E34] + multi[E35]*multi[E35] + multi[E45]*multi[E45]
+ multi[E123]*multi[E123] + multi[E124]*multi[E124] + multi[E125]*multi[E125]
+ multi[E134]*multi[E134] + multi[E135]*multi[E135] + multi[E145]*multi[E145]
+ multi[E234]*multi[E234] + multi[E235]*multi[E235] + multi[E245]*multi[E245] + multi[E345]*multi[E345]
+ multi[E1234]*multi[E1234] + multi[E1235]*multi[E1235] + multi[E1245]*multi[E1245] + multi[E1345]*multi[E1345] + multi[E2345]*multi[E2345]
+ multi[E12345]*multi[E12345]
}
fn gen_hyperbolic_point(vec: &CGA) -> CGA { fn gen_hyperbolic_point(vec: &CGA) -> CGA {
let vec_sqr = (vec * vec)[SCALAR]; let vec_sqr = (vec * vec)[SCALAR];
if vec_sqr >= 1. { if vec_sqr >= 1. {
@@ -365,20 +451,7 @@ fn gen_hyperbolic_point(vec: &CGA) -> CGA {
fn bivector_exponential(bivector: &CGA) -> CGA { fn bivector_exponential(bivector: &CGA) -> CGA {
//Explicitly take only the bivector part. //Explicitly take only the bivector part.
//The library doesn't provide a grade 2 selection. //The library doesn't provide a grade 2 selection.
let a = bivector[E12]; let bivector = grade_selection(bivector, 2);
let b = bivector[E13];
let c = bivector[E14];
let d = bivector[E15];
let e = bivector[E23];
let f = bivector[E24];
let g = bivector[E25];
let h = bivector[E34];
let i = bivector[E35];
let j = bivector[E45];
let bivector = a*CGA::e12() + b*CGA::e13() + c*CGA::e14()
+ d*CGA::e15() + e*CGA::e23() + f*CGA::e24() + g*CGA::e25()
+ h*CGA::e34() + i *CGA::e35() + j*CGA::e45();
let sqr = (&bivector*&bivector)[SCALAR]; let sqr = (&bivector*&bivector)[SCALAR];
if sqr.abs() < ERROR { if sqr.abs() < ERROR {
CGA::new(1., SCALAR) + bivector CGA::new(1., SCALAR) + bivector
@@ -396,22 +469,28 @@ struct Asteroid {
vel: CGA, vel: CGA,
} }
fn circle_from_coords(x: f64, y: f64, r: f64) -> CGA {
let (a_x, a_y) = (x + r * 0.0_f64.cos(), y + r * 0.0_f64.sin());
let (b_x, b_y) = (x + r * 1.0_f64.cos(), y + r * 1.0_f64.sin());
let (c_x, c_y) = (x + r * 2.0_f64.cos(), y + r * 2.0_f64.sin());
let a = point_to_cga(a_x, a_y);
let b = point_to_cga(b_x, b_y);
let c = point_to_cga(c_x, c_y);
let circle = a^b^c^CGA::e3();
circle
}
impl Asteroid { impl Asteroid {
fn new() -> Asteroid { fn new() -> Asteroid {
let v = 0.1; let v = 0.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::e15() + v_y*CGA::e25();
Self::new_from_coords(0.0_f64, 0.0_f64, 0.1_f64, vel) let circle = circle_from_coords(0., 0., 0.);
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 (a_x, a_y) = (x + r * 0.0_f64.cos(), y + r * 0.0_f64.sin()); let circle = circle_from_coords(x, y, r);
let (b_x, b_y) = (x + r * 1.0_f64.cos(), y + r * 1.0_f64.sin());
let (c_x, c_y) = (x + r * 2.0_f64.cos(), y + r * 2.0_f64.sin());
let a = point_to_cga(a_x, a_y);
let b = point_to_cga(b_x, b_y);
let c = point_to_cga(c_x, c_y);
let circle = a^b^c^CGA::e3();
Asteroid { circle, vel } Asteroid { circle, vel }
} }
@@ -433,6 +512,7 @@ pub struct Game {
context: CanvasRenderingContext2d, context: CanvasRenderingContext2d,
ship: Ship, ship: Ship,
asteroids: Vec::<Asteroid>, asteroids: Vec::<Asteroid>,
boundary: CGA,
keys: HashSet<String>, keys: HashSet<String>,
} }
@@ -463,9 +543,11 @@ impl Game {
orientation: CGA::new(1., SCALAR), orientation: CGA::new(1., SCALAR),
}; };
let boundary = circle_from_coords(0., 0., 0.99);
Game { Game {
context: context, context: context,
ship, ship,
boundary,
asteroids: vec![Asteroid::new()], asteroids: vec![Asteroid::new()],
keys: HashSet::new(), keys: HashSet::new(),
} }
@@ -479,6 +561,7 @@ impl Game {
self.context.set_stroke_style_str(BLACK); self.context.set_stroke_style_str(BLACK);
self.context.arc(CENTER_X, CENTER_Y, RADIUS, 0., TWO_PI).unwrap(); self.context.arc(CENTER_X, CENTER_Y, RADIUS, 0., TWO_PI).unwrap();
self.context.stroke(); self.context.stroke();
draw_line(&self.context, &self.boundary);
self.ship.draw(&self.context); self.ship.draw(&self.context);
for asteroid in &self.asteroids { for asteroid in &self.asteroids {
asteroid.draw(&self.context); asteroid.draw(&self.context);