2015-05-19 02:41:35 +00:00
|
|
|
//! Points on the 2D character grid.
|
2016-10-02 22:22:29 +00:00
|
|
|
|
2016-07-13 04:01:11 +00:00
|
|
|
use XY;
|
2017-01-11 01:39:21 +00:00
|
|
|
use num::traits::Zero;
|
2017-10-11 22:07:13 +00:00
|
|
|
use std::cmp::{max, min, Ordering};
|
2016-06-28 05:10:59 +00:00
|
|
|
use std::ops::{Add, Div, Mul, Sub};
|
2015-05-15 18:58:47 +00:00
|
|
|
|
2016-07-14 06:18:59 +00:00
|
|
|
/// Simple 2D size, in cells.
|
|
|
|
///
|
|
|
|
/// Note: due to a bug in rustdoc ([#32077]), the documentation for `Vec2` is
|
|
|
|
/// currently shown on the [`XY`] page.
|
|
|
|
///
|
|
|
|
/// [#32077]: https://github.com/rust-lang/rust/issues/32077
|
|
|
|
/// [`XY`]: ../struct.XY.html
|
2016-07-13 04:01:11 +00:00
|
|
|
pub type Vec2 = XY<usize>;
|
2015-05-15 18:58:47 +00:00
|
|
|
|
2017-10-12 23:38:55 +00:00
|
|
|
impl<T: PartialOrd> PartialOrd for XY<T> {
|
2016-07-14 05:11:03 +00:00
|
|
|
/// `a < b` <=> `a.x < b.x && a.y < b.y`
|
2017-10-11 22:07:13 +00:00
|
|
|
fn partial_cmp(&self, other: &XY<T>) -> Option<Ordering> {
|
2016-03-15 22:37:57 +00:00
|
|
|
if self == other {
|
|
|
|
Some(Ordering::Equal)
|
|
|
|
} else if self.x < other.x && self.y < other.y {
|
|
|
|
Some(Ordering::Less)
|
|
|
|
} else if self.x > other.x && self.y > other.y {
|
|
|
|
Some(Ordering::Greater)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2015-06-08 03:58:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-14 23:32:01 +00:00
|
|
|
impl XY<usize> {
|
|
|
|
/// Saturating subtraction. Computes `self - other`, saturating at 0.
|
|
|
|
///
|
|
|
|
/// Never panics.
|
|
|
|
pub fn saturating_sub<O: Into<Self>>(&self, other: O) -> Self {
|
|
|
|
let other = other.into();
|
2017-10-11 22:07:13 +00:00
|
|
|
Self::new(
|
|
|
|
self.x.saturating_sub(other.x),
|
|
|
|
self.y.saturating_sub(other.y),
|
|
|
|
)
|
2017-08-14 23:32:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Checked subtraction. Computes `self - other` if possible.
|
|
|
|
///
|
|
|
|
/// Returns `None` if `self.x < other.x || self.y < other.y`.
|
|
|
|
///
|
|
|
|
/// Never panics.
|
|
|
|
pub fn checked_sub<O: Into<Self>>(&self, other: O) -> Option<Self> {
|
|
|
|
let other = other.into();
|
|
|
|
if self.fits(other) {
|
|
|
|
Some(*self - other)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a `XY<isize>` from `self`.
|
|
|
|
pub fn signed(self) -> XY<isize> {
|
|
|
|
self.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-11 01:39:21 +00:00
|
|
|
impl<T: Ord> XY<T> {
|
|
|
|
/// Returns `true` if `self` could fit inside `other`.
|
|
|
|
///
|
|
|
|
/// Shortcut for `self.x <= other.x && self.y <= other.y`.
|
2017-08-14 23:32:01 +00:00
|
|
|
///
|
|
|
|
/// If this returns `true`, then `other - self` will not underflow.
|
2017-01-11 01:39:21 +00:00
|
|
|
pub fn fits_in<O: Into<Self>>(&self, other: O) -> bool {
|
|
|
|
let other = other.into();
|
|
|
|
self.x <= other.x && self.y <= other.y
|
|
|
|
}
|
|
|
|
|
2017-08-14 23:32:01 +00:00
|
|
|
/// Returns `true` if `other` could fit inside `self`.
|
|
|
|
///
|
|
|
|
/// Shortcut for `self.x >= other.x && self.y >= other.y`.
|
|
|
|
///
|
|
|
|
/// If this returns `true`, then `self - other` will not underflow.
|
|
|
|
pub fn fits<O: Into<Self>>(&self, other: O) -> bool {
|
|
|
|
let other = other.into();
|
|
|
|
self.x >= other.x && self.y >= other.y
|
|
|
|
}
|
|
|
|
|
2015-05-19 02:41:35 +00:00
|
|
|
/// Returns a new Vec2 that is a maximum per coordinate.
|
2017-01-11 01:39:21 +00:00
|
|
|
pub fn max<A: Into<XY<T>>, B: Into<XY<T>>>(a: A, b: B) -> Self {
|
2016-07-13 04:01:11 +00:00
|
|
|
let a = a.into();
|
|
|
|
let b = b.into();
|
2016-07-14 05:11:03 +00:00
|
|
|
a.zip_map(b, max)
|
2015-05-19 02:41:35 +00:00
|
|
|
}
|
|
|
|
|
2015-05-15 18:58:47 +00:00
|
|
|
/// Returns a new Vec2 that is no larger than any input in both dimensions.
|
2017-01-11 01:39:21 +00:00
|
|
|
pub fn min<A: Into<XY<T>>, B: Into<XY<T>>>(a: A, b: B) -> Self {
|
2016-07-13 04:01:11 +00:00
|
|
|
let a = a.into();
|
|
|
|
let b = b.into();
|
2016-07-14 05:11:03 +00:00
|
|
|
a.zip_map(b, min)
|
2015-05-19 02:41:35 +00:00
|
|
|
}
|
|
|
|
|
2016-07-13 04:01:11 +00:00
|
|
|
/// Returns the minimum of `self` and `other`.
|
2017-01-11 01:39:21 +00:00
|
|
|
pub fn or_min<O: Into<XY<T>>>(self, other: O) -> Self {
|
|
|
|
Self::min(self, other)
|
2016-07-13 04:01:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the maximum of `self` and `other`.
|
2017-01-11 01:39:21 +00:00
|
|
|
pub fn or_max<O: Into<XY<T>>>(self, other: O) -> Self {
|
|
|
|
Self::max(self, other)
|
2015-05-15 18:58:47 +00:00
|
|
|
}
|
2017-01-11 01:39:21 +00:00
|
|
|
}
|
2015-06-08 03:58:10 +00:00
|
|
|
|
2017-01-11 01:39:21 +00:00
|
|
|
impl<T: Ord + Add<Output = T> + Clone> XY<T> {
|
2015-06-08 03:58:10 +00:00
|
|
|
/// Returns (max(self.x,other.x), self.y+other.y)
|
2017-01-11 01:39:21 +00:00
|
|
|
pub fn stack_vertical(&self, other: &Self) -> Self {
|
2017-10-11 22:07:13 +00:00
|
|
|
Self::new(
|
|
|
|
max(self.x.clone(), other.x.clone()),
|
|
|
|
self.y.clone() + other.y.clone(),
|
|
|
|
)
|
2015-06-08 03:58:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns (self.x+other.x, max(self.y,other.y))
|
2017-01-11 01:39:21 +00:00
|
|
|
pub fn stack_horizontal(&self, other: &Self) -> Self {
|
2017-10-11 22:07:13 +00:00
|
|
|
Self::new(
|
|
|
|
self.x.clone() + other.x.clone(),
|
|
|
|
max(self.y.clone(), other.y.clone()),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns `true` if `self` fits in the given rectangle.
|
|
|
|
pub fn fits_in_rect<O1, O2>(&self, top_left: O1, size: O2) -> bool
|
|
|
|
where
|
|
|
|
O1: Into<Self>,
|
|
|
|
O2: Into<Self>,
|
|
|
|
{
|
|
|
|
let top_left = top_left.into();
|
|
|
|
self.fits(top_left.clone()) && self < &(top_left + size)
|
2015-06-08 03:58:10 +00:00
|
|
|
}
|
2017-01-11 01:39:21 +00:00
|
|
|
}
|
2016-07-13 08:19:05 +00:00
|
|
|
|
2017-01-11 01:39:21 +00:00
|
|
|
impl<T: Zero + Clone> XY<T> {
|
|
|
|
/// Returns a vector with the X component of self, and y=0.
|
|
|
|
pub fn keep_x(&self) -> Self {
|
|
|
|
Self::new(self.x.clone(), T::zero())
|
2016-07-13 08:19:05 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 01:39:21 +00:00
|
|
|
/// Returns a vector with the Y component of self, and x=0.
|
|
|
|
pub fn keep_y(&self) -> Self {
|
|
|
|
Self::new(T::zero(), self.y.clone())
|
2016-07-26 17:49:37 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 01:39:21 +00:00
|
|
|
/// Alias for `Self::new(0,0)`.
|
|
|
|
pub fn zero() -> Self {
|
|
|
|
Self::new(T::zero(), T::zero())
|
2016-07-26 17:49:37 +00:00
|
|
|
}
|
2017-01-11 01:39:21 +00:00
|
|
|
}
|
2016-07-26 17:49:37 +00:00
|
|
|
|
2017-02-07 02:18:17 +00:00
|
|
|
impl<T: Into<XY<usize>>> From<T> for XY<isize> {
|
2017-01-11 01:39:21 +00:00
|
|
|
fn from(t: T) -> Self {
|
|
|
|
let other = t.into();
|
|
|
|
Self::new(other.x as isize, other.y as isize)
|
2016-07-13 08:19:05 +00:00
|
|
|
}
|
2015-05-15 18:58:47 +00:00
|
|
|
}
|
|
|
|
|
2016-07-14 06:18:59 +00:00
|
|
|
impl From<(i32, i32)> for XY<usize> {
|
2016-07-12 02:24:00 +00:00
|
|
|
fn from((x, y): (i32, i32)) -> Self {
|
|
|
|
(x as usize, y as usize).into()
|
2015-05-20 17:31:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-14 06:18:59 +00:00
|
|
|
impl From<(u32, u32)> for XY<usize> {
|
2016-07-12 02:24:00 +00:00
|
|
|
fn from((x, y): (u32, u32)) -> Self {
|
|
|
|
(x as usize, y as usize).into()
|
2015-05-15 18:58:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-14 07:08:58 +00:00
|
|
|
impl From<(u8, u8)> for XY<usize> {
|
|
|
|
fn from((x, y): (u8, u8)) -> Self {
|
|
|
|
(x as usize, y as usize).into()
|
2017-10-08 22:58:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<(u16, u16)> for XY<usize> {
|
|
|
|
fn from((x, y): (u16, u16)) -> Self {
|
|
|
|
(x as usize, y as usize).into()
|
2017-06-14 07:08:58 +00:00
|
|
|
}
|
|
|
|
}
|
2015-05-15 22:00:20 +00:00
|
|
|
|
2017-02-07 02:18:17 +00:00
|
|
|
impl<T: Add<Output = T>, O: Into<XY<T>>> Add<O> for XY<T> {
|
2017-01-11 01:39:21 +00:00
|
|
|
type Output = Self;
|
2015-05-15 18:58:47 +00:00
|
|
|
|
2017-01-11 01:39:21 +00:00
|
|
|
fn add(self, other: O) -> Self {
|
2016-07-14 05:11:03 +00:00
|
|
|
self.zip_map(other.into(), Add::add)
|
2015-05-15 18:58:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-07 02:18:17 +00:00
|
|
|
impl<T: Sub<Output = T>, O: Into<XY<T>>> Sub<O> for XY<T> {
|
2017-01-11 01:39:21 +00:00
|
|
|
type Output = Self;
|
2015-05-15 18:58:47 +00:00
|
|
|
|
2017-01-11 01:39:21 +00:00
|
|
|
fn sub(self, other: O) -> Self {
|
2016-07-14 05:11:03 +00:00
|
|
|
self.zip_map(other.into(), Sub::sub)
|
2015-05-15 18:58:47 +00:00
|
|
|
}
|
|
|
|
}
|
2015-05-15 23:06:48 +00:00
|
|
|
|
2017-02-07 02:18:17 +00:00
|
|
|
impl<T: Clone + Div<Output = T>> Div<T> for XY<T> {
|
2017-01-11 01:39:21 +00:00
|
|
|
type Output = Self;
|
2015-05-15 23:06:48 +00:00
|
|
|
|
2017-01-11 01:39:21 +00:00
|
|
|
fn div(self, other: T) -> Self {
|
|
|
|
self.map(|s| s / other.clone())
|
2015-05-15 23:06:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-14 06:18:59 +00:00
|
|
|
impl Mul<usize> for XY<usize> {
|
2015-05-15 23:06:48 +00:00
|
|
|
type Output = Vec2;
|
|
|
|
|
2015-05-25 21:46:29 +00:00
|
|
|
fn mul(self, other: usize) -> Vec2 {
|
2016-07-14 05:11:03 +00:00
|
|
|
self.map(|s| s * other)
|
2015-05-15 23:06:48 +00:00
|
|
|
}
|
|
|
|
}
|
2015-05-25 21:56:51 +00:00
|
|
|
|
|
|
|
/// Four values representing each direction.
|
2017-10-11 22:07:13 +00:00
|
|
|
#[derive(Clone, Copy)]
|
2015-05-25 21:56:51 +00:00
|
|
|
pub struct Vec4 {
|
|
|
|
/// Left margin
|
|
|
|
pub left: usize,
|
|
|
|
/// Right margin
|
|
|
|
pub right: usize,
|
|
|
|
/// Top margin
|
|
|
|
pub top: usize,
|
|
|
|
/// Bottom margin
|
|
|
|
pub bottom: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Vec4 {
|
|
|
|
/// Creates a new Vec4.
|
|
|
|
pub fn new(left: usize, right: usize, top: usize, bottom: usize) -> Self {
|
|
|
|
Vec4 {
|
|
|
|
left: left,
|
|
|
|
right: right,
|
|
|
|
top: top,
|
|
|
|
bottom: bottom,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns left + right.
|
|
|
|
pub fn horizontal(&self) -> usize {
|
|
|
|
self.left + self.right
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns top + bottom.
|
|
|
|
pub fn vertical(&self) -> usize {
|
|
|
|
self.top + self.bottom
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns (left+right, top+bottom).
|
|
|
|
pub fn combined(&self) -> Vec2 {
|
|
|
|
Vec2::new(self.horizontal(), self.vertical())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns (left, top).
|
|
|
|
pub fn top_left(&self) -> Vec2 {
|
|
|
|
Vec2::new(self.left, self.top)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns (right, bottom).
|
|
|
|
pub fn bot_right(&self) -> Vec2 {
|
|
|
|
Vec2::new(self.right, self.bottom)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-12 02:24:00 +00:00
|
|
|
impl From<(usize, usize, usize, usize)> for Vec4 {
|
|
|
|
fn from((left, right, top, bottom): (usize, usize, usize, usize)) -> Vec4 {
|
|
|
|
Vec4::new(left, right, top, bottom)
|
2015-05-25 21:56:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-12 02:24:00 +00:00
|
|
|
impl From<(i32, i32, i32, i32)> for Vec4 {
|
|
|
|
fn from((left, right, top, bottom): (i32, i32, i32, i32)) -> Vec4 {
|
|
|
|
(left as usize, right as usize, top as usize, bottom as usize).into()
|
2015-05-25 21:56:51 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-03 02:36:22 +00:00
|
|
|
|
2016-10-12 22:37:35 +00:00
|
|
|
impl From<((i32, i32), (i32, i32))> for Vec4 {
|
|
|
|
fn from(((left, right), (top, bottom)): ((i32, i32), (i32, i32))) -> Vec4 {
|
|
|
|
(left, right, top, bottom).into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl From<((usize, usize), (usize, usize))> for Vec4 {
|
2017-10-11 22:07:13 +00:00
|
|
|
fn from(
|
|
|
|
((left, right), (top, bottom)): ((usize, usize), (usize, usize))
|
|
|
|
) -> Vec4 {
|
2016-10-12 22:37:35 +00:00
|
|
|
(left, right, top, bottom).into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-12 02:24:00 +00:00
|
|
|
impl<T: Into<Vec4>> Add<T> for Vec4 {
|
2015-06-03 02:36:22 +00:00
|
|
|
type Output = Vec4;
|
|
|
|
|
|
|
|
fn add(self, other: T) -> Vec4 {
|
2016-07-12 02:24:00 +00:00
|
|
|
let ov = other.into();
|
2015-06-03 02:36:22 +00:00
|
|
|
|
|
|
|
Vec4 {
|
|
|
|
left: self.left + ov.left,
|
|
|
|
right: self.right + ov.right,
|
|
|
|
top: self.top + ov.top,
|
|
|
|
bottom: self.bottom + ov.bottom,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-12 02:24:00 +00:00
|
|
|
impl<T: Into<Vec4>> Sub<T> for Vec4 {
|
2015-06-03 02:36:22 +00:00
|
|
|
type Output = Vec4;
|
|
|
|
|
|
|
|
fn sub(self, other: T) -> Vec4 {
|
2016-07-12 02:24:00 +00:00
|
|
|
let ov = other.into();
|
2015-06-03 02:36:22 +00:00
|
|
|
|
|
|
|
Vec4 {
|
|
|
|
left: self.left - ov.left,
|
|
|
|
right: self.right - ov.right,
|
|
|
|
top: self.top - ov.top,
|
|
|
|
bottom: self.bottom - ov.bottom,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Div<usize> for Vec4 {
|
|
|
|
type Output = Vec4;
|
|
|
|
|
|
|
|
fn div(self, other: usize) -> Vec4 {
|
|
|
|
Vec4 {
|
|
|
|
left: self.left / other,
|
|
|
|
right: self.right / other,
|
|
|
|
top: self.top / other,
|
|
|
|
bottom: self.bottom / other,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Mul<usize> for Vec4 {
|
|
|
|
type Output = Vec4;
|
|
|
|
|
|
|
|
fn mul(self, other: usize) -> Vec4 {
|
|
|
|
Vec4 {
|
|
|
|
left: self.left * other,
|
|
|
|
right: self.right * other,
|
|
|
|
top: self.top * other,
|
|
|
|
bottom: self.bottom * other,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-13 04:33:24 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::Vec2;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_from() {
|
|
|
|
let vi32 = Vec2::from((4i32, 5i32));
|
|
|
|
let vu32 = Vec2::from((4u32, 5u32));
|
|
|
|
|
|
|
|
let vusize = Vec2::from((4usize, 5usize));
|
|
|
|
let vvec = Vec2::from(Vec2::new(4, 5));
|
|
|
|
|
|
|
|
assert_eq!(vi32 - vu32, vusize - vvec);
|
|
|
|
}
|
|
|
|
}
|