forked from 1b-agent/opencadstudio-upstream
Merge PR #1577 from mechpanos/fix/zoom-cursor-and-extents: zoom cursor per navigation tool, and ZOOM EXTENTS frames everything
This commit is contained in:
commit
e8a4f1316f
8 files changed
+514
-341
No files matched your search
@@ -72,5 +72,8 @@ mod viewport_wide_polyline_plot_width;
|
||||
#[path = "xclip_plot_test.rs"]
|
||||
mod xclip_plot_test;
|
||||
|
||||
#[path = "zoom_extents_coverage.rs"]
|
||||
mod zoom_extents_coverage;
|
||||
|
||||
#[path = "zoom_extents_xline.rs"]
|
||||
mod zoom_extents_xline;
|
||||
@@ -0,0 +1,123 @@
|
||||
//! ZOOM EXTENTS must frame every visible entity, the way commercial solutions
|
||||
//! do — no heuristic allowed to decide that part of the drawing does not count.
|
||||
//!
|
||||
//! Two things used to stop it. A quartile filter dropped any wire whose
|
||||
//! centroid sat far from the consensus of the others, so a detail parked away
|
||||
//! from the main body was silently left outside the fit. And HATCH tessellates
|
||||
//! to no wires at all, so a drawing whose outermost geometry is a fill had
|
||||
//! nothing for the model-space walk to read.
|
||||
#![cfg(not(target_arch = "wasm32"))]
|
||||
|
||||
use codec::entities::hatch::{BoundaryEdge, BoundaryPath, LineEdge};
|
||||
use codec::entities::{Hatch, Line};
|
||||
use codec::types::{Vector2, Vector3};
|
||||
use codec::EntityType;
|
||||
use OpenCADStudio::scene::Scene;
|
||||
|
||||
fn add_line(scene: &mut Scene, x1: f64, y1: f64, x2: f64, y2: f64) {
|
||||
let mut line = Line::new();
|
||||
line.start = Vector3::new(x1, y1, 0.0);
|
||||
line.end = Vector3::new(x2, y2, 0.0);
|
||||
scene.add_entity(EntityType::Line(line));
|
||||
}
|
||||
|
||||
/// A solid square fill with corners (x, y) .. (x + size, y + size).
|
||||
fn square_hatch(x: f64, y: f64, size: f64) -> Hatch {
|
||||
let mut path = BoundaryPath::new();
|
||||
for (sx, sy, ex, ey) in [
|
||||
(0.0, 0.0, size, 0.0),
|
||||
(size, 0.0, size, size),
|
||||
(size, size, 0.0, size),
|
||||
(0.0, size, 0.0, 0.0),
|
||||
] {
|
||||
path.edges.push(BoundaryEdge::Line(LineEdge {
|
||||
start: Vector2::new(x + sx, y + sy),
|
||||
end: Vector2::new(x + ex, y + ey),
|
||||
}));
|
||||
}
|
||||
let mut hatch = Hatch::new();
|
||||
hatch.paths.push(path);
|
||||
hatch
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fit_all_reaches_an_entity_parked_far_from_the_rest() {
|
||||
let mut scene = Scene::new();
|
||||
// A dense consensus cluster — more than the eight wires the old quartile
|
||||
// filter needed before it switched itself on.
|
||||
for i in 0..12 {
|
||||
let x = i as f64;
|
||||
add_line(&mut scene, x, 0.0, x, 10.0);
|
||||
}
|
||||
// …and one line far outside it. Nothing about it is invalid: it is simply
|
||||
// somewhere else, which is exactly what the filter could not tell apart
|
||||
// from parser junk.
|
||||
add_line(&mut scene, 50_000.0, 50_000.0, 50_010.0, 50_010.0);
|
||||
|
||||
scene.fit_all();
|
||||
|
||||
// The fit centres on the extents box, so the target alone says whether the
|
||||
// remote line counted: dropping it leaves the camera on the cluster at
|
||||
// about (5.5, 5) instead of halfway out to (25005, 25005).
|
||||
let cam = scene.camera.borrow();
|
||||
assert!(
|
||||
(cam.target.x - 25_005.0).abs() < 50.0 && (cam.target.y - 25_005.0).abs() < 50.0,
|
||||
"the fit must span cluster and remote line, target = {:?}",
|
||||
cam.target
|
||||
);
|
||||
assert!(
|
||||
cam.ortho_size() >= 25_005.0,
|
||||
"the view must be wide enough to hold both, ortho_size = {}",
|
||||
cam.ortho_size()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fit_all_frames_a_hatch_only_drawing() {
|
||||
let mut scene = Scene::new();
|
||||
scene.add_entity(EntityType::Hatch(square_hatch(100.0, 200.0, 40.0)));
|
||||
|
||||
scene.fit_all();
|
||||
|
||||
// Nothing else is in the drawing, so without the fill the camera never
|
||||
// moves and stays on the origin.
|
||||
let cam = scene.camera.borrow();
|
||||
assert!(
|
||||
(cam.target.x - 120.0).abs() < 1.0 && (cam.target.y - 220.0).abs() < 1.0,
|
||||
"a hatch is geometry: ZOOM EXTENTS must centre on it, target = {:?}",
|
||||
cam.target
|
||||
);
|
||||
assert!(
|
||||
cam.ortho_size() >= 20.0,
|
||||
"the view must hold the whole fill, ortho_size = {}",
|
||||
cam.ortho_size()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fit_all_keeps_a_hatch_outside_the_wires_in_view() {
|
||||
let mut scene = Scene::new();
|
||||
for i in 0..12 {
|
||||
let x = i as f64;
|
||||
add_line(&mut scene, x, 0.0, x, 10.0);
|
||||
}
|
||||
// The fill is the outermost thing in the drawing; the wires alone would
|
||||
// frame a 12 x 10 strip and leave it off screen.
|
||||
scene.add_entity(EntityType::Hatch(square_hatch(500.0, 500.0, 50.0)));
|
||||
|
||||
scene.fit_all();
|
||||
|
||||
// Wires alone centre near (5.5, 5); including the fill pulls the centre
|
||||
// out to about (275, 275).
|
||||
let cam = scene.camera.borrow();
|
||||
assert!(
|
||||
cam.target.x > 200.0 && cam.target.y > 200.0,
|
||||
"the fill must widen the fit past the wires, target = {:?}",
|
||||
cam.target
|
||||
);
|
||||
assert!(
|
||||
cam.ortho_size() >= 275.0,
|
||||
"the view must reach the far corner of the fill, ortho_size = {}",
|
||||
cam.ortho_size()
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user