use super::path::*;
use super::rect::*;
use super::point::*;
use super::curve::*;
use super::element::*;
use curves::*;
pub trait HasBoundingBox {
fn bounding_box(&self) -> Rect;
}
impl From<(PathPoint, PathElement)> for Rect {
fn from((start_point, element): (PathPoint, PathElement)) -> Rect {
use self::PathElement::*;
match element {
Move(point) => Rect::new(start_point, point).normalize(),
Line(point) => Rect::new(start_point, point).normalize(),
Close => Rect::new(start_point, start_point).normalize(),
Bezier(point, cp1, cp2) => {
let curve = PathCurve(start_point, Bezier(point, cp1, cp2));
let (topleft, bottomright) = curve.bounding_box();
Rect::new(topleft, bottomright).normalize()
}
}
}
}
impl From<(PathElement, PathElement)> for Rect {
fn from((previous, next): (PathElement, PathElement)) -> Rect {
use self::PathElement::*;
if let Close = previous {
let only_point = match next {
Move(point) => point,
Line(point) => point,
Bezier(point, _cp1, _cp2) => point,
Close => PathPoint::origin()
};
Rect::new(only_point, only_point)
} else {
let start_point = match previous {
Move(point) => point,
Line(point) => point,
Bezier(point, _cp1, _cp2) => point,
Close => PathPoint::origin()
};
Rect::from((start_point, next))
}
}
}
impl<'a> From<&'a Path> for Rect {
fn from(p: &'a Path) -> Rect {
let previous = p.elements.iter().take(p.elements.len()-1);
let following = p.elements.iter().skip(1);
let mut bounds = Rect::empty();
for (previous, next) in previous.zip(following) {
bounds = bounds.union(Rect::from((*previous, *next)));
}
bounds
}
}
impl From<Path> for Rect {
#[inline]
fn from(p: Path) -> Rect {
Rect::from(&p)
}
}
impl HasBoundingBox for Path {
#[inline]
fn bounding_box(&self) -> Rect {
Rect::from(self)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn can_get_bounding_box_for_line_element() {
let bounds = Rect::from((PathPoint::new(30.0, 30.0), PathElement::Line(PathPoint::new(60.0, 20.0))));
assert!(bounds.x1 == 30.0);
assert!(bounds.y1 == 20.0);
assert!(bounds.x2 == 60.0);
assert!(bounds.y2 == 30.0);
}
#[test]
fn can_get_bounding_box_for_move_and_line_element() {
let bounds = Rect::from((PathElement::Move(PathPoint::new(30.0, 30.0)), PathElement::Line(PathPoint::new(60.0, 20.0))));
assert!(bounds.x1 == 30.0);
assert!(bounds.y1 == 20.0);
assert!(bounds.x2 == 60.0);
assert!(bounds.y2 == 30.0);
}
#[test]
fn can_get_bounding_box_for_line_path() {
use self::PathElement::*;
let line_path = Path::from_elements(vec![
Move(PathPoint::new(30.0, 30.0)),
Line(PathPoint::new(60.0, 20.0))
]);
let bounds = line_path.bounding_box();
assert!(bounds.x1 == 30.0);
assert!(bounds.y1 == 20.0);
assert!(bounds.x2 == 60.0);
assert!(bounds.y2 == 30.0);
}
#[test]
fn can_get_bounding_box_for_triangle_path() {
use self::PathElement::*;
let line_path = Path::from_elements(vec![
Move(PathPoint::new(30.0, 30.0)),
Line(PathPoint::new(60.0, 20.0)),
Line(PathPoint::new(120.0, 50.0))
]);
let bounds = line_path.bounding_box();
assert!(bounds.x1 == 30.0);
assert!(bounds.y1 == 20.0);
assert!(bounds.x2 == 120.0);
assert!(bounds.y2 == 50.0);
}
#[test]
fn can_get_bounding_box_for_simple_line_bezier_path() {
use self::PathElement::*;
let line_path = Path::from_elements(vec![
Move(PathPoint::new(30.0, 30.0)),
Bezier(PathPoint::new(60.0, 60.0), PathPoint::new(40.0, 40.0), PathPoint::new(50.0, 50.0))
]);
let bounds = line_path.bounding_box();
assert!(bounds.x1 == 30.0);
assert!(bounds.y1 == 30.0);
assert!(bounds.x2 == 60.0);
assert!(bounds.y2 == 60.0);
}
#[test]
fn can_get_bounding_box_for_curved_bezier_path() {
use self::PathElement::*;
let line_path = Path::from_elements(vec![
Move(PathPoint::new(0.0, 1.0)),
Bezier(PathPoint::new(2.0, 3.0), PathPoint::new(-1.1875291, 1.5), PathPoint::new(1.5, 2.5))
]);
let bounds = line_path.bounding_box();
assert!((bounds.x1- -0.3).abs() < 0.0001);
assert!((bounds.y1- 1.0).abs() < 0.0001);
assert!((bounds.x2- 2.0).abs() < 0.0001);
assert!((bounds.y2- 3.0).abs() < 0.0001);
}
}