// Copyright 2013 The Servo Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms.
#[cfg(feature = "bytemuck")] use bytemuck::{Pod, Zeroable}; use num_traits::{Float, NumCast}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize};
use core::borrow::Borrow; use core::cmp::PartialOrd; use core::fmt; use core::hash::{Hash, Hasher}; use core::ops::{Add, Div, DivAssign, Mul, MulAssign, Range, Sub};
/// An axis aligned 3D box represented by its minimum and maximum coordinates. #[repr(C)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(
feature = "serde",
serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>"))
)] pubstruct Box3D<T, U> { pub min: Point3D<T, U>, pub max: Point3D<T, U>,
}
/// Creates a Box3D of the given size, at offset zero. #[inline] pubfn from_size(size: Size3D<T, U>) -> Self where
T: Zero,
{
Box3D {
min: Point3D::zero(),
max: point3(size.width, size.height, size.depth),
}
}
}
impl<T, U> Box3D<T, U> where
T: PartialOrd,
{ /// Returns true if the box has a negative volume. /// /// The common interpretation for a negative box is to consider it empty. It can be obtained /// by calculating the intersection of two boxes that do not intersect. #[inline] pubfn is_negative(&self) -> bool { self.max.x < self.min.x || self.max.y < self.min.y || self.max.z < self.min.z
}
/// Returns true if the size is zero, negative or NaN. #[inline] pubfn is_empty(&self) -> bool {
!(self.max.x > self.min.x && self.max.y > self.min.y && self.max.z > self.min.z)
}
/// Returns `true` if this box3d contains the point `p`. A point is considered /// in the box3d if it lies on the front, left or top faces, but outside if it lies /// on the back, right or bottom faces. #[inline] pubfn contains(&self, other: Point3D<T, U>) -> bool {
(self.min.x <= other.x)
& (other.x < self.max.x)
& (self.min.y <= other.y)
& (other.y < self.max.y)
& (self.min.z <= other.z)
& (other.z < self.max.z)
}
/// Returns `true` if this box3d contains the point `p`. A point is considered /// in the box3d if it lies on any face of the box3d. #[inline] pubfn contains_inclusive(&self, other: Point3D<T, U>) -> bool {
(self.min.x <= other.x)
& (other.x <= self.max.x)
& (self.min.y <= other.y)
& (other.y <= self.max.y)
& (self.min.z <= other.z)
& (other.z <= self.max.z)
}
/// Returns `true` if this box3d contains the interior of the other box3d. Always /// returns `true` if other is empty, and always returns `false` if other is /// nonempty but this box3d is empty. #[inline] pubfn contains_box(&self, other: &Self) -> bool {
other.is_empty()
|| ((self.min.x <= other.min.x)
& (other.max.x <= self.max.x)
& (self.min.y <= other.min.y)
& (other.max.y <= self.max.y)
& (self.min.z <= other.min.z)
& (other.max.z <= self.max.z))
}
}
/// Computes the union of two boxes. /// /// If either of the boxes is empty, the other one is returned. #[inline] pubfn union(&self, other: &Self) -> Self { if other.is_empty() { return *self;
} ifself.is_empty() { return *other;
}
impl<T: NumCast + Copy, U> Box3D<T, U> { /// Cast from one numeric representation to another, preserving the units. /// /// When casting from floating point to integer coordinates, the decimals are truncated /// as one would expect from a simple cast, but this behavior does not always make sense /// geometrically. Consider using round(), round_in or round_out() before casting. #[inline] pubfn cast<NewT: NumCast>(&self) -> Box3D<NewT, U> {
Box3D::new(self.min.cast(), self.max.cast())
}
/// Fallible cast from one numeric representation to another, preserving the units. /// /// When casting from floating point to integer coordinates, the decimals are truncated /// as one would expect from a simple cast, but this behavior does not always make sense /// geometrically. Consider using round(), round_in or round_out() before casting. pubfn try_cast<NewT: NumCast>(&self) -> Option<Box3D<NewT, U>> { match (self.min.try_cast(), self.max.try_cast()) {
(Some(a), Some(b)) => Some(Box3D::new(a, b)),
_ => None,
}
}
// Convenience functions for common casts
/// Cast into an `f32` box3d. #[inline] pubfn to_f32(&self) -> Box3D<f32, U> { self.cast()
}
/// Cast into an `f64` box3d. #[inline] pubfn to_f64(&self) -> Box3D<f64, U> { self.cast()
}
/// Cast into an `usize` box3d, truncating decimals if any. /// /// When casting from floating point cuboids, it is worth considering whether /// to `round()`, `round_in()` or `round_out()` before the cast in order to /// obtain the desired conversion behavior. #[inline] pubfn to_usize(&self) -> Box3D<usize, U> { self.cast()
}
/// Cast into an `u32` box3d, truncating decimals if any. /// /// When casting from floating point cuboids, it is worth considering whether /// to `round()`, `round_in()` or `round_out()` before the cast in order to /// obtain the desired conversion behavior. #[inline] pubfn to_u32(&self) -> Box3D<u32, U> { self.cast()
}
/// Cast into an `i32` box3d, truncating decimals if any. /// /// When casting from floating point cuboids, it is worth considering whether /// to `round()`, `round_in()` or `round_out()` before the cast in order to /// obtain the desired conversion behavior. #[inline] pubfn to_i32(&self) -> Box3D<i32, U> { self.cast()
}
/// Cast into an `i64` box3d, truncating decimals if any. /// /// When casting from floating point cuboids, it is worth considering whether /// to `round()`, `round_in()` or `round_out()` before the cast in order to /// obtain the desired conversion behavior. #[inline] pubfn to_i64(&self) -> Box3D<i64, U> { self.cast()
}
}
impl<T: Float, U> Box3D<T, U> { /// Returns true if all members are finite. #[inline] pubfn is_finite(self) -> bool { self.min.is_finite() && self.max.is_finite()
}
}
impl<T, U> Box3D<T, U> where
T: Round,
{ /// Return a box3d with edges rounded to integer coordinates, such that /// the returned box3d has the same set of pixel centers as the original /// one. /// Values equal to 0.5 round up. /// Suitable for most places where integral device coordinates /// are needed, but note that any translation should be applied first to /// avoid pixel rounding errors. /// Note that this is *not* rounding to nearest integer if the values are negative. /// They are always rounding as floor(n + 0.5). #[must_use] pubfn round(&self) -> Self {
Box3D::new(self.min.round(), self.max.round())
}
}
impl<T, U> Box3D<T, U> where
T: Floor + Ceil,
{ /// Return a box3d with faces/edges rounded to integer coordinates, such that /// the original box3d contains the resulting box3d. #[must_use] pubfn round_in(&self) -> Self {
Box3D {
min: self.min.ceil(),
max: self.max.floor(),
}
}
/// Return a box3d with faces/edges rounded to integer coordinates, such that /// the original box3d is contained in the resulting box3d. #[must_use] pubfn round_out(&self) -> Self {
Box3D {
min: self.min.floor(),
max: self.max.ceil(),
}
}
}
impl<T, U> From<Size3D<T, U>> for Box3D<T, U> where
T: Copy + Zero + PartialOrd,
{ fn from(b: Size3D<T, U>) -> Self { Self::from_size(b)
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.