Files
OneCAD-Draft/tests/zoom_extents_coverage.rs
Hakan SevenandClaude Opus 5.5 e4d04ef132 Cargo: codec e023bc3 (acadrust sync), kernel abca4e8, graph c63556f
The codec now holds wide EntityType variants boxed (MText, Helix,
Dimension, Hatch, Viewport, MultiLeader, Surface, Table, Ole2Frame,
Light, Extended). Constructors box their entity; nested patterns reach
a dimension through entities::dimension::as_dimension(_mut). Also
follows BlockAction::action_ids, LineTypeComplexData::source_flags and
the decimal tab stop with an explicit character.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-16 09:17:01 +03:00

124 lines
4.3 KiB
Rust

//! 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(Box::new(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(Box::new(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()
);
}