mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-13 08:29:14 +00:00
Merge pull request #6976 from dotCooCoo/fix/followup-6847
Cutting Tools: weeding lines stop at an outline that lies on a line
This commit is contained in:
@@ -40,7 +40,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Weed Box and Lines…",
|
||||
["Object", "Plug-ins", "Cutting Tools"],
|
||||
None,
|
||||
"{margin?: pt 0..100000 (9: from the art to the weed box), box?: true (false: the weeding lines only), direction?: \"horizontal\" | \"vertical\" | \"both\" (\"both\"), count?: whole number 0..1000 of lines each way (1), spacing?: pt (instead of count: as few lines as keep them at most this far apart), gap?: pt 0..100000 (0: the lines stop at the art's outlines), weight?: pt 0.01..1000 (0.3), swatch?: a color swatch the lines are stroked in (\"[Registration]\")} add a weed box around the selected art and weeding lines across it that divide it evenly, each running from one side of the box to the other and left out over the art and within `gap` of its outlines, so the waste lifts off in pieces. The art is measured by the outlines a cutter cuts: closed paths enclose their area by their fill rule and open paths are lines, compound paths by all their subpaths, type by its glyph outlines, a clip group by what shows inside its clipping path, images by their frames, placed files by the art they show (by their boxes when the file can't be read), symbol instances by their art and live objects by the art they draw; strokes, effects and hidden objects are left out. One group named Weeding, stroked with no fill, on top of the current layer (outside the clip groups around a group edited in isolation), selected, as one undo step → {id: the group, box: its weed box or null, lines (pieces of weeding line)}",
|
||||
"{margin?: pt 0..100000 (9: from the art to the weed box), box?: true (false: the weeding lines only), direction?: \"horizontal\" | \"vertical\" | \"both\" (\"both\"), count?: whole number 0..1000 of lines each way (1), spacing?: pt more than 0 and at most 100000 (instead of count, never with it: as few lines as keep them at most this far apart, up to 1000 each way), gap?: pt 0..100000 (0: the lines stop at the art's outlines), weight?: pt 0.01..1000 (0.3), swatch?: a color swatch the lines are stroked in (\"[Registration]\")} add a weed box around the selected art and weeding lines across it that divide it evenly, each running from one side of the box to the other and left out over the art and within `gap` of its outlines, so the waste lifts off in pieces. The art is measured by the outlines a cutter cuts: closed paths enclose their area by their fill rule and open paths are lines, compound paths by all their subpaths, type by its glyph outlines, a clip group by what shows inside its clipping path, images by their frames, placed files by the art they show (by their boxes when the file can't be read), symbol instances by their art and live objects by the art they draw; strokes, effects and hidden objects are left out. One group named Weeding, stroked with no fill, on top of the current layer (outside the clip groups around a group edited in isolation), selected, as one undo step → {id: the group, box: its weed box or null, lines (pieces of weeding line)}",
|
||||
has_selection,
|
||||
weed
|
||||
)]
|
||||
|
||||
@@ -723,12 +723,13 @@ pub(super) fn lines(region: &Region, outline: &[Segment], frame: Rect, n: Counts
|
||||
continue;
|
||||
}
|
||||
// The lines (0-based) each outline segment comes within `gap` of: lines k (1-based) lie at
|
||||
// v0 + k·step.
|
||||
// v0 + k·step. The range is widened by a small tolerance so that a line whose position
|
||||
// rounds just past a segment's end is still measured; `near` drops lines the segment misses.
|
||||
let reach = |&(a, b): &Segment| {
|
||||
let (va, vb) = (uv(a, vertical).1, uv(b, vertical).1);
|
||||
let (lo, hi) = (va.min(vb) - gap, va.max(vb) + gap);
|
||||
let first = ((lo - v0) / step).ceil().max(1.0);
|
||||
let last = ((hi - v0) / step).floor().min(count as f64);
|
||||
let first = ((lo - v0) / step - 1e-9).ceil().max(1.0);
|
||||
let last = ((hi - v0) / step + 1e-9).floor().min(count as f64);
|
||||
if step > 0.0 && first <= last { (first as usize - 1)..(last as usize) } else { 0..0 }
|
||||
};
|
||||
// The outlines near each line, found once for all of them, by index into `outline`.
|
||||
|
||||
@@ -541,6 +541,24 @@ fn indexed_crossings_find_the_same_stretches() {
|
||||
}
|
||||
}
|
||||
|
||||
/// An outline that lies on a weeding line stops it even when the line's position rounds just past
|
||||
/// the outline's: the one line across 0.1 to 0.5 lies at 0.1 + 0.2, which is 0.30000000000000004,
|
||||
/// and (0.30000000000000004 - 0.1) / 0.2 is 1.0000000000000002.
|
||||
#[test]
|
||||
fn an_outline_on_a_rounded_line_position_stops_the_line() {
|
||||
let doc = vectorcraft_doc::Document::new(800.0, 600.0);
|
||||
let c = 0.1 + 0.2;
|
||||
let mut p = BezPath::new();
|
||||
p.move_to((20.0, c));
|
||||
p.line_to((80.0, c));
|
||||
let n = Node::path(NodeId(1), PathData::from_bezpath(&p), Appearance::default());
|
||||
let region = super::geometry::Reader::new(&doc).read(&[&n]).unwrap().unwrap();
|
||||
let outline = region.outline().unwrap();
|
||||
let counts = super::geometry::Counts { horizontal: 1, vertical: 0 };
|
||||
let pieces = super::geometry::lines(®ion, &outline, Rect::new(0.0, 0.1, 100.0, 0.5), counts, 0.0, 100).unwrap();
|
||||
assert_eq!(pieces, [(Point::new(0.0, c), Point::new(20.0, c)), (Point::new(80.0, c), Point::new(100.0, c))]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn art_nested_too_deep_is_refused() {
|
||||
// A rectangle inside `levels` groups, each holding the next. A document keeps none this deep,
|
||||
|
||||
+4
-3
@@ -10180,9 +10180,10 @@ selected art and weeding lines across the box, so the waste vinyl around the art
|
||||
VectorCraft's own. The weed box is a rectangle `margin` points (0 to 100000, default 9) outside the art's bounds;
|
||||
`box: false` leaves it out. The weeding lines run `"horizontal"`, `"vertical"` or `"both"` ways (default `"both"`) from
|
||||
one side of the box to the other and divide it evenly: `count` lines each way (a whole number from 0 to 1000, default 1),
|
||||
or with `spacing` instead, as few lines as keep them at most that far apart. A line is left out over the art's area and
|
||||
within `gap` points of its outlines (0 to 100000, default 0: the lines stop at the outlines), so it ends in several
|
||||
pieces, each a straight path. The lines and the box are stroked `weight` points wide (0.01 to 1000, default 0.3) in the
|
||||
or with `spacing` points instead (more than 0 and at most 100000), as few lines as keep them at most that far apart. A
|
||||
`spacing` that needs more than 1000 lines each way is refused, and so is a request that gives both `count` and
|
||||
`spacing`. A line is left out over the art's area and within `gap` points of its outlines (0 to 100000, default 0: the
|
||||
lines stop at the outlines), so it ends in several pieces, each a straight path. The lines and the box are stroked `weight` points wide (0.01 to 1000, default 0.3) in the
|
||||
color swatch `swatch` (default `"[Registration]"`), with no fill.
|
||||
|
||||
The art is measured by the outlines a cutter cuts. Closed paths enclose their area by their fill rule, so the hole of a
|
||||
|
||||
Reference in New Issue
Block a user