diff --git a/app-proto/Cargo.toml b/app-proto/Cargo.toml index c11fef4..38205a7 100644 --- a/app-proto/Cargo.toml +++ b/app-proto/Cargo.toml @@ -26,7 +26,6 @@ console_error_panic_hook = { version = "0.1.7", optional = true } [dependencies.web-sys] version = "0.3.69" features = [ - 'DomRect', 'HtmlCanvasElement', 'HtmlInputElement', 'Performance', diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index fb5bbf7..59cba41 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -1,4 +1,4 @@ -use nalgebra::{DMatrix, DVector, Vector3}; +use nalgebra::{DMatrix, DVector}; use rustc_hash::FxHashMap; use slab::Slab; use std::{collections::BTreeSet, sync::atomic::{AtomicU64, Ordering}}; @@ -65,49 +65,6 @@ impl Element { column_index: 0 } } - - // the smallest positive depth, represented as a multiple of `dir`, where - // the line generated by `dir` hits the element (which is assumed to be a - // sphere). returns `None` if the line misses the sphere. this function - // should be kept synchronized with `sphere_cast` in `inversive.frag`, which - // does essentially the same thing on the GPU side - pub fn cast(&self, dir: Vector3, assembly_to_world: &DMatrix) -> Option { - // if `a/b` is less than this threshold, we approximate - // `a*u^2 + b*u + c` by the linear function `b*u + c` - const DEG_THRESHOLD: f64 = 1e-9; - - let rep = self.representation.with_untracked(|rep| assembly_to_world * rep); - let a = -rep[3] * dir.norm_squared(); - let b = rep.rows_range(..3).dot(&dir); - let c = -rep[4]; - - let adjust = 4.0*a*c/(b*b); - if adjust < 1.0 { - // as long as `b` is non-zero, the linear approximation of - // - // a*u^2 + b*u + c - // - // at `u = 0` will reach zero at a finite depth `u_lin`. the root of - // the quadratic adjacent to `u_lin` is stored in `lin_root`. if - // both roots have the same sign, `lin_root` will be the one closer - // to `u = 0` - let square_rect_ratio = 1.0 + (1.0 - adjust).sqrt(); - let lin_root = -(2.0*c)/b / square_rect_ratio; - if a.abs() > DEG_THRESHOLD * b.abs() { - if lin_root > 0.0 { - Some(lin_root) - } else { - let other_root = -b/(2.*a) * square_rect_ratio; - (other_root > 0.0).then_some(other_root) - } - } else { - (lin_root > 0.0).then_some(lin_root) - } - } else { - // the line through `dir` misses the sphere completely - None - } - } } diff --git a/app-proto/src/display.rs b/app-proto/src/display.rs index c39e575..ee0af47 100644 --- a/app-proto/src/display.rs +++ b/app-proto/src/display.rs @@ -4,9 +4,7 @@ use sycamore::{prelude::*, motion::create_raf}; use web_sys::{ console, window, - Element, KeyboardEvent, - MouseEvent, WebGl2RenderingContext, WebGlProgram, WebGlShader, @@ -14,7 +12,7 @@ use web_sys::{ wasm_bindgen::{JsCast, JsValue} }; -use crate::{AppState, assembly::ElementKey}; +use crate::AppState; fn compile_shader( context: &WebGl2RenderingContext, @@ -84,24 +82,6 @@ fn bind_vertex_attrib( ); } -// the direction in camera space that a mouse event is pointing along -fn event_dir(event: &MouseEvent) -> Vector3 { - let target: Element = event.target().unwrap().unchecked_into(); - let rect = target.get_bounding_client_rect(); - let width = rect.width(); - let height = rect.height(); - let shortdim = width.min(height); - - // this constant should be kept synchronized with `inversive.frag` - const FOCAL_SLOPE: f64 = 0.3; - - Vector3::new( - FOCAL_SLOPE * (2.0*(f64::from(event.client_x()) - rect.left()) - width) / shortdim, - FOCAL_SLOPE * (2.0*(rect.bottom() - f64::from(event.client_y())) - height) / shortdim, - -1.0 - ) -} - #[component] pub fn Display() -> View { let state = use_context::(); @@ -109,9 +89,6 @@ pub fn Display() -> View { // canvas let display = create_node_ref(); - // viewpoint - let assembly_to_world = create_signal(DMatrix::::identity(5, 5)); - // navigation let pitch_up = create_signal(0.0); let pitch_down = create_signal(0.0); @@ -319,7 +296,7 @@ pub fn Display() -> View { 0.0, 0.0, 0.0, 0.0, 1.0 ]) }; - let asm_to_world = &location * &orientation; + let assembly_to_world = &location * &orientation; // get the assembly let ( @@ -334,7 +311,7 @@ pub fn Display() -> View { // representation vectors in world coordinates elts.iter().map( - |(_, elt)| elt.representation.with(|rep| &asm_to_world * rep) + |(_, elt)| elt.representation.with(|rep| &assembly_to_world * rep) ).collect::>(), // colors @@ -393,9 +370,6 @@ pub fn Display() -> View { // draw the scene ctx.draw_arrays(WebGl2RenderingContext::TRIANGLES, 0, VERTEX_CNT as i32); - // update the viewpoint - assembly_to_world.set(asm_to_world); - // clear the scene change flag scene_changed.set( pitch_up_val != 0.0 @@ -484,31 +458,6 @@ pub fn Display() -> View { yaw_left.set(0.0); roll_ccw.set(0.0); roll_cw.set(0.0); - }, - on:click=move |event: MouseEvent| { - // find the nearest element along the pointer direction - let dir = event_dir(&event); - console::log_1(&JsValue::from(dir.to_string())); - let mut clicked: Option<(ElementKey, f64)> = None; - for (key, elt) in state.assembly.elements.get_clone_untracked() { - match assembly_to_world.with(|asm_to_world| elt.cast(dir, asm_to_world)) { - Some(depth) => match clicked { - Some((_, best_depth)) => { - if depth < best_depth { - clicked = Some((key, depth)) - } - }, - None => clicked = Some((key, depth)) - } - None => () - }; - } - - // if we clicked something, select it - match clicked { - Some((key, _)) => state.select(key, event.shift_key()), - None => state.selection.update(|sel| sel.clear()) - }; } ) } diff --git a/app-proto/src/main.rs b/app-proto/src/main.rs index 8a012d3..897f9d4 100644 --- a/app-proto/src/main.rs +++ b/app-proto/src/main.rs @@ -25,24 +25,6 @@ impl AppState { selection: create_signal(FxHashSet::default()) } } - - // in single-selection mode, select the element with the given key. in - // multiple-selection mode, toggle whether the element with the given key - // is selected - fn select(&self, key: ElementKey, multi: bool) { - if multi { - self.selection.update(|sel| { - if !sel.remove(&key) { - sel.insert(key); - } - }); - } else { - self.selection.update(|sel| { - sel.clear(); - sel.insert(key); - }); - } - } } fn main() { diff --git a/app-proto/src/outline.rs b/app-proto/src/outline.rs index 148f870..e2cf49c 100644 --- a/app-proto/src/outline.rs +++ b/app-proto/src/outline.rs @@ -83,7 +83,18 @@ fn ElementOutlineItem(key: ElementKey, element: assembly::Element) -> View { move |event: KeyboardEvent| { match event.key().as_str() { "Enter" => { - state.select(key, event.shift_key()); + if event.shift_key() { + state.selection.update(|sel| { + if !sel.remove(&key) { + sel.insert(key); + } + }); + } else { + state.selection.update(|sel| { + sel.clear(); + sel.insert(key); + }); + } event.prevent_default(); }, "ArrowRight" if constrained.get() => {