Improved geometry finding to be more pedagogical. Minor modifications to remove some warnings.

This commit is contained in:
2025-08-25 17:31:11 -05:00
parent 6d5b9456ea
commit 231173656f

View File

@@ -30,7 +30,7 @@ use cga::CGA;
const PI: f64 = f64::consts::PI; const PI: f64 = f64::consts::PI;
const TWO_PI: f64 = 2.*PI; const TWO_PI: f64 = 2.*PI;
const ERROR: f64 = 0.0001; const ERROR: f64 = 0.000001;
const WIDTH: f64 = 600.; const WIDTH: f64 = 600.;
const HEIGHT: f64 = 600.; const HEIGHT: f64 = 600.;
@@ -144,7 +144,7 @@ impl Ship {
let com_p = com * gen_hyperbolic_point(&CGA::zero()) * com.Reverse(); let com_p = com * gen_hyperbolic_point(&CGA::zero()) * com.Reverse();
let delta_gen = com * orient_rotor * CGA::e14() * &orient_rotor.Reverse() * com.Reverse(); let delta_gen = com * orient_rotor * CGA::e14() * &orient_rotor.Reverse() * com.Reverse();
let dot = delta_gen | &com_p; let dot = delta_gen | &com_p;
let line = CGA::e4() ^ com_p ^ dot ^ CGA::e3(); let line = CGA::e4() ^ com_p ^ dot;// ^ CGA::e3();
draw_line(context, &line); draw_line(context, &line);
@@ -153,8 +153,7 @@ impl Ship {
enum Geometry { enum Geometry {
Circle(f64, f64, f64), //x,y,r Circle(f64, f64, f64), //x,y,r
Line(f64, f64, f64), //x,r,theta Line(f64, f64, f64), //x,y,theta
Null,
} }
/* Translation of a Euclidean Point. Need to use hyperbolic*/ /* Translation of a Euclidean Point. Need to use hyperbolic*/
@@ -242,33 +241,31 @@ fn get_point(point: &CGA) -> (f64, f64) {
(x/norm, y/norm) (x/norm, y/norm)
} }
fn get_geometry(circle: &CGA) -> Geometry { fn get_geometry(trivector: &CGA) -> Geometry {
//Naively assume we are given a valid line/circle let trivector = grade_selection(trivector, 3);
let i4 = CGA::e1() ^ CGA::e2() ^ CGA::e4() ^ CGA::e5(); //Left out e3 intentionally
let i2 = CGA::e1() ^ CGA::e2();
let n_bar = CGA::e4() - CGA::e5(); let n_bar = CGA::e4() - CGA::e5();
let n_vec = CGA::e4() + CGA::e5(); let n_vec = CGA::e4() + CGA::e5();
let dual = (&circle).Dual();
let l = (&dual | &n_vec)[SCALAR];
let c = (&dual | &n_bar)[SCALAR];
let a = (&dual | CGA::e1())[SCALAR];
let b = (&dual | CGA::e2())[SCALAR];
if l.abs() < ERROR { let wedge = &trivector ^ &n_vec;
//LINE let mag = magnitude(&wedge);
let theta = (-a).atan2(b); let dual = &trivector * &i4;
let norm_sqr = a*a + b*b; if mag < ERROR {
if norm_sqr < ERROR*ERROR { //Line
return Geometry::Null; let d = 0.5*(&dual | &n_bar)[SCALAR];
} let m = -1.*(&dual - 0.5*d*&n_vec)*&i2;
let x = a*c/norm_sqr/2.; let theta = (m[E2]).atan2(m[E1]);
let y = b*c/norm_sqr/2.; return Geometry::Line(0., -d/m[E1], theta);
return Geometry::Line(x,y,theta);
} else { } else {
//Circle //Circle
let c_x = a/l; let normalize = -(&dual | &n_vec)[SCALAR];
let c_y = b/l; let dual = dual * (1.0/normalize);
let r_sqr = c_x*c_x + c_y*c_y + c/l; let center = &trivector * &n_vec * &trivector;
let r = r_sqr.sqrt(); let (x,y) = get_point(&center);
return Geometry::Circle(-c_x, -c_y, r); let sqr = (&dual * &dual)[SCALAR];
let r = sqr.sqrt();
return Geometry::Circle(x, y, r);
} }
} }
@@ -292,13 +289,12 @@ fn draw_line(context: &CanvasRenderingContext2d, line: &CGA) {
context.move_to(canvas_x1, canvas_y1); context.move_to(canvas_x1, canvas_y1);
context.line_to(canvas_x2, canvas_y2); context.line_to(canvas_x2, canvas_y2);
}, },
Geometry::Null => {},
} }
context.stroke(); context.stroke();
} }
fn draw_line_between(context: &CanvasRenderingContext2d, a: &CGA, b: &CGA) { fn draw_line_between(context: &CanvasRenderingContext2d, a: &CGA, b: &CGA) {
let line = CGA::e4() ^ a ^ b ^ CGA::e3(); let line = CGA::e4() ^ a ^ b;
let geometry = get_geometry(&line); let geometry = get_geometry(&line);
context.begin_path(); context.begin_path();
context.set_stroke_style_str(GREEN); context.set_stroke_style_str(GREEN);
@@ -352,20 +348,20 @@ fn _get_hyperbolic_translation(vec: &CGA) -> CGA {
t t
} }
enum CircleIntersection { enum _CircleIntersection {
Two_Points(CGA, CGA), TwoPoints(CGA, CGA),
One_Point(CGA), OnePoint(CGA),
None, None,
} }
/*fn get_circle_intersection(circle_1: &CGA, circle_2: &CGA) -> CircleIntersection { /*fn get_circle_intersection(circle_1: &CGA, circle_2: &CGA) -> CircleIntersection {
if !circle_intersection(circle_1, circle_2) { if !circle_intersection(;//circle_1, circle_2) {
return CircleIntersection::None; return CircleIntersection::None;
} }
let n = CGA::e4() + CGA::e5(); let n = CGA::e4() + CGA::e5();
}*/ }*/
fn circle_intersection(circle_1: &CGA, circle_2: &CGA) -> bool { fn _circle_intersection(circle_1: &CGA, circle_2: &CGA) -> bool {
let circle_1 = grade_selection(circle_1, 4); let circle_1 = grade_selection(circle_1, 4);
let circle_2 = grade_selection(circle_2, 4); let circle_2 = grade_selection(circle_2, 4);
let meet = circle_1 & circle_2; let meet = circle_1 & circle_2;
@@ -378,7 +374,7 @@ fn circle_intersection(circle_1: &CGA, circle_2: &CGA) -> bool {
} }
} }
fn line_intersection(line_1: &CGA, line_2: &CGA) -> bool { fn _line_intersection(line_1: &CGA, line_2: &CGA) -> bool {
let line_1 = grade_selection(line_1, 4); let line_1 = grade_selection(line_1, 4);
let line_2 = grade_selection(line_2, 4); let line_2 = grade_selection(line_2, 4);
let meet = line_1 & line_2; let meet = line_1 & line_2;
@@ -390,8 +386,8 @@ fn line_intersection(line_1: &CGA, line_2: &CGA) -> bool {
} }
} }
fn get_line_intersection(line_1: &CGA, line_2: &CGA) -> Option<CGA> { fn _get_line_intersection(line_1: &CGA, line_2: &CGA) -> Option<CGA> {
if !line_intersection(line_1, line_2) { if !_line_intersection(line_1, line_2) {
return None; return None;
} }
let n = CGA::e4() + CGA::e5(); let n = CGA::e4() + CGA::e5();
@@ -489,7 +485,7 @@ impl Asteroid {
Asteroid { circle, vel } 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 = circle_from_coords(x, y, r);
Asteroid { circle, vel } Asteroid { circle, vel }
} }
@@ -561,6 +557,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); 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 {