Skip to content

Instantly share code, notes, and snippets.

@jFransham
Created May 18, 2016 17:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jFransham/668e1a8943975b6a3bbbfd1c92c0854d to your computer and use it in GitHub Desktop.
Save jFransham/668e1a8943975b6a3bbbfd1c92c0854d to your computer and use it in GitHub Desktop.
use ::set::Set;
use std::convert::TryFrom;
use std::ops::Add;
use sdl2::rect::Rect as SdlRect;
use num::Num;
pub type Bounds = Rectangle<f64>;
pub type Clip = Rectangle<u32>;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Rectangle<P, S=P> {
pub x: P,
pub y: P,
pub width: S,
pub height: S,
}
impl<P: Clone, S: Clone> Rectangle<P, S> {
pub fn with_position(&self, x: P, y: P) -> Self {
Rectangle {
x: x,
y: y,
.. self.clone()
}
}
pub fn with_size(&self, w: S, h: S) -> Self {
Rectangle {
width: w,
height: h,
.. self.clone()
}
}
}
impl<O, P: Copy + Add<S, Output=O>, S: Copy> Rectangle<P, S> {
pub fn left(&self) -> P { self.x }
pub fn right(&self) -> O { self.x + self.width }
pub fn top(&self) -> P { self.y }
pub fn bottom(&self) -> O { self.y + self.height }
}
trait MinMax {
fn min(self, other: Self) -> Self;
fn max(self, other: Self) -> Self;
}
impl<T: PartialOrd> MinMax for T {
fn min(self, other: Self) -> Self {
if self < other {
self
} else {
other
}
}
fn max(self, other: Self) -> Self {
if self > other {
self
} else {
other
}
}
}
impl<T: Num + PartialOrd + Copy> Rectangle<T> {
pub fn clip_inside(&self, boundary: &Self) -> Option<Self> {
if self.width > boundary.width || self.height > boundary.height {
None
} else {
Some(
Rectangle {
x: self.x
.max(boundary.x)
.min(boundary.right() - self.width),
y: self.y
.max(boundary.y)
.min(boundary.bottom() - self.height),
width: self.width,
height: self.height,
}
)
}
}
}
impl Default for Bounds {
fn default() -> Self {
use std::f64;
Bounds {
x: 0.0,
y: 0.0,
width: f64::NAN,
height: f64::NAN,
}
}
}
impl<P: Default, S: Default> Default for Rectangle<P, S> {
default fn default() -> Self {
Rectangle {
x: Default::default(),
y: Default::default(),
width: Default::default(),
height: Default::default(),
}
}
}
impl Set for Bounds {
fn union(&self, other: &Self) -> Self {
let (x, y) = (
self.x.min(other.x),
self.y.min(other.y),
);
Bounds {
x: x,
y: y,
width: self.right().max(other.right()) - x,
height: self.bottom().max(other.bottom()) - y,
}
}
fn intersection(&self, other: &Self) -> Option<Self> {
let (x, y) = (
self.x.max(other.x),
self.y.max(other.y),
);
let (w, h) = (
self.right().min(other.right()) - x,
self.bottom().min(other.bottom()) - y,
);
if w > 0.0 && h > 0.0 {
Some(
Bounds {
x: x,
y: y,
width: w,
height: h,
}
)
} else {
None
}
}
fn contains(&self, subset: &Self) -> bool {
subset.left() >= self.left() &&
subset.right() <= self.right() &&
subset.top() >= self.top() &&
subset.bottom() <= self.bottom()
}
}
impl TryFrom<Bounds> for SdlRect {
type Err = ();
fn try_from(bounds: Bounds) -> Result<SdlRect, ()> {
use std::i32::MAX as IMAX;
use std::u32::MAX as UMAX;
let (imax, umax) = (IMAX as f64, UMAX as f64);
if
bounds.x.abs() <= imax &&
bounds.y.abs() <= imax &&
bounds.width <= umax &&
bounds.height <= umax &&
bounds.width > 0.0 &&
bounds.height > 0.0
{
Ok(
SdlRect::new(
bounds.x as _,
bounds.y as _,
bounds.width as _,
bounds.height as _
)
)
} else {
Err(())
}
}
}
impl From<Clip> for SdlRect {
fn from(clip: Clip) -> SdlRect {
SdlRect::new(
clip.x as _,
clip.y as _,
clip.width,
clip.height
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment