
# Objective Bevy seems to want to standardize on "American English" spellings. Not sure if this is laid out anywhere in writing, but see also #15947. While perusing the docs for `typos`, I noticed that it has a `locale` config option and tried it out. ## Solution Switch to `en-us` locale in the `typos` config and run `typos -w` ## Migration Guide The following methods or fields have been renamed from `*dependants*` to `*dependents*`. - `ProcessorAssetInfo::dependants` - `ProcessorAssetInfos::add_dependant` - `ProcessorAssetInfos::non_existent_dependants` - `AssetInfo::dependants_waiting_on_load` - `AssetInfo::dependants_waiting_on_recursive_dep_load` - `AssetInfos::loader_dependants` - `AssetInfos::remove_dependants_and_labels`
485 lines
15 KiB
Rust
485 lines
15 KiB
Rust
use crate::{IRect, Rect, UVec2};
|
|
|
|
#[cfg(feature = "bevy_reflect")]
|
|
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
|
#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
|
|
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
|
|
|
/// A rectangle defined by two opposite corners.
|
|
///
|
|
/// The rectangle is axis aligned, and defined by its minimum and maximum coordinates,
|
|
/// stored in `URect::min` and `URect::max`, respectively. The minimum/maximum invariant
|
|
/// must be upheld by the user when directly assigning the fields, otherwise some methods
|
|
/// produce invalid results. It is generally recommended to use one of the constructor
|
|
/// methods instead, which will ensure this invariant is met, unless you already have
|
|
/// the minimum and maximum corners.
|
|
#[repr(C)]
|
|
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
|
#[cfg_attr(
|
|
feature = "bevy_reflect",
|
|
derive(Reflect),
|
|
reflect(Debug, PartialEq, Hash, Default)
|
|
)]
|
|
#[cfg_attr(
|
|
all(feature = "serialize", feature = "bevy_reflect"),
|
|
reflect(Serialize, Deserialize)
|
|
)]
|
|
pub struct URect {
|
|
/// The minimum corner point of the rect.
|
|
pub min: UVec2,
|
|
/// The maximum corner point of the rect.
|
|
pub max: UVec2,
|
|
}
|
|
|
|
impl URect {
|
|
/// An empty `URect`, represented by maximum and minimum corner points
|
|
/// with `max == UVec2::MIN` and `min == UVec2::MAX`, so the
|
|
/// rect has an extremely large negative size.
|
|
/// This is useful, because when taking a union B of a non-empty `URect` A and
|
|
/// this empty `URect`, B will simply equal A.
|
|
pub const EMPTY: Self = Self {
|
|
max: UVec2::MIN,
|
|
min: UVec2::MAX,
|
|
};
|
|
/// Create a new rectangle from two corner points.
|
|
///
|
|
/// The two points do not need to be the minimum and/or maximum corners.
|
|
/// They only need to be two opposite corners.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::URect;
|
|
/// let r = URect::new(0, 4, 10, 6); // w=10 h=2
|
|
/// let r = URect::new(2, 4, 5, 0); // w=3 h=4
|
|
/// ```
|
|
#[inline]
|
|
pub fn new(x0: u32, y0: u32, x1: u32, y1: u32) -> Self {
|
|
Self::from_corners(UVec2::new(x0, y0), UVec2::new(x1, y1))
|
|
}
|
|
|
|
/// Create a new rectangle from two corner points.
|
|
///
|
|
/// The two points do not need to be the minimum and/or maximum corners.
|
|
/// They only need to be two opposite corners.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::{URect, UVec2};
|
|
/// // Unit rect from [0,0] to [1,1]
|
|
/// let r = URect::from_corners(UVec2::ZERO, UVec2::ONE); // w=1 h=1
|
|
/// // Same; the points do not need to be ordered
|
|
/// let r = URect::from_corners(UVec2::ONE, UVec2::ZERO); // w=1 h=1
|
|
/// ```
|
|
#[inline]
|
|
pub fn from_corners(p0: UVec2, p1: UVec2) -> Self {
|
|
Self {
|
|
min: p0.min(p1),
|
|
max: p0.max(p1),
|
|
}
|
|
}
|
|
|
|
/// Create a new rectangle from its center and size.
|
|
///
|
|
/// # Rounding Behavior
|
|
///
|
|
/// If the size contains odd numbers they will be rounded down to the nearest whole number.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// This method panics if any of the components of the size is negative or if `origin - (size / 2)` results in any negatives.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::{URect, UVec2};
|
|
/// let r = URect::from_center_size(UVec2::ONE, UVec2::splat(2)); // w=2 h=2
|
|
/// assert_eq!(r.min, UVec2::splat(0));
|
|
/// assert_eq!(r.max, UVec2::splat(2));
|
|
/// ```
|
|
#[inline]
|
|
pub fn from_center_size(origin: UVec2, size: UVec2) -> Self {
|
|
assert!(origin.cmpge(size / 2).all(), "Origin must always be greater than or equal to (size / 2) otherwise the rectangle is undefined! Origin was {origin} and size was {size}");
|
|
let half_size = size / 2;
|
|
Self::from_center_half_size(origin, half_size)
|
|
}
|
|
|
|
/// Create a new rectangle from its center and half-size.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// This method panics if any of the components of the half-size is negative or if `origin - half_size` results in any negatives.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::{URect, UVec2};
|
|
/// let r = URect::from_center_half_size(UVec2::ONE, UVec2::ONE); // w=2 h=2
|
|
/// assert_eq!(r.min, UVec2::splat(0));
|
|
/// assert_eq!(r.max, UVec2::splat(2));
|
|
/// ```
|
|
#[inline]
|
|
pub fn from_center_half_size(origin: UVec2, half_size: UVec2) -> Self {
|
|
assert!(origin.cmpge(half_size).all(), "Origin must always be greater than or equal to half_size otherwise the rectangle is undefined! Origin was {origin} and half_size was {half_size}");
|
|
Self {
|
|
min: origin - half_size,
|
|
max: origin + half_size,
|
|
}
|
|
}
|
|
|
|
/// Check if the rectangle is empty.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::{URect, UVec2};
|
|
/// let r = URect::from_corners(UVec2::ZERO, UVec2::new(0, 1)); // w=0 h=1
|
|
/// assert!(r.is_empty());
|
|
/// ```
|
|
#[inline]
|
|
pub fn is_empty(&self) -> bool {
|
|
self.min.cmpge(self.max).any()
|
|
}
|
|
|
|
/// Rectangle width (max.x - min.x).
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::URect;
|
|
/// let r = URect::new(0, 0, 5, 1); // w=5 h=1
|
|
/// assert_eq!(r.width(), 5);
|
|
/// ```
|
|
#[inline]
|
|
pub const fn width(&self) -> u32 {
|
|
self.max.x - self.min.x
|
|
}
|
|
|
|
/// Rectangle height (max.y - min.y).
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::URect;
|
|
/// let r = URect::new(0, 0, 5, 1); // w=5 h=1
|
|
/// assert_eq!(r.height(), 1);
|
|
/// ```
|
|
#[inline]
|
|
pub const fn height(&self) -> u32 {
|
|
self.max.y - self.min.y
|
|
}
|
|
|
|
/// Rectangle size.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::{URect, UVec2};
|
|
/// let r = URect::new(0, 0, 5, 1); // w=5 h=1
|
|
/// assert_eq!(r.size(), UVec2::new(5, 1));
|
|
/// ```
|
|
#[inline]
|
|
pub fn size(&self) -> UVec2 {
|
|
self.max - self.min
|
|
}
|
|
|
|
/// Rectangle half-size.
|
|
///
|
|
/// # Rounding Behavior
|
|
///
|
|
/// If the full size contains odd numbers they will be rounded down to the nearest whole number when calculating the half size.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::{URect, UVec2};
|
|
/// let r = URect::new(0, 0, 4, 2); // w=4 h=2
|
|
/// assert_eq!(r.half_size(), UVec2::new(2, 1));
|
|
/// ```
|
|
#[inline]
|
|
pub fn half_size(&self) -> UVec2 {
|
|
self.size() / 2
|
|
}
|
|
|
|
/// The center point of the rectangle.
|
|
///
|
|
/// # Rounding Behavior
|
|
///
|
|
/// If the (min + max) contains odd numbers they will be rounded down to the nearest whole number when calculating the center.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::{URect, UVec2};
|
|
/// let r = URect::new(0, 0, 4, 2); // w=4 h=2
|
|
/// assert_eq!(r.center(), UVec2::new(2, 1));
|
|
/// ```
|
|
#[inline]
|
|
pub fn center(&self) -> UVec2 {
|
|
(self.min + self.max) / 2
|
|
}
|
|
|
|
/// Check if a point lies within this rectangle, inclusive of its edges.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::URect;
|
|
/// let r = URect::new(0, 0, 5, 1); // w=5 h=1
|
|
/// assert!(r.contains(r.center()));
|
|
/// assert!(r.contains(r.min));
|
|
/// assert!(r.contains(r.max));
|
|
/// ```
|
|
#[inline]
|
|
pub fn contains(&self, point: UVec2) -> bool {
|
|
(point.cmpge(self.min) & point.cmple(self.max)).all()
|
|
}
|
|
|
|
/// Build a new rectangle formed of the union of this rectangle and another rectangle.
|
|
///
|
|
/// The union is the smallest rectangle enclosing both rectangles.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::{URect, UVec2};
|
|
/// let r1 = URect::new(0, 0, 5, 1); // w=5 h=1
|
|
/// let r2 = URect::new(1, 0, 3, 8); // w=2 h=4
|
|
/// let r = r1.union(r2);
|
|
/// assert_eq!(r.min, UVec2::new(0, 0));
|
|
/// assert_eq!(r.max, UVec2::new(5, 8));
|
|
/// ```
|
|
#[inline]
|
|
pub fn union(&self, other: Self) -> Self {
|
|
Self {
|
|
min: self.min.min(other.min),
|
|
max: self.max.max(other.max),
|
|
}
|
|
}
|
|
|
|
/// Build a new rectangle formed of the union of this rectangle and a point.
|
|
///
|
|
/// The union is the smallest rectangle enclosing both the rectangle and the point. If the
|
|
/// point is already inside the rectangle, this method returns a copy of the rectangle.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::{URect, UVec2};
|
|
/// let r = URect::new(0, 0, 5, 1); // w=5 h=1
|
|
/// let u = r.union_point(UVec2::new(3, 6));
|
|
/// assert_eq!(u.min, UVec2::ZERO);
|
|
/// assert_eq!(u.max, UVec2::new(5, 6));
|
|
/// ```
|
|
#[inline]
|
|
pub fn union_point(&self, other: UVec2) -> Self {
|
|
Self {
|
|
min: self.min.min(other),
|
|
max: self.max.max(other),
|
|
}
|
|
}
|
|
|
|
/// Build a new rectangle formed of the intersection of this rectangle and another rectangle.
|
|
///
|
|
/// The intersection is the largest rectangle enclosed in both rectangles. If the intersection
|
|
/// is empty, this method returns an empty rectangle ([`URect::is_empty()`] returns `true`), but
|
|
/// the actual values of [`URect::min`] and [`URect::max`] are implementation-dependent.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::{URect, UVec2};
|
|
/// let r1 = URect::new(0, 0, 2, 2); // w=2 h=2
|
|
/// let r2 = URect::new(1, 1, 3, 3); // w=2 h=2
|
|
/// let r = r1.intersect(r2);
|
|
/// assert_eq!(r.min, UVec2::new(1, 1));
|
|
/// assert_eq!(r.max, UVec2::new(2, 2));
|
|
/// ```
|
|
#[inline]
|
|
pub fn intersect(&self, other: Self) -> Self {
|
|
let mut r = Self {
|
|
min: self.min.max(other.min),
|
|
max: self.max.min(other.max),
|
|
};
|
|
// Collapse min over max to enforce invariants and ensure e.g. width() or
|
|
// height() never return a negative value.
|
|
r.min = r.min.min(r.max);
|
|
r
|
|
}
|
|
|
|
/// Create a new rectangle by expanding it evenly on all sides.
|
|
///
|
|
/// A positive expansion value produces a larger rectangle,
|
|
/// while a negative expansion value produces a smaller rectangle.
|
|
/// If this would result in zero width or height, [`URect::EMPTY`] is returned instead.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_math::{URect, UVec2};
|
|
/// let r = URect::new(4, 4, 6, 6); // w=2 h=2
|
|
/// let r2 = r.inflate(1); // w=4 h=4
|
|
/// assert_eq!(r2.min, UVec2::splat(3));
|
|
/// assert_eq!(r2.max, UVec2::splat(7));
|
|
///
|
|
/// let r = URect::new(4, 4, 8, 8); // w=4 h=4
|
|
/// let r2 = r.inflate(-1); // w=2 h=2
|
|
/// assert_eq!(r2.min, UVec2::splat(5));
|
|
/// assert_eq!(r2.max, UVec2::splat(7));
|
|
/// ```
|
|
#[inline]
|
|
pub fn inflate(&self, expansion: i32) -> Self {
|
|
let mut r = Self {
|
|
min: UVec2::new(
|
|
self.min.x.saturating_add_signed(-expansion),
|
|
self.min.y.saturating_add_signed(-expansion),
|
|
),
|
|
max: UVec2::new(
|
|
self.max.x.saturating_add_signed(expansion),
|
|
self.max.y.saturating_add_signed(expansion),
|
|
),
|
|
};
|
|
// Collapse min over max to enforce invariants and ensure e.g. width() or
|
|
// height() never return a negative value.
|
|
r.min = r.min.min(r.max);
|
|
r
|
|
}
|
|
|
|
/// Returns self as [`Rect`] (f32)
|
|
#[inline]
|
|
pub fn as_rect(&self) -> Rect {
|
|
Rect::from_corners(self.min.as_vec2(), self.max.as_vec2())
|
|
}
|
|
|
|
/// Returns self as [`IRect`] (i32)
|
|
#[inline]
|
|
pub fn as_irect(&self) -> IRect {
|
|
IRect::from_corners(self.min.as_ivec2(), self.max.as_ivec2())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn well_formed() {
|
|
let r = URect::from_center_size(UVec2::new(10, 16), UVec2::new(8, 12));
|
|
|
|
assert_eq!(r.min, UVec2::new(6, 10));
|
|
assert_eq!(r.max, UVec2::new(14, 22));
|
|
|
|
assert_eq!(r.center(), UVec2::new(10, 16));
|
|
|
|
assert_eq!(r.width(), 8);
|
|
assert_eq!(r.height(), 12);
|
|
assert_eq!(r.size(), UVec2::new(8, 12));
|
|
assert_eq!(r.half_size(), UVec2::new(4, 6));
|
|
|
|
assert!(r.contains(UVec2::new(7, 10)));
|
|
assert!(r.contains(UVec2::new(14, 10)));
|
|
assert!(r.contains(UVec2::new(10, 22)));
|
|
assert!(r.contains(UVec2::new(6, 22)));
|
|
assert!(r.contains(UVec2::new(14, 22)));
|
|
assert!(!r.contains(UVec2::new(50, 5)));
|
|
}
|
|
|
|
#[test]
|
|
fn rect_union() {
|
|
let r = URect::from_center_size(UVec2::splat(4), UVec2::splat(4)); // [2, 2] - [6, 6]
|
|
|
|
// overlapping
|
|
let r2 = URect {
|
|
min: UVec2::new(0, 0),
|
|
max: UVec2::new(3, 3),
|
|
};
|
|
let u = r.union(r2);
|
|
assert_eq!(u.min, UVec2::new(0, 0));
|
|
assert_eq!(u.max, UVec2::new(6, 6));
|
|
|
|
// disjoint
|
|
let r2 = URect {
|
|
min: UVec2::new(4, 7),
|
|
max: UVec2::new(8, 8),
|
|
};
|
|
let u = r.union(r2);
|
|
assert_eq!(u.min, UVec2::new(2, 2));
|
|
assert_eq!(u.max, UVec2::new(8, 8));
|
|
|
|
// included
|
|
let r2 = URect::from_center_size(UVec2::splat(4), UVec2::splat(2));
|
|
let u = r.union(r2);
|
|
assert_eq!(u.min, r.min);
|
|
assert_eq!(u.max, r.max);
|
|
|
|
// including
|
|
let r2 = URect::from_center_size(UVec2::splat(4), UVec2::splat(6));
|
|
let u = r.union(r2);
|
|
assert_eq!(u.min, r2.min);
|
|
assert_eq!(u.min, r2.min);
|
|
}
|
|
|
|
#[test]
|
|
fn rect_union_pt() {
|
|
let r = URect::from_center_size(UVec2::splat(4), UVec2::splat(4)); // [2, 2] - [6, 6]
|
|
|
|
// inside
|
|
let v = UVec2::new(2, 5);
|
|
let u = r.union_point(v);
|
|
assert_eq!(u.min, r.min);
|
|
assert_eq!(u.max, r.max);
|
|
|
|
// outside
|
|
let v = UVec2::new(10, 5);
|
|
let u = r.union_point(v);
|
|
assert_eq!(u.min, UVec2::new(2, 2));
|
|
assert_eq!(u.max, UVec2::new(10, 6));
|
|
}
|
|
|
|
#[test]
|
|
fn rect_intersect() {
|
|
let r = URect::from_center_size(UVec2::splat(6), UVec2::splat(8)); // [2, 2] - [10, 10]
|
|
|
|
// overlapping
|
|
let r2 = URect {
|
|
min: UVec2::new(8, 8),
|
|
max: UVec2::new(12, 12),
|
|
};
|
|
let u = r.intersect(r2);
|
|
assert_eq!(u.min, UVec2::new(8, 8));
|
|
assert_eq!(u.max, UVec2::new(10, 10));
|
|
|
|
// disjoint
|
|
let r2 = URect {
|
|
min: UVec2::new(12, 12),
|
|
max: UVec2::new(14, 18),
|
|
};
|
|
let u = r.intersect(r2);
|
|
assert!(u.is_empty());
|
|
assert_eq!(u.width(), 0);
|
|
|
|
// included
|
|
let r2 = URect::from_center_size(UVec2::splat(6), UVec2::splat(2));
|
|
let u = r.intersect(r2);
|
|
assert_eq!(u.min, r2.min);
|
|
assert_eq!(u.max, r2.max);
|
|
|
|
// including
|
|
let r2 = URect::from_center_size(UVec2::splat(6), UVec2::splat(10));
|
|
let u = r.intersect(r2);
|
|
assert_eq!(u.min, r.min);
|
|
assert_eq!(u.max, r.max);
|
|
}
|
|
|
|
#[test]
|
|
fn rect_inflate() {
|
|
let r = URect::from_center_size(UVec2::splat(6), UVec2::splat(6)); // [3, 3] - [9, 9]
|
|
|
|
let r2 = r.inflate(2);
|
|
assert_eq!(r2.min, UVec2::new(1, 1));
|
|
assert_eq!(r2.max, UVec2::new(11, 11));
|
|
}
|
|
}
|