214 lines
5.6 KiB
Rust
214 lines
5.6 KiB
Rust
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::<HtmlCanvasElement>()?;
|
|
|
|
canvas.set_width(WIDTH as u32);
|
|
canvas.set_height(HEIGHT as u32);
|
|
|
|
let context = canvas
|
|
.get_context("2d")?
|
|
.unwrap()
|
|
.dyn_into::<CanvasRenderingContext2d>()?;
|
|
|
|
//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(())
|
|
}
|