Do intersect_all
This commit is contained in:
parent
ade8859701
commit
6d8852260e
|
@ -152,6 +152,43 @@ impl Rectangle {
|
|||
|| self.top_right().left_of(&other.top_left())
|
||||
|| self.bottom_left().above(&other.top_left()))
|
||||
}
|
||||
|
||||
pub fn intersection(&self, other: &Rectangle) -> Option<Rectangle> {
|
||||
if !self.intersects(other) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// idk wtf this is lol
|
||||
let in_top_left;
|
||||
let in_bottom_right;
|
||||
if self.top_left().right_of(&other.top_left()) {
|
||||
if self.top_left().below(&other.top_left()) {
|
||||
in_top_left = self.top_left();
|
||||
} else {
|
||||
in_top_left = Point::new(self.top_left().x(), other.top_left().y());
|
||||
}
|
||||
} else {
|
||||
if self.top_left().below(&other.top_left()) {
|
||||
in_top_left = Point::new(other.top_left().x(), self.top_left().y());
|
||||
} else {
|
||||
in_top_left = other.top_left();
|
||||
}
|
||||
}
|
||||
if self.bottom_right().left_of(&other.bottom_right()) {
|
||||
if self.bottom_right().below(&other.bottom_right()) {
|
||||
in_bottom_right = Point::new(self.bottom_right().x(), other.bottom_right().y());
|
||||
} else {
|
||||
in_bottom_right = self.bottom_right();
|
||||
}
|
||||
} else {
|
||||
if self.bottom_right().below(&other.bottom_right()) {
|
||||
in_bottom_right = other.bottom_right();
|
||||
} else {
|
||||
in_bottom_right = Point::new(other.bottom_right().x(), self.bottom_right().y());
|
||||
}
|
||||
}
|
||||
Some(Rectangle::from_corners(in_top_left, in_bottom_right))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -88,3 +88,58 @@ where
|
|||
// The type of the collect() function is chosen based on the return type that it's meant to fit
|
||||
rects.map(|r| (r, r.area())).collect()
|
||||
}
|
||||
|
||||
pub fn intersect_all<T>(mut rects: T) -> Option<Rectangle>
|
||||
where
|
||||
T: Iterator<Item = Rectangle>,
|
||||
{
|
||||
let first = rects.next();
|
||||
|
||||
if let None = first {
|
||||
// Can't do intersection if no items.
|
||||
return None;
|
||||
}
|
||||
|
||||
fn intersect_helper(acc: Option<Rectangle>, rect: Rectangle) -> Option<Rectangle> {
|
||||
match acc {
|
||||
None => None,
|
||||
Some(a) => a.intersection(&rect),
|
||||
}
|
||||
}
|
||||
|
||||
rects.fold(first, intersect_helper)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const INCREASING_ENCLOSING: [Rectangle; 5] = [
|
||||
Rectangle::at_origin_with_size(1, 1),
|
||||
Rectangle::at_origin_with_size(2, 2),
|
||||
Rectangle::at_origin_with_size(3, 3),
|
||||
Rectangle::at_origin_with_size(4, 4),
|
||||
Rectangle::at_origin_with_size(5, 5),
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn test_intersect_all_1() {
|
||||
let mut v = Vec::new();
|
||||
v.extend(INCREASING_ENCLOSING.iter());
|
||||
// Drain is a bit different to iter in that it releases ownership of each object,
|
||||
// instead of just giving a reference.
|
||||
assert_eq!(Some(INCREASING_ENCLOSING[0]), intersect_all(v.drain(0..)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_intersect_all_2() {
|
||||
// Deliberately inconsistent with above code to show a different way of doing things.
|
||||
let mut various_rects = vec![
|
||||
Rectangle::from_corner_width_height(Point::new(20, 110), 10, 10),
|
||||
Rectangle::from_corner_width_height(Point::new(25, 115), 10, 10),
|
||||
Rectangle::from_corner_width_height(Point::new(10, 100), 1000, 1000),
|
||||
Rectangle::from_corner_width_height(Point::new(2010, 2100), 1, 1),
|
||||
];
|
||||
assert_eq!(None, intersect_all(various_rects.drain(0..)));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue