forked from StudioInfinity/dyna3
Click the display to select points
This commit is contained in:
parent
bbd4ee08b6
commit
b7375e7101
1 changed files with 36 additions and 11 deletions
|
@ -92,7 +92,7 @@ pub trait DisplayItem {
|
||||||
// the smallest positive depth, represented as a multiple of `dir`, where
|
// the smallest positive depth, represented as a multiple of `dir`, where
|
||||||
// the line generated by `dir` hits the element. returns `None` if the line
|
// the line generated by `dir` hits the element. returns `None` if the line
|
||||||
// misses the element
|
// misses the element
|
||||||
fn cast(&self, dir: Vector3<f64>, assembly_to_world: &DMatrix<f64>) -> Option<f64>;
|
fn cast(&self, dir: Vector3<f64>, assembly_to_world: &DMatrix<f64>, pixel_size: f64) -> Option<f64>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayItem for Sphere {
|
impl DisplayItem for Sphere {
|
||||||
|
@ -106,7 +106,7 @@ impl DisplayItem for Sphere {
|
||||||
|
|
||||||
// this method should be kept synchronized with `sphere_cast` in
|
// this method should be kept synchronized with `sphere_cast` in
|
||||||
// `spheres.frag`, which does essentially the same thing on the GPU side
|
// `spheres.frag`, which does essentially the same thing on the GPU side
|
||||||
fn cast(&self, dir: Vector3<f64>, assembly_to_world: &DMatrix<f64>) -> Option<f64> {
|
fn cast(&self, dir: Vector3<f64>, assembly_to_world: &DMatrix<f64>, _pixel_size: f64) -> Option<f64> {
|
||||||
// if `a/b` is less than this threshold, we approximate
|
// if `a/b` is less than this threshold, we approximate
|
||||||
// `a*u^2 + b*u + c` by the linear function `b*u + c`
|
// `a*u^2 + b*u + c` by the linear function `b*u + c`
|
||||||
const DEG_THRESHOLD: f64 = 1e-9;
|
const DEG_THRESHOLD: f64 = 1e-9;
|
||||||
|
@ -155,8 +155,30 @@ impl DisplayItem for Point {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SCAFFOLDING */
|
/* SCAFFOLDING */
|
||||||
fn cast(&self, _dir: Vector3<f64>, _assembly_to_world: &DMatrix<f64>) -> Option<f64> {
|
fn cast(&self, dir: Vector3<f64>, assembly_to_world: &DMatrix<f64>, pixel_size: f64) -> Option<f64> {
|
||||||
None
|
let rep = self.representation.with_untracked(|rep| assembly_to_world * rep);
|
||||||
|
if rep[2] < 0.0 {
|
||||||
|
// this constant should be kept synchronized with `point.frag`
|
||||||
|
const POINT_RADIUS_PX: f64 = 4.0;
|
||||||
|
|
||||||
|
// find the radius of the point in screen projection units
|
||||||
|
let point_radius_proj = POINT_RADIUS_PX * pixel_size;
|
||||||
|
|
||||||
|
// find the squared distance between the screen projections of the
|
||||||
|
// ray and the point
|
||||||
|
let dir_proj = -dir.fixed_rows::<2>(0) / dir[2];
|
||||||
|
let rep_proj = -rep.fixed_rows::<2>(0) / rep[2];
|
||||||
|
let dist_sq = (dir_proj - rep_proj).norm_squared();
|
||||||
|
|
||||||
|
// if the ray hits the point, return its depth
|
||||||
|
if dist_sq < point_radius_proj * point_radius_proj {
|
||||||
|
Some(rep[2] / dir[2])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +304,7 @@ fn bind_new_buffer_to_attribute(
|
||||||
}
|
}
|
||||||
|
|
||||||
// the direction in camera space that a mouse event is pointing along
|
// the direction in camera space that a mouse event is pointing along
|
||||||
fn event_dir(event: &MouseEvent) -> Vector3<f64> {
|
fn event_dir(event: &MouseEvent) -> (Vector3<f64>, f64) {
|
||||||
let target: web_sys::Element = event.target().unwrap().unchecked_into();
|
let target: web_sys::Element = event.target().unwrap().unchecked_into();
|
||||||
let rect = target.get_bounding_client_rect();
|
let rect = target.get_bounding_client_rect();
|
||||||
let width = rect.width();
|
let width = rect.width();
|
||||||
|
@ -293,10 +315,13 @@ fn event_dir(event: &MouseEvent) -> Vector3<f64> {
|
||||||
// `point.vert`
|
// `point.vert`
|
||||||
const FOCAL_SLOPE: f64 = 0.3;
|
const FOCAL_SLOPE: f64 = 0.3;
|
||||||
|
|
||||||
Vector3::new(
|
(
|
||||||
FOCAL_SLOPE * (2.0*(f64::from(event.client_x()) - rect.left()) - width) / shortdim,
|
Vector3::new(
|
||||||
FOCAL_SLOPE * (2.0*(rect.bottom() - f64::from(event.client_y())) - height) / shortdim,
|
FOCAL_SLOPE * (2.0*(f64::from(event.client_x()) - rect.left()) - width) / shortdim,
|
||||||
-1.0
|
FOCAL_SLOPE * (2.0*(rect.bottom() - f64::from(event.client_y())) - height) / shortdim,
|
||||||
|
-1.0
|
||||||
|
),
|
||||||
|
FOCAL_SLOPE * 2.0 / shortdim
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,11 +847,11 @@ pub fn Display() -> View {
|
||||||
},
|
},
|
||||||
on:click=move |event: MouseEvent| {
|
on:click=move |event: MouseEvent| {
|
||||||
// find the nearest element along the pointer direction
|
// find the nearest element along the pointer direction
|
||||||
let dir = event_dir(&event);
|
let (dir, pixel_size) = event_dir(&event);
|
||||||
console::log_1(&JsValue::from(dir.to_string()));
|
console::log_1(&JsValue::from(dir.to_string()));
|
||||||
let mut clicked: Option<(ElementKey, f64)> = None;
|
let mut clicked: Option<(ElementKey, f64)> = None;
|
||||||
for (key, elt) in state.assembly.elements.get_clone_untracked() {
|
for (key, elt) in state.assembly.elements.get_clone_untracked() {
|
||||||
match assembly_to_world.with(|asm_to_world| elt.cast(dir, asm_to_world)) {
|
match assembly_to_world.with(|asm_to_world| elt.cast(dir, asm_to_world, pixel_size)) {
|
||||||
Some(depth) => match clicked {
|
Some(depth) => match clicked {
|
||||||
Some((_, best_depth)) => {
|
Some((_, best_depth)) => {
|
||||||
if depth < best_depth {
|
if depth < best_depth {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue