mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 09:33:36 +00:00
.ai save: an open frame whose ends meet is written as outlines
Area type whose open frame ends where it starts was written as text and read back in a closed frame. It is now written as its outlines, alone or as a frame of a thread.
This commit is contained in:
@@ -3479,6 +3479,43 @@ fn a_thread_of_horizontal_and_vertical_frames_is_written_as_its_outlines() {
|
||||
assert!(!program(&doc).contains("/AI11Text"));
|
||||
}
|
||||
|
||||
/// Area type in an open frame whose ends meet is written as its outlines, alone or as a frame of a
|
||||
/// thread: as text it would be read back in a closed frame.
|
||||
#[test]
|
||||
fn an_open_frame_whose_ends_meet_is_written_as_its_outlines() {
|
||||
use vectorcraft_doc::{TextKind, TextObject};
|
||||
let open = |r: Rect| {
|
||||
let mut frame = shapes::rectangle(r);
|
||||
frame.subpaths[0].closed = false;
|
||||
let start = frame.subpaths[0].anchors[0].clone();
|
||||
frame.subpaths[0].anchors.push(start);
|
||||
frame
|
||||
};
|
||||
let mut alone = TextObject::point(vectorcraft_geom::Point::ZERO, "Open", style(10.0, Color::BLACK));
|
||||
alone.kind = TextKind::Area { frame: open(Rect::new(10.0, 10.0, 90.0, 40.0)) };
|
||||
alone.xf = Affine::IDENTITY;
|
||||
let mut doc = Document::new(200.0, 100.0);
|
||||
let layer = doc.layers[0].id;
|
||||
let n = text_node(&mut doc, alone.clone());
|
||||
doc.insert(Some(layer), usize::MAX, n).unwrap();
|
||||
assert_eq!(export_ai_editing(&doc, &opts()).unwrap().warnings, [writer::TYPE]);
|
||||
assert!(!program(&doc).contains("/AI11Text"));
|
||||
|
||||
let mut first = alone;
|
||||
first.kind = TextKind::Area { frame: shapes::rectangle(Rect::new(10.0, 10.0, 90.0, 40.0)) };
|
||||
let mut second = first.clone();
|
||||
second.runs[0].text.clear();
|
||||
second.kind = TextKind::Area { frame: open(Rect::new(110.0, 10.0, 190.0, 90.0)) };
|
||||
let mut doc = Document::new(200.0, 100.0);
|
||||
let layer = doc.layers[0].id;
|
||||
let (first, second) = (text_node(&mut doc, first), text_node(&mut doc, second));
|
||||
doc.text_threads.push(vec![first.id, second.id]);
|
||||
doc.insert(Some(layer), usize::MAX, first).unwrap();
|
||||
doc.insert(Some(layer), usize::MAX, second).unwrap();
|
||||
assert_eq!(export_ai_editing(&doc, &opts()).unwrap().warnings, [writer::TYPE]);
|
||||
assert!(!program(&doc).contains("/AI11Text"));
|
||||
}
|
||||
|
||||
/// A thread with a frame in art cut to a clipping object that isn't a path is written as its
|
||||
/// outlines, every frame of it; so is type whose size is past what the reader reads.
|
||||
#[test]
|
||||
|
||||
@@ -197,7 +197,7 @@ pub(in crate::ai_editing) fn holds(n: &Node, t: &TextObject) -> bool {
|
||||
let xf = t.xf.as_coeffs();
|
||||
let shape_ok = match &t.kind {
|
||||
TextKind::Point => xf.iter().all(|v| v.is_finite()) && t.xf.determinant() > 1e-12,
|
||||
TextKind::Area { .. } => shape(t).as_ref().and_then(segments).is_some_and(|s| closed(&s)),
|
||||
TextKind::Area { .. } => closed_frame(t),
|
||||
// An open path whose ends meet would be read back closed.
|
||||
TextKind::OnPath { path, .. } => {
|
||||
let open = path.subpaths.iter().any(|sp| !sp.anchors.is_empty() && !sp.closed);
|
||||
@@ -214,6 +214,12 @@ pub(in crate::ai_editing) fn holds(n: &Node, t: &TextObject) -> bool {
|
||||
&& within_reader(t, story_scale(t))
|
||||
}
|
||||
|
||||
/// Is the frame of area type `t` one closed part? An open frame whose ends meet would be read back
|
||||
/// closed.
|
||||
fn closed_frame(t: &TextObject) -> bool {
|
||||
shape(t).filter(|p| p.subpaths.iter().all(|sp| sp.anchors.is_empty() || sp.closed)).as_ref().and_then(segments).is_some_and(|s| closed(&s))
|
||||
}
|
||||
|
||||
/// Document points to a unit of the story of type `t`: its scale is put into its lengths.
|
||||
fn story_scale(t: &TextObject) -> f64 {
|
||||
1.0 / t.xf.determinant().abs().sqrt()
|
||||
@@ -839,7 +845,7 @@ impl TextDoc {
|
||||
&& runs_held(t)
|
||||
&& (story_scale(t) / scale - 1.0).abs() <= 1e-9
|
||||
&& within_reader(t, scale)
|
||||
&& shape(t).as_ref().and_then(segments).is_some_and(|s| closed(&s))
|
||||
&& closed_frame(t)
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user