use std::f64; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement}; //use web_sys::console; mod cga; use cga::CGA; const PI: f64 = f64::consts::PI; const TWO_PI: f64 = 2.*PI; const ERROR: f64 = 0.0001; const WIDTH: f64 = 600.; const HEIGHT: f64 = 600.; const CENTER_X: f64 = 300.; const CENTER_Y: f64 = 300.; const RADIUS: f64 = 250.; const BACKGROUND: &str = "#ffffff"; const BLACK: &str = "#000000"; const RED: &str = "#ff0000"; const GREEN: &str = "#00ff00"; 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 E12: usize = 6; //const E13: usize = 7; //const E14: usize = 8; //const E15: usize = 9; //const E23: usize = 10; //const E24: usize = 11; //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; struct Ship { _pos: CGA, _vel: CGA, _orientation: CGA, } fn point_to_cga(x: f64, y: f64) -> CGA { let x_vec = CGA::e1(); let y_vec = CGA::e2(); let _z_vec =CGA::e3(); let e_vec = CGA::e4(); let e_bar = CGA::e5(); let n_vec = &e_vec + &e_bar; let n_bar = &e_vec - &e_bar; let mut ux = x; let mut uy = y; let mut mag_sqr = ux*ux + uy*uy; if mag_sqr > 1. { ux /= mag_sqr.sqrt(); uy /= mag_sqr.sqrt(); mag_sqr = 1.; } 0.5*mag_sqr*n_vec + ux*x_vec + uy*y_vec - 0.5*n_bar } fn draw_point(context: &CanvasRenderingContext2d, point: &CGA) { //Naively assume we are given a valid point let x = point[1]*RADIUS + CENTER_X; let y = point[2]*RADIUS + CENTER_Y; context.begin_path(); context.set_fill_style_str(RED); context.arc(x, y, 2., 0., TWO_PI).unwrap(); context.fill(); } fn draw_line(context: &CanvasRenderingContext2d, line: &CGA) { context.begin_path(); context.set_stroke_style_str(GREEN); //Naively assume we are given a valid line/circle let n_bar = CGA::e4() - CGA::e5(); let n_vec = CGA::e4() + CGA::e5(); let dual = line.Dual(); let lambda = -(&dual | &n_vec)[SCALAR]; let mu = (&dual | &n_bar)[SCALAR]; let x = dual[E1]; let y = dual[E2]; if lambda.abs() < ERROR { //Line let norm_sqr = x*x+y*y; if norm_sqr < ERROR { return; } else { let norm = norm_sqr.sqrt(); let px = mu * 0.5 * x / norm_sqr; let py = mu * 0.5 * y / norm_sqr; let tx = -y / norm; let ty = x / norm; let p1x = px + tx * 1000.; let p1y = py + ty * 1000.; let p2x = px - tx * 1000.; let p2y = py - ty * 1000.; context.move_to(p1x*RADIUS + CENTER_X, p1y*RADIUS + CENTER_Y); context.line_to(p2x*RADIUS + CENTER_X, p2y*RADIUS + CENTER_Y); } } else { //Extract Center and Radius let c_x = x/lambda; let c_y = y/lambda; let r_sqr = c_x*c_x + c_y*c_y - mu/lambda; let r = r_sqr.sqrt(); //draw_point(context, &point_to_cga(c_x, c_y)); //Convert into Canvas Space let canvas_cx = c_x*RADIUS + CENTER_X; let canvas_cy = c_y*RADIUS + CENTER_Y; let canvas_r = r*RADIUS; //Draw context.arc(canvas_cx, canvas_cy, canvas_r, 0., TWO_PI).unwrap(); } context.stroke(); } // Start entry point #[wasm_bindgen(start)] pub fn start() -> Result<(), JsValue> { let _ship = Ship { _pos: point_to_cga(0.,0.), _vel: CGA::zero(), _orientation: CGA::zero() }; // Grab document and canvas let window = web_sys::window().unwrap(); let document = window.document().unwrap(); let canvas = document .get_element_by_id("game-canvas") .unwrap() .dyn_into::()?; canvas.set_width(WIDTH as u32); canvas.set_height(HEIGHT as u32); let context = canvas .get_context("2d")? .unwrap() .dyn_into::()?; //Set up play area. context.begin_path(); context.set_fill_style_str(BACKGROUND); context.fill_rect(0.0, 0.0, WIDTH, HEIGHT); context.fill(); context.set_stroke_style_str(BLACK); context.arc(CENTER_X, CENTER_Y, RADIUS, 0., TWO_PI).unwrap(); context.stroke(); let point = point_to_cga(0.,0.); draw_point(&context, &point); let p1 = point_to_cga(0.9, 0.0); draw_point(&context, &p1); let p2 = point_to_cga(0.0, 0.9); draw_point(&context, &p2); let p3 = point_to_cga(0.7, 0.6); draw_point(&context, &p3); let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3(); draw_line(&context, &circle); let p1 = point_to_cga(0.9, 0.2); draw_point(&context, &p1); let p2 = point_to_cga(-0.9, -0.); draw_point(&context, &p2); let p3 = point_to_cga(0., 0.1); draw_point(&context, &p3); let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3(); draw_line(&context, &circle); let p1 = point_to_cga(0.9, 0.1); draw_point(&context, &p1); let p2 = point_to_cga(-0.9, -0.1); draw_point(&context, &p2); let p3 = point_to_cga(0., 0.0); draw_point(&context, &p3); let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3(); draw_line(&context, &circle); Ok(()) }