mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 13:04:50 +00:00
Merge pull request #6380 from dotCooCoo/fix/preview-bounds-butt-line
Transform: butt-capped lines measure to their end points with Use Preview Bounds
This commit is contained in:
@@ -125,15 +125,20 @@ fn bounds_transform(s: &Session, p: &Value, ids: Vec<NodeId>, least: f64, anchor
|
||||
// The scales and the point above can miss the size or the reference point when the margins of
|
||||
// the objects differ, the members of groups and the objects in symbols' art included, and with
|
||||
// strokes that scale, when the sizes are out of proportion. The objects are then measured one
|
||||
// by one ([`Spans::measure`]), and the scales solved for. Objects with geometry effects are
|
||||
// measured as drawn after each scale tried instead ([`refit_drawn`]).
|
||||
// by one ([`Spans::measure`]), and the scales solved for. Objects with geometry effects, and
|
||||
// objects with a butt-capped stroke along a segment at a slant, whose margins change with the
|
||||
// segment's direction, are measured as drawn after each scale tried instead ([`refit_drawn`]).
|
||||
let symbols = d.symbol_boxes();
|
||||
let drawn = || ids.iter().filter_map(|id| d.node(*id)).any(|n| effects::preview::draws_geometry(&symbols, n));
|
||||
let to_local = frame.to_doc().inverse();
|
||||
let drawn = || {
|
||||
ids.iter()
|
||||
.filter_map(|id| d.node(*id))
|
||||
.any(|n| effects::preview::draws_geometry(&symbols, n) || n.has_slanted_butt_stroke(&symbols, to_local))
|
||||
};
|
||||
let solved = if !(s.prefs.use_preview_bounds && w >= 0.0 && h >= 0.0) {
|
||||
None
|
||||
} else if transforms_objects(p) && !bool_or(p, "typeAreas", false) && drawn() {
|
||||
let options = scaling_options(s, p);
|
||||
let to_local = frame.to_doc().inverse();
|
||||
let measure = |sx: f64, sy: f64| {
|
||||
let xf = frame.conjugate(about(rp, Affine::scale_non_uniform(sx, sy)));
|
||||
let sc = if Scaling::factor(xf).is_some() { options } else { Scaling::default() };
|
||||
|
||||
@@ -618,6 +618,77 @@ fn set_bounds_leaves_the_height_of_lines_with_no_height() {
|
||||
assert!(close(geometric(&s, ids[1]), Rect::new(8.3, 100.0, 30.0, 100.0)), "{:?}", geometric(&s, ids[1]));
|
||||
}
|
||||
|
||||
/// A line with a 2 pt stroke and butt caps, selected, with Use Preview Bounds on.
|
||||
fn butt_line(s: &mut Session, from: (f64, f64), to: (f64, f64)) -> NodeId {
|
||||
let id = NodeId(run(s, "shape.line", json!({"x1": from.0, "y1": from.1, "x2": to.0, "y2": to.1}))["id"].as_u64().unwrap());
|
||||
run(s, "stroke.set", json!({"weight": 2, "cap": "butt"}));
|
||||
preview(s, true);
|
||||
run(s, "select.set", json!({"ids": [id.0]}));
|
||||
id
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_bounds_gives_a_butt_line_the_whole_height() {
|
||||
// A butt cap ends at the anchor, so 10 mm (28.3465 pt) is the length of the line itself.
|
||||
let mut s = session();
|
||||
let id = butt_line(&mut s, (100.0, 100.0), (100.0, 140.0));
|
||||
assert!(close(s.transform_bounds(&[id]).unwrap(), Rect::new(99.0, 100.0, 101.0, 140.0)), "{:?}", s.transform_bounds(&[id]));
|
||||
run(&mut s, "object.setBounds", json!({"height": 28.3465, "reference": 0, "strokes": false}));
|
||||
assert!(close(geometric(&s, id), Rect::new(100.0, 100.0, 100.0, 128.3465)), "{:?}", geometric(&s, id));
|
||||
assert!(close(s.transform_bounds(&[id]).unwrap(), Rect::new(99.0, 100.0, 101.0, 128.3465)), "{:?}", s.transform_bounds(&[id]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_bounds_gives_a_diagonal_butt_line_the_size_out_of_proportion() {
|
||||
// The stroke's corners follow the line's slope, which a scale out of proportion changes.
|
||||
let mut s = session();
|
||||
let id = butt_line(&mut s, (100.0, 100.0), (130.0, 140.0));
|
||||
let before = s.transform_bounds(&[id]).unwrap();
|
||||
// The stroke's corners reach 0.8 pt across x and 0.6 pt across y at this 3-4-5 slope.
|
||||
assert!(close(before, Rect::new(99.2, 99.4, 130.8, 140.6)), "{before:?}");
|
||||
run(&mut s, "object.setBounds", json!({"height": 100, "reference": 0, "strokes": false}));
|
||||
let v = s.transform_bounds(&[id]).unwrap();
|
||||
assert!((v.height() - 100.0).abs() < 1e-6, "{v:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_bounds_gives_a_butt_path_with_slanted_corners_the_size_out_of_proportion() {
|
||||
// Square ends, but the bevel join at the apex sets the top edge by the slanted segments'
|
||||
// corners, which a scale out of proportion moves.
|
||||
let mut s = session();
|
||||
let anchors = json!([{"x": 100, "y": 150}, {"x": 100, "y": 140}, {"x": 110, "y": 100}, {"x": 120, "y": 140}, {"x": 120, "y": 150}]);
|
||||
let id = NodeId(run(&mut s, "path.create", json!({"anchors": anchors}))["id"].as_u64().unwrap());
|
||||
run(&mut s, "stroke.set", json!({"weight": 2, "cap": "butt", "join": "bevel"}));
|
||||
preview(&mut s, true);
|
||||
run(&mut s, "select.set", json!({"ids": [id.0]}));
|
||||
run(&mut s, "object.setBounds", json!({"width": 60, "height": 20, "reference": 0, "strokes": false}));
|
||||
let v = s.transform_bounds(&[id]).unwrap();
|
||||
assert!((v.width() - 60.0).abs() < 1e-6 && (v.height() - 20.0).abs() < 1e-6, "{v:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_bounds_gives_a_symbol_instance_of_a_diagonal_butt_line_the_size_out_of_proportion() {
|
||||
let mut s = session();
|
||||
butt_line(&mut s, (100.0, 100.0), (130.0, 140.0));
|
||||
let id = NodeId(run(&mut s, "symbol.new", json!({"name": "Line"}))["id"].as_u64().unwrap());
|
||||
run(&mut s, "select.set", json!({"ids": [id.0]}));
|
||||
run(&mut s, "object.setBounds", json!({"width": 20, "height": 100, "reference": 0, "strokes": false}));
|
||||
let v = s.transform_bounds(&[id]).unwrap();
|
||||
assert!((v.width() - 20.0).abs() < 1e-6 && (v.height() - 100.0).abs() < 1e-6, "{v:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn align_places_a_vertical_butt_line_by_its_end_points() {
|
||||
// With Use Preview Bounds on, a butt line's ends line up with the top of a rectangle without
|
||||
// a stroke.
|
||||
let mut s = session();
|
||||
rect(&mut s, 20.0, 50.0, 0.0);
|
||||
let id = butt_line(&mut s, (200.0, 160.0), (200.0, 190.0));
|
||||
run(&mut s, "select.all", json!({}));
|
||||
run(&mut s, "object.align", json!({"vertical": "top"}));
|
||||
assert!(close(geometric(&s, id), Rect::new(200.0, 100.0, 200.0, 130.0)), "{:?}", geometric(&s, id));
|
||||
}
|
||||
|
||||
/// The rectangles of [`thin_and_thick`] in a group, the thick one in a group of its own inside it
|
||||
/// when `nested`, selected with an unstroked rectangle from x 100 to 110 when `plain`. Returns the
|
||||
/// selected objects.
|
||||
|
||||
Reference in New Issue
Block a user