9 点结构模块(point.rs)
一、point.rs源码
use super::UnknownUnit;
use crate::approxeq::ApproxEq;
use crate::approxord::{max, min};
use crate::length::Length;
use crate::num::*;
use crate::scale::Scale;
use crate::size::{Size2D, Size3D};
use crate::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)]
pub struct Point2D<T, U> {pub x: T,pub y: T,#[doc(hidden)]pub _unit: PhantomData<U>,
}impl<T: Copy, U> Copy for Point2D<T, U> {}impl<T: Clone, U> Clone for Point2D<T, U> {fn clone(&self) -> Self {Point2D {x: self.x.clone(),y: self.y.clone(),_unit: PhantomData,}}
}//反序列化
#[cfg(feature = "serde")]
impl<'de, T, U> serde::Deserialize<'de> for Point2D<T, U>
whereT: serde::Deserialize<'de>,
{fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>whereD: serde::Deserializer<'de>,{let (x, y) = serde::Deserialize::deserialize(deserializer)?;Ok(Point2D {x,y,_unit: PhantomData,})}
}//序列化
#[cfg(feature = "serde")]
impl<T, U> serde::Serialize for Point2D<T, U>
whereT: serde::Serialize,
{fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>whereS: serde::Serializer,{(&self.x, &self.y).serialize(serializer)}
}
//模糊测试的库特性,提供随机数,提高测试范围
#[cfg(feature = "arbitrary")]
impl<'a, T, U> arbitrary::Arbitrary<'a> for Point2D<T, U>
whereT: arbitrary::Arbitrary<'a>,
{fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {let (x, y) = arbitrary::Arbitrary::arbitrary(u)?;Ok(Point2D {x,y,_unit: PhantomData,})}
}#[cfg(feature = "bytemuck")]
unsafe impl<T: Zeroable, U> Zeroable for Point2D<T, U> {}#[cfg(feature = "bytemuck")]
unsafe impl<T: Pod, U: 'static> Pod for Point2D<T, U> {}impl<T, U> Eq for Point2D<T, U> where T: Eq {}impl<T, U> PartialEq for Point2D<T, U>
whereT: PartialEq,
{fn eq(&self, other: &Self) -> bool {self.x == other.x && self.y == other.y}
}impl<T, U> Hash for Point2D<T, U>
whereT: Hash,
{fn hash<H: core::hash::Hasher>(&self, h: &mut H) {self.x.hash(h);self.y.hash(h);}
}mint_vec!(Point2D[x, y] = Point2);impl<T: fmt::Debug, U> fmt::Debug for Point2D<T, U> {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {f.debug_tuple("").field(&self.x).field(&self.y).finish()}
}impl<T: Default, U> Default for Point2D<T, U> {fn default() -> Self {Point2D::new(Default::default(), Default::default())}
}impl<T, U> Point2D<T, U> {/// Constructor, setting all components to zero.#[inline]pub fn origin() -> SelfwhereT: Zero,{point2(Zero::zero(), Zero::zero())}/// The same as [`Point2D::origin`].#[inline]pub fn zero() -> SelfwhereT: Zero,{Self::origin()}/// Constructor taking scalar values directly.#[inline]pub const fn new(x: T, y: T) -> Self {Point2D {x,y,_unit: PhantomData,}}/// Constructor taking properly Lengths instead of scalar values.#[inline]pub fn from_lengths(x: Length<T, U>, y: Length<T, U>) -> Self {point2(x.0, y.0)}/// Constructor setting all components to the same value.#[inline]pub fn splat(v: T) -> SelfwhereT: Clone,{Point2D {x: v.clone(),y: v,_unit: PhantomData,}}/// Tag a unitless value with units.#[inline]pub fn 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]pub fn 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]pub fn 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]pub fn 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]pub fn 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]pub fn 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]pub fn 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]pub fn 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]pub fn 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]pub fn to_tuple(self) -> (T, T) {(self.x, self.y)}/// Convert into a 3d point with z-coordinate equals to zero.#[inline]pub fn to_3d(self) -> Point3D<T, U>whereT: 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]pub fn round(self) -> SelfwhereT: 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]pub fn ceil(self) -> SelfwhereT: 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]pub fn floor(self) -> SelfwhereT: 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]pub fn lerp(self, other: Self, t: T) -> SelfwhereT: 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)}
}impl<T: PartialOrd, U> Point2D<T, U> {#[inline]pub fn min(self, other: Self) -> Self {point2(min(self.x, other.x), min(self.y, other.y))}#[inline]pub fn max(self, other: Self) -> Self {point2(max(self.x, other.x), max(self.y, 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]pub fn clamp(self, start: Self, end: Self) -> SelfwhereT: 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]pub fn 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.pub fn 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]pub fn to_f32(self) -> Point2D<f32, U> {self.cast()}/// Cast into an `f64` point.#[inline]pub fn 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]pub fn 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]pub fn 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]pub fn 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]pub fn to_i64(self) -> Point2D<i64, U> {self.cast()}
}impl<T: Float, U> Point2D<T, U> {/// Returns `true` if all members are finite.#[inline]pub fn is_finite(self) -> bool {self.x.is_finite() && self.y.is_finite()}
}impl<T: Copy + Add<T, Output = T>, U> Point2D<T, U> {#[inline]pub fn add_size(self, other: &Size2D<T, U>) -> Self {point2(self.x + other.width, self.y + other.height)}
}impl<T: Real + Sub<T, Output = T>, U> Point2D<T, U> {#[inline]pub fn distance_to(self, other: Self) -> T {(self - other).length()}
}impl<T: Neg, U> Neg for Point2D<T, U> {type Output = Point2D<T::Output, U>;#[inline]fn neg(self) -> Self::Output {point2(-self.x, -self.y)}
}impl<T: Add, U> Add<Size2D<T, U>> for Point2D<T, U> {type Output = Point2D<T::Output, U>;#[inline]fn add(self, other: Size2D<T, U>) -> Self::Output {point2(self.x + other.width, self.y + other.height)}
}impl<T: AddAssign, U> AddAssign<Size2D<T, U>> for Point2D<T, U> {#[inline]fn add_assign(&mut self, other: Size2D<T, U>) {self.x += other.width;self.y += other.height;}
}impl<T: Add, U> Add<Vector2D<T, U>> for Point2D<T, U> {type Output = Point2D<T::Output, U>;#[inline]fn add(self, other: Vector2D<T, U>) -> Self::Output {point2(self.x + other.x, self.y + other.y)}
}impl<T: Copy + Add<T, Output = T>, U> AddAssign<Vector2D<T, U>> for Point2D<T, U> {#[inline]fn add_assign(&mut self, other: Vector2D<T, U>) {*self = *self + other;}
}impl<T: Sub, U> Sub for Point2D<T, U> {type Output = Vector2D<T::Output, U>;#[inline]fn sub(self, other: Self) -> Self::Output {vec2(self.x - other.x, self.y - other.y)}
}impl<T: Sub, U> Sub<Size2D<T, U>> for Point2D<T, U> {type Output = Point2D<T::Output, U>;#[inline]fn sub(self, other: Size2D<T, U>) -> Self::Output {point2(self.x - other.width, self.y - other.height)}
}impl<T: SubAssign, U> SubAssign<Size2D<T, U>> for Point2D<T, U> {#[inline]fn sub_assign(&mut self, other: Size2D<T, U>) {self.x -= other.width;self.y -= other.height;}
}impl<T: Sub, U> Sub<Vector2D<T, U>> for Point2D<T, U> {type Output = Point2D<T::Output, U>;#[inline]fn sub(self, other: Vector2D<T, U>) -> Self::Output {point2(self.x - other.x, self.y - other.y)}
}impl<T: Copy + Sub<T, Output = T>, U> SubAssign<Vector2D<T, U>> for Point2D<T, U> {#[inline]fn sub_assign(&mut self, other: Vector2D<T, U>) {*self = *self - other;}
}impl<T: Copy + Mul, U> Mul<T> for Point2D<T, U> {type Output = Point2D<T::Output, U>;#[inline]fn mul(self, scale: T) -> Self::Output {point2(self.x * scale, self.y * scale)}
}impl<T: Copy + Mul<T, Output = T>, U> MulAssign<T> for Point2D<T, U> {#[inline]fn mul_assign(&mut self, scale: T) {*self = *self * scale;}
}impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Point2D<T, U1> {type Output = Point2D<T::Output, U2>;#[inline]fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {point2(self.x * scale.0, self.y * scale.0)}
}impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Point2D<T, U> {#[inline]fn mul_assign(&mut self, scale: Scale<T, U, U>) {self.x *= scale.0;self.y *= scale.0;}
}impl<T: Copy + Div, U> Div<T> for Point2D<T, U> {type Output = Point2D<T::Output, U>;#[inline]fn div(self, scale: T) -> Self::Output {point2(self.x / scale, self.y / scale)}
}impl<T: Copy + Div<T, Output = T>, U> DivAssign<T> for Point2D<T, U> {#[inline]fn div_assign(&mut self, scale: T) {*self = *self / scale;}
}impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Point2D<T, U2> {type Output = Point2D<T::Output, U1>;#[inline]fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {point2(self.x / scale.0, self.y / scale.0)}
}impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Point2D<T, U> {#[inline]fn div_assign(&mut self, scale: Scale<T, U, U>) {self.x /= scale.0;self.y /= scale.0;}
}impl<T: Zero, U> Zero for Point2D<T, U> {#[inline]fn zero() -> Self {Self::origin()}
}impl<T: Round, U> Round for Point2D<T, U> {/// See [`Point2D::round`].#[inline]fn round(self) -> Self {self.round()}
}impl<T: Ceil, U> Ceil for Point2D<T, U> {/// See [`Point2D::ceil`].#[inline]fn ceil(self) -> Self {self.ceil()}
}impl<T: Floor, U> Floor for Point2D<T, U> {/// See [`Point2D::floor`].#[inline]fn floor(self) -> Self {self.floor()}
}impl<T: ApproxEq<T>, U> ApproxEq<Point2D<T, U>> for Point2D<T, U> {#[inline]fn approx_epsilon() -> Self {point2(T::approx_epsilon(), T::approx_epsilon())}#[inline]fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {self.x.approx_eq_eps(&other.x, &eps.x) && self.y.approx_eq_eps(&other.y, &eps.y)}
}impl<T: Euclid, U> Point2D<T, U> {/// Calculates the least nonnegative remainder of `self (mod other)`.////// # Example////// ```rust/// use euclid::point2;/// use euclid::default::{Point2D, Size2D};////// let p = Point2D::new(7.0, -7.0);/// let s = Size2D::new(4.0, -4.0);////// assert_eq!(p.rem_euclid(&s), point2(3.0, 1.0));/// assert_eq!((-p).rem_euclid(&s), point2(1.0, 3.0));/// assert_eq!(p.rem_euclid(&-s), point2(3.0, 1.0));/// ```#[inline]pub fn rem_euclid(&self, other: &Size2D<T, U>) -> Self {point2(self.x.rem_euclid(&other.width),self.y.rem_euclid(&other.height),)}/// Calculates Euclidean division, the matching method for `rem_euclid`.////// # Example////// ```rust/// use euclid::point2;/// use euclid::default::{Point2D, Size2D};////// let p = Point2D::new(7.0, -7.0);/// let s = Size2D::new(4.0, -4.0);////// assert_eq!(p.div_euclid(&s), point2(1.0, 2.0));/// assert_eq!((-p).div_euclid(&s), point2(-2.0, -1.0));/// assert_eq!(p.div_euclid(&-s), point2(-1.0, -2.0));/// ```#[inline]pub fn div_euclid(&self, other: &Size2D<T, U>) -> Self {point2(self.x.div_euclid(&other.width),self.y.div_euclid(&other.height),)}
}impl<T, U> From<Point2D<T, U>> for [T; 2] {fn from(p: Point2D<T, U>) -> Self {[p.x, p.y]}
}impl<T, U> From<[T; 2]> for Point2D<T, U> {fn from([x, y]: [T; 2]) -> Self {point2(x, y)}
}impl<T, U> From<Point2D<T, U>> for (T, T) {fn from(p: Point2D<T, U>) -> Self {(p.x, p.y)}
}impl<T, U> From<(T, T)> for Point2D<T, U> {fn from(tuple: (T, T)) -> Self {point2(tuple.0, tuple.1)}
}/// A 3d Point tagged with a unit.
#[repr(C)]
pub struct Point3D<T, U> {pub x: T,pub y: T,pub z: T,#[doc(hidden)]pub _unit: PhantomData<U>,
}mint_vec!(Point3D[x, y, z] = Point3);impl<T: Copy, U> Copy for Point3D<T, U> {}impl<T: Clone, U> Clone for Point3D<T, U> {fn clone(&self) -> Self {Point3D {x: self.x.clone(),y: self.y.clone(),z: self.z.clone(),_unit: PhantomData,}}
}#[cfg(feature = "serde")]
impl<'de, T, U> serde::Deserialize<'de> for Point3D<T, U>
whereT: serde::Deserialize<'de>,
{fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>whereD: serde::Deserializer<'de>,{let (x, y, z) = serde::Deserialize::deserialize(deserializer)?;Ok(Point3D {x,y,z,_unit: PhantomData,})}
}#[cfg(feature = "serde")]
impl<T, U> serde::Serialize for Point3D<T, U>
whereT: serde::Serialize,
{fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>whereS: serde::Serializer,{(&self.x, &self.y, &self.z).serialize(serializer)}
}#[cfg(feature = "arbitrary")]
impl<'a, T, U> arbitrary::Arbitrary<'a> for Point3D<T, U>
whereT: arbitrary::Arbitrary<'a>,
{fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {let (x, y, z) = arbitrary::Arbitrary::arbitrary(u)?;Ok(Point3D {x,y,z,_unit: PhantomData,})}
}#[cfg(feature = "bytemuck")]
unsafe impl<T: Zeroable, U> Zeroable for Point3D<T, U> {}#[cfg(feature = "bytemuck")]
unsafe impl<T: Pod, U: 'static> Pod for Point3D<T, U> {}impl<T, U> Eq for Point3D<T, U> where T: Eq {}impl<T, U> PartialEq for Point3D<T, U>
whereT: PartialEq,
{fn eq(&self, other: &Self) -> bool {self.x == other.x && self.y == other.y && self.z == other.z}
}impl<T, U> Hash for Point3D<T, U>
whereT: Hash,
{fn hash<H: core::hash::Hasher>(&self, h: &mut H) {self.x.hash(h);self.y.hash(h);self.z.hash(h);}
}impl<T: fmt::Debug, U> fmt::Debug for Point3D<T, U> {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {f.debug_tuple("").field(&self.x).field(&self.y).field(&self.z).finish()}
}impl<T: Default, U> Default for Point3D<T, U> {fn default() -> Self {Point3D::new(Default::default(), Default::default(), Default::default())}
}impl<T, U> Point3D<T, U> {/// Constructor, setting all components to zero.#[inline]pub fn origin() -> SelfwhereT: Zero,{point3(Zero::zero(), Zero::zero(), Zero::zero())}/// The same as [`Point3D::origin`].#[inline]pub fn zero() -> SelfwhereT: Zero,{Self::origin()}/// Constructor taking scalar values directly.#[inline]pub const fn new(x: T, y: T, z: T) -> Self {Point3D {x,y,z,_unit: PhantomData,}}/// Constructor taking properly Lengths instead of scalar values.#[inline]pub fn from_lengths(x: Length<T, U>, y: Length<T, U>, z: Length<T, U>) -> Self {point3(x.0, y.0, z.0)}/// Constructor setting all components to the same value.#[inline]pub fn splat(v: T) -> SelfwhereT: Clone,{Point3D {x: v.clone(),y: v.clone(),z: v,_unit: PhantomData,}}/// Tag a unitless value with units.#[inline]pub fn 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]pub fn 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]pub fn 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]pub fn 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]pub fn xy(self) -> Point2D<T, U> {point2(self.x, self.y)}/// Returns a 2d point using this point's x and z coordinates#[inline]pub fn xz(self) -> Point2D<T, U> {point2(self.x, self.z)}/// Returns a 2d point using this point's x and z coordinates#[inline]pub fn 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]pub fn to_array(self) -> [T; 3] {[self.x, self.y, self.z]}#[inline]pub fn to_array_4d(self) -> [T; 4]whereT: One,{[self.x, self.y, self.z, One::one()]}/// Cast into a tuple 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_tuple(), (1, -8, 0));/// ```#[inline]pub fn to_tuple(self) -> (T, T, T) {(self.x, self.y, self.z)}#[inline]pub fn to_tuple_4d(self) -> (T, T, T, T)whereT: One,{(self.x, self.y, self.z, One::one())}/// 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]pub fn 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]pub fn cast_unit<V>(self) -> Point3D<T, V> {point3(self.x, self.y, self.z)}/// Convert into a 2d point.#[inline]pub fn 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]pub fn round(self) -> SelfwhereT: 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]pub fn ceil(self) -> SelfwhereT: 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]pub fn floor(self) -> SelfwhereT: 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]pub fn lerp(self, other: Self, t: T) -> SelfwhereT: 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,)}
}impl<T: PartialOrd, U> Point3D<T, U> {#[inline]pub fn min(self, other: Self) -> Self {point3(min(self.x, other.x),min(self.y, other.y),min(self.z, other.z),)}#[inline]pub fn max(self, other: Self) -> Self {point3(max(self.x, other.x),max(self.y, other.y),max(self.z, 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]pub fn clamp(self, start: Self, end: Self) -> SelfwhereT: 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]pub fn 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.pub fn 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]pub fn to_f32(self) -> Point3D<f32, U> {self.cast()}/// Cast into an `f64` point.#[inline]pub fn 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]pub fn 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]pub fn 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]pub fn 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]pub fn to_i64(self) -> Point3D<i64, U> {self.cast()}
}impl<T: Float, U> Point3D<T, U> {/// Returns `true` if all members are finite.#[inline]pub fn is_finite(self) -> bool {self.x.is_finite() && self.y.is_finite() && self.z.is_finite()}
}impl<T: Copy + Add<T, Output = T>, U> Point3D<T, U> {#[inline]pub fn add_size(self, other: Size3D<T, U>) -> Self {point3(self.x + other.width,self.y + other.height,self.z + other.depth,)}
}impl<T: Real + Sub<T, Output = T>, U> Point3D<T, U> {#[inline]pub fn distance_to(self, other: Self) -> T {(self - other).length()}
}impl<T: Neg, U> Neg for Point3D<T, U> {type Output = Point3D<T::Output, U>;#[inline]fn neg(self) -> Self::Output {point3(-self.x, -self.y, -self.z)}
}impl<T: Add, U> Add<Size3D<T, U>> for Point3D<T, U> {type Output = Point3D<T::Output, U>;#[inline]fn add(self, other: Size3D<T, U>) -> Self::Output {point3(self.x + other.width,self.y + other.height,self.z + other.depth,)}
}impl<T: AddAssign, U> AddAssign<Size3D<T, U>> for Point3D<T, U> {#[inline]fn add_assign(&mut self, other: Size3D<T, U>) {self.x += other.width;self.y += other.height;self.z += other.depth;}
}impl<T: Add, U> Add<Vector3D<T, U>> for Point3D<T, U> {type Output = Point3D<T::Output, U>;#[inline]fn add(self, other: Vector3D<T, U>) -> Self::Output {point3(self.x + other.x, self.y + other.y, self.z + other.z)}
}impl<T: Copy + Add<T, Output = T>, U> AddAssign<Vector3D<T, U>> for Point3D<T, U> {#[inline]fn add_assign(&mut self, other: Vector3D<T, U>) {*self = *self + other;}
}impl<T: Sub, U> Sub for Point3D<T, U> {type Output = Vector3D<T::Output, U>;#[inline]fn sub(self, other: Self) -> Self::Output {vec3(self.x - other.x, self.y - other.y, self.z - other.z)}
}impl<T: Sub, U> Sub<Size3D<T, U>> for Point3D<T, U> {type Output = Point3D<T::Output, U>;#[inline]fn sub(self, other: Size3D<T, U>) -> Self::Output {point3(self.x - other.width,self.y - other.height,self.z - other.depth,)}
}impl<T: SubAssign, U> SubAssign<Size3D<T, U>> for Point3D<T, U> {#[inline]fn sub_assign(&mut self, other: Size3D<T, U>) {self.x -= other.width;self.y -= other.height;self.z -= other.depth;}
}impl<T: Sub, U> Sub<Vector3D<T, U>> for Point3D<T, U> {type Output = Point3D<T::Output, U>;#[inline]fn sub(self, other: Vector3D<T, U>) -> Self::Output {point3(self.x - other.x, self.y - other.y, self.z - other.z)}
}impl<T: Copy + Sub<T, Output = T>, U> SubAssign<Vector3D<T, U>> for Point3D<T, U> {#[inline]fn sub_assign(&mut self, other: Vector3D<T, U>) {*self = *self - other;}
}impl<T: Copy + Mul, U> Mul<T> for Point3D<T, U> {type Output = Point3D<T::Output, U>;#[inline]fn mul(self, scale: T) -> Self::Output {point3(self.x * scale, self.y * scale, self.z * scale)}
}impl<T: Copy + MulAssign, U> MulAssign<T> for Point3D<T, U> {#[inline]fn mul_assign(&mut self, scale: T) {self.x *= scale;self.y *= scale;self.z *= scale;}
}impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Point3D<T, U1> {type Output = Point3D<T::Output, U2>;#[inline]fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {point3(self.x * scale.0, self.y * scale.0, self.z * scale.0)}
}impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Point3D<T, U> {#[inline]fn mul_assign(&mut self, scale: Scale<T, U, U>) {*self *= scale.0;}
}impl<T: Copy + Div, U> Div<T> for Point3D<T, U> {type Output = Point3D<T::Output, U>;#[inline]fn div(self, scale: T) -> Self::Output {point3(self.x / scale, self.y / scale, self.z / scale)}
}impl<T: Copy + DivAssign, U> DivAssign<T> for Point3D<T, U> {#[inline]fn div_assign(&mut self, scale: T) {self.x /= scale;self.y /= scale;self.z /= scale;}
}impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Point3D<T, U2> {type Output = Point3D<T::Output, U1>;#[inline]fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {point3(self.x / scale.0, self.y / scale.0, self.z / scale.0)}
}impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Point3D<T, U> {#[inline]fn div_assign(&mut self, scale: Scale<T, U, U>) {*self /= scale.0;}
}impl<T: Zero, U> Zero for Point3D<T, U> {#[inline]fn zero() -> Self {Self::origin()}
}impl<T: Round, U> Round for Point3D<T, U> {/// See [`Point3D::round`].#[inline]fn round(self) -> Self {self.round()}
}impl<T: Ceil, U> Ceil for Point3D<T, U> {/// See [`Point3D::ceil`].#[inline]fn ceil(self) -> Self {self.ceil()}
}impl<T: Floor, U> Floor for Point3D<T, U> {/// See [`Point3D::floor`].#[inline]fn floor(self) -> Self {self.floor()}
}impl<T: ApproxEq<T>, U> ApproxEq<Point3D<T, U>> for Point3D<T, U> {#[inline]fn approx_epsilon() -> Self {point3(T::approx_epsilon(),T::approx_epsilon(),T::approx_epsilon(),)}#[inline]fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {self.x.approx_eq_eps(&other.x, &eps.x)&& self.y.approx_eq_eps(&other.y, &eps.y)&& self.z.approx_eq_eps(&other.z, &eps.z)}
}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);////// assert_eq!(p.rem_euclid(&s), point3(3.0, 1.0, 0.0));/// assert_eq!((-p).rem_euclid(&s), point3(1.0, 3.0, 0.0));/// assert_eq!(p.rem_euclid(&-s), point3(3.0, 1.0, 0.0));/// ```#[inline]pub fn rem_euclid(&self, other: &Size3D<T, U>) -> Self {point3(self.x.rem_euclid(&other.width),self.y.rem_euclid(&other.height),self.z.rem_euclid(&other.depth),)}/// Calculates Euclidean division, the matching method for `rem_euclid`.////// # 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);////// assert_eq!(p.div_euclid(&s), point3(1.0, 2.0, 0.0));/// assert_eq!((-p).div_euclid(&s), point3(-2.0, -1.0, 0.0));/// assert_eq!(p.div_euclid(&-s), point3(-1.0, -2.0, 0.0));/// ```#[inline]pub fn div_euclid(&self, other: &Size3D<T, U>) -> Self {point3(self.x.div_euclid(&other.width),self.y.div_euclid(&other.height),self.z.div_euclid(&other.depth),)}
}impl<T, U> From<Point3D<T, U>> for [T; 3] {fn from(p: Point3D<T, U>) -> Self {[p.x, p.y, p.z]}
}impl<T, U> From<[T; 3]> for Point3D<T, U> {fn from([x, y, z]: [T; 3]) -> Self {point3(x, y, z)}
}impl<T, U> From<Point3D<T, U>> for (T, T, T) {fn from(p: Point3D<T, U>) -> Self {(p.x, p.y, p.z)}
}impl<T, U> From<(T, T, T)> for Point3D<T, U> {fn from(tuple: (T, T, T)) -> Self {point3(tuple.0, tuple.1, tuple.2)}
}/// Shorthand for `Point2D::new(x, y)`.
#[inline]
pub const fn point2<T, U>(x: T, y: T) -> Point2D<T, U> {Point2D {x,y,_unit: PhantomData,}
}/// Shorthand for `Point3D::new(x, y)`.
#[inline]
pub const fn point3<T, U>(x: T, y: T, z: T) -> Point3D<T, U> {Point3D {x,y,z,_unit: PhantomData,}
}#[cfg(test)]
mod point2d {use crate::default::Point2D;use crate::point2;#[cfg(feature = "mint")]use mint;#[test]pub fn 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]pub fn 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]pub fn 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]pub fn test_conv_vector() {for i in 0..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]pub fn test_swizzling() {let p: Point2D<i32> = point2(1, 2);assert_eq!(p.yx(), point2(2, 1));}#[test]pub fn test_distance_to() {let p1 = Point2D::new(1.0, 2.0);let p2 = Point2D::new(2.0, 2.0);assert_eq!(p1.distance_to(p2), 1.0);let p1 = Point2D::new(1.0, 2.0);let p2 = Point2D::new(1.0, 4.0);assert_eq!(p1.distance_to(p2), 2.0);}mod ops {use crate::default::Point2D;use crate::scale::Scale;use crate::{size2, vec2, Vector2D};pub enum Mm {}pub enum Cm {}pub type Point2DMm<T> = crate::Point2D<T, Mm>;pub type Point2DCm<T> = crate::Point2D<T, Cm>;#[test]pub fn test_neg() {assert_eq!(-Point2D::new(1.0, 2.0), Point2D::new(-1.0, -2.0));assert_eq!(-Point2D::new(0.0, 0.0), Point2D::new(-0.0, -0.0));assert_eq!(-Point2D::new(-1.0, -2.0), Point2D::new(1.0, 2.0));}#[test]pub fn test_add_size() {let p1 = Point2DMm::new(1.0, 2.0);let p2 = size2(3.0, 4.0);let result = p1 + p2;assert_eq!(result, Point2DMm::new(4.0, 6.0));}#[test]pub fn test_add_assign_size() {let mut p1 = Point2DMm::new(1.0, 2.0);p1 += size2(3.0, 4.0);assert_eq!(p1, Point2DMm::new(4.0, 6.0));}#[test]pub fn test_add_vec() {let p1 = Point2DMm::new(1.0, 2.0);let p2 = vec2(3.0, 4.0);let result = p1 + p2;assert_eq!(result, Point2DMm::new(4.0, 6.0));}#[test]pub fn test_add_assign_vec() {let mut p1 = Point2DMm::new(1.0, 2.0);p1 += vec2(3.0, 4.0);assert_eq!(p1, Point2DMm::new(4.0, 6.0));}#[test]pub fn test_sub() {let p1 = Point2DMm::new(1.0, 2.0);let p2 = Point2DMm::new(3.0, 4.0);let result = p1 - p2;assert_eq!(result, Vector2D::<_, Mm>::new(-2.0, -2.0));}#[test]pub fn test_sub_size() {let p1 = Point2DMm::new(1.0, 2.0);let p2 = size2(3.0, 4.0);let result = p1 - p2;assert_eq!(result, Point2DMm::new(-2.0, -2.0));}#[test]pub fn test_sub_assign_size() {let mut p1 = Point2DMm::new(1.0, 2.0);p1 -= size2(3.0, 4.0);assert_eq!(p1, Point2DMm::new(-2.0, -2.0));}#[test]pub fn test_sub_vec() {let p1 = Point2DMm::new(1.0, 2.0);let p2 = vec2(3.0, 4.0);let result = p1 - p2;assert_eq!(result, Point2DMm::new(-2.0, -2.0));}#[test]pub fn test_sub_assign_vec() {let mut p1 = Point2DMm::new(1.0, 2.0);p1 -= vec2(3.0, 4.0);assert_eq!(p1, Point2DMm::new(-2.0, -2.0));}#[test]pub fn test_mul_scalar() {let p1: Point2D<f32> = Point2D::new(3.0, 5.0);let result = p1 * 5.0;assert_eq!(result, Point2D::new(15.0, 25.0));}#[test]pub fn test_mul_assign_scalar() {let mut p1 = Point2D::new(3.0, 5.0);p1 *= 5.0;assert_eq!(p1, Point2D::new(15.0, 25.0));}#[test]pub fn test_mul_scale() {let p1 = Point2DMm::new(1.0, 2.0);let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);let result = p1 * cm_per_mm;assert_eq!(result, Point2DCm::new(0.1, 0.2));}#[test]pub fn test_mul_assign_scale() {let mut p1 = Point2DMm::new(1.0, 2.0);let scale: Scale<f32, Mm, Mm> = Scale::new(0.1);p1 *= scale;assert_eq!(p1, Point2DMm::new(0.1, 0.2));}#[test]pub fn test_div_scalar() {let p1: Point2D<f32> = Point2D::new(15.0, 25.0);let result = p1 / 5.0;assert_eq!(result, Point2D::new(3.0, 5.0));}#[test]pub fn test_div_assign_scalar() {let mut p1: Point2D<f32> = Point2D::new(15.0, 25.0);p1 /= 5.0;assert_eq!(p1, Point2D::new(3.0, 5.0));}#[test]pub fn test_div_scale() {let p1 = Point2DCm::new(0.1, 0.2);let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);let result = p1 / cm_per_mm;assert_eq!(result, Point2DMm::new(1.0, 2.0));}#[test]pub fn test_div_assign_scale() {let mut p1 = Point2DMm::new(0.1, 0.2);let scale: Scale<f32, Mm, Mm> = Scale::new(0.1);p1 /= scale;assert_eq!(p1, Point2DMm::new(1.0, 2.0));}#[test]pub fn test_point_debug_formatting() {let n = 1.23456789;let p1 = Point2D::new(n, -n);let should_be = format!("({:.4}, {:.4})", n, -n);let got = format!("{:.4?}", p1);assert_eq!(got, should_be);}}mod euclid {use crate::default::{Point2D, Size2D};use crate::point2;#[test]pub fn test_rem_euclid() {let p = Point2D::new(7.0, -7.0);let s = Size2D::new(4.0, -4.0);assert_eq!(p.rem_euclid(&s), point2(3.0, 1.0));assert_eq!((-p).rem_euclid(&s), point2(1.0, 3.0));assert_eq!(p.rem_euclid(&-s), point2(3.0, 1.0));}#[test]pub fn test_div_euclid() {let p = Point2D::new(7.0, -7.0);let s = Size2D::new(4.0, -4.0);assert_eq!(p.div_euclid(&s), point2(1.0, 2.0));assert_eq!((-p).div_euclid(&s), point2(-2.0, -1.0));assert_eq!(p.div_euclid(&-s), point2(-1.0, -2.0));}}
}#[cfg(test)]
mod point3d {use crate::default;use crate::default::Point3D;use crate::{point2, point3};#[cfg(feature = "mint")]use mint;#[test]pub fn test_min() {let p1 = Point3D::new(1.0, 3.0, 5.0);let p2 = Point3D::new(2.0, 2.0, -1.0);let result = p1.min(p2);assert_eq!(result, Point3D::new(1.0, 2.0, -1.0));}#[test]pub fn test_max() {let p1 = Point3D::new(1.0, 3.0, 5.0);let p2 = Point3D::new(2.0, 2.0, -1.0);let result = p1.max(p2);assert_eq!(result, Point3D::new(2.0, 3.0, 5.0));}#[test]pub fn test_conv_vector() {use crate::point3;for i in 0..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);}}#[test]pub fn test_swizzling() {let p: default::Point3D<i32> = point3(1, 2, 3);assert_eq!(p.xy(), point2(1, 2));assert_eq!(p.xz(), point2(1, 3));assert_eq!(p.yz(), point2(2, 3));}#[test]pub fn test_distance_to() {let p1 = Point3D::new(1.0, 2.0, 3.0);let p2 = Point3D::new(2.0, 2.0, 3.0);assert_eq!(p1.distance_to(p2), 1.0);let p1 = Point3D::new(1.0, 2.0, 3.0);let p2 = Point3D::new(1.0, 4.0, 3.0);assert_eq!(p1.distance_to(p2), 2.0);let p1 = Point3D::new(1.0, 2.0, 3.0);let p2 = Point3D::new(1.0, 2.0, 6.0);assert_eq!(p1.distance_to(p2), 3.0);}#[cfg(feature = "mint")]#[test]pub fn test_mint() {let p1 = Point3D::new(1.0, 3.0, 5.0);let pm: mint::Point3<_> = p1.into();let p2 = Point3D::from(pm);assert_eq!(p1, p2);}mod ops {use crate::default::Point3D;use crate::scale::Scale;use crate::{size3, vec3, Vector3D};pub enum Mm {}pub enum Cm {}pub type Point3DMm<T> = crate::Point3D<T, Mm>;pub type Point3DCm<T> = crate::Point3D<T, Cm>;#[test]pub fn test_neg() {assert_eq!(-Point3D::new(1.0, 2.0, 3.0), Point3D::new(-1.0, -2.0, -3.0));assert_eq!(-Point3D::new(0.0, 0.0, 0.0), Point3D::new(-0.0, -0.0, -0.0));assert_eq!(-Point3D::new(-1.0, -2.0, -3.0), Point3D::new(1.0, 2.0, 3.0));}#[test]pub fn test_add_size() {let p1 = Point3DMm::new(1.0, 2.0, 3.0);let p2 = size3(4.0, 5.0, 6.0);let result = p1 + p2;assert_eq!(result, Point3DMm::new(5.0, 7.0, 9.0));}#[test]pub fn test_add_assign_size() {let mut p1 = Point3DMm::new(1.0, 2.0, 3.0);p1 += size3(4.0, 5.0, 6.0);assert_eq!(p1, Point3DMm::new(5.0, 7.0, 9.0));}#[test]pub fn test_add_vec() {let p1 = Point3DMm::new(1.0, 2.0, 3.0);let p2 = vec3(4.0, 5.0, 6.0);let result = p1 + p2;assert_eq!(result, Point3DMm::new(5.0, 7.0, 9.0));}#[test]pub fn test_add_assign_vec() {let mut p1 = Point3DMm::new(1.0, 2.0, 3.0);p1 += vec3(4.0, 5.0, 6.0);assert_eq!(p1, Point3DMm::new(5.0, 7.0, 9.0));}#[test]pub fn test_sub() {let p1 = Point3DMm::new(1.0, 2.0, 3.0);let p2 = Point3DMm::new(4.0, 5.0, 6.0);let result = p1 - p2;assert_eq!(result, Vector3D::<_, Mm>::new(-3.0, -3.0, -3.0));}#[test]pub fn test_sub_size() {let p1 = Point3DMm::new(1.0, 2.0, 3.0);let p2 = size3(4.0, 5.0, 6.0);let result = p1 - p2;assert_eq!(result, Point3DMm::new(-3.0, -3.0, -3.0));}#[test]pub fn test_sub_assign_size() {let mut p1 = Point3DMm::new(1.0, 2.0, 3.0);p1 -= size3(4.0, 5.0, 6.0);assert_eq!(p1, Point3DMm::new(-3.0, -3.0, -3.0));}#[test]pub fn test_sub_vec() {let p1 = Point3DMm::new(1.0, 2.0, 3.0);let p2 = vec3(4.0, 5.0, 6.0);let result = p1 - p2;assert_eq!(result, Point3DMm::new(-3.0, -3.0, -3.0));}#[test]pub fn test_sub_assign_vec() {let mut p1 = Point3DMm::new(1.0, 2.0, 3.0);p1 -= vec3(4.0, 5.0, 6.0);assert_eq!(p1, Point3DMm::new(-3.0, -3.0, -3.0));}#[test]pub fn test_mul_scalar() {let p1: Point3D<f32> = Point3D::new(3.0, 5.0, 7.0);let result = p1 * 5.0;assert_eq!(result, Point3D::new(15.0, 25.0, 35.0));}#[test]pub fn test_mul_assign_scalar() {let mut p1: Point3D<f32> = Point3D::new(3.0, 5.0, 7.0);p1 *= 5.0;assert_eq!(p1, Point3D::new(15.0, 25.0, 35.0));}#[test]pub fn test_mul_scale() {let p1 = Point3DMm::new(1.0, 2.0, 3.0);let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);let result = p1 * cm_per_mm;assert_eq!(result, Point3DCm::new(0.1, 0.2, 0.3));}#[test]pub fn test_mul_assign_scale() {let mut p1 = Point3DMm::new(1.0, 2.0, 3.0);let scale: Scale<f32, Mm, Mm> = Scale::new(0.1);p1 *= scale;assert_eq!(p1, Point3DMm::new(0.1, 0.2, 0.3));}#[test]pub fn test_div_scalar() {let p1: Point3D<f32> = Point3D::new(15.0, 25.0, 35.0);let result = p1 / 5.0;assert_eq!(result, Point3D::new(3.0, 5.0, 7.0));}#[test]pub fn test_div_assign_scalar() {let mut p1: Point3D<f32> = Point3D::new(15.0, 25.0, 35.0);p1 /= 5.0;assert_eq!(p1, Point3D::new(3.0, 5.0, 7.0));}#[test]pub fn test_div_scale() {let p1 = Point3DCm::new(0.1, 0.2, 0.3);let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);let result = p1 / cm_per_mm;assert_eq!(result, Point3DMm::new(1.0, 2.0, 3.0));}#[test]pub fn test_div_assign_scale() {let mut p1 = Point3DMm::new(0.1, 0.2, 0.3);let scale: Scale<f32, Mm, Mm> = Scale::new(0.1);p1 /= scale;assert_eq!(p1, Point3DMm::new(1.0, 2.0, 3.0));}}mod euclid {use crate::default::{Point3D, Size3D};use crate::point3;#[test]pub fn test_rem_euclid() {let p = Point3D::new(7.0, -7.0, 0.0);let s = Size3D::new(4.0, -4.0, 12.0);assert_eq!(p.rem_euclid(&s), point3(3.0, 1.0, 0.0));assert_eq!((-p).rem_euclid(&s), point3(1.0, 3.0, 0.0));assert_eq!(p.rem_euclid(&-s), point3(3.0, 1.0, 0.0));}#[test]pub fn test_div_euclid() {let p = Point3D::new(7.0, -7.0, 0.0);let s = Size3D::new(4.0, -4.0, 12.0);assert_eq!(p.div_euclid(&s), point3(1.0, 2.0, 0.0));assert_eq!((-p).div_euclid(&s), point3(-2.0, -1.0, 0.0));assert_eq!(p.div_euclid(&-s), point3(-1.0, -2.0, 0.0));}}
}
二、Point2D结构体定义
代码定义了一个名为 Point2D 的泛型结构体,它表示一个二维点,并且这个结构体被标记(或说是“携带”)了一个单位(unit)。这里的单位可能是用来表示坐标的某种度量单位或者其它信息,但具体是什么并不在这个结构体定义中明确给出,而是通过泛型参数 U 提供的。
1、源码
#[repr(C)]
pub struct Point2D<T, U> {pub x: T,pub y: T,#[doc(hidden)]pub _unit: PhantomData<U>,
}
2、泛型参数
Point2D<T, U> 有两个泛型参数,T 和 U。T 用于表示点的坐标类型(比如 f32、f64、i32 等),而 U 用于表示与这个点相关的单位信息。
3、字段
- pub x: T:表示点的 X 坐标,其类型为泛型 T。
- pub y: T:表示点的 Y 坐标,其类型也为泛型 T。
- #[doc(hidden)] pub _unit: PhantomData< U >:这里使用了 PhantomData< U > 来携带单位信息 U 而不占用实际的内存空间。PhantomData 是一个在标准库中定义的结构体,用于在泛型代码中表示某种类型存在而不增加运行时的大小。#[doc(hidden)] 属性意味着这个字段在生成的文档中会被隐藏,可能是因为它对于最终用户来说不是很有用或者是一个实现细节。
4、#[repr©] 属性
这个属性指定了结构体的内存布局应该与 C 语言中的结构体布局兼容。这对于与 C 语言代码进行互操作时非常有用,因为它确保了结构体中字段的顺序和内存对齐方式与 C 语言中的相同。
5、总结
Point2D<T, U> 是一个用于表示二维点的泛型结构体,它允许指定坐标的类型(T)和与该点相关的单位信息(U),而不增加任何实际的内存开销用于存储单位信息。
三、二维点特性实现
- Copy 实现:
对于任何实现了Copy特性的T类型,Point2D<T, U>也实现了Copy。这意味着Point2D的实例可以通过值复制,而不需要显式的克隆操作。 - Clone 实现:
对于任何实现了Clone特性的T类型,Point2D<T, U>也实现了Clone。clone方法通过调用x和y的clone方法,创建了Point2D的一个新实例。 - 序列化和反序列化(依赖serde库):
当启用serde特性时,Point2D<T, U>可以被序列化和反序列化,只要T类型支持相应的操作。这允许Point2D实例被方便地转换为JSON等格式,或从JSON等格式恢复。
四、二维点实用方法
- map 方法:
- map方法接受一个闭包f,并将Point2D的每个坐标值(x和y)作为参数传递给闭包,生成一个新的Point2D实例,其坐标类型为闭包返回的类型V。
- 这允许对点的坐标进行各种转换,比如饱和减法(saturating_sub),而不改变点的类型参数U。
- zip 方法:
- zip方法接受另一个Point2D实例rhs和一个闭包f,对两个点的对应坐标值应用闭包f,生成一个新的Vector2D实例(假设Vector2D是一个二维向量结构)。
- 这允许对两个点的坐标进行成对的转换,比如计算两个点之间的差值(如示例中的饱和减法)。
- extend 方法:
- 将一个二维点扩展为一个三维点,通过指定一个z值。
- 参数z的类型与点的x和y坐标类型相同(T)。
- 返回Point3D<T, U>类型的新实例。
- to_vector 方法:
- 将点转换为一个向量。这在数学上等同于从原点(0,0)减去该点。
- 返回Vector2D<T, U>类型的新实例。
- 使用PhantomData来携带单位类型U,但在此方法中未直接使用U。
- yx 方法:
- 交换点的x和y坐标。
- 返回与输入相同类型的新实例(Self类型)。
- 示例代码展示了如何使用这个方法。
- ceil 方法:
- 对点的每个坐标值向上取整(即,取不小于原数的最小整数)。
- 需要在T类型上实现Ceil trait(这通常意味着T是支持浮点运算的类型,如f32或f64)。
- 返回与输入相同类型的新实例。
- 示例代码展示了如何处理负数的向上取整。
- floor 方法:
- 对点的每个坐标值向下取整(即,取不大于原数的最大整数)。
- 需要在T类型上实现Floor trait(类似于Ceil)。
- 返回与输入相同类型的新实例。
- 示例代码展示了如何处理负数的向下取整。
-
线性插值方法 (lerp)
线性插值方法lerp接受当前点(self)、另一个点(other)和一个参数t,然后返回这两个点之间的一个新点,这个点位于从当前点到另一个点的直线上,具体位置由t决定。t的取值范围是实数,通常用于动画和渐变效果中。当t=0.0时,返回当前点;当t=1.0时,返回另一个点;当t在0到1之间时,返回两点之间的某个点;当t超出这个范围时,返回的是当前点和另一个点之外的点。
代码实现是正确的,但需要注意,当t为负值或大于1时,返回的点可能会超出原始两点的范围,这在某些情况下是有用的,但在其他情况下可能不是预期的行为。
转换为整数类型的方法
to_i32和to_i64方法将二维点的坐标从浮点数转换为整数(i32或i64),这里假设原始点的坐标是浮点数。这些方法简单地将浮点数坐标截断为整数,这可能会导致精度损失。在转换之前,您可能希望使用round(), ceil(), 或floor()函数来决定如何处理小数部分。 -
min 方法
min方法的描述中似乎有些文本缺失,但从上下文中可以推断,它应该返回一个新点,该点的每个坐标都是当前点和另一个点相应坐标中的最小值。这个方法的实现可能需要比较两个点的x和y坐标,并返回一个新点,其x和y坐标分别是这两个点对应坐标的最小值。 -
is_finite 方法
is_finite方法检查点的x和y坐标是否都是有限的(不是NaN或无穷大)。这对于数值计算的安全性很重要,可以避免因为使用了无效数值而导致的不可预测行为。 -
add_size 方法
add_size方法将一个Size2D对象(表示宽度和高度)加到当前点上,返回一个新点。这个方法可能用于在图形界面编程中调整点的位置,以适应新的大小或边界。 -
距离计算 (distance_to 方法):
- 实现了两个Point2D实例之间的距离计算。
- 它依赖于T类型实现了Real和Sub trait(Real不是Rust标准库的一部分,可能来自某个数学库,表示实数类型;Sub用于执行减法操作)。
- 方法内部通过减去另一个点并调用.length()方法计算距离。
- 取反 (Neg trait实现):
- 允许对Point2D实例进行取反操作(即坐标乘以-1)。
- 依赖于T类型实现了Neg trait。
- 与Size2D相加 (Add trait实现):
- 允许将Point2D与Size2D相加,可能用于将点的位置按照某个尺寸进行偏移。
- 依赖于T类型实现了Add trait。
- 就地与Size2D相加 (AddAssign trait实现):
- 类似于Add,但直接在原地修改Point2D实例。
- 依赖于T类型实现了AddAssign trait。
- 与Vector2D相加 (Add trait的另一个实现):
- 允许将Point2D与Vector2D相加,可能用于将点的位置按照某个向量进行移动。
- 依赖于T类型实现了Add trait。
- 零值 (Zero trait实现):
- 提供了Point2D的零值(原点)。
- 依赖于T类型实现了Zero trait。
- 四舍五入 (Round trait实现):
- 对Point2D的每个坐标进行四舍五入。
- 依赖于T类型实现了Round trait。
- 向上取整 (Ceil trait实现):
- 对Point2D的每个坐标进行向上取整。
- 依赖于T类型实现了Ceil trait。
- 向下取整 (Floor trait实现):
- 对Point2D的每个坐标进行向下取整。
- 依赖于T类型实现了Floor trait。
- 近似相等 (ApproxEq trait实现):
- 允许比较两个Point2D实例是否在指定的误差范围内近似相等。
- 依赖于T类型实现了ApproxEq trait。
- rem_euclid方法:
+这个方法计算Point2D对象self相对于另一个Size2D对象other的欧几里得余数。
- 欧几里得余数与普通余数不同,它总是非负的。
- 方法接受一个&Size2D<T, U>作为参数,返回一个新的Point2D<T, U>,其中每个坐标都是self对应坐标对other对应维度的欧几里得余数。
- div_euclid方法:
- 这个方法计算Point2D对象self相对于另一个Size2D对象other的欧几里得除法结果。
- euclid除法返回的是商,即self每个坐标除以other对应维度的整数部分。
- 同样,方法接受一个&Size2D<T, U>作为参数,返回一个新的Point2D<T, U>。
- 实现Point2D<T, U>到[T; 2]的转换:
- 通过实现From<Point2D<T, U>> for [T; 2] trait,允许将Point2D转换为包含两个T类型元素的数组。
- 转换直接取Point2D的x和y坐标作为数组的两个元素。
- 实现[T; 2]到Point2D<T, U>的转换:
- 通过实现From<[T; 2]> for Point2D<T, U> trait,允许将包含两个T类型元素的数组转换为Point2D。
- 转换将数组的前两个元素分别作为Point2D的x和y坐标。
- 实现Point2D<T, U>到(T, T)的转换:
- 通过实现From<Point2D<T, U>> for (T, T) trait,允许将Point2D转换为包含两个T类型元素的元组。
- 转换与到数组的转换类似,取Point2D的x和y坐标作为元组的两个元素。
- 实现(T, T)到Point2D<T, U>的转换:
- 通过实现From<(T, T)> for Point2D<T, U> trait,允许将包含两个T类型元素的元组转换为Point2D。
- 转换将元组的两个元素分别作为Point2D的x和y坐标。
五、Point3D结构体
比Point2D多一个z值,方法与Point2D相似。
相关文章:
9 点结构模块(point.rs)
一、point.rs源码 use super::UnknownUnit; use crate::approxeq::ApproxEq; use crate::approxord::{max, min}; use crate::length::Length; use crate::num::*; use crate::scale::Scale; use crate::size::{Size2D, Size3D}; use crate::vector::{vec2, vec3, Vector2D, V…...
基于vue船运物流管理系统设计与实现(源码+数据库+文档)
船运物流管理系统目录 目录 基于springboot船运物流管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员登录 2、货运单管理 3、公告管理 4、公告类型管理 5、新闻管理 6、新闻类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考…...
海思ISP开发说明
1、概述 ISP(Image Signal Processor)图像信号处理器是专门用于处理图像信号的硬件或处理单元,广泛应用于图像传感器(如 CMOS 或 CCD 传感器)与显示设备之间的信号转换过程中。ISP通过一系列数字图像处理算法完成对数字…...
【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.12 连续数组:为什么contiguous这么重要?
2.12 连续数组:为什么contiguous这么重要? 目录 #mermaid-svg-wxhozKbHdFIldAkj {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-wxhozKbHdFIldAkj .error-icon{fill:#552222;}#mermaid-svg-…...
Chromium132 编译指南 - Android 篇(一):编译前准备
1. 引言 欢迎来到《Chromium 132 编译指南 - Android 篇》系列的第一部分。本系列指南将引导您逐步完成在 Android 平台上编译 Chromium 132 版本的全过程。Chromium 作为一款由 Google 主导开发的开源浏览器引擎,为众多现代浏览器提供了核心驱动力。而 Android 作…...
Jenkins未在第一次登录后设置用户名,第二次登录不进去怎么办?
Jenkins在第一次进行登录的时候,只需要输入Jenkins\secrets\initialAdminPassword中的密码,登录成功后,本次我们没有修改密码,就会导致后面第二次登录,Jenkins需要进行用户名和密码的验证,但是我们根本就没…...
#define,源文件与头文件,赋值表达式
1.#define 1.1定义 #define 是一个预处理指令,用于定义宏 宏,是预处理阶段(在编译之前)由预处理器处理的代码片段 1.2使用 1.2.1 #define 可以定义常量 #define PI 3.14159 1.2.2 #define 可以定义宏函数 #define SQUARE(x) ((…...
wordpress外贸独立站常用询盘软件
LiveChat LiveChat是一家提供实时聊天软件的公司,帮助企业通过其平台与客户进行即时通讯,提高客户满意度和忠诚度。他们的产品允许企业在网站、应用程序或电子邮件等多个渠道与客户互动,从而提升客户体验并促进销售增长。 LiveChat的软件特…...
网络爬虫学习:应用selenium获取Edge浏览器版本号,自动下载对应版本msedgedriver,确保Edge浏览器顺利打开。
一、前言 我从24年11月份开始学习网络爬虫应用开发,经过2个来月的努力,于1月下旬完成了开发一款网络爬虫软件的学习目标。这里对本次学习及应用开发进行一下回顾总结。 前几天我已经发了一篇日志(网络爬虫学习:应用selenium从搜…...
Zookeeper入门部署(单点与集群)
本篇文章基于docker方式部署zookeeper集群,请先安装docker 目录 1. docker初期准备 2.启动zookeeper 2.1 单点部署 2.2 集群部署 3. Linux脚本实现快速切换启动关闭 1. docker初期准备 拉取zookeeper镜像 docker pull zookeeper:3.5.6 如果拉取时间过长…...
2025最新在线模型转换工具onnx转换ncnn,mnn,tengine等
文章目录 引言最新网址地点一、模型转换1. 框架转换全景图2. 安全的模型转换3. 网站全景图 二、转换说明三、模型转换流程图四、感谢 引言 在yolov5,yolov8,yolov11等等模型转换的领域中,时间成本常常是开发者头疼的问题。最近发现一个超棒的…...
文件读写操作
写入文本文件 #include <iostream> #include <fstream>//ofstream类需要包含的头文件 using namespace std;void test01() {//1、包含头文件 fstream//2、创建流对象ofstream fout;/*3、指定打开方式:1.ios::out、ios::trunc 清除文件内容后打开2.ios:…...
AJAX XML
AJAX XML 引言 随着互联网技术的不断发展,Web应用对用户交互性和实时性的要求越来越高。AJAX(Asynchronous JavaScript and XML)技术的出现,为Web应用开发提供了强大的支持。AJAX技术允许Web应用在不重新加载整个页面的情况下,与服务器进行异步通信。XML作为数据传输格式…...
Linux文件原生操作
Linux 中一切皆文件,那么 Linux 文件是什么? 在 Linux 中的文件 可以是:传统意义上的有序数据集合,即:文件系统中的物理文件 也可以是:设备,管道,内存。。。(Linux 管理的一切对象…...
JavaScript常用的内置构造函数
JavaScript作为一种广泛应用的编程语言,提供了丰富的内置构造函数,帮助开发者处理不同类型的数据和操作。这些内置构造函数在创建和操作对象时非常有用。本文将详细介绍JavaScript中常用的内置构造函数及其用途。 常用内置构造函数概述 1. Object Obj…...
Shell篇-字符串处理
目录 1.变量引用 2.获取字符串长度 3.字符串截取 4.删除子字符串 5.字符串替换 总结: Bash(Shell 脚本)中的字符串处理语法。以下是对其的介绍和总结:Bash 变量可以使用不同的语法来获取、修改和删除字符串的内容。图片中列…...
Arduino大师练成手册 -- 控制 AS608 指纹识别模块
要在 Arduino 上控制 AS608 指纹识别模块,你可以按照以下步骤进行: 硬件连接 连接指纹模块:将 AS608 指纹模块与 Arduino 连接。通常,AS608 使用 UART 接口进行通信。你需要将 AS608 的 TX、RX、VCC 和 GND 引脚分别连接到 Ardu…...
C++ Primer 命名空间的using声明
欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…...
C#,入门教程(12)——数组及数组使用的基础知识
上一篇: C#,入门教程(11)——枚举(Enum)的基础知识和高级应用https://blog.csdn.net/beijinghorn/article/details/123917587https://blog.csdn.net/beijinghorn/article/details/123917587 数组是一种数据集合,是一组…...
深入浅出并查集(不相交集合实现思路)
引言 并查集(Disjoint Set Union,简称DSU)是一种用于处理一些不交集的合并及查询问题。它主要支持两种操作:查找(Find)和合并(Union)。 查找:确定某个元素属于哪一个子…...
M|哪吒之魔童闹海
rating: 8.5 豆瓣: 8.5 上映时间: “2025” 类型: M动画 导演: 饺子 主演: 国家/地区: 中国大陆 片长/分钟: 144分钟 M|哪吒之魔童闹海 制作精良,除了剧情逻辑有一点瑕疵,各方面都很到位。总体瑕不掩瑜。 上映时间: &…...
【c++】类与对象详解
目录 面向过程思想和面向对象思想类的定义引入类的关键字类定义的两种方式类的访问限定符类的作用域类大小的计算封装 this指针类的6个默认成员函数构造函数初步理解构造函数深入理解构造函数初始化列表单参数构造函数引发的隐式类型转换 析构函数拷贝构造函数赋值运算符重载运…...
LabVIEW如何有效地进行数据采集?
数据采集(DAQ)是许多工程项目中的核心环节,无论是测试、监控还是控制系统,准确、高效的数据采集都是至关重要的。LabVIEW作为一个图形化编程环境,提供了丰富的功能来实现数据采集,确保数据的实时性与可靠性…...
Golang 并发机制-4:用Mutex管理共享资源
并发性是Go的强大功能之一,它允许多个线程(并发线程)同时执行。然而,权力越大,责任越大。当多个例程并发地访问和修改共享资源时,可能会导致数据损坏、竞争条件和不可预测的程序行为。为了解决这些问题&…...
如何用微信小程序写春联
生活没有模板,只需心灯一盏。 如果笑能让你释然,那就开怀一笑;如果哭能让你减压,那就让泪水流下来。如果沉默是金,那就不用解释;如果放下能更好地前行,就别再扛着。 一、引入 Vant UI 1、通过 npm 安装 npm i @vant/weapp -S --production 2、修改 app.json …...
从零开始:用Qt开发一个功能强大的文本编辑器——WPS项目全解析
文章目录 引言项目功能介绍1. **文件操作**2. **文本编辑功能**3. **撤销与重做**4. **剪切、复制与粘贴**5. **文本查找与替换**6. **打印功能**7. **打印预览**8. **设置字体颜色**9. **设置字号**10. **设置字体**11. **左对齐**12. **右对齐**13. **居中对齐**14. **两侧对…...
LLMs之OpenAI o系列:OpenAI o3-mini的简介、安装和使用方法、案例应用之详细攻略
LLMs之OpenAI o系列:OpenAI o3-mini的简介、安装和使用方法、案例应用之详细攻略 目录 相关文章 LLMs之o3:《Deliberative Alignment: Reasoning Enables Safer Language Models》翻译与解读 LLMs之OpenAI o系列:OpenAI o3-mini的简介、安…...
DeepSeek-R1 低成本训练的根本原因是?
在人工智能领域,大语言模型(LLM)正以前所未有的速度发展,驱动着自然语言处理、内容生成、智能客服等众多应用的革新。然而,高性能的背后往往是高昂的训练成本,动辄数百万美元的投入让许多企业和研究机构望而…...
C语言:结构体
一,结构体 C语⾔已经提供了内置类型,如:char、short、int、long、float、double等,但是只有这些内置类型还是不够的,假设我想描述学⽣,描述⼀本书,这时单⼀的内置类型是不⾏的。 描述⼀个学⽣需…...
java练习(5)
ps:题目来自力扣 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这…...
【高等数学】贝塞尔函数
贝塞尔函数(Bessel functions)是数学中一类重要的特殊函数,通常用于解决涉及圆对称或球对称的微分方程。它们在物理学、工程学、天文学等多个领域都有广泛的应用,例如在波动方程、热传导方程、电磁波传播等问题中。 贝塞尔函数的…...
贪吃蛇实现
1.资料来源 https://learn.microsoft.com/zh-cn/windows/console/getstdhandle 2.前言 简介 贪吃蛇是久负盛名的游戏,和俄罗斯方块、扫雷等游戏位列于经典游戏的行列。 《贪食蛇》中玩家控制一条不断移动的蛇,在屏幕上吃掉出现的食物。每吃掉一个食物…...
Windows电脑本地部署运行DeepSeek R1大模型(基于Ollama和Chatbox)
文章目录 一、环境准备二、安装Ollama2.1 访问Ollama官方网站2.2 下载适用于Windows的安装包2.3 安装Ollama安装包2.4 指定Ollama安装目录2.5 指定Ollama的大模型的存储目录 三、选择DeepSeek R1模型四、下载并运行DeepSeek R1模型五、使用Chatbox进行交互5.1 下载Chatbox安装包…...
在C++中,成员变量必须在对象构造完成前初始化,但初始化的方式有多种...
在C中,成员变量必须在对象构造完成前初始化,但初始化的方式可以有多种,具体取决于成员变量的类型和设计需求。以下是C中成员变量初始化的规则和相关机制: 1. 成员变量必须初始化 如果成员变量是基本类型(如 int、doub…...
maven mysql jdk nvm node npm 环境安装
安装JDK 1.8 11 环境 maven环境安装 打开网站 下载 下载zip格式 解压 自己创建一个maven库 以后在idea 使用maven时候重新设置一下 这三个地方分别设置 这时候maven才算设置好 nvm 管理 npm nodejs nvm下载 安装 Releases coreybutler/nvm-windows GitHub 一键安装且若有…...
算法随笔_37: 交替合并字符串
上一篇:算法随笔_36: 复写零-CSDN博客 题目描述如下: 给你两个字符串 word1 和 word2 。请你从 word1 开始,通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长,就将多出来的字母追加到合并后字符串的末尾。 返回 合并后的字符串 。 示例…...
w188校园商铺管理系统设计与实现
🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…...
(2025 年最新)MacOS Redis Desktop Manager中文版下载,附详细图文
MacOS Redis Desktop Manager中文版下载 大家好,今天给大家带来一款非常实用的 Redis 可视化工具——Redis Desktop Manager(简称 RDM)。相信很多开发者都用过 Redis 数据库,但如果你想要更高效、更方便地管理 Redis 数据&#x…...
【Block总结】Shuffle Attention,新型的Shuffle注意力|即插即用
一、论文信息 标题: SA-Net: Shuffle Attention for Deep Convolutional Neural Networks 论文链接: arXiv 代码链接: GitHub 二、创新点 Shuffle Attention(SA)模块的主要创新在于高效结合了通道注意力和空间注意力,同时通过通道重排技…...
解锁豆瓣高清海报(一) 深度爬虫与requests进阶之路
前瞻 PosterBandit 这个脚本能够根据用户指定的日期,爬取你看过的影视最高清的海报,然后使用 PixelWeaver.py 自动拼接成指定大小的长图。 你是否发现直接从豆瓣爬取下来的海报清晰度很低? 使用 .pic .nbg img CSS 选择器,在 我…...
【机器学习与数据挖掘实战】案例11:基于灰色预测和SVR的企业所得税预测分析
【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈机器学习与数据挖掘实战 ⌋ ⌋ ⌋ 机器学习是人工智能的一个分支,专注于让计算机系统通过数据学习和改进。它利用统计和计算方法,使模型能够从数据中自动提取特征并做出预测或决策。数据挖掘则是从大型数据集中发现模式、关联…...
聚簇索引、哈希索引、覆盖索引、索引分类、最左前缀原则、判断索引使用情况、索引失效条件、优化查询性能
聚簇索引 聚簇索引像一本按目录排版的书,用空间换时间,适合读多写少的场景。设计数据库时,主键的选择(如自增ID vs 随机UUID)会直接影响聚簇索引的性能。 什么是聚簇索引? 数据即索引:聚簇索引…...
克隆OpenAI(基于openai API和streamlit)
utils.py: from langchain_openai import ChatOpenAI from langchain.memory import ConversationBufferMemory from langchain.chains import ConversationChain import osdef get_chat_response(api_key,prompt,memory): # memory不能是函数的内部局部变量&…...
DeepSeek技术深度解析:从不同技术角度的全面探讨
DeepSeek技术深度解析:从不同技术角度的全面探讨 引言 DeepSeek是一个集成了多种先进技术的平台,旨在通过深度学习和其他前沿技术来解决复杂的问题。本文将从算法、架构、数据处理以及应用等不同技术角度对DeepSeek进行详细分析。 一、算法层面 深度学…...
完全卸载mysql server步骤
1. 在控制面板中卸载mysql 2. 打开注册表,运行regedit, 删除mysql信息 HKEY_LOCAL_MACHINE-> SYSTEM->CurrentContolSet->Services->EventLog->Application->Mysql HKEY_LOCAL_MACHINE-> SYSTEM->CurrentContolSet->Services->Mysql …...
2025年大年初一篇,C#调用GPU并行计算推荐
C#调用GPU库的主要目的是利用GPU的并行计算能力,加速计算密集型任务,提高程序性能,支持大规模数据处理,优化资源利用,满足特定应用场景的需求,并提升用户体验。在需要处理大量并行数据或进行复杂计算的场景…...
机器学习优化算法:从梯度下降到Adam及其实验改进
机器学习优化算法:从梯度下降到Adam及其实验改进 在机器学习和深度学习领域,模型的训练过程本质上是一个优化问题。优化算法的作用是通过调整模型参数,使得模型在给定的数据 集上实现最优性能。而优化算法的效率和效果直接决定了模型的收敛速…...
在 Ubuntu 中使用 Conda 创建和管理虚拟环境
Conda 是一个广泛使用的包管理和环境管理系统,尤其适用于数据科学和 Python 开发。本文将指导你如何在 Ubuntu 系统中安装 Conda 并创建基于 python3.11 的虚拟环境。 1. 安装 Miniconda 或 Anaconda 方法 1:下载并安装 Miniconda Miniconda 是一个轻量…...
【深度学习】搭建卷积神经网络并进行参数解读
第一步 导包 import torch import torch.nn as nn import torch.optim as optim import torch.nn.functional as F from torchvision import datasets,transforms import matplotlib.pyplot as plt import numpy as np %matplotlib inline transforms 模块是 torchvision 库的…...
稀疏进化训练:机器学习优化算法中的高效解决方案
稀疏进化训练:机器学习优化算法中的高效解决方案 稀疏进化训练:机器学习优化算法中的高效解决方案引言第一部分:背景与动机1.1 传统优化算法的局限性1.2 进化策略的优势1.3 稀疏性的重要性 第二部分:稀疏进化训练的核心思想2.1 稀…...