use crate::canvas::Item;
use crate::scene::{Point, Segment, Transform};
use crate::Error;
use super::Engine;
impl Engine {
pub fn view_box(&mut self, a: Point, b: Point, c: Point, d: Point, slice: bool) {
let t = self.st.transform.compose(&self.st.pending);
let (vw, vh) = ((b.x - a.x).abs().max(1e-9), (b.y - a.y).abs().max(1e-9));
let (tw, th) = ((d.x - c.x).abs(), (d.y - c.y).abs());
let s = if slice { (tw / vw).max(th / vh) } else { (tw / vw).min(th / vh) };
let (vc, tc) = (a.lerp(b, 0.5), c.lerp(d, 0.5));
let corners = [Point::new(c.x, c.y), Point::new(d.x, c.y), Point::new(d.x, d.y), Point::new(c.x, d.y)].map(|p| t.apply(p));
if self.counts_for_size() {
corners.iter().for_each(|p| self.canvas.include(*p));
}
if slice {
let mut segs = vec![Segment::MoveTo(corners[0])];
segs.extend(corners[1..].iter().map(|p| Segment::LineTo(*p)));
segs.push(Segment::Close);
self.open_in_scope(Item::Clip { segments: segs, even_odd: false });
}
if let Some(sc) = self.scopes.last_mut() {
sc.clipped = true;
}
let m = Transform::translation(tc.x, tc.y).compose(&Transform::scaling(s, s)).compose(&Transform::translation(-vc.x, -vc.y));
let canvas = t.compose(&m).compose(&t.inverse());
self.open_in_scope(Item::Transform { transform: canvas });
}
pub fn view_key(&mut self, spec: &str, slice: bool) -> Result<(), Error> {
let spec = spec.trim().trim_start_matches('{').trim_end_matches('}');
let Some((view, target)) = spec.split_once(" at ") else {
self.warn(format!("{}: '{spec}' is not '(a) (b) at (c) (d)': ignored", if slice { "slice" } else { "meet" }));
return Ok(());
};
let inverse = self.st.transform.compose(&self.st.pending).inverse();
let mut points = Vec::new();
for part in [view, target] {
for c in part.split(')').map(|c| c.trim().trim_start_matches('(').trim()).filter(|c| !c.is_empty()) {
let p = self.coordinate(c)?.p;
points.push(inverse.apply(p));
}
}
let [a, b, c, d] = points[..] else {
self.warn(format!("view box '{spec}': four points expected: ignored"));
return Ok(());
};
self.view_box(a, b, c, d, slice);
Ok(())
}
pub fn begin_view_box_scope(&mut self) -> Result<(), Error> {
let mut points = [Point::default(); 4];
for p in points.iter_mut() {
*p = self.point_arg()?;
}
let kind = self.argument_string()?;
self.begin_group();
self.begin_scope();
self.view_box(points[0], points[1], points[2], points[3], kind.trim() == "slice");
self.st.apply_pending();
Ok(())
}
}