Camera: Fit (F6, navigation bar) frames the selection when there is one; the wheel zooms toward the model's surface under the cursor
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
a3d187ccd1
commit
aee1e941bf
2 files changed
+61
-1
No files matched your search
@@ -599,7 +599,11 @@ impl SolveApp {
|
||||
pub fn animate_view(&mut self, v: &str) {
|
||||
let mut to = self.cam;
|
||||
match v {
|
||||
"fit" => to = self.fitted(to),
|
||||
// With something selected, Fit frames the selection.
|
||||
"fit" => match viewport::selection_bounds(self) {
|
||||
Some(b) => to.fit(&b),
|
||||
None => to = self.fitted(to),
|
||||
},
|
||||
"home" => {
|
||||
to.set_view(StandardView::Iso);
|
||||
to = self.fitted(to);
|
||||
|
||||
@@ -664,6 +664,58 @@ pub fn section_plane(app: &SolveApp) -> Option<(Vec3, Vec3)> {
|
||||
app.session.section
|
||||
}
|
||||
|
||||
/// The box around what is selected (bodies, faces, edges, vertices, sketch curves and the
|
||||
/// bodies of selected features), where it is shown.
|
||||
pub fn selection_bounds(app: &SolveApp) -> Option<solvecraft_engine::geom::Aabb3> {
|
||||
let st = app.session.world_state();
|
||||
let mut b = solvecraft_engine::geom::Aabb3::EMPTY;
|
||||
for s in &app.session.selection {
|
||||
match s {
|
||||
Sel::Body { name } => {
|
||||
if let Some(x) = st.body(name) {
|
||||
b = b.union(&x.mesh().bounds());
|
||||
}
|
||||
}
|
||||
Sel::Face { body, index, .. } => {
|
||||
if let Some(x) = st.body(body) {
|
||||
let m = x.mesh();
|
||||
for (t, f) in m.triangles.iter().zip(&m.tri_face) {
|
||||
if *f as usize == *index {
|
||||
for p in m.tri(t).into_iter().flatten() {
|
||||
b.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Sel::Edge { body, index, .. } => {
|
||||
if let Some(e) = st.body(body).and_then(|x| x.mesh().edges.get(*index).cloned()) {
|
||||
for p in e {
|
||||
b.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
Sel::Vertex { point, .. } => b.add(*point),
|
||||
Sel::Feature { id } => {
|
||||
for x in st.bodies.iter().filter(|x| x.feature == *id) {
|
||||
b = b.union(&x.mesh().bounds());
|
||||
}
|
||||
}
|
||||
Sel::SketchCurve { id } => {
|
||||
for ss in &st.sketches {
|
||||
if let Some(i) = ss.sketch.curve_index(id) {
|
||||
for q in ss.sketch.polyline(i) {
|
||||
b.add(ss.plane.to_world(q));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
(!b.is_empty()).then_some(b)
|
||||
}
|
||||
|
||||
/// The section as the shader's clip plane (normal, d), zero when there is none.
|
||||
/// The surface analysis for the shader (see `gpu::ViewportCallback::analysis`).
|
||||
fn analysis_uniform(app: &SolveApp) -> [f32; 8] {
|
||||
@@ -1079,6 +1131,10 @@ pub fn show(app: &mut SolveApp, ui: &mut egui::Ui) {
|
||||
let f = (-scroll as f64 * 0.0015 * crate::prefs::zoom_sign(app)).exp();
|
||||
let anchor = hover.map(|p| {
|
||||
let proj = projection(app, rect);
|
||||
// Toward the model's surface under the cursor, else the target's depth.
|
||||
if let Some(q) = pick_cached(app, &proj, p).iter().find_map(|h| if let Hit::Face { point, .. } = h { Some(*point) } else { None }) {
|
||||
return q;
|
||||
}
|
||||
let (o, d) = proj.ray(p);
|
||||
let n = app.cam.back();
|
||||
let den = d.dot(n);
|
||||
|
||||
Reference in new issue
Block a user