mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Merge pull request #2058 from EricKuck/fix/ai-pattern-gradient-canvas
AI import: a gradient in a pattern's definition is placed from the canvas, as the file's PDF part draws it
This commit is contained in:
@@ -238,6 +238,11 @@ impl Instance {
|
||||
}
|
||||
}
|
||||
|
||||
/// Does it carry a matrix of its own (`Xm` or `Bm`) rather than only `Bg`'s numbers?
|
||||
pub fn has_matrix(&self) -> bool {
|
||||
self.xm.is_some() || self.bm.is_some()
|
||||
}
|
||||
|
||||
/// The paint, through `to_doc` (art space → the document), when the gradient is defined.
|
||||
pub fn paint(&self, defs: &HashMap<String, Gradient>, to_doc: Affine) -> Option<Paint> {
|
||||
let name = self.name.as_ref()?;
|
||||
|
||||
@@ -732,6 +732,7 @@ impl<'a> Reader<'a> {
|
||||
// The gradients defined so far, lent (and those it defines kept).
|
||||
sub.gradients = std::mem::take(&mut self.gradients);
|
||||
sub.nodes = self.nodes;
|
||||
sub.template = self.template;
|
||||
let read = sub.open(Kind::Group, false).and_then(|()| sub.run());
|
||||
self.nodes = sub.nodes;
|
||||
self.gradients = std::mem::take(&mut sub.gradients);
|
||||
@@ -1754,7 +1755,16 @@ impl<'a> Reader<'a> {
|
||||
}
|
||||
|
||||
fn set_instance(&mut self, i: &Instance) {
|
||||
let to_doc = self.space();
|
||||
let mut to_doc = self.space();
|
||||
// In a pattern's definition a gradient's `Xm` and `Bm` are written y down about the canvas point of art space's
|
||||
// origin, as the file's PDF part draws them.
|
||||
if self.pattern.is_some()
|
||||
&& i.has_matrix()
|
||||
&& let Some(t) = self.template
|
||||
{
|
||||
let (cx, cy) = ((t[0] + t[2]) / 2.0, (t[1] + t[3]) / 2.0);
|
||||
to_doc *= Affine::new([1.0, 0.0, 0.0, -1.0, CANVAS_CENTRE - cx, CANVAS_CENTRE + cy]);
|
||||
}
|
||||
match i.paint(&self.gradients, to_doc) {
|
||||
Some(p) if i.stroke => self.pending_stroke = Some(p),
|
||||
Some(p) => self.pending_fill = Some(p),
|
||||
|
||||
@@ -217,6 +217,29 @@ fn a_pattern_tiles_from_its_lower_left_wherever_its_definition_drew_it() {
|
||||
assert_eq!(xf * Point::ZERO, Point::new(0.0, 92.0));
|
||||
}
|
||||
|
||||
/// A gradient in a pattern's definition is placed by an `Xm` written y down about the canvas point of
|
||||
/// art space's origin (here 7941, 7941: the canvas's centre less the template box's): its ramp from
|
||||
/// (10, 0) up to (10, 20) in the pattern's space is `0 -20 20 0 -7931 7941 Xm`.
|
||||
#[test]
|
||||
fn a_gradient_in_a_patterns_definition_is_placed_from_the_canvas() {
|
||||
let defs =
|
||||
"%AI5_BeginGradient: (G)\n(G) 0 2 Bd\n[\n<00FF>\n0\n%_0 0 0 0 1 0 0 2 1 6 50 0 Bs\n%_0 0 0 0 0 0 1 2 1 6 50 100 Bs\nBD\n%AI5_EndGradient\n";
|
||||
let tile = rect_path(0.0, 0.0, 20.0, 20.0).replace('\n', "\n%_");
|
||||
let pattern = format!(
|
||||
"%AI3_BeginPattern: (Shade)\n(Shade) 0 0 20 20\n%_0 A\n%_0 Xw\n%_0 Ae\n%_u\n%_Bb\n%_1 (G) 0 0 90 1 1 0 0 1 0 0 1 Bg\n\
|
||||
%_0 -20 20 0 -7931 7941 Xm\n%_{tile}f\n%_0 BB\n%_U\nE\n%AI3_EndPattern\n"
|
||||
);
|
||||
let file = stream(&format!("{defs}{pattern}{}", layer(&(rect_path(0.0, 0.0, 1.0, 1.0) + "f\n"))))
|
||||
.replace("%%EndComments", "%AI3_TemplateBox: 250.5 -250.5 250.5 -250.5\n%%EndComments");
|
||||
let doc = read(file.as_bytes()).unwrap().doc;
|
||||
let def = doc.pattern("Shade").unwrap();
|
||||
let shaded = &def.art[0].children().unwrap()[0];
|
||||
let Paint::Gradient(g) = fill(shaded) else { panic!("{:?}", fill(shaded)) };
|
||||
let geom = g.geom.unwrap();
|
||||
// The pattern's space is y down.
|
||||
assert!(geom.start.distance(Point::new(10.0, 0.0)) < 1e-9 && geom.end.distance(Point::new(10.0, -20.0)) < 1e-9, "{geom:?}");
|
||||
}
|
||||
|
||||
/// A pattern whose definition it can't read whole isn't kept: a fill with it is something the file
|
||||
/// has that isn't read, where it shows. Its definition costs nothing else.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user