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
76 changes: 73 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,74 @@ 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
Zero,
miniex marked this conversation as resolved.
Show resolved Hide resolved
Infinite,
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
#[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 +93,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