Skip to content

Commit

Permalink
Merge pull request #806 from jeevcat/sam/translate
Browse files Browse the repository at this point in the history
Moving the model should work without a focus point
  • Loading branch information
hannobraun authored Jul 13, 2022
2 parents 01b0e7e + 74bc14e commit 33ea122
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 90 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions crates/fj-viewer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ path = "../fj-interop"
version = "0.7.0"
path = "../fj-math"

[dependencies.fj-operations]
version = "0.7.0"
path = "../fj-operations"

[dependencies.egui]
version = "0.18.1"

Expand Down
40 changes: 18 additions & 22 deletions crates/fj-viewer/src/camera.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Viewer camera module
use std::f64::consts::FRAC_PI_2;

use fj_interop::mesh::Mesh;
use fj_math::{Aabb, Point, Scalar, Transform, Triangle, Vector};
use fj_operations::shape_processor::ProcessedShape;

use crate::screen::NormalizedPosition;

Expand Down Expand Up @@ -121,21 +121,25 @@ impl Camera {
pub fn focus_point(
&self,
cursor: Option<NormalizedPosition>,
mesh: &Mesh<fj_math::Point<3>>,
shape: &ProcessedShape,
) -> FocusPoint {
let cursor = match cursor {
Some(cursor) => cursor,
None => return FocusPoint::none(),
};
self.calculate_focus_point(cursor, shape)
.unwrap_or_else(|| FocusPoint(shape.aabb.center()))
}

fn calculate_focus_point(
&self,
cursor: Option<NormalizedPosition>,
shape: &ProcessedShape,
) -> Option<FocusPoint> {
// Transform camera and cursor positions to model space.
let origin = self.position();
let cursor = self.cursor_to_model_space(cursor);
let cursor = self.cursor_to_model_space(cursor?);
let dir = (cursor - origin).normalize();

let mut min_t = None;

for triangle in mesh.triangles() {
for triangle in shape.mesh.triangles() {
let t = Triangle::from_points(triangle.points).cast_local_ray(
origin,
dir,
Expand All @@ -150,7 +154,7 @@ impl Camera {
}
}

FocusPoint(min_t.map(|t| origin + dir * t))
Some(FocusPoint(origin + dir * min_t?))
}

/// Access the transform from camera to model space.
Expand Down Expand Up @@ -211,17 +215,9 @@ impl Camera {
}
}

/// The point on the model that the cursor is currently pointing at.
/// The point around which camera movement happens.
///
/// Such a point might or might not exist, depending on whether the cursor is
/// pointing at the model or not.
pub struct FocusPoint(pub Option<Point<3>>);

impl FocusPoint {
/// Construct the "none" instance of `FocusPoint`
///
/// This instance represents the case that no focus point exists.
pub fn none() -> Self {
Self(None)
}
}
/// This will be the point on the model that the cursor is currently pointing at if such a point exists,
/// falling back to the center point of the model's bounding volume otherwise.
#[derive(Clone, Copy)]
pub struct FocusPoint(pub Point<3>);
30 changes: 11 additions & 19 deletions crates/fj-viewer/src/input/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,36 @@ use crate::camera::{Camera, FocusPoint};
///
/// Takes user input and applies them to application state.
pub struct Handler {
focus_point: FocusPoint,

movement: Movement,
rotation: Rotation,
zoom: Zoom,
}

impl Handler {
/// Handle an input event
pub fn handle_event(&mut self, event: Event, camera: &mut Camera) {
pub fn handle_event(
&mut self,
event: Event,
focus_point: FocusPoint,
camera: &mut Camera,
) {
match event {
Event::Translate { previous, current } => self.movement.apply(
previous,
current,
&self.focus_point,
camera,
),
Event::Translate { previous, current } => {
self.movement.apply(previous, current, focus_point, camera)
}
Event::Rotation { angle_x, angle_y } => {
self.rotation
.apply(angle_x, angle_y, &self.focus_point, camera)
self.rotation.apply(angle_x, angle_y, focus_point, camera)
}
Event::Zoom(zoom_delta) => {
self.zoom.apply(zoom_delta, &self.focus_point, camera)
self.zoom.apply(zoom_delta, focus_point, camera)
}
}
}

/// A new focus point was selected (or deselected)
pub fn focus(&mut self, focus_point: FocusPoint) {
self.focus_point = focus_point;
}
}

impl Default for Handler {
fn default() -> Self {
Self {
focus_point: FocusPoint::none(),

movement: Movement,
rotation: Rotation,
zoom: Zoom,
Expand Down
24 changes: 11 additions & 13 deletions crates/fj-viewer/src/input/movement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,23 @@ impl Movement {
&mut self,
previous: NormalizedPosition,
current: NormalizedPosition,
focus_point: &FocusPoint,
focus_point: FocusPoint,
camera: &mut Camera,
) {
let previous = camera.cursor_to_model_space(previous);
let cursor = camera.cursor_to_model_space(current);

if let Some(focus_point) = focus_point.0 {
let d1 = Point::distance(&camera.position(), &cursor);
let d2 = Point::distance(&camera.position(), &focus_point);
let d1 = Point::distance(&camera.position(), &cursor);
let d2 = Point::distance(&camera.position(), &focus_point.0);

let diff = (cursor - previous) * d2 / d1;
let offset = camera.camera_to_model().transform_vector(&diff);
let diff = (cursor - previous) * d2 / d1;
let offset = camera.camera_to_model().transform_vector(&diff);

camera.translation = camera.translation
* Transform::translation(Vector::from([
offset.x,
offset.y,
Scalar::ZERO,
]));
}
camera.translation = camera.translation
* Transform::translation(Vector::from([
offset.x,
offset.y,
Scalar::ZERO,
]));
}
}
8 changes: 3 additions & 5 deletions crates/fj-viewer/src/input/rotation.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use fj_math::{Point, Transform, Vector};
use fj_math::{Transform, Vector};

use crate::camera::{Camera, FocusPoint};

Expand All @@ -9,12 +9,10 @@ impl Rotation {
&self,
angle_x: f64,
angle_y: f64,
focus_point: &FocusPoint,
focus_point: FocusPoint,
camera: &mut Camera,
) {
let rotate_around: Vector<3> =
focus_point.0.unwrap_or_else(Point::origin).coords;
let rotate_around = Transform::translation(rotate_around);
let rotate_around = Transform::translation(focus_point.0.coords);

// the model rotates not the camera, so invert the transform
let camera_rotation = camera.rotation.inverse();
Expand Down
7 changes: 2 additions & 5 deletions crates/fj-viewer/src/input/zoom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,10 @@ impl Zoom {
pub fn apply(
&mut self,
zoom_delta: f64,
focus_point: &FocusPoint,
focus_point: FocusPoint,
camera: &mut Camera,
) {
let distance = match focus_point.0 {
Some(fp) => (fp - camera.position()).magnitude(),
None => camera.position().coords.magnitude(),
};
let distance = (focus_point.0 - camera.position()).magnitude();
let displacement = zoom_delta * distance.into_f64();
camera.translation = camera.translation
* Transform::translation(Vector::from([0.0, 0.0, -displacement]));
Expand Down
56 changes: 30 additions & 26 deletions crates/fj-window/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
use std::error;

use fj_host::Watcher;
use fj_operations::shape_processor::{ProcessedShape, ShapeProcessor};
use fj_operations::shape_processor::ShapeProcessor;
use fj_viewer::{
camera::{Camera, FocusPoint},
camera::Camera,
graphics::{self, DrawConfig, Renderer},
input,
screen::{NormalizedPosition, Screen as _, Size},
Expand Down Expand Up @@ -36,6 +36,7 @@ pub fn run(

let mut previous_cursor = None;
let mut held_mouse_button = None;
let mut focus_point = None;

let mut input_handler = input::Handler::default();
let mut renderer = block_on(Renderer::new(&window))?;
Expand Down Expand Up @@ -179,12 +180,20 @@ pub fn run(
_ => {}
}

// fj-viewer events
if let (Some(shape), Some(camera)) = (&shape, &mut camera) {
if let Some(focus_event) =
focus(&event, previous_cursor, shape, camera)
{
input_handler.focus(focus_event);
// fj-viewer input events
// These can fire multiple times per frame

if let (Some(shape), Some(camera), Some(should_focus)) =
(&shape, &camera, focus_event(&event))
{
if should_focus {
// Don't unnecessarily recalculate focus point
if focus_point.is_none() {
focus_point =
Some(camera.focus_point(previous_cursor, shape));
}
} else {
focus_point = None;
}
}

Expand All @@ -194,8 +203,10 @@ pub fn run(
&held_mouse_button,
&mut previous_cursor,
);
if let (Some(input_event), Some(camera)) = (input_event, &mut camera) {
input_handler.handle_event(input_event, camera);
if let (Some(input_event), Some(fp), Some(camera)) =
(input_event, focus_point, &mut camera)
{
input_handler.handle_event(input_event, fp, camera);
}
});
}
Expand Down Expand Up @@ -253,13 +264,10 @@ fn input_event(
}
}

fn focus(
event: &Event<()>,
previous_cursor: Option<NormalizedPosition>,
shape: &ProcessedShape,
camera: &Camera,
) -> Option<FocusPoint> {
let focus_point = match event {
/// Returns true/false if focus point point should be created/removed
/// None means no change to focus point is needed
fn focus_event(event: &Event<()>) -> Option<bool> {
match event {
Event::WindowEvent {
event:
WindowEvent::MouseInput {
Expand All @@ -269,19 +277,15 @@ fn focus(
},
..
} => match state {
ElementState::Pressed => {
camera.focus_point(previous_cursor, &shape.mesh)
}
ElementState::Released => FocusPoint::none(),
ElementState::Pressed => Some(true),
ElementState::Released => Some(false),
},
Event::WindowEvent {
event: WindowEvent::MouseWheel { .. },
..
} => camera.focus_point(previous_cursor, &shape.mesh),

_ => return None,
};
Some(focus_point)
} => Some(true),
_ => None,
}
}

/// Error in main loop
Expand Down

0 comments on commit 33ea122

Please sign in to comment.