use crate::aabb::bounding_rect;
use crate::math::*;
use crate::path::iterator::*;
use crate::path::Path;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FitStyle {
Stretch,
Min,
Max,
Horizontal,
Vertical,
}
pub fn fit_rectangle(src_rect: &Rect, dst_rect: &Rect, style: FitStyle) -> Transform {
let scale: Vector = vector(
dst_rect.size.width / src_rect.size.width,
dst_rect.size.height / src_rect.size.height,
);
let scale = match style {
FitStyle::Stretch => scale,
FitStyle::Min => {
let s = f32::min(scale.x, scale.y);
vector(s, s)
}
FitStyle::Max => {
let s = f32::max(scale.x, scale.y);
vector(s, s)
}
FitStyle::Horizontal => vector(scale.x, scale.x),
FitStyle::Vertical => vector(scale.y, scale.y),
};
let src_center = src_rect.origin.lerp(src_rect.max(), 0.5);
let dst_center = dst_rect.origin.lerp(dst_rect.max(), 0.5);
Transform::translation(-src_center.x, -src_center.y)
.then_scale(scale.x, scale.y)
.then_translate(dst_center.to_vector())
}
pub fn fit_path(path: &Path, output_rect: &Rect, style: FitStyle) -> Path {
let aabb = bounding_rect(path.iter());
let transform = fit_rectangle(&aabb, output_rect, style);
let mut builder = Path::builder();
for evt in path.iter().transformed(&transform) {
builder.path_event(evt)
}
builder.build()
}
#[test]
fn simple_fit() {
fn approx_eq(a: &Rect, b: &Rect) -> bool {
use crate::geom::euclid::approxeq::ApproxEq;
let result = a.origin.approx_eq(&b.origin) && a.max().approx_eq(&b.max());
if !result {
println!("{:?} == {:?}", a, b);
}
result
}
let t = fit_rectangle(
&rect(0.0, 0.0, 1.0, 1.0),
&rect(0.0, 0.0, 2.0, 2.0),
FitStyle::Stretch,
);
assert!(approx_eq(
&t.outer_transformed_rect(&rect(0.0, 0.0, 1.0, 1.0)),
&rect(0.0, 0.0, 2.0, 2.0)
));
let t = fit_rectangle(
&rect(1.0, 2.0, 4.0, 4.0),
&rect(0.0, 0.0, 2.0, 8.0),
FitStyle::Stretch,
);
assert!(approx_eq(
&t.outer_transformed_rect(&rect(1.0, 2.0, 4.0, 4.0)),
&rect(0.0, 0.0, 2.0, 8.0)
));
let t = fit_rectangle(
&rect(1.0, 2.0, 2.0, 4.0),
&rect(0.0, 0.0, 2.0, 2.0),
FitStyle::Horizontal,
);
assert!(approx_eq(
&t.outer_transformed_rect(&rect(1.0, 2.0, 2.0, 4.0)),
&rect(0.0, -1.0, 2.0, 4.0)
));
let t = fit_rectangle(
&rect(1.0, 2.0, 2.0, 2.0),
&rect(0.0, 0.0, 4.0, 2.0),
FitStyle::Horizontal,
);
assert!(approx_eq(
&t.outer_transformed_rect(&rect(1.0, 2.0, 2.0, 2.0)),
&rect(0.0, -1.0, 4.0, 4.0)
));
}