mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-07 18:03:32 +00:00
.ai import: version 7 pattern fills in brush art use their operands
A brush's art is read by a reader of its own, which was given the patterns defined before it but not the record of which of them use the version 7 form. A fill in that art with such a pattern then ignored its offset, scale, rotation, reflection and shear operands, and placed the tiles by the matrix alone. The brush-art reader now receives that record as well, so those operands place the tiles. A brush whose art has such a fill without all nine operands is now not read, as other art the reader can't read whole isn't; before, the brush was kept.
This commit is contained in:
@@ -575,9 +575,10 @@ impl<'a> Reader<'a> {
|
||||
// In a space of its own (y down), with no head to take.
|
||||
sub.pattern = Some(PatternHead { taken: true, ..PatternHead::default() });
|
||||
sub.subreader_depth = self.subreader_depth + 1;
|
||||
// The gradients and patterns defined so far, lent.
|
||||
// The gradients and patterns defined so far, and which patterns are in the version 7 form, lent.
|
||||
sub.gradients = std::mem::take(&mut self.gradients);
|
||||
sub.pattern_tiles = std::mem::take(&mut self.pattern_tiles);
|
||||
sub.v7_patterns = std::mem::take(&mut self.v7_patterns);
|
||||
sub.global_names = std::mem::take(&mut self.global_names);
|
||||
sub.nodes = self.nodes;
|
||||
sub.template = self.template;
|
||||
@@ -585,6 +586,7 @@ impl<'a> Reader<'a> {
|
||||
self.nodes = sub.nodes;
|
||||
self.gradients = std::mem::take(&mut sub.gradients);
|
||||
self.pattern_tiles = std::mem::take(&mut sub.pattern_tiles);
|
||||
self.v7_patterns = std::mem::take(&mut sub.v7_patterns);
|
||||
self.global_names = std::mem::take(&mut sub.global_names);
|
||||
// Images aren't kept: the document's images don't count a brush's art among their users. Art
|
||||
// read with a note (something left out of it) isn't kept either.
|
||||
|
||||
@@ -6419,6 +6419,41 @@ fn a_brushs_art_takes_the_patterns_defined_before_it() {
|
||||
assert!(matches!(fill(&s.art), Paint::Pattern { ref pattern, .. } if pattern == "Dots"), "{:?}", r.warnings);
|
||||
}
|
||||
|
||||
/// A brush's art filled with a pattern defined in the version 7 form places the tiles with the
|
||||
/// fill's offset, scale, rotation, reflection and shear operands, and a brush whose art has such a
|
||||
/// fill without all nine of them isn't read.
|
||||
#[test]
|
||||
fn a_brushs_art_places_a_version_7_patterns_tiles_with_its_operands() {
|
||||
let def = pattern7("Grid", "(0 g) @ _ &\n");
|
||||
let read_with = |ops: &str| {
|
||||
let section = format!("%AI8_BeginBrushPattern\n(Dot art)\n0 A\n(Grid) {ops} p\n{}f\n%AI8_EndBrushPattern\n", rect_path(0.0, 0.0, 4.0, 4.0));
|
||||
read_ok(&format!("{def}{section}{}{}", plugin_object(SCATTER, "Spray", SPRAY), layer("")))
|
||||
};
|
||||
let placed = |ops: &str| {
|
||||
let r = read_with(ops);
|
||||
let lib = vectorcraft_brush::library(&r.doc);
|
||||
let vectorcraft_brush::BrushKind::Scatter(s) = brush_named(&lib, "Spray") else { panic!("scatter") };
|
||||
match fill(&s.art) {
|
||||
Paint::Pattern { xf, .. } => xf,
|
||||
p => panic!("{ops}: {p:?} {:?}", r.warnings),
|
||||
}
|
||||
};
|
||||
let plain = placed("0 0 1 1 0 0 0 0 0 [1 0 0 1 0 0]");
|
||||
// The operands and the move they make from the plain placement (a b c d e f): those of
|
||||
// `a_pattern_fill_applies_its_offset_scale_rotation_reflection_and_shear` with y down, as the
|
||||
// art's space has it.
|
||||
let cases = [
|
||||
("10 15 1 1 0 0 0 0 0 [1 0 0 1 0 0]", [1.0, 0.0, 0.0, 1.0, 10.0, -15.0]),
|
||||
("-5 7 2 .5 -45 0 0 -15 45 [1 0 0 1 0 0]", [1.793151, 0.353553, -1.035276, 0.353553, -5.0, -7.0]),
|
||||
];
|
||||
for (ops, want) in cases {
|
||||
let got = (placed(ops) * plain.inverse()).as_coeffs();
|
||||
assert!(got.iter().zip(want).all(|(g, w)| (g - w).abs() < 1e-6), "{ops}: {got:?}");
|
||||
}
|
||||
let r = read_with("0 0 1 1 0 0 0 0 [1 0 0 1 0 0]");
|
||||
assert!(!vectorcraft_brush::library(&r.doc).iter().any(|b| b.name == "Spray"), "{:?}", r.warnings);
|
||||
}
|
||||
|
||||
/// A file without brush objects keeps the default brushes.
|
||||
#[test]
|
||||
fn a_file_without_brushes_keeps_the_default_ones() {
|
||||
|
||||
Reference in New Issue
Block a user