Grid: stay on the ground (XY) by default; following the view is a preference (#2035)
#1583 turned the grid to the upright origin plane in side views for everyone. That is now Preferences > Grid follows the view, off by default; headless pictures keep the ground grid. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a6eeb88de0
commit
72145d4aba
5 files changed
+19
-5
No files matched your search
@@ -1146,6 +1146,8 @@
|
|||||||
"ui.fully_constrained": "Fully constrained",
|
"ui.fully_constrained": "Fully constrained",
|
||||||
"ui.general": "General",
|
"ui.general": "General",
|
||||||
"ui.graphics": "Graphics",
|
"ui.graphics": "Graphics",
|
||||||
|
"ui.grid_follows_view": "Grid follows the view",
|
||||||
|
"ui.grid_follows_view_hint": "Side views show the grid on the upright plane facing them instead of the ground",
|
||||||
"ui.ground_shadow": "Ground shadow",
|
"ui.ground_shadow": "Ground shadow",
|
||||||
"ui.groupSelected": "Group Selected",
|
"ui.groupSelected": "Group Selected",
|
||||||
"ui.heading_add_ins": "ADD-INS",
|
"ui.heading_add_ins": "ADD-INS",
|
||||||
|
|||||||
@@ -390,13 +390,13 @@ fn build_scene(
|
|||||||
};
|
};
|
||||||
let b = bounds(s);
|
let b = bounds(s);
|
||||||
sc.radius = (b.diagonal() * 0.5).max(cam.half_height()).max(10.0) + b.center().dist(cam.target);
|
sc.radius = (b.diagonal() * 0.5).max(cam.half_height()).max(10.0) + b.center().dist(cam.target);
|
||||||
// Grid on the ground plane (XY with Z up, XZ with Y up), or the upright origin plane facing
|
// Grid on the ground plane (XY with Z up, XZ with Y up), drawn under the model as in the viewport.
|
||||||
// a view that sees the ground edge-on ([`grid_plane`]), drawn under the model as in the viewport.
|
|
||||||
if guides.grid {
|
if guides.grid {
|
||||||
let (minor, major) = grid_step(cam.half_height());
|
let (minor, major) = grid_step(cam.half_height());
|
||||||
let ext = (cam.half_height() * 3.0 / major).ceil() * major;
|
let ext = (cam.half_height() * 3.0 / major).ceil() * major;
|
||||||
let tf = cam.to_frame(cam.target);
|
let tf = cam.to_frame(cam.target);
|
||||||
let (u, v) = grid_plane(cam.to_frame(cam.back()));
|
// Headless pictures keep the grid on the ground, the viewport's default.
|
||||||
|
let (u, v) = (Vec3::X, Vec3::Y);
|
||||||
let snap = |a: Vec3| a * ((tf.dot(a) / major).round() * major);
|
let snap = |a: Vec3| a * ((tf.dot(a) / major).round() * major);
|
||||||
let c = snap(u) + snap(v);
|
let c = snap(u) + snap(v);
|
||||||
let w = |p: Vec3| cam.from_frame(p);
|
let w = |p: Vec3| cam.from_frame(p);
|
||||||
|
|||||||
@@ -280,6 +280,9 @@ pub struct Prefs {
|
|||||||
pub space_mouse_axis_speed: [f32; 6],
|
pub space_mouse_axis_speed: [f32; 6],
|
||||||
/// Anti-aliasing samples (applies on restart).
|
/// Anti-aliasing samples (applies on restart).
|
||||||
pub msaa: u32,
|
pub msaa: u32,
|
||||||
|
/// The grid turns to the upright origin plane facing a side view (#1470). Off by default: the
|
||||||
|
/// grid stays on the ground plane (XY) whatever the view.
|
||||||
|
pub grid_follows_view: bool,
|
||||||
/// How finely the viewport tessellates curved faces and edges: `coarse`, `normal`, `fine` or
|
/// How finely the viewport tessellates curved faces and edges: `coarse`, `normal`, `fine` or
|
||||||
/// `ultra` (#1287). Only the display plan the viewport draws; never the design or exports.
|
/// `ultra` (#1287). Only the display plan the viewport draws; never the design or exports.
|
||||||
pub display_quality: String,
|
pub display_quality: String,
|
||||||
@@ -410,6 +413,7 @@ impl Default for Prefs {
|
|||||||
space_mouse_reverse: [false; 6],
|
space_mouse_reverse: [false; 6],
|
||||||
space_mouse_axis_speed: [1.0; 6],
|
space_mouse_axis_speed: [1.0; 6],
|
||||||
msaa: 4,
|
msaa: 4,
|
||||||
|
grid_follows_view: false,
|
||||||
display_quality: "normal".into(),
|
display_quality: "normal".into(),
|
||||||
supersampling: 1.0,
|
supersampling: 1.0,
|
||||||
supersampling_adaptive: true,
|
supersampling_adaptive: true,
|
||||||
@@ -1265,6 +1269,10 @@ fn page(app: &mut SolveApp, ui: &mut egui::Ui, t: &Tokens) {
|
|||||||
ui.label(crate::i18n::tr_label("Grid"));
|
ui.label(crate::i18n::tr_label("Grid"));
|
||||||
ui.checkbox(&mut app.ui.show_grid, "");
|
ui.checkbox(&mut app.ui.show_grid, "");
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
ui.label(crate::i18n::tr_label("Grid follows the view"));
|
||||||
|
ui.add_enabled(app.ui.show_grid, egui::Checkbox::without_text(&mut app.preferences.grid_follows_view))
|
||||||
|
.on_hover_text(crate::i18n::tr_label("Side views show the grid on the upright plane facing them instead of the ground"));
|
||||||
|
ui.end_row();
|
||||||
ui.label(crate::i18n::tr_label("Ground shadow"));
|
ui.label(crate::i18n::tr_label("Ground shadow"));
|
||||||
ui.checkbox(&mut app.ui.ground_shadow, "");
|
ui.checkbox(&mut app.ui.ground_shadow, "");
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|||||||
@@ -290,7 +290,10 @@ fn unzip_one(zip: &Path, name: &str, to: &Path) -> Result<bool, String> {
|
|||||||
let file = std::fs::File::open(zip).map_err(|e| format!("{}: {e}", zip.display()))?;
|
let file = std::fs::File::open(zip).map_err(|e| format!("{}: {e}", zip.display()))?;
|
||||||
let mut archive = zip::ZipArchive::new(file).map_err(|e| format!("{}: {e}", zip.display()))?;
|
let mut archive = zip::ZipArchive::new(file).map_err(|e| format!("{}: {e}", zip.display()))?;
|
||||||
let index = (0..archive.len()).find(|&i| {
|
let index = (0..archive.len()).find(|&i| {
|
||||||
archive.name_for_index(i).is_some_and(|n| n.rsplit(['/', '\\']).next().is_some_and(|f| f.eq_ignore_ascii_case(name)) && !n.ends_with('/'))
|
archive
|
||||||
|
.name_for_index(i)
|
||||||
|
.and_then(Result::ok)
|
||||||
|
.is_some_and(|n| n.rsplit(['/', '\\']).next().is_some_and(|f| f.eq_ignore_ascii_case(name)) && !n.ends_with('/'))
|
||||||
});
|
});
|
||||||
let Some(index) = index else { return Ok(false) };
|
let Some(index) = index else { return Ok(false) };
|
||||||
let mut entry = archive.by_index(index).map_err(|e| format!("{}: {e}", zip.display()))?;
|
let mut entry = archive.by_index(index).map_err(|e| format!("{}: {e}", zip.display()))?;
|
||||||
|
|||||||
@@ -733,7 +733,8 @@ fn build_sketch_scene(app: &SolveApp, proj: &Proj) -> GpuScene {
|
|||||||
// The ground plane: XY with Z up, XZ with Y up (laid out in the camera's Z-up frame), or
|
// The ground plane: XY with Z up, XZ with Y up (laid out in the camera's Z-up frame), or
|
||||||
// the upright origin plane facing the view when the ground is seen edge-on.
|
// the upright origin plane facing the view when the ground is seen edge-on.
|
||||||
let tf = app.cam.to_frame(app.cam.target);
|
let tf = app.cam.to_frame(app.cam.target);
|
||||||
let (u, v) = grid_plane(app.cam.to_frame(app.cam.back()));
|
// On the ground (XY) unless the Grid follows the view preference is on (#1470).
|
||||||
|
let (u, v) = if app.preferences.grid_follows_view { grid_plane(app.cam.to_frame(app.cam.back())) } else { (Vec3::X, Vec3::Y) };
|
||||||
let snap = |a: Vec3| a * ((tf.dot(a) / major).round() * major);
|
let snap = |a: Vec3| a * ((tf.dot(a) / major).round() * major);
|
||||||
let c = snap(u) + snap(v);
|
let c = snap(u) + snap(v);
|
||||||
let w3 = |p: Vec3| app.cam.from_frame(p).to_f32();
|
let w3 = |p: Vec3| app.cam.from_frame(p).to_f32();
|
||||||
|
|||||||
Reference in new issue
Block a user