Hyperbolic Asteroids, first commit. Rendering Poincare disk, circles, and lines.
This commit is contained in:
213
src/lib.rs
Normal file
213
src/lib.rs
Normal file
@@ -0,0 +1,213 @@
|
||||
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(())
|
||||
}
|
||||
Reference in New Issue
Block a user