Look At pressed again looks from the other side (#1886) (#1904)

Thanks @DuBearte.
This commit is contained in:
DuBearte authored and GitHub committed 2026-10-17 04:08:09 -04:00
1 parent 39850fb6ab
commit cd9db57366
4 files changed
+47 -7

No files matched your search

+20 -3
View File
@@ -3505,19 +3505,36 @@ fn plane_by_name(app: &SolveApp, name: &str) -> Option<solidcraft_engine::geom::
/// Animate the camera to look straight at the active sketch plane.
pub fn look_at_sketch(app: &mut SolveApp) {
look_at_sketch_from(app, false);
}
/// Look At asked for by the user (Ctrl+8, the Look At buttons): like [`look_at_sketch`], and
/// from the sketch's other side when the view already faces it (#1886).
pub fn look_at_sketch_again(app: &mut SolveApp) {
look_at_sketch_from(app, true);
}
fn look_at_sketch_from(app: &mut SolveApp, again: bool) {
let st = app.session.world_state();
if let Some(ss) = app.session.active_sketch.and_then(|id| st.sketch(id)) {
let mut to = app.cam.looking_from(ss.plane.normal());
let n = facing(app, ss.plane.normal(), again);
let mut to = app.cam.looking_from(n);
// Keep the sketch's own x axis to the right when looking straight down or up.
if ss.plane.normal().z.abs() > 0.999 {
if n.z.abs() > 0.999 {
let x = ss.plane.x;
to.yaw = if ss.plane.normal().z > 0.0 { (-x.y).atan2(x.x) } else { x.y.atan2(x.x) };
to.yaw = if n.z > 0.0 { (-x.y).atan2(x.x) } else { x.y.atan2(x.x) };
}
to.target = ss.plane.origin;
app.animate_to(to);
}
}
/// The side to look from at a plane with normal `n`: its own side, or with `again` the other
/// side when the view already looks from `n`, so a second Look At turns the view round (#1886).
pub(crate) fn facing(app: &SolveApp, n: Vec3, again: bool) -> Vec3 {
if again && app.cam.back().dot(n) > 0.999 { -n } else { n }
}
fn sels(d: &Dialog, i: usize) -> &[Sel] {
d.inputs.get(i).map(|x| x.items.as_slice()).unwrap_or(&[])
}
+22
View File
@@ -915,4 +915,26 @@ mod view_key_tests {
}
assert!(crate::keymap::RESERVED.contains(&crate::keymap::key_name(egui::Key::Num8, egui::Modifiers::COMMAND).as_str()));
}
/// #1886: Ctrl+8 looks straight at the sketch; pressed again while the view faces it, it
/// looks from the other side, and a third press turns it back. Opening a sketch never flips.
#[test]
fn ctrl_8_again_looks_from_the_other_side() {
let mut h = Harness::new();
h.app.preferences.look_at_anim = false;
h.app.run("sketch.create", json!({"plane": "XY"})).unwrap();
h.frames(2);
let back_z = |h: &Harness| h.app.cam.back().z;
for want in [1.0, -1.0, 1.0] {
h.step(&json!({"key": "8", "cmd": true})).unwrap();
h.frames(2);
assert!((back_z(&h) - want).abs() < 1e-3, "looking from z {want}: back {:?}", h.app.cam.back());
}
// Programmatic look-at (as on opening a sketch) keeps the sketch's own side.
crate::dialogs::look_at_sketch(&mut h.app);
h.frames(2);
crate::dialogs::look_at_sketch(&mut h.app);
h.frames(2);
assert!((back_z(&h) - 1.0).abs() < 1e-3, "{:?}", h.app.cam.back());
}
}
+1 -1
View File
@@ -575,7 +575,7 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
app.start(id);
}
if look {
crate::dialogs::look_at_sketch(app);
crate::dialogs::look_at_sketch_again(app);
}
if finish {
app.finish_sketch();
+4 -3
View File
@@ -3348,7 +3348,8 @@ pub(crate) fn nearest_quarter_turn(yaw: f64) -> f64 {
}
/// Navigation bar (bottom centre).
/// Turn the view to face the selected planar face or plane, else the active sketch.
/// Turn the view to face the selected planar face or plane, else the active sketch; asked again
/// while it already faces it, from the other side (#1886).
pub fn look_at_selection(app: &mut SolveApp) {
let target = app.session.selection.iter().find_map(|s| match s {
Sel::Face { body, index, point } => crate::dialogs::planar_face(&app.session, body, *index).map(|(_, n)| (*point, n)),
@@ -3357,11 +3358,11 @@ pub fn look_at_selection(app: &mut SolveApp) {
});
match target {
Some((p, n)) => {
let mut to = app.cam.looking_from(n);
let mut to = app.cam.looking_from(crate::dialogs::facing(app, n, true));
to.target = p;
app.animate_to(to);
}
None => crate::dialogs::look_at_sketch(app),
None => crate::dialogs::look_at_sketch_again(app),
}
}