// Copyright 2018 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.
use core::cmp::{Eq, PartialEq}; use core::fmt; use core::hash::Hash; use core::marker::PhantomData; use core::ops::{Add, AddAssign, Neg, Sub, SubAssign};
#[cfg(feature = "bytemuck")] use bytemuck::{Pod, Zeroable}; use num_traits::NumCast; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize};
/// A 2d transformation from a space to another that can only express translations. /// /// The main benefit of this type over a Vector2D is the ability to cast /// between a source and a destination spaces. /// /// Example: /// /// ``` /// use euclid::{Translation2D, Point2D, point2}; /// struct ParentSpace; /// struct ChildSpace; /// type ScrollOffset = Translation2D<i32, ParentSpace, ChildSpace>; /// type ParentPoint = Point2D<i32, ParentSpace>; /// type ChildPoint = Point2D<i32, ChildSpace>; /// /// let scrolling = ScrollOffset::new(0, 100); /// let p1: ParentPoint = point2(0, 0); /// let p2: ChildPoint = scrolling.transform_point(p1); /// ``` /// #[repr(C)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(
feature = "serde",
serde(bound(
serialize = "T: serde::Serialize",
deserialize = "T: serde::Deserialize<'de>"
))
)] pubstruct Translation2D<T, Src, Dst> { pub x: T, pub y: T, #[doc(hidden)] pub _unit: PhantomData<(Src, Dst)>,
}
#[cfg(feature = "arbitrary")] impl<'a, T, Src, Dst> arbitrary::Arbitrary<'a> for Translation2D<T, Src, Dst> where
T: arbitrary::Arbitrary<'a>,
{ fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { let (x, y) = arbitrary::Arbitrary::arbitrary(u)?;
Ok(Translation2D {
x,
y,
_unit: PhantomData,
})
}
}
impl<T: Copy, Src, Dst> Copy for Translation2D<T, Src, Dst> {}
/// Cast into an array with x and y. #[inline] pubfn to_array(&self) -> [T; 2] {
[self.x, self.y]
}
/// Cast into a tuple with x and y. #[inline] pubfn to_tuple(&self) -> (T, T) {
(self.x, self.y)
}
/// Drop the units, preserving only the numeric value. #[inline] pubfn to_untyped(&self) -> Translation2D<T, UnknownUnit, UnknownUnit> {
Translation2D {
x: self.x,
y: self.y,
_unit: PhantomData,
}
}
/// Tag a unitless value with units. #[inline] pubfn from_untyped(t: &Translation2D<T, UnknownUnit, UnknownUnit>) -> Self {
Translation2D {
x: t.x,
y: t.y,
_unit: PhantomData,
}
}
/// Returns the matrix representation of this translation. #[inline] pubfn to_transform(&self) -> Transform2D<T, Src, Dst> where
T: Zero + One,
{
(*self).into()
}
/// Translate a point and cast its unit. #[inline] pubfn transform_point(&self, p: Point2D<T, Src>) -> Point2D<T::Output, Dst> where
T: Add,
{
point2(p.x + self.x, p.y + self.y)
}
/// Translate a rectangle and cast its unit. #[inline] pubfn transform_rect(&self, r: &Rect<T, Src>) -> Rect<T::Output, Dst> where
T: Add<Output = T>,
{
Rect {
origin: self.transform_point(r.origin),
size: self.transform_size(r.size),
}
}
/// Translate a 2D box and cast its unit. #[inline] pubfn transform_box(&self, r: &Box2D<T, Src>) -> Box2D<T::Output, Dst> where
T: Add,
{
Box2D {
min: self.transform_point(r.min),
max: self.transform_point(r.max),
}
}
/// Return the inverse transformation. #[inline] pubfn inverse(&self) -> Translation2D<T::Output, Dst, Src> where
T: Neg,
{
Translation2D::new(-self.x, -self.y)
}
}
impl<T: NumCast + Copy, Src, Dst> Translation2D<T, Src, Dst> { /// Cast from one numeric representation to another, preserving the units. /// /// When casting from floating vector 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()`, `ceil()` or `floor()` before casting. #[inline] pubfn cast<NewT: NumCast>(self) -> Translation2D<NewT, Src, Dst> { self.try_cast().unwrap()
}
/// Fallible cast from one numeric representation to another, preserving the units. /// /// When casting from floating vector 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()`, `ceil()` or `floor()` before casting. pubfn try_cast<NewT: NumCast>(self) -> Option<Translation2D<NewT, Src, Dst>> { match (NumCast::from(self.x), NumCast::from(self.y)) {
(Some(x), Some(y)) => Some(Translation2D::new(x, y)),
_ => None,
}
}
// Convenience functions for common casts.
/// Cast into an `f32` vector. #[inline] pubfn to_f32(self) -> Translation2D<f32, Src, Dst> { self.cast()
}
/// Cast into an `f64` vector. #[inline] pubfn to_f64(self) -> Translation2D<f64, Src, Dst> { self.cast()
}
/// Cast into an `usize` vector, truncating decimals if any. /// /// When casting from floating vector vectors, it is worth considering whether /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain /// the desired conversion behavior. #[inline] pubfn to_usize(self) -> Translation2D<usize, Src, Dst> { self.cast()
}
/// Cast into an `u32` vector, truncating decimals if any. /// /// When casting from floating vector vectors, it is worth considering whether /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain /// the desired conversion behavior. #[inline] pubfn to_u32(self) -> Translation2D<u32, Src, Dst> { self.cast()
}
/// Cast into an i32 vector, truncating decimals if any. /// /// When casting from floating vector vectors, it is worth considering whether /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain /// the desired conversion behavior. #[inline] pubfn to_i32(self) -> Translation2D<i32, Src, Dst> { self.cast()
}
/// Cast into an i64 vector, truncating decimals if any. /// /// When casting from floating vector vectors, it is worth considering whether /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain /// the desired conversion behavior. #[inline] pubfn to_i64(self) -> Translation2D<i64, Src, Dst> { self.cast()
}
}
/// A 3d transformation from a space to another that can only express translations. /// /// The main benefit of this type over a Vector3D is the ability to cast /// between a source and a destination spaces. #[repr(C)] pubstruct Translation3D<T, Src, Dst> { pub x: T, pub y: T, pub z: T, #[doc(hidden)] pub _unit: PhantomData<(Src, Dst)>,
}
impl<T: Copy, Src, Dst> Copy for Translation3D<T, Src, Dst> {}
/// Creates no-op translation (`x`, `y` and `z` is `zero()`). #[inline] pubfn identity() -> Self where
T: Zero,
{
Translation3D::new(T::zero(), T::zero(), T::zero())
}
/// Check if translation does nothing (`x`, `y` and `z` is `zero()`). /// /// ```rust /// use euclid::default::Translation3D; /// /// assert_eq!(Translation3D::<f32>::identity().is_identity(), true); /// assert_eq!(Translation3D::new(0, 0, 0).is_identity(), true); /// assert_eq!(Translation3D::new(1, 0, 0).is_identity(), false); /// assert_eq!(Translation3D::new(0, 1, 0).is_identity(), false); /// assert_eq!(Translation3D::new(0, 0, 1).is_identity(), false); /// ``` #[inline] pubfn is_identity(&self) -> bool where
T: Zero + PartialEq,
{ let _0 = T::zero(); self.x == _0 && self.y == _0 && self.z == _0
}
/// No-op, just cast the unit. #[inline] pubfn transform_size(self, s: Size2D<T, Src>) -> Size2D<T, Dst> {
Size2D::new(s.width, s.height)
}
}
impl<T: Copy, Src, Dst> Translation3D<T, Src, Dst> { /// Cast into a 3D vector. #[inline] pubfn to_vector(&self) -> Vector3D<T, Src> {
vec3(self.x, self.y, self.z)
}
/// Cast into an array with x, y and z. #[inline] pubfn to_array(&self) -> [T; 3] {
[self.x, self.y, self.z]
}
/// Cast into a tuple with x, y and z. #[inline] pubfn to_tuple(&self) -> (T, T, T) {
(self.x, self.y, self.z)
}
/// Drop the units, preserving only the numeric value. #[inline] pubfn to_untyped(&self) -> Translation3D<T, UnknownUnit, UnknownUnit> {
Translation3D {
x: self.x,
y: self.y,
z: self.z,
_unit: PhantomData,
}
}
/// Tag a unitless value with units. #[inline] pubfn from_untyped(t: &Translation3D<T, UnknownUnit, UnknownUnit>) -> Self {
Translation3D {
x: t.x,
y: t.y,
z: t.z,
_unit: PhantomData,
}
}
/// Returns the matrix representation of this translation. #[inline] pubfn to_transform(&self) -> Transform3D<T, Src, Dst> where
T: Zero + One,
{
(*self).into()
}
/// Translate a point and cast its unit. #[inline] pubfn transform_point3d(&self, p: &Point3D<T, Src>) -> Point3D<T::Output, Dst> where
T: Add,
{
point3(p.x + self.x, p.y + self.y, p.z + self.z)
}
/// Translate a point and cast its unit. #[inline] pubfn transform_point2d(&self, p: &Point2D<T, Src>) -> Point2D<T::Output, Dst> where
T: Add,
{
point2(p.x + self.x, p.y + self.y)
}
/// Translate a 2D box and cast its unit. #[inline] pubfn transform_box2d(&self, b: &Box2D<T, Src>) -> Box2D<T::Output, Dst> where
T: Add,
{
Box2D {
min: self.transform_point2d(&b.min),
max: self.transform_point2d(&b.max),
}
}
/// Translate a 3D box and cast its unit. #[inline] pubfn transform_box3d(&self, b: &Box3D<T, Src>) -> Box3D<T::Output, Dst> where
T: Add,
{
Box3D {
min: self.transform_point3d(&b.min),
max: self.transform_point3d(&b.max),
}
}
/// Translate a rectangle and cast its unit. #[inline] pubfn transform_rect(&self, r: &Rect<T, Src>) -> Rect<T, Dst> where
T: Add<Output = T>,
{
Rect {
origin: self.transform_point2d(&r.origin),
size: self.transform_size(r.size),
}
}
impl<T: NumCast + Copy, Src, Dst> Translation3D<T, Src, Dst> { /// Cast from one numeric representation to another, preserving the units. /// /// When casting from floating vector 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()`, `ceil()` or `floor()` before casting. #[inline] pubfn cast<NewT: NumCast>(self) -> Translation3D<NewT, Src, Dst> { self.try_cast().unwrap()
}
/// Fallible cast from one numeric representation to another, preserving the units. /// /// When casting from floating vector 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()`, `ceil()` or `floor()` before casting. pubfn try_cast<NewT: NumCast>(self) -> Option<Translation3D<NewT, Src, Dst>> { match (
NumCast::from(self.x),
NumCast::from(self.y),
NumCast::from(self.z),
) {
(Some(x), Some(y), Some(z)) => Some(Translation3D::new(x, y, z)),
_ => None,
}
}
// Convenience functions for common casts.
/// Cast into an `f32` vector. #[inline] pubfn to_f32(self) -> Translation3D<f32, Src, Dst> { self.cast()
}
/// Cast into an `f64` vector. #[inline] pubfn to_f64(self) -> Translation3D<f64, Src, Dst> { self.cast()
}
/// Cast into an `usize` vector, truncating decimals if any. /// /// When casting from floating vector vectors, it is worth considering whether /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain /// the desired conversion behavior. #[inline] pubfn to_usize(self) -> Translation3D<usize, Src, Dst> { self.cast()
}
/// Cast into an `u32` vector, truncating decimals if any. /// /// When casting from floating vector vectors, it is worth considering whether /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain /// the desired conversion behavior. #[inline] pubfn to_u32(self) -> Translation3D<u32, Src, Dst> { self.cast()
}
/// Cast into an i32 vector, truncating decimals if any. /// /// When casting from floating vector vectors, it is worth considering whether /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain /// the desired conversion behavior. #[inline] pubfn to_i32(self) -> Translation3D<i32, Src, Dst> { self.cast()
}
/// Cast into an i64 vector, truncating decimals if any. /// /// When casting from floating vector vectors, it is worth considering whether /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain /// the desired conversion behavior. #[inline] pubfn to_i64(self) -> Translation3D<i64, Src, Dst> { self.cast()
}
}
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.