mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-09 06:06:38 +00:00
.ai import: tests for Pattern brushes' number counts and an older Art brush's first number
A Pattern brush reads its scale from 3 or more numbers (the older form's 8 too) and isn't read with fewer; an 8-number Art brush is the older form whatever its first number. The module notes say the count tells the form.
This commit is contained in:
@@ -28,10 +28,11 @@
|
||||
//! [`vectorcraft_brush::ArtBrush`]'s `overlap: false`).
|
||||
//! - A Scatter, Art or Pattern brush's parameters are fields split by `/`: a number, the art's
|
||||
//! section names (one for Scatter, five for Art and Pattern, empty where there is none, each
|
||||
//! after a space for Art and Pattern), more fields, and last 15 numbers. Brushes whose first
|
||||
//! number is 1, as older files write them, have one field fewer before the numbers and 8 numbers;
|
||||
//! an Art brush in that form is read from its art's name alone (its numbers aren't known, so it
|
||||
//! keeps the defaults and its paths their drawn look).
|
||||
//! after a space for Art and Pattern), more fields, and last 15 numbers. Older files write
|
||||
//! brushes with first number 1, one field fewer before the numbers and 8 numbers; an Art brush
|
||||
//! with 8 numbers, whatever its first number, is read from its art's name alone (its numbers
|
||||
//! aren't known, so it keeps the defaults and its paths their drawn look). A Pattern brush needs
|
||||
//! only its first 3 numbers (its scale is the third).
|
||||
//! - Scatter: the size (2, 3), spacing (5, 6) and scatter (8, 9) as (low, high) factors of the
|
||||
//! art, the rotation in degrees (11, 12), how each varies (4, 7, 10, 13) and whether the
|
||||
//! rotation follows the path (14), and 1 Tints (1).
|
||||
@@ -339,7 +340,8 @@ pub(super) fn parse_tool_object(kind: Tool, name: &str, params: &str) -> Result<
|
||||
}
|
||||
Tool::Art => {
|
||||
// The older form's 8 numbers aren't known: its brush keeps the defaults and its
|
||||
// paths their drawn look. Any other count isn't a form this reads.
|
||||
// paths their drawn look. The count tells the form, not the first number.
|
||||
// Any other count isn't a form this reads.
|
||||
let (colorization, plain) = if let Ok(n15) = <&[f64; 15]>::try_from(n.as_slice()) {
|
||||
(if n15[1] == 1.0 { Colorization::Tints } else { Colorization::None }, art_is_plain(n15))
|
||||
} else if n.len() == 8 {
|
||||
|
||||
@@ -8225,6 +8225,10 @@ fn an_older_art_brush_comes_in_with_its_art() {
|
||||
assert_eq!(brush::parse_tool_object(brush::Tool::Art, "Ribbon", bad), Err(brush::BrushError::Values), "{bad}");
|
||||
}
|
||||
assert_eq!(brush::parse_tool_object(brush::Tool::Scatter, "Spray", "1 /Dot art/ 0 1 / 1 0 1 0 1 0 0 0"), Err(brush::BrushError::Values));
|
||||
// 8 numbers are the older form whatever the first number says: read with the defaults.
|
||||
let d = brush::parse_tool_object(brush::Tool::Art, "Ribbon", "0 / Ribbon art/ / / / / 0 1 / 1 0 1 0 1 0 0 0").unwrap();
|
||||
let brush::DraftKind::Art { ref brush, ref art, plain } = d.kind else { panic!("art") };
|
||||
assert_eq!((art.as_str(), plain, brush.colorization), ("Ribbon art", false, vectorcraft_brush::ArtBrush::default().colorization));
|
||||
let objects = [plugin_object(ART_BRUSH, "Ribbon", OLD_RIBBON), plugin_object(ART_BRUSH, "Bare", "1 / / / / / / 0 1 / 1 0 1 0 1 0 0 0")].concat();
|
||||
let r = read_ok(&format!("{}{objects}{}", brush_art("Ribbon art", 4.0), layer("")));
|
||||
let lib = vectorcraft_brush::library(&r.doc);
|
||||
@@ -8234,6 +8238,26 @@ fn an_older_art_brush_comes_in_with_its_art() {
|
||||
assert!(r.warnings.iter().any(|w| w.ends_with("Brushes panel (1)")), "{:?}", r.warnings);
|
||||
}
|
||||
|
||||
/// A Pattern brush needs only its first 3 numbers, its scale the third (as a percentage), so the
|
||||
/// older form's 8 numbers read too; fewer than 3 aren't read.
|
||||
#[test]
|
||||
fn a_pattern_brush_reads_its_scale_from_three_or_more_numbers() {
|
||||
const SLOTS: &str = "1 / Tile one/ Tile two/ / / Tile five/ 0 1 / ";
|
||||
for numbers in ["1 0 0.5", "1 0 0.5 0 1 0 0 0"] {
|
||||
let d = brush::parse_tool_object(brush::Tool::Pattern, "Fence", &format!("{SLOTS}{numbers}")).unwrap();
|
||||
let brush::DraftKind::Pattern { tiles, scale } = d.kind else { panic!("{d:?}") };
|
||||
assert_eq!(tiles[1].as_deref(), Some("Tile two"), "{numbers}");
|
||||
assert!((scale - 50.0).abs() < 1e-9, "{numbers}: {scale}");
|
||||
}
|
||||
for numbers in ["", "1", "1 0"] {
|
||||
assert_eq!(
|
||||
brush::parse_tool_object(brush::Tool::Pattern, "Fence", &format!("{SLOTS}{numbers}")),
|
||||
Err(brush::BrushError::Values),
|
||||
"{numbers:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A brush's art filled with a pattern the file defines before it is read, with that pattern.
|
||||
#[test]
|
||||
fn a_brushs_art_takes_the_patterns_defined_before_it() {
|
||||
|
||||
Reference in New Issue
Block a user