diff --git a/src/lib.rs b/src/lib.rs index 396f874..e4831fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,9 +47,9 @@ const BLUE: &str = "#0000ff"; const SCALAR: usize = 0; const E1: usize = 1; const E2: usize = 2; -//const E3: usize = 3; -//const E4: usize = 4; -//const E5: usize = 5; +const E3: usize = 3; +const E4: usize = 4; +const E5: usize = 5; const E12: usize = 6; const E13: usize = 7; const E14: usize = 8; @@ -60,22 +60,22 @@ const E25: usize = 12; const E34: usize = 13; const E35: usize = 14; const E45: usize = 15; -//const E123: usize = 16; -//const E124: usize = 17; -//const E125: usize = 18; -//const E134: usize = 19; -//const E135: usize = 20; -//const E145: usize = 21; -//const E234: usize = 22; -//const E235: usize = 23; -//const E245: usize = 24; -//const E345: usize = 25; -//const E1234: usize = 26; -//const E1235: usize = 27; -//const E1245: usize = 28; -//const E1345: usize = 29; -//const E2345: usize = 30; -//const E12345: usize = 31; +const E123: usize = 16; +const E124: usize = 17; +const E125: usize = 18; +const E134: usize = 19; +const E135: usize = 20; +const E145: usize = 21; +const E234: usize = 22; +const E235: usize = 23; +const E245: usize = 24; +const E345: usize = 25; +const E1234: usize = 26; +const E1235: usize = 27; +const E1245: usize = 28; +const E1345: usize = 29; +const E2345: usize = 30; +const E12345: usize = 31; const DRAG: f64 = 1.; const ACCEL_STR: f64 = 1.; @@ -352,6 +352,92 @@ fn _get_hyperbolic_translation(vec: &CGA) -> CGA { 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 { + 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 { let vec_sqr = (vec * vec)[SCALAR]; if vec_sqr >= 1. { @@ -365,20 +451,7 @@ fn gen_hyperbolic_point(vec: &CGA) -> CGA { fn bivector_exponential(bivector: &CGA) -> CGA { //Explicitly take only the bivector part. //The library doesn't provide a grade 2 selection. - let a = bivector[E12]; - 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 bivector = grade_selection(bivector, 2); let sqr = (&bivector*&bivector)[SCALAR]; if sqr.abs() < ERROR { CGA::new(1., SCALAR) + bivector @@ -396,22 +469,28 @@ struct Asteroid { 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 { fn new() -> Asteroid { let v = 0.1; 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(); - 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 { - 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(); + let circle = circle_from_coords(x, y, r); Asteroid { circle, vel } } @@ -433,6 +512,7 @@ pub struct Game { context: CanvasRenderingContext2d, ship: Ship, asteroids: Vec::, + boundary: CGA, keys: HashSet, } @@ -463,9 +543,11 @@ impl Game { orientation: CGA::new(1., SCALAR), }; + let boundary = circle_from_coords(0., 0., 0.99); Game { context: context, ship, + boundary, asteroids: vec![Asteroid::new()], keys: HashSet::new(), } @@ -479,6 +561,7 @@ impl Game { self.context.set_stroke_style_str(BLACK); self.context.arc(CENTER_X, CENTER_Y, RADIUS, 0., TWO_PI).unwrap(); self.context.stroke(); + draw_line(&self.context, &self.boundary); self.ship.draw(&self.context); for asteroid in &self.asteroids { asteroid.draw(&self.context);