// 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.
usesuper::UnknownUnit; usecrate::approxeq::ApproxEq; usecrate::approxord::{max, min}; usecrate::length::Length; usecrate::num::*; usecrate::scale::Scale; usecrate::size::{Size2D, Size3D}; usecrate::vector::{vec2, vec3, Vector2D, Vector3D}; use core::cmp::{Eq, PartialEq}; use core::fmt; use core::hash::Hash; use core::marker::PhantomData; use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; #[cfg(feature = "mint")] use mint; use num_traits::real::Real; use num_traits::{Euclid, Float, NumCast}; #[cfg(feature = "serde")] use serde;
#[cfg(feature = "bytemuck")] use bytemuck::{Pod, Zeroable};
/// A 2d Point tagged with a unit. #[repr(C)] pubstruct Point2D<T, U> { pub x: T, pub y: T, #[doc(hidden)] pub _unit: PhantomData<U>,
}
/// Constructor setting all components to the same value. #[inline] pubfn splat(v: T) -> Self where
T: Clone,
{
Point2D {
x: v.clone(),
y: v,
_unit: PhantomData,
}
}
/// Tag a unitless value with units. #[inline] pubfn from_untyped(p: Point2D<T, UnknownUnit>) -> Self {
point2(p.x, p.y)
}
/// Apply the function `f` to each component of this point. /// /// # Example /// /// This may be used to perform unusual arithmetic which is not already offered as methods. /// /// ``` /// use euclid::default::Point2D; /// /// let p = Point2D::<u32>::new(5, 15); /// assert_eq!(p.map(|coord| coord.saturating_sub(10)), Point2D::new(0, 5)); /// ``` #[inline] pubfn map<V, F: FnMut(T) -> V>(self, mut f: F) -> Point2D<V, U> {
point2(f(self.x), f(self.y))
}
/// Apply the function `f` to each pair of components of this point and `rhs`. /// /// # Example /// /// This may be used to perform unusual arithmetic which is not already offered as methods. /// /// ``` /// use euclid::{default::{Point2D, Vector2D}, point2}; /// /// let a: Point2D<u32> = point2(50, 200); /// let b: Point2D<u32> = point2(100, 100); /// assert_eq!(a.zip(b, u32::saturating_sub), Vector2D::new(0, 100)); /// ``` #[inline] pubfn zip<V, F: FnMut(T, T) -> V>(self, rhs: Self, mut f: F) -> Vector2D<V, U> {
vec2(f(self.x, rhs.x), f(self.y, rhs.y))
}
}
impl<T: Copy, U> Point2D<T, U> { /// Create a 3d point from this one, using the specified z value. #[inline] pubfn extend(self, z: T) -> Point3D<T, U> {
point3(self.x, self.y, z)
}
/// Cast this point into a vector. /// /// Equivalent to subtracting the origin from this point. #[inline] pubfn to_vector(self) -> Vector2D<T, U> {
Vector2D {
x: self.x,
y: self.y,
_unit: PhantomData,
}
}
/// Swap x and y. /// /// # Example /// /// ```rust /// # use euclid::{Point2D, point2}; /// enum Mm {} /// /// let point: Point2D<_, Mm> = point2(1, -8); /// /// assert_eq!(point.yx(), point2(-8, 1)); /// ``` #[inline] pubfn yx(self) -> Self {
point2(self.y, self.x)
}
/// Drop the units, preserving only the numeric value. /// /// # Example /// /// ```rust /// # use euclid::{Point2D, point2}; /// enum Mm {} /// /// let point: Point2D<_, Mm> = point2(1, -8); /// /// assert_eq!(point.x, point.to_untyped().x); /// assert_eq!(point.y, point.to_untyped().y); /// ``` #[inline] pubfn to_untyped(self) -> Point2D<T, UnknownUnit> {
point2(self.x, self.y)
}
/// Cast the unit, preserving the numeric value. /// /// # Example /// /// ```rust /// # use euclid::{Point2D, point2}; /// enum Mm {} /// enum Cm {} /// /// let point: Point2D<_, Mm> = point2(1, -8); /// /// assert_eq!(point.x, point.cast_unit::<Cm>().x); /// assert_eq!(point.y, point.cast_unit::<Cm>().y); /// ``` #[inline] pubfn cast_unit<V>(self) -> Point2D<T, V> {
point2(self.x, self.y)
}
/// Cast into an array with x and y. /// /// # Example /// /// ```rust /// # use euclid::{Point2D, point2}; /// enum Mm {} /// /// let point: Point2D<_, Mm> = point2(1, -8); /// /// assert_eq!(point.to_array(), [1, -8]); /// ``` #[inline] pubfn to_array(self) -> [T; 2] {
[self.x, self.y]
}
/// Cast into a tuple with x and y. /// /// # Example /// /// ```rust /// # use euclid::{Point2D, point2}; /// enum Mm {} /// /// let point: Point2D<_, Mm> = point2(1, -8); /// /// assert_eq!(point.to_tuple(), (1, -8)); /// ``` #[inline] pubfn to_tuple(self) -> (T, T) {
(self.x, self.y)
}
/// Convert into a 3d point with z-coordinate equals to zero. #[inline] pubfn to_3d(self) -> Point3D<T, U> where
T: Zero,
{
point3(self.x, self.y, Zero::zero())
}
/// Rounds each component to the nearest integer value. /// /// This behavior is preserved for negative values (unlike the basic cast). /// /// ```rust /// # use euclid::point2; /// enum Mm {} /// /// assert_eq!(point2::<_, Mm>(-0.1, -0.8).round(), point2::<_, Mm>(0.0, -1.0)) /// ``` #[inline] #[must_use] pubfn round(self) -> Self where
T: Round,
{
point2(self.x.round(), self.y.round())
}
/// Rounds each component to the smallest integer equal or greater than the original value. /// /// This behavior is preserved for negative values (unlike the basic cast). /// /// ```rust /// # use euclid::point2; /// enum Mm {} /// /// assert_eq!(point2::<_, Mm>(-0.1, -0.8).ceil(), point2::<_, Mm>(0.0, 0.0)) /// ``` #[inline] #[must_use] pubfn ceil(self) -> Self where
T: Ceil,
{
point2(self.x.ceil(), self.y.ceil())
}
/// Rounds each component to the biggest integer equal or lower than the original value. /// /// This behavior is preserved for negative values (unlike the basic cast). /// /// ```rust /// # use euclid::point2; /// enum Mm {} /// /// assert_eq!(point2::<_, Mm>(-0.1, -0.8).floor(), point2::<_, Mm>(-1.0, -1.0)) /// ``` #[inline] #[must_use] pubfn floor(self) -> Self where
T: Floor,
{
point2(self.x.floor(), self.y.floor())
}
/// Linearly interpolate between this point and another point. /// /// # Example /// /// ```rust /// use euclid::point2; /// use euclid::default::Point2D; /// /// let from: Point2D<_> = point2(0.0, 10.0); /// let to: Point2D<_> = point2(8.0, -4.0); /// /// assert_eq!(from.lerp(to, -1.0), point2(-8.0, 24.0)); /// assert_eq!(from.lerp(to, 0.0), point2( 0.0, 10.0)); /// assert_eq!(from.lerp(to, 0.5), point2( 4.0, 3.0)); /// assert_eq!(from.lerp(to, 1.0), point2( 8.0, -4.0)); /// assert_eq!(from.lerp(to, 2.0), point2(16.0, -18.0)); /// ``` #[inline] pubfn lerp(self, other: Self, t: T) -> Self where
T: One + Sub<Output = T> + Mul<Output = T> + Add<Output = T>,
{ let one_t = T::one() - t;
point2(one_t * self.x + t * other.x, one_t * self.y + t * other.y)
}
}
/// Returns the point each component of which clamped by corresponding /// components of `start` and `end`. /// /// Shortcut for `self.max(start).min(end)`. #[inline] pubfn clamp(self, start: Self, end: Self) -> Self where
T: Copy,
{ self.max(start).min(end)
}
}
impl<T: NumCast + Copy, U> Point2D<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()`, `ceil()` or `floor()` before casting. #[inline] pubfn cast<NewT: NumCast>(self) -> Point2D<NewT, U> { self.try_cast().unwrap()
}
/// 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()`, `ceil()` or `floor()` before casting. pubfn try_cast<NewT: NumCast>(self) -> Option<Point2D<NewT, U>> { match (NumCast::from(self.x), NumCast::from(self.y)) {
(Some(x), Some(y)) => Some(point2(x, y)),
_ => None,
}
}
// Convenience functions for common casts
/// Cast into an `f32` point. #[inline] pubfn to_f32(self) -> Point2D<f32, U> { self.cast()
}
/// Cast into an `f64` point. #[inline] pubfn to_f64(self) -> Point2D<f64, U> { self.cast()
}
/// Cast into an `usize` point, truncating decimals if any. /// /// When casting from floating point points, 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) -> Point2D<usize, U> { self.cast()
}
/// Cast into an `u32` point, truncating decimals if any. /// /// When casting from floating point points, 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) -> Point2D<u32, U> { self.cast()
}
/// Cast into an i32 point, truncating decimals if any. /// /// When casting from floating point points, 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) -> Point2D<i32, U> { self.cast()
}
/// Cast into an i64 point, truncating decimals if any. /// /// When casting from floating point points, 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) -> Point2D<i64, U> { self.cast()
}
}
impl<T: Float, U> Point2D<T, U> { /// Returns true if all members are finite. #[inline] pubfn is_finite(self) -> bool { self.x.is_finite() && self.y.is_finite()
}
}
/// Constructor setting all components to the same value. #[inline] pubfn splat(v: T) -> Self where
T: Clone,
{
Point3D {
x: v.clone(),
y: v.clone(),
z: v,
_unit: PhantomData,
}
}
/// Tag a unitless value with units. #[inline] pubfn from_untyped(p: Point3D<T, UnknownUnit>) -> Self {
point3(p.x, p.y, p.z)
}
/// Apply the function `f` to each component of this point. /// /// # Example /// /// This may be used to perform unusual arithmetic which is not already offered as methods. /// /// ``` /// use euclid::default::Point3D; /// /// let p = Point3D::<u32>::new(5, 11, 15); /// assert_eq!(p.map(|coord| coord.saturating_sub(10)), Point3D::new(0, 1, 5)); /// ``` #[inline] pubfn map<V, F: FnMut(T) -> V>(self, mut f: F) -> Point3D<V, U> {
point3(f(self.x), f(self.y), f(self.z))
}
/// Apply the function `f` to each pair of components of this point and `rhs`. /// /// # Example /// /// This may be used to perform unusual arithmetic which is not already offered as methods. /// /// ``` /// use euclid::{default::{Point3D, Vector3D}, point2}; /// /// let a: Point3D<u32> = Point3D::new(50, 200, 400); /// let b: Point3D<u32> = Point3D::new(100, 100, 150); /// assert_eq!(a.zip(b, u32::saturating_sub), Vector3D::new(0, 100, 250)); /// ``` #[inline] pubfn zip<V, F: FnMut(T, T) -> V>(self, rhs: Self, mut f: F) -> Vector3D<V, U> {
vec3(f(self.x, rhs.x), f(self.y, rhs.y), f(self.z, rhs.z))
}
}
impl<T: Copy, U> Point3D<T, U> { /// Cast this point into a vector. /// /// Equivalent to subtracting the origin to this point. #[inline] pubfn to_vector(self) -> Vector3D<T, U> {
Vector3D {
x: self.x,
y: self.y,
z: self.z,
_unit: PhantomData,
}
}
/// Returns a 2d point using this point's x and y coordinates #[inline] pubfn xy(self) -> Point2D<T, U> {
point2(self.x, self.y)
}
/// Returns a 2d point using this point's x and z coordinates #[inline] pubfn xz(self) -> Point2D<T, U> {
point2(self.x, self.z)
}
/// Returns a 2d point using this point's x and z coordinates #[inline] pubfn yz(self) -> Point2D<T, U> {
point2(self.y, self.z)
}
/// Cast into an array with x, y and z. /// /// # Example /// /// ```rust /// # use euclid::{Point3D, point3}; /// enum Mm {} /// /// let point: Point3D<_, Mm> = point3(1, -8, 0); /// /// assert_eq!(point.to_array(), [1, -8, 0]); /// ``` #[inline] pubfn to_array(self) -> [T; 3] {
[self.x, self.y, self.z]
}
/// Drop the units, preserving only the numeric value. /// /// # Example /// /// ```rust /// # use euclid::{Point3D, point3}; /// enum Mm {} /// /// let point: Point3D<_, Mm> = point3(1, -8, 0); /// /// assert_eq!(point.x, point.to_untyped().x); /// assert_eq!(point.y, point.to_untyped().y); /// assert_eq!(point.z, point.to_untyped().z); /// ``` #[inline] pubfn to_untyped(self) -> Point3D<T, UnknownUnit> {
point3(self.x, self.y, self.z)
}
/// Cast the unit, preserving the numeric value. /// /// # Example /// /// ```rust /// # use euclid::{Point3D, point3}; /// enum Mm {} /// enum Cm {} /// /// let point: Point3D<_, Mm> = point3(1, -8, 0); /// /// assert_eq!(point.x, point.cast_unit::<Cm>().x); /// assert_eq!(point.y, point.cast_unit::<Cm>().y); /// assert_eq!(point.z, point.cast_unit::<Cm>().z); /// ``` #[inline] pubfn cast_unit<V>(self) -> Point3D<T, V> {
point3(self.x, self.y, self.z)
}
/// Convert into a 2d point. #[inline] pubfn to_2d(self) -> Point2D<T, U> { self.xy()
}
/// Rounds each component to the nearest integer value. /// /// This behavior is preserved for negative values (unlike the basic cast). /// /// ```rust /// # use euclid::point3; /// enum Mm {} /// /// assert_eq!(point3::<_, Mm>(-0.1, -0.8, 0.4).round(), point3::<_, Mm>(0.0, -1.0, 0.0)) /// ``` #[inline] #[must_use] pubfn round(self) -> Self where
T: Round,
{
point3(self.x.round(), self.y.round(), self.z.round())
}
/// Rounds each component to the smallest integer equal or greater than the original value. /// /// This behavior is preserved for negative values (unlike the basic cast). /// /// ```rust /// # use euclid::point3; /// enum Mm {} /// /// assert_eq!(point3::<_, Mm>(-0.1, -0.8, 0.4).ceil(), point3::<_, Mm>(0.0, 0.0, 1.0)) /// ``` #[inline] #[must_use] pubfn ceil(self) -> Self where
T: Ceil,
{
point3(self.x.ceil(), self.y.ceil(), self.z.ceil())
}
/// Rounds each component to the biggest integer equal or lower than the original value. /// /// This behavior is preserved for negative values (unlike the basic cast). /// /// ```rust /// # use euclid::point3; /// enum Mm {} /// /// assert_eq!(point3::<_, Mm>(-0.1, -0.8, 0.4).floor(), point3::<_, Mm>(-1.0, -1.0, 0.0)) /// ``` #[inline] #[must_use] pubfn floor(self) -> Self where
T: Floor,
{
point3(self.x.floor(), self.y.floor(), self.z.floor())
}
/// Linearly interpolate between this point and another point. /// /// # Example /// /// ```rust /// use euclid::point3; /// use euclid::default::Point3D; /// /// let from: Point3D<_> = point3(0.0, 10.0, -1.0); /// let to: Point3D<_> = point3(8.0, -4.0, 0.0); /// /// assert_eq!(from.lerp(to, -1.0), point3(-8.0, 24.0, -2.0)); /// assert_eq!(from.lerp(to, 0.0), point3( 0.0, 10.0, -1.0)); /// assert_eq!(from.lerp(to, 0.5), point3( 4.0, 3.0, -0.5)); /// assert_eq!(from.lerp(to, 1.0), point3( 8.0, -4.0, 0.0)); /// assert_eq!(from.lerp(to, 2.0), point3(16.0, -18.0, 1.0)); /// ``` #[inline] pubfn lerp(self, other: Self, t: T) -> Self where
T: One + Sub<Output = T> + Mul<Output = T> + Add<Output = T>,
{ let one_t = T::one() - t;
point3(
one_t * self.x + t * other.x,
one_t * self.y + t * other.y,
one_t * self.z + t * other.z,
)
}
}
/// Returns the point each component of which clamped by corresponding /// components of `start` and `end`. /// /// Shortcut for `self.max(start).min(end)`. #[inline] pubfn clamp(self, start: Self, end: Self) -> Self where
T: Copy,
{ self.max(start).min(end)
}
}
impl<T: NumCast + Copy, U> Point3D<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()`, `ceil()` or `floor()` before casting. #[inline] pubfn cast<NewT: NumCast>(self) -> Point3D<NewT, U> { self.try_cast().unwrap()
}
/// 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()`, `ceil()` or `floor()` before casting. pubfn try_cast<NewT: NumCast>(self) -> Option<Point3D<NewT, U>> { match (
NumCast::from(self.x),
NumCast::from(self.y),
NumCast::from(self.z),
) {
(Some(x), Some(y), Some(z)) => Some(point3(x, y, z)),
_ => None,
}
}
// Convenience functions for common casts
/// Cast into an `f32` point. #[inline] pubfn to_f32(self) -> Point3D<f32, U> { self.cast()
}
/// Cast into an `f64` point. #[inline] pubfn to_f64(self) -> Point3D<f64, U> { self.cast()
}
/// Cast into an `usize` point, truncating decimals if any. /// /// When casting from floating point points, 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) -> Point3D<usize, U> { self.cast()
}
/// Cast into an `u32` point, truncating decimals if any. /// /// When casting from floating point points, 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) -> Point3D<u32, U> { self.cast()
}
/// Cast into an `i32` point, truncating decimals if any. /// /// When casting from floating point points, 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) -> Point3D<i32, U> { self.cast()
}
/// Cast into an `i64` point, truncating decimals if any. /// /// When casting from floating point points, 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) -> Point3D<i64, U> { self.cast()
}
}
impl<T: Float, U> Point3D<T, U> { /// Returns true if all members are finite. #[inline] pubfn is_finite(self) -> bool { self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
}
}
impl<T: Euclid, U> Point3D<T, U> { /// Calculates the least nonnegative remainder of `self (mod other)`. /// /// # Example /// /// ```rust /// use euclid::point3; /// use euclid::default::{Point3D, Size3D}; /// /// let p = Point3D::new(7.0, -7.0, 0.0); /// let s = Size3D::new(4.0, -4.0, 12.0);
#[cfg(test)] mod point2d { usecrate::default::Point2D; usecrate::point2;
#[cfg(feature = "mint")] use mint;
#[test] pubfn test_min() { let p1 = Point2D::new(1.0, 3.0); let p2 = Point2D::new(2.0, 2.0);
let result = p1.min(p2);
assert_eq!(result, Point2D::new(1.0, 2.0));
}
#[test] pubfn test_max() { let p1 = Point2D::new(1.0, 3.0); let p2 = Point2D::new(2.0, 2.0);
let result = p1.max(p2);
assert_eq!(result, Point2D::new(2.0, 3.0));
}
#[cfg(feature = "mint")] #[test] pubfn test_mint() { let p1 = Point2D::new(1.0, 3.0); let pm: mint::Point2<_> = p1.into(); let p2 = Point2D::from(pm);
assert_eq!(p1, p2);
}
#[test] pubfn test_conv_vector() { for i in0..100 { // We don't care about these values as long as they are not the same. let x = i as f32 * 0.012345; let y = i as f32 * 0.987654; let p: Point2D<f32> = point2(x, y);
assert_eq!(p.to_vector().to_point(), p);
}
}
#[test] pubfn test_conv_vector() { usecrate::point3; for i in0..100 { // We don't care about these values as long as they are not the same. let x = i as f32 * 0.012345; let y = i as f32 * 0.987654; let z = x * y; let p: Point3D<f32> = point3(x, y, z);
assert_eq!(p.to_vector().to_point(), p);
}
}
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.