Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add common aspect ratio constants and improve documentation #15091

Merged
merged 14 commits into from
Sep 9, 2024
83 changes: 80 additions & 3 deletions crates/bevy_math/src/aspect_ratio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,81 @@ use bevy_reflect::Reflect;
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))]
pub struct AspectRatio(f32);

#[derive(Debug, PartialEq)]
pub enum AspectRatioError {
miniex marked this conversation as resolved.
Show resolved Hide resolved
/// Error due to width or height having zero as a value.
Zero,
miniex marked this conversation as resolved.
Show resolved Hide resolved
/// Error due to width or height being infinite.
Infinite,
/// Error due to width or height being Not a Number (NaN).
NaN,
}

impl AspectRatio {
/// Create a new `AspectRatio` from a given `width` and `height`.
/// Standard 16:9 aspect ratio
pub const SIXTEEN_NINE: Self = Self(16.0 / 9.0);
/// Standard 4:3 aspect ratio
pub const FOUR_THREE: Self = Self(4.0 / 3.0);
/// Standard 21:9 ultrawide aspect ratio
pub const ULTRAWIDE: Self = Self(21.0 / 9.0);

/// Create a new [`AspectRatio`] from a given width and height.
miniex marked this conversation as resolved.
Show resolved Hide resolved
///
/// # Panics
/// Panics when the width and height values are invalid, such a zero or infinite widths/heights, or if either
/// value is `NaN`.
#[inline]
pub fn new(width: f32, height: f32) -> Self {
miniex marked this conversation as resolved.
Show resolved Hide resolved
Self(width / height)
Self::try_new(width, height).expect("Invalid aspect ratio")
}

/// Create a new `AspectRatio` from a given amount of `x` pixels and `y` pixels.
/// Create a new [`AspectRatio`] from a given amount of x pixels and y pixels.
#[inline]
pub fn from_pixels(x: u32, y: u32) -> Self {
Self::new(x as f32, y as f32)
}

/// Attempts to create a new [`AspectRatio`] from a given width and height.
///
/// # Errors
///
/// Returns an `Err` with [`AspectRatioError`] if:
/// - Either width or height is zero (`AspectRatioError::Zero`)
/// - Either width or height is infinite (`AspectRatioError::Infinite`)
/// - Either width or height is NaN (`AspectRatioError::NaN`)
#[inline]
pub fn try_new(width: f32, height: f32) -> Result<Self, AspectRatioError> {
match (width, height) {
(w, h) if w == 0.0 || h == 0.0 => Err(AspectRatioError::Zero),
(w, h) if w.is_infinite() || h.is_infinite() => Err(AspectRatioError::Infinite),
(w, h) if w.is_nan() || h.is_nan() => Err(AspectRatioError::NaN),
_ => Ok(Self(width / height)),
}
}

/// Returns the inverse of this aspect ratio (height/width).
#[inline]
pub fn inverse(&self) -> Self {
Self(1.0 / self.0)
}

/// Returns true if the aspect ratio represents a landscape orientation.
#[inline]
pub fn is_landscape(&self) -> bool {
self.0 > 1.0
}

/// Returns true if the aspect ratio represents a portrait orientation.
#[inline]
pub fn is_portrait(&self) -> bool {
self.0 < 1.0
}

/// Returns true if the aspect ratio is exactly square.
#[inline]
pub fn is_square(&self) -> bool {
(self.0 - 1.0).abs() < f32::EPSILON
miniex marked this conversation as resolved.
Show resolved Hide resolved
}
}

impl From<Vec2> for AspectRatio {
Expand All @@ -37,3 +100,17 @@ impl From<AspectRatio> for f32 {
aspect_ratio.0
}
}

impl From<(f32, f32)> for AspectRatio {
#[inline]
fn from(value: (f32, f32)) -> Self {
Self::new(value.0, value.1)
}
}

impl From<(u32, u32)> for AspectRatio {
#[inline]
fn from(value: (u32, u32)) -> Self {
Self::from_pixels(value.0, value.1)
}
}
Loading