//! Rectangles and points.
#![allow(const_err)]
use crate::sys;
use std::mem;
use std::ptr;
use std::ops::{Deref, DerefMut, Add, AddAssign, BitAnd, BitOr, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use std::convert::{AsRef, AsMut};
use std::hash::{Hash, Hasher};
/// The maximal integer value that can be used for rectangles.
///
/// This value is smaller than strictly needed, but is useful in ensuring that
/// rect sizes will never have to be truncated when clamping.
pub fn max_int_value() -> u32 {
i32::max_value() as u32 / 2
}
/// The minimal integer value that can be used for rectangle positions
/// and points.
///
/// This value is needed, because otherwise the width of a rectangle created
/// from a point would be able to exceed the maximum width.
pub fn min_int_value() -> i32 {
i32::min_value() / 2
}
fn clamp_size(val: u32) -> u32 {
if val == 0 {
1
} else if val > max_int_value() {
max_int_value()
} else {
val
}
}
fn clamp_position(val: i32) -> i32 {
if val > max_int_value() as i32 {
max_int_value() as i32
} else if val < min_int_value() {
min_int_value()
} else {
val
}
}
fn clamped_mul(a: i32, b: i32) -> i32 {
match a.checked_mul(b) {
Some(val) => val,
None => {
if (a < 0) ^ (b < 0) {
min_int_value()
} else {
max_int_value() as i32
}
}
}
}
/// A (non-empty) rectangle.
///
/// The width and height of a `Rect` must always be strictly positive (never
/// zero). In cases where empty rects may need to represented, it is
/// recommended to use `Option<Rect>`, with `None` representing an empty
/// rectangle (see, for example, the output of the
/// [`intersection`](#method.intersection) method).
#[derive(Clone, Copy)]
pub struct Rect {
raw: sys::SDL_Rect,
}
impl ::std::fmt::Debug for Rect {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
return write!(fmt, "Rect {{ x: {}, y: {}, w: {}, h: {} }}",
self.raw.x, self.raw.y, self.raw.w, self.raw.h);
}
}
impl PartialEq for Rect {
fn eq(&self, other: &Rect) -> bool {
self.raw.x == other.raw.x &&
self.raw.y == other.raw.y &&
self.raw.w == other.raw.w &&
self.raw.h == other.raw.h
}
}
impl Eq for Rect {}
impl Hash for Rect {
fn hash<H: Hasher>(&self, state: &mut H) {
self.raw.x.hash(state);
self.raw.y.hash(state);
self.raw.w.hash(state);
self.raw.h.hash(state);
}
}
impl Rect {
/// Creates a new rectangle from the given values.
///
/// The width and height are clamped to ensure that the right and bottom
/// sides of the rectangle does not exceed i32::max_value() (the value
/// 2147483647, the maximal positive size of an i32). This means that the
/// rect size will behave oddly if you move it very far to the right or
/// downwards on the screen.
///
/// `Rect`s must always be non-empty, so a `width` and/or `height` argument
/// of 0 will be replaced with 1.
pub fn new(x: i32, y: i32, width: u32, height: u32) -> Rect {
let raw = sys::SDL_Rect {
x: clamp_position(x),
y: clamp_position(y),
w: clamp_size(width) as i32,
h: clamp_size(height) as i32,
};
Rect { raw: raw }
}
/// Creates a new rectangle centered on the given position.
///
/// The width and height are clamped to ensure that the right and bottom
/// sides of the rectangle does not exceed i32::max_value() (the value
/// 2147483647, the maximal positive size of an i32). This means that the
/// rect size will behave oddly if you move it very far to the right or
/// downwards on the screen.
///
/// `Rect`s must always be non-empty, so a `width` and/or `height` argument
/// of 0 will be replaced with 1.
pub fn from_center<P>(center: P, width: u32, height: u32)
-> Rect where P: Into<Point> {
let raw = sys::SDL_Rect {
x: 0,
y: 0,
w: clamp_size(width) as i32,
h: clamp_size(height) as i32,
};
let mut rect = Rect { raw: raw };
rect.center_on(center.into());
rect
}
/// The horizontal position of this rectangle.
pub fn x(&self) -> i32 {
self.raw.x
}
/// The vertical position of this rectangle.
pub fn y(&self) -> i32 {
self.raw.y
}
/// The width of this rectangle.
pub fn width(&self) -> u32 {
self.raw.w as u32
}
/// The height of this rectangle.
pub fn height(&self) -> u32 {
self.raw.h as u32
}
/// Returns the width and height of this rectangle.
pub fn size(&self) -> (u32, u32) {
(self.width(), self.height())
}
/// Sets the horizontal position of this rectangle to the given value,
/// clamped to be less than or equal to i32::max_value() / 2.
pub fn set_x(&mut self, x: i32) {
self.raw.x = clamp_position(x);
}
/// Sets the vertical position of this rectangle to the given value,
/// clamped to be less than or equal to i32::max_value() / 2.
pub fn set_y(&mut self, y: i32) {
self.raw.y = clamp_position(y);
}
/// Sets the width of this rectangle to the given value,
/// clamped to be less than or equal to i32::max_value() / 2.
///
/// `Rect`s must always be non-empty, so a `width` argument of 0 will be
/// replaced with 1.
pub fn set_width(&mut self, width: u32) {
self.raw.w = clamp_size(width) as i32;
}
/// Sets the height of this rectangle to the given value,
/// clamped to be less than or equal to i32::max_value() / 2.
///
/// `Rect`s must always be non-empty, so a `height` argument of 0 will be
/// replaced with 1.
pub fn set_height(&mut self, height: u32) {
self.raw.h = clamp_size(height) as i32;
}
/// Returns the x-position of the left side of this rectangle.
pub fn left(&self) -> i32 {
self.raw.x
}
/// Returns the x-position of the right side of this rectangle.
pub fn right(&self) -> i32 {
self.raw.x + self.raw.w
}
/// Returns the y-position of the top side of this rectangle.
pub fn top(&self) -> i32 {
self.raw.y
}
/// Returns the y-position of the bottom side of this rectangle.
pub fn bottom(&self) -> i32 {
self.raw.y + self.raw.h
}
/// Returns the center position of this rectangle.
///
/// Note that if the width or height is not a multiple of two,
/// the center will be rounded down.
///
/// # Example
///
/// ```
/// use sdl2::rect::{Rect,Point};
/// let rect = Rect::new(1,0,2,3);
/// assert_eq!(Point::new(2,1),rect.center());
/// ```
pub fn center(&self) -> Point {
let x = self.raw.x + (self.raw.w / 2);
let y = self.raw.y + (self.raw.h / 2);
Point::new(x, y)
}
/// Returns the top-left corner of this rectangle.
///
/// # Example
///
/// ```
/// use sdl2::rect::{Rect, Point};
/// let rect = Rect::new(1, 0, 2, 3);
/// assert_eq!(Point::new(1, 0), rect.top_left());
/// ```
pub fn top_left(&self) -> Point {
Point::new(self.left(), self.top())
}
/// Returns the top-right corner of this rectangle.
///
/// # Example
///
/// ```
/// use sdl2::rect::{Rect, Point};
/// let rect = Rect::new(1, 0, 2, 3);
/// assert_eq!(Point::new(3, 0), rect.top_right());
/// ```
pub fn top_right(&self) -> Point {
Point::new(self.right(), self.top())
}
/// Returns the bottom-left corner of this rectangle.
///
/// # Example
///
/// ```
/// use sdl2::rect::{Rect, Point};
/// let rect = Rect::new(1, 0, 2, 3);
/// assert_eq!(Point::new(1, 3), rect.bottom_left());
/// ```
pub fn bottom_left(&self) -> Point {
Point::new(self.left(), self.bottom())
}
/// Returns the bottom-right corner of this rectangle.
///
/// # Example
///
/// ```
/// use sdl2::rect::{Rect, Point};
/// let rect = Rect::new(1, 0, 2, 3);
/// assert_eq!(Point::new(3, 3), rect.bottom_right());
/// ```
pub fn bottom_right(&self) -> Point {
Point::new(self.right(), self.bottom())
}
/// Sets the position of the right side of this rectangle to the given
/// value, clamped to be less than or equal to i32::max_value() / 2.
pub fn set_right(&mut self, right: i32) {
self.raw.x = clamp_position(clamp_position(right) - self.raw.w);
}
/// Sets the position of the bottom side of this rectangle to the given
/// value, clamped to be less than or equal to i32::max_value() / 2.
pub fn set_bottom(&mut self, bottom: i32) {
self.raw.y = clamp_position(clamp_position(bottom) - self.raw.h);
}
/// Centers the rectangle on the given point.
pub fn center_on<P>(&mut self, point: P) where P: Into<(i32, i32)> {
let (x, y) = point.into();
self.raw.x = clamp_position(clamp_position(x) - self.raw.w / 2);
self.raw.y = clamp_position(clamp_position(y) - self.raw. h / 2);
}
/// Move this rect and clamp the positions to prevent over/underflow.
/// This also clamps the size to prevent overflow.
pub fn offset(&mut self, x: i32, y: i32) {
match self.raw.x.checked_add(x) {
Some(val) => self.raw.x = clamp_position(val),
None => {
if x >= 0 {
self.raw.x = max_int_value() as i32;
} else {
self.raw.x = i32::min_value();
}
},
}
match self.raw.y.checked_add(y) {
Some(val) => self.raw.y = clamp_position(val),
None => {
if y >= 0 {
self.raw.y = max_int_value() as i32;
} else {
self.raw.y = i32::min_value();
}
},
}
}
/// Moves this rect to the given position after clamping the values.
pub fn reposition<P>(&mut self, point: P) where P: Into<(i32, i32)> {
let (x, y) = point.into();
self.raw.x = clamp_position(x);
self.raw.y = clamp_position(y);
}
/// Resizes this rect to the given size after clamping the values.
pub fn resize(&mut self, width: u32, height: u32) {
self.raw.w = clamp_size(width) as i32;
self.raw.h = clamp_size(height) as i32;
}
/// Checks whether this rect contains a given point, or touches it on the
/// right and/or bottom edges. This method is deprecated in favor of
/// [`Rect::contains_point`](#method.contains_point).
///
/// For [historical
/// reasons](https://github.com/AngryLawyer/rust-sdl2/issues/569), this
/// method differs in behavior from
/// [`SDL_PointInRect`](https://wiki.libsdl.org/SDL_PointInRect) by
/// including points along the bottom and right edges of the rectangle, so
/// that a 1-by-1 rectangle actually covers an area of four points, not
/// one.
///
/// # Examples
///
/// ```
/// use sdl2::rect::{Rect, Point};
/// let rect = Rect::new(1, 2, 3, 4);
/// assert!(rect.contains(Point::new(1, 2)));
/// assert!(!rect.contains(Point::new(0, 1)));
/// assert!(rect.contains(Point::new(3, 5)));
/// assert!(rect.contains(Point::new(4, 6))); // N.B.
/// assert!(!rect.contains(Point::new(5, 7)));
/// ```
#[deprecated(since = "0.30.0", note = "use `contains_point` instead")]
pub fn contains<P>(&self, point: P) -> bool where P: Into<(i32, i32)> {
let (x, y) = point.into();
let inside_x = x >= self.left() && x <= self.right();
inside_x && (y >= self.top() && y <= self.bottom())
}
/// Checks whether this rectangle contains a given point.
///
/// Points along the right and bottom edges are not considered to be inside
/// the rectangle; this way, a 1-by-1 rectangle contains only a single
/// point. Another way to look at it is that this method returns true if
/// and only if the given point would be painted by a call to
/// [`Renderer::fill_rect`](
/// ../render/struct.Renderer.html#method.fill_rect).
///
/// # Examples
///
/// ```
/// use sdl2::rect::{Rect, Point};
/// let rect = Rect::new(1, 2, 3, 4);
/// assert!(rect.contains_point(Point::new(1, 2)));
/// assert!(!rect.contains_point(Point::new(0, 1)));
/// assert!(rect.contains_point(Point::new(3, 5)));
/// assert!(!rect.contains_point(Point::new(4, 6)));
/// ```
pub fn contains_point<P>(&self, point: P) -> bool
where P: Into<(i32, i32)> {
let (x, y) = point.into();
let inside_x = x >= self.left() && x < self.right();
inside_x && (y >= self.top() && y < self.bottom())
}
/// Checks whether this rectangle completely contains another rectangle.
///
/// This method returns true if and only if every point contained by
/// `other` is also contained by `self`; in other words, if the
/// intersection of `self` and `other` is equal to `other`.
///
/// # Examples
///
/// ```
/// use sdl2::rect::Rect;
/// let rect = Rect::new(1, 2, 3, 4);
/// assert!(rect.contains_rect(rect));
/// assert!(rect.contains_rect(Rect::new(3, 3, 1, 1)));
/// assert!(!rect.contains_rect(Rect::new(2, 1, 1, 1)));
/// assert!(!rect.contains_rect(Rect::new(3, 3, 2, 1)));
/// ```
pub fn contains_rect(&self, other: Rect) -> bool {
other.left() >= self.left() && other.right() <= self.right() &&
other.top() >= self.top() && other.bottom() <= self.bottom()
}
/// Returns the underlying C Rect.
pub fn raw(&self) -> *const sys::SDL_Rect {
&self.raw
}
pub fn raw_mut(&mut self) -> *mut sys::SDL_Rect {
self.raw() as *mut _
}
pub fn raw_slice(slice: &[Rect]) -> *const sys::SDL_Rect {
unsafe {
mem::transmute(slice.as_ptr())
}
}
pub fn from_ll(raw: sys::SDL_Rect) -> Rect {
Rect::new(raw.x, raw.y, raw.w as u32, raw.h as u32)
}
/// Calculate a minimal rectangle enclosing a set of points.
/// If a clipping rectangle is given, only points that are within it will be
/// considered.
pub fn from_enclose_points<R: Into<Option<Rect>>>(points: &[Point], clipping_rect: R)
-> Option<Rect>
where R: Into<Option<Rect>>
{
let clipping_rect = clipping_rect.into();
if points.is_empty() {
return None;
}
let mut out = unsafe {
mem::uninitialized()
};
let clip_ptr = match clipping_rect.as_ref() {
Some(r) => r.raw(),
None => ptr::null()
};
let result = unsafe {
sys::SDL_EnclosePoints(
Point::raw_slice(points),
points.len() as i32,
clip_ptr,
&mut out
) != sys::SDL_bool::SDL_FALSE
};
if result {
// Return an error if the dimensions are too large.
Some(Rect::from_ll(out))
} else {
None
}
}
/// Determines whether two rectangles intersect.
///
/// Rectangles that share an edge but don't actually overlap are not
/// considered to intersect.
///
/// # Examples
///
/// ```
/// use sdl2::rect::Rect;
/// let rect = Rect::new(0, 0, 5, 5);
/// assert!(rect.has_intersection(rect));
/// assert!(rect.has_intersection(Rect::new(2, 2, 5, 5)));
/// assert!(!rect.has_intersection(Rect::new(5, 0, 5, 5)));
/// ```
pub fn has_intersection(&self, other: Rect) -> bool {
unsafe {
sys::SDL_HasIntersection(self.raw(), other.raw()) != sys::SDL_bool::SDL_FALSE
}
}
/// Calculates the intersection of two rectangles.
///
/// Returns `None` if the two rectangles don't intersect. Rectangles that
/// share an edge but don't actually overlap are not considered to
/// intersect.
///
/// The bitwise AND operator `&` can also be used.
///
/// # Examples
///
/// ```
/// use sdl2::rect::Rect;
/// let rect = Rect::new(0, 0, 5, 5);
/// assert_eq!(rect.intersection(rect), Some(rect));
/// assert_eq!(rect.intersection(Rect::new(2, 2, 5, 5)),
/// Some(Rect::new(2, 2, 3, 3)));
/// assert_eq!(rect.intersection(Rect::new(5, 0, 5, 5)), None);
/// ```
pub fn intersection(&self, other: Rect) -> Option<Rect> {
let mut out = unsafe { mem::uninitialized() };
let success = unsafe {
sys::SDL_IntersectRect(self.raw(), other.raw(), &mut out) != sys::SDL_bool::SDL_FALSE
};
if success {
Some(Rect::from_ll(out))
} else {
None
}
}
/// Calculates the union of two rectangles (i.e. the smallest rectangle
/// that contains both).
///
/// The bitwise OR operator `|` can also be used.
///
/// # Examples
///
/// ```
/// use sdl2::rect::Rect;
/// let rect = Rect::new(0, 0, 5, 5);
/// assert_eq!(rect.union(rect), rect);
/// assert_eq!(rect.union(Rect::new(2, 2, 5, 5)), Rect::new(0, 0, 7, 7));
/// assert_eq!(rect.union(Rect::new(5, 0, 5, 5)), Rect::new(0, 0, 10, 5));
/// ```
pub fn union(&self, other: Rect) -> Rect {
let mut out = unsafe {
mem::uninitialized()
};
unsafe {
// If `self` and `other` are both empty, `out` remains uninitialized.
// Because empty rectangles aren't allowed in Rect, we don't need to worry about this.
sys::SDL_UnionRect(self.raw(), other.raw(), &mut out)
};
Rect::from_ll(out)
}
/// Calculates the intersection of a rectangle and a line segment and
/// returns the points of their intersection.
pub fn intersect_line(&self, start: Point, end: Point)
-> Option<(Point, Point)> {
let (mut start_x, mut start_y) = (start.x(), start.y());
let (mut end_x, mut end_y) = (end.x(), end.y());
let intersected = unsafe {
sys::SDL_IntersectRectAndLine(
self.raw(),
&mut start_x, &mut start_y,
&mut end_x, &mut end_y
) != sys::SDL_bool::SDL_FALSE
};
if intersected {
Some((Point::new(start_x, start_y), Point::new(end_x, end_y)))
} else {
None
}
}
}
impl Deref for Rect {
type Target = sys::SDL_Rect;
/// # Example
///
/// ```rust
/// use sdl2::rect::Rect;
/// let rect = Rect::new(2, 3, 4, 5);
/// assert_eq!(2, rect.x);
/// ```
fn deref(&self) -> &sys::SDL_Rect {
&self.raw
}
}
impl DerefMut for Rect {
/// # Example
///
/// ```rust
/// use sdl2::rect::Rect;
/// let mut rect = Rect::new(2, 3, 4, 5);
/// rect.x = 60;
/// assert_eq!(60, rect.x);
/// ```
fn deref_mut(&mut self) -> &mut sys::SDL_Rect {
&mut self.raw
}
}
impl Into<sys::SDL_Rect> for Rect {
fn into(self) -> sys::SDL_Rect {
self.raw
}
}
impl Into<(i32, i32, u32, u32)> for Rect {
fn into(self) -> (i32, i32, u32, u32) {
(self.raw.x, self.raw.y, self.raw.w as u32, self.raw.h as u32)
}
}
impl From<sys::SDL_Rect> for Rect {
fn from(raw: sys::SDL_Rect) -> Rect {
Rect { raw: raw }
}
}
impl From<(i32, i32, u32, u32)> for Rect {
fn from((x, y, width, height): (i32, i32, u32, u32)) -> Rect {
Rect::new(x, y, width, height)
}
}
impl AsRef<sys::SDL_Rect> for Rect {
fn as_ref(&self) -> &sys::SDL_Rect {
&self.raw
}
}
impl AsMut<sys::SDL_Rect> for Rect {
fn as_mut(&mut self) -> &mut sys::SDL_Rect {
&mut self.raw
}
}
// Intersection
impl BitAnd<Rect> for Rect {
type Output = Option<Rect>;
fn bitand(self, rhs: Rect) -> Option<Rect> { self.intersection(rhs) }
}
// Union
impl BitOr<Rect> for Rect {
type Output = Rect;
fn bitor(self, rhs: Rect) -> Rect { self.union(rhs) }
}
/// Immutable point type, consisting of x and y.
#[derive(Copy, Clone)]
pub struct Point {
raw: sys::SDL_Point
}
impl ::std::fmt::Debug for Point {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
return write!(fmt, "Point {{ x: {}, y: {} }}", self.raw.x, self.raw.y);
}
}
impl PartialEq for Point {
fn eq(&self, other: &Point) -> bool {
self.raw.x == other.raw.x && self.raw.y == other.raw.y
}
}
impl Eq for Point {}
impl Hash for Point {
fn hash<H: Hasher>(&self, state: &mut H) {
self.raw.x.hash(state);
self.raw.y.hash(state);
}
}
impl Deref for Point {
type Target = sys::SDL_Point;
/// # Example
///
/// ```rust
/// use sdl2::rect::Point;
/// let point = Point::new(2, 3);
/// assert_eq!(2, point.x);
/// ```
fn deref(&self) -> &sys::SDL_Point {
&self.raw
}
}
impl DerefMut for Point {
/// # Example
///
/// ```rust
/// use sdl2::rect::Point;
/// let mut point = Point::new(2, 3);
/// point.x = 4;
/// assert_eq!(4, point.x);
/// ```
fn deref_mut(&mut self) -> &mut sys::SDL_Point {
&mut self.raw
}
}
impl AsRef<sys::SDL_Point> for Point {
fn as_ref(&self) -> &sys::SDL_Point {
&self.raw
}
}
impl AsMut<sys::SDL_Point> for Point {
fn as_mut(&mut self) -> &mut sys::SDL_Point {
&mut self.raw
}
}
impl From<sys::SDL_Point> for Point {
fn from(prim: sys::SDL_Point) -> Point {
Point { raw: prim }
}
}
impl From<(i32, i32)> for Point {
fn from((x, y): (i32, i32)) -> Point {
Point::new(x, y)
}
}
impl Into<sys::SDL_Point> for Point {
fn into(self) -> sys::SDL_Point {
self.raw
}
}
impl Into<(i32, i32)> for Point {
fn into(self) -> (i32, i32) {
(self.x(), self.y())
}
}
impl Point {
/// Creates a new point from the given coordinates.
pub fn new(x: i32, y: i32) -> Point {
Point {
raw: sys::SDL_Point {
x: clamp_position(x),
y: clamp_position(y),
}
}
}
pub fn from_ll(raw: sys::SDL_Point) -> Point {
Point::new(raw.x, raw.y)
}
pub fn raw_slice(slice: &[Point]) -> *const sys::SDL_Point {
unsafe {
mem::transmute(slice.as_ptr())
}
}
pub fn raw(&self) -> *const sys::SDL_Point {
&self.raw
}
/// Returns a new point by shifting this point's coordinates by the given
/// x and y values.
pub fn offset(&self, x: i32, y: i32) -> Point {
let x = match self.raw.x.checked_add(x) {
Some(val) => val,
None => {
if x < 0 {
min_int_value()
} else {
max_int_value() as i32
}
}
};
let y = match self.raw.y.checked_add(y) {
Some(val) => val,
None => {
if y < 0 {
min_int_value()
} else {
max_int_value() as i32
}
}
};
Point::new(x, y)
}
/// Returns a new point by multiplying this point's coordinates by the
/// given scale factor.
pub fn scale(&self, f: i32) -> Point {
Point::new(clamped_mul(self.raw.x, f),
clamped_mul(self.raw.y, f))
}
/// Returns the x-coordinate of this point.
pub fn x(&self) -> i32 {
self.raw.x
}
/// Returns the y-coordinate of this point.
pub fn y(&self) -> i32 {
self.raw.y
}
}
impl Add for Point {
type Output = Point;
fn add(self, rhs: Point) -> Point {
self.offset(rhs.x(), rhs.y())
}
}
impl AddAssign for Point {
fn add_assign(&mut self, rhs: Point) {
self.raw.x = clamp_position(self.x() + rhs.x());
self.raw.y = clamp_position(self.y() + rhs.y());
}
}
impl Neg for Point {
type Output = Point;
fn neg(self) -> Point {
Point::new(-self.x(), -self.y())
}
}
impl Sub for Point {
type Output = Point;
fn sub(self, rhs: Point) -> Point {
self.offset(-rhs.x(), -rhs.y())
}
}
impl SubAssign for Point {
fn sub_assign(&mut self, rhs: Point) {
self.raw.x = clamp_position(self.x() - rhs.x());
self.raw.y = clamp_position(self.y() - rhs.y());
}
}
impl Mul<i32> for Point {
type Output = Point;
fn mul(self, rhs: i32) -> Point {
self.scale(rhs)
}
}
impl MulAssign<i32> for Point {
fn mul_assign(&mut self, rhs: i32) {
self.raw.x = clamped_mul(self.x(), rhs);
self.raw.y = clamped_mul(self.y(), rhs);
}
}
impl Div<i32> for Point {
type Output = Point;
fn div(self, rhs: i32) -> Point {
Point::new(self.x() / rhs, self.y() / rhs)
}
}
impl DivAssign<i32> for Point {
fn div_assign(&mut self, rhs: i32) {
self.raw.x /= rhs;
self.raw.y /= rhs;
}
}
#[cfg(test)]
mod test {
use super::{Rect, Point, max_int_value, min_int_value};
/// Used to compare "literal" (unclamped) rect values.
fn tuple(x: i32, y: i32, w: u32, h: u32) -> (i32, i32, u32, u32) {
(x, y, w, h)
}
#[test]
fn enclose_points_valid() {
assert_eq!(
Some(tuple(2, 4, 4, 6)),
Rect::from_enclose_points(
&[Point::new(2, 4), Point::new(5,9)],
None
).map(|r| r.into())
);
}
#[test]
fn enclose_points_outside_clip_rect() {
assert_eq!(
Rect::from_enclose_points(
&[Point::new(0, 0), Point::new(10,10)],
Some(Rect::new(3, 3, 1, 1))),
None
);
}
#[test]
fn enclose_points_max_values() {
// Try to enclose the top-left-most and bottom-right-most points.
assert_eq!(
Some(tuple(
min_int_value(), min_int_value(),
max_int_value(), max_int_value()
)),
Rect::from_enclose_points(
&[Point::new(i32::min_value(), i32::min_value()),
Point::new(i32::max_value(), i32::max_value())], None
).map(|r| r.into())
);
}
#[test]
fn has_intersection() {
let rect = Rect::new(0, 0, 10, 10);
assert!(rect.has_intersection(Rect::new(9, 9, 10, 10)));
// edge
assert!(! rect.has_intersection(Rect::new(10, 10, 10, 10)));
// out
assert!(! rect.has_intersection(Rect::new(11, 11, 10, 10)));
}
#[test]
fn intersection() {
let rect = Rect::new(0, 0, 10, 10);
assert_eq!(
rect & Rect::new(9, 9, 10, 10),
Some(Rect::new(9, 9, 1, 1))
);
assert_eq!(
rect & Rect::new(11, 11, 10, 10),
None
);
}
#[test]
fn union() {
assert_eq!(
Rect::new(0, 0, 1, 1) | Rect::new(9, 9, 1, 1),
Rect::new(0, 0, 10, 10)
);
}
#[test]
fn intersect_line() {
assert_eq!(
Rect::new(1, 1, 5, 5).intersect_line(
Point::new(0, 0), Point::new(10, 10)
),
Some((Point::new(1, 1), Point::new(5, 5)))
);
}
#[test]
fn clamp_size_zero() {
assert_eq!(
tuple(0, 0, 1, 1),
Rect::new(0, 0, 0, 0).into()
);
}
#[test]
fn clamp_position_min() {
assert_eq!(
tuple(min_int_value(), min_int_value(), 1, 1),
Rect::new(i32::min_value(), i32::min_value(), 1, 1).into()
);
}
#[test]
fn clamp_size_max() {
assert_eq!(
tuple(0, 0, max_int_value(), max_int_value()),
Rect::new(0, 0, max_int_value() + 1, max_int_value() + 1).into()
);
}
#[test]
fn clamp_i32_max() {
assert_eq!(
tuple(0, 0, max_int_value(), max_int_value()),
Rect::new(
0, 0, i32::max_value() as u32, i32::max_value() as u32
).into()
)
}
#[test]
fn clamp_position_max() {
assert_eq!(
tuple(max_int_value() as i32, max_int_value() as i32, 1, 1),
Rect::new(
max_int_value() as i32 + 1, max_int_value() as i32 + 1, 1, 1
).into()
);
}
#[test]
fn rect_into() {
let test: (i32, i32, u32, u32) = (-11, 5, 50, 20);
assert_eq!(
test,
Rect::new(-11, 5, 50, 20).into()
);
}
#[test]
fn rect_from() {
assert_eq!(
Rect::from((-11, 5, 50, 20)),
Rect::new(-11, 5, 50, 20)
);
}
#[test]
fn point_into() {
let test: (i32, i32) = (-11, 5);
assert_eq!(
test,
Point::new(-11, 5).into()
);
}
#[test]
fn point_from() {
let test: (i32, i32) = (-11, 5);
assert_eq!(
test,
Point::new(-11, 5).into()
);
}
#[test]
fn point_add() {
assert_eq!(
Point::new(-5, 7),
Point::new(-11, 5) + Point::new(6, 2)
);
}
#[test]
fn point_add_assign() {
let mut point = Point::new(-11, 5);
point += Point::new(6, 2);
assert_eq!(
point,
Point::new(-11, 5) + Point::new(6, 2)
);
}
#[test]
fn point_sub() {
assert_eq!(
Point::new(-17, 3),
Point::new(-11, 5) - Point::new(6, 2)
);
}
#[test]
fn point_sub_assign() {
let mut point = Point::new(-11, 5);
point -= Point::new(6, 2);
assert_eq!(
point,
Point::new(-11, 5) - Point::new(6, 2)
);
}
#[test]
fn point_mul() {
assert_eq!(
Point::new(-33, 15),
Point::new(-11, 5) * 3
);
}
#[test]
fn point_mul_assign() {
let mut point = Point::new(-11, 5);
point *= 3;
assert_eq!(
point,
Point::new(-11, 5) * 3
);
}
#[test]
fn point_mul_clamp() {
assert_eq!(
Point::new(0x7fffffff, -0x7fffffff),
Point::new(-1000000, 5000000) * -3000000
);
}
#[test]
fn point_mul_assign_clamp() {
let mut point = Point::new(-1000000, 5000000);
point *= -3000000;
assert_eq!(
point,
Point::new(-1000000, 5000000) * -3000000
);
}
#[test]
fn point_div() {
assert_eq!(
Point::new(-3, 1),
Point::new(-11, 5) / 3
);
}
#[test]
fn point_div_assign () {
let mut point = Point::new(-11, 5);
point /= 3;
assert_eq!(
point,
Point::new(-11, 5) / 3
);
}
}