diff --git a/src/app/update/viewport.rs b/src/app/update/viewport.rs index 1996ba6e8..7a63147ad 100644 --- a/src/app/update/viewport.rs +++ b/src/app/update/viewport.rs @@ -1436,9 +1436,13 @@ impl OpenCADStudio { if sel.orbit.pivot.is_none() { let scene = &self.tabs[i].scene; let bounds = scene.active_model_tile_bounds(vp_size.0, vp_size.1); + // The surface under the pointer where the drag + // began, so the model turns about what is grabbed. + let grabbed = iced::Point::new(last.x - bounds.x, last.y - bounds.y); sel.orbit.pivot = Some( scene .orbit_pivot() + .or_else(|| scene.surface_pivot_at(bounds, grabbed)) .or_else(|| scene.view_center_surface_pivot(bounds)) .unwrap_or_else(|| scene.camera.borrow().target), ); diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 47f988779..2f173a262 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -11322,14 +11322,22 @@ impl Scene { } pub fn view_center_surface_pivot(&self, bounds: iced::Rectangle) -> Option { + self.surface_pivot_at(bounds, iced::Point::new(bounds.width * 0.5, bounds.height * 0.5)) + } + + /// The nearest solid or mesh surface under `local` (relative to `bounds`). + pub fn surface_pivot_at( + &self, + bounds: iced::Rectangle, + local: iced::Point, + ) -> Option { let camera = self.camera.borrow(); let view_rot = camera.view_proj_rte(bounds); let eye = camera.eye(); drop(camera); let meshes = self.interaction_meshes_arc(); - let center = iced::Point::new(bounds.width * 0.5, bounds.height * 0.5); pick::hit_test::mesh_click_point( - center, + local, meshes.iter().filter_map(|set| { let handle = set.entity_handle()?; let mesh = set.geometry_lods().first()?;