Mark as const-fn some constructors of Point, Translation, Quaternion

This commit is contained in:
Crozet Sébastien 2021-04-12 10:32:17 +02:00
parent bedf48dbc2
commit bc7db9d139
14 changed files with 140 additions and 131 deletions

View File

@ -46,9 +46,8 @@
use crate::base::storage::Storage;
use crate::{
Allocator, DefaultAllocator, DualQuaternion, Isometry3, Point, Point3, Quaternion,
SimdRealField, Translation3, Unit, UnitDualQuaternion, UnitQuaternion, Vector, Vector3, U1, U3,
U4,
DualQuaternion, Isometry3, Point, Point3, Quaternion, SimdRealField, Translation3, Unit,
UnitDualQuaternion, UnitQuaternion, Vector, Vector3, U3,
};
use std::mem;
use std::ops::{
@ -140,9 +139,7 @@ macro_rules! dual_quaternion_op_impl(
$lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty $(=> $VDimA: ty, $VDimB: ty)*;
$action: expr; $($lives: tt),*) => {
impl<$($lives ,)* T: SimdRealField $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs
where T::Element: SimdRealField,
DefaultAllocator: Allocator<T, $LhsRDim, $LhsCDim> +
Allocator<T, $RhsRDim, $RhsCDim> {
where T::Element: SimdRealField, {
type Output = $Result;
#[inline]
@ -963,9 +960,7 @@ macro_rules! dual_quaternion_op_impl(
$lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty $(=> $VDimA: ty, $VDimB: ty)*;
$action: expr; $($lives: tt),*) => {
impl<$($lives ,)* T: SimdRealField> $OpAssign<$Rhs> for $Lhs
where T::Element: SimdRealField,
DefaultAllocator: Allocator<T, $LhsRDim, $LhsCDim> +
Allocator<T, $RhsRDim, $RhsCDim> {
where T::Element: SimdRealField {
#[inline]
fn $op_assign(&mut $lhs, $rhs: $Rhs) {

View File

@ -4,9 +4,7 @@ use std::ops::{Div, DivAssign, Mul, MulAssign};
use simba::scalar::{ClosedAdd, ClosedMul};
use simba::simd::SimdRealField;
use crate::base::allocator::Allocator;
use crate::base::dimension::{U1, U2, U3};
use crate::base::{Const, DefaultAllocator, SVector, Unit};
use crate::base::{SVector, Unit};
use crate::Scalar;
use crate::geometry::{

View File

@ -22,9 +22,6 @@ macro_rules! md_impl(
$($lives: tt),*) => {
impl<$($lives ,)* T $(, $DimsDecl)* $(, const $D: usize)*> $Op<$Rhs> for $Lhs
where T: Scalar + Zero + One + ClosedAdd + ClosedMul $($(+ $ScalarBounds)*)*,
DefaultAllocator: Allocator<T, $R1, $C1> +
Allocator<T, $R2, $C2> +
Allocator<T, $R1, $C2>,
$( $ConstraintType: $ConstraintBound$(<$( $ConstraintBoundParams $( = $EqBound )*),*>)* ),*
{
type Output = $Result;
@ -117,8 +114,6 @@ macro_rules! md_assign_impl(
impl<$($lives ,)* T $(, $DimsDecl)* $(, const $D: usize)*> $Op<$Rhs> for $Lhs
where T: Scalar + Zero + One + ClosedAdd + ClosedMul $($(+ $ScalarBounds)*)*,
$($(T::Element: $ElementBounds,)*)*
DefaultAllocator: Allocator<T, $R1, $C1> +
Allocator<T, $R2, $C2>,
$( $ConstraintType: $ConstraintBound $(<$( $ConstraintBoundParams $( = $EqBound )*),*>)* ),*
{
#[inline]
@ -172,7 +167,7 @@ macro_rules! md_assign_impl_all(
/// Macro for the implementation of addition and subtraction.
macro_rules! add_sub_impl(
($Op: ident, $op: ident, $bound: ident;
($R1: ty, $C1: ty),($R2: ty, $C2: ty) $(-> ($RRes: ty))*
($R1: ty, $C1: ty),($R2: ty, $C2: ty) $(-> ($RRes: ty, $CRes: ty))*
// Const type declaration
const $($D: ident),*;
// Other generic type declarations.
@ -183,11 +178,8 @@ macro_rules! add_sub_impl(
$action: expr; $($lives: tt),*) => {
impl<$($lives ,)* T $(, $DimsDecl)* $(, const $D: usize)*> $Op<$Rhs> for $Lhs
where T: Scalar + $bound,
DefaultAllocator: Allocator<T, $R1, $C1> +
Allocator<T, $R2, $C2> +
SameShapeAllocator<T, $R1, $C1, $R2, $C2>,
ShapeConstraint: SameNumberOfRows<$R1, $R2 $(, Representative = $RRes)*> +
SameNumberOfColumns<$C1, $C2>,
SameNumberOfColumns<$C1, $C2 $(, Representative = $CRes)*>,
$( $ConstraintType: $ConstraintBound$(<$( $ConstraintBoundParams $( = $EqBound )*),*>)* ),* {
type Output = $Result;

View File

@ -17,7 +17,7 @@ use simba::simd::SimdPartialOrd;
use crate::base::allocator::Allocator;
use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1};
use crate::base::iter::{MatrixIter, MatrixIterMut};
use crate::base::{Const, DefaultAllocator, OVector, Scalar};
use crate::base::{Const, DefaultAllocator, OVector, SVector, Scalar};
/// A point in an euclidean space.
///
@ -40,9 +40,9 @@ use crate::base::{Const, DefaultAllocator, OVector, Scalar};
/// of said transformations for details.
#[repr(C)]
#[derive(Debug, Clone)]
pub struct Point<T: Scalar, const D: usize> {
pub struct Point<T, const D: usize> {
/// The coordinates of this point, i.e., the shift from the origin.
pub coords: OVector<T, Const<D>>,
pub coords: SVector<T, D>,
}
impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Point<T, D> {
@ -55,7 +55,7 @@ impl<T: Scalar + Copy, const D: usize> Copy for Point<T, D> {}
#[cfg(feature = "bytemuck")]
unsafe impl<T: Scalar, const D: usize> bytemuck::Zeroable for Point<T, D> where
OVector<T, Const<D>>: bytemuck::Zeroable
SVector<T, D>: bytemuck::Zeroable
{
}
@ -63,7 +63,7 @@ unsafe impl<T: Scalar, const D: usize> bytemuck::Zeroable for Point<T, D> where
unsafe impl<T: Scalar, const D: usize> bytemuck::Pod for Point<T, D>
where
T: Copy,
OVector<T, Const<D>>: bytemuck::Pod,
SVector<T, D>: bytemuck::Pod,
{
}
@ -83,7 +83,6 @@ impl<'a, T: Scalar + Deserialize<'a>, const D: usize> Deserialize<'a> for Point<
where
Des: Deserializer<'a>,
{
use crate::SVector;
let coords = SVector::<T, D>::deserialize(deserializer)?;
Ok(Self::from(coords))
@ -94,7 +93,7 @@ impl<'a, T: Scalar + Deserialize<'a>, const D: usize> Deserialize<'a> for Point<
impl<T, const D: usize> Abomonation for Point<T, D>
where
T: Scalar,
OVector<T, Const<D>>: Abomonation,
SVector<T, D>: Abomonation,
{
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
self.coords.entomb(writer)
@ -183,7 +182,7 @@ impl<T: Scalar, const D: usize> Point<T, D> {
/// Creates a new point with the given coordinates.
#[deprecated(note = "Use Point::from(vector) instead.")]
#[inline]
pub fn from_coordinates(coords: OVector<T, Const<D>>) -> Self {
pub fn from_coordinates(coords: SVector<T, D>) -> Self {
Self { coords }
}

View File

@ -181,7 +181,7 @@ where
// NOTE: the impl for Point1 is not with the others so that we
// can add a section with the impl block comment.
/// # Construction from individual components
impl<T: Scalar> Point1<T> {
impl<T> Point1<T> {
/// Initializes this point from its components.
///
/// # Example
@ -192,20 +192,22 @@ impl<T: Scalar> Point1<T> {
/// assert_eq!(p.x, 1.0);
/// ```
#[inline]
pub fn new(x: T) -> Self {
Vector1::new(x).into()
pub const fn new(x: T) -> Self {
Point {
coords: Vector1::new(x),
}
}
}
macro_rules! componentwise_constructors_impl(
($($doc: expr; $Point: ident, $Vector: ident, $($args: ident:$irow: expr),*);* $(;)*) => {$(
impl<T: Scalar> $Point<T> {
impl<T> $Point<T> {
#[doc = "Initializes this point from its components."]
#[doc = "# Example\n```"]
#[doc = $doc]
#[doc = "```"]
#[inline]
pub fn new($($args: T),*) -> Self {
$Vector::new($($args),*).into()
pub const fn new($($args: T),*) -> Self {
Point { coords: $Vector::new($($args),*) }
}
}
)*}

View File

@ -5,13 +5,12 @@ use std::ops::{
use simba::scalar::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub};
use crate::base::allocator::{Allocator, SameShapeAllocator};
use crate::base::constraint::{
AreMultipliable, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
};
use crate::base::dimension::{Dim, U1};
use crate::base::storage::Storage;
use crate::base::{Const, DefaultAllocator, Matrix, Scalar, Vector, VectorSum};
use crate::base::{Const, Matrix, SVector, Scalar, Vector};
use crate::geometry::Point;
@ -67,32 +66,32 @@ impl<'a, T: Scalar + ClosedNeg, const D: usize> Neg for &'a Point<T, D> {
// Point - Point
add_sub_impl!(Sub, sub, ClosedSub;
(Const<D>, U1), (Const<D>, U1)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: &'a Point<T, D>, right: &'b Point<T, D>, Output = VectorSum<T, Const<D>, Const<D>>;
self: &'a Point<T, D>, right: &'b Point<T, D>, Output = SVector<T, D>;
&self.coords - &right.coords; 'a, 'b);
add_sub_impl!(Sub, sub, ClosedSub;
(Const<D>, U1), (Const<D>, U1)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: &'a Point<T, D>, right: Point<T, D>, Output = VectorSum<T, Const<D>, Const<D>>;
self: &'a Point<T, D>, right: Point<T, D>, Output = SVector<T, D>;
&self.coords - right.coords; 'a);
add_sub_impl!(Sub, sub, ClosedSub;
(Const<D>, U1), (Const<D>, U1)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: Point<T, D>, right: &'b Point<T, D>, Output = VectorSum<T, Const<D>, Const<D>>;
self: Point<T, D>, right: &'b Point<T, D>, Output = SVector<T, D>;
self.coords - &right.coords; 'b);
add_sub_impl!(Sub, sub, ClosedSub;
(Const<D>, U1), (Const<D>, U1)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: Point<T, D>, right: Point<T, D>, Output = VectorSum<T, Const<D>, Const<D>>;
self: Point<T, D>, right: Point<T, D>, Output = SVector<T, D>;
self.coords - right.coords; );
// Point - Vector
add_sub_impl!(Sub, sub, ClosedSub;
(Const<D1>, U1), (D2, U1) -> (Const<D1>)
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1)
const D1;
for D2, SB;
where D2: Dim, SB: Storage<T, D2>;
@ -100,7 +99,7 @@ add_sub_impl!(Sub, sub, ClosedSub;
Self::Output::from(&self.coords - right); 'a, 'b);
add_sub_impl!(Sub, sub, ClosedSub;
(Const<D1>, U1), (D2, U1) -> (Const<D1>)
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1)
const D1;
for D2, SB;
where D2: Dim, SB: Storage<T, D2>;
@ -108,7 +107,7 @@ add_sub_impl!(Sub, sub, ClosedSub;
Self::Output::from(&self.coords - &right); 'a); // TODO: should not be a ref to `right`.
add_sub_impl!(Sub, sub, ClosedSub;
(Const<D1>, U1), (D2, U1) -> (Const<D1>)
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1)
const D1;
for D2, SB;
where D2: Dim, SB: Storage<T, D2>;
@ -116,7 +115,7 @@ add_sub_impl!(Sub, sub, ClosedSub;
Self::Output::from(self.coords - right); 'b);
add_sub_impl!(Sub, sub, ClosedSub;
(Const<D1>, U1), (D2, U1) -> (Const<D1>)
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1)
const D1;
for D2, SB;
where D2: Dim, SB: Storage<T, D2>;
@ -125,7 +124,7 @@ add_sub_impl!(Sub, sub, ClosedSub;
// Point + Vector
add_sub_impl!(Add, add, ClosedAdd;
(Const<D1>, U1), (D2, U1) -> (Const<D1>)
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1)
const D1;
for D2, SB;
where D2: Dim, SB: Storage<T, D2>;
@ -133,7 +132,7 @@ add_sub_impl!(Add, add, ClosedAdd;
Self::Output::from(&self.coords + right); 'a, 'b);
add_sub_impl!(Add, add, ClosedAdd;
(Const<D1>, U1), (D2, U1) -> (Const<D1>)
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1)
const D1;
for D2, SB;
where D2: Dim, SB: Storage<T, D2>;
@ -141,7 +140,7 @@ add_sub_impl!(Add, add, ClosedAdd;
Self::Output::from(&self.coords + &right); 'a); // TODO: should not be a ref to `right`.
add_sub_impl!(Add, add, ClosedAdd;
(Const<D1>, U1), (D2, U1) -> (Const<D1>)
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1)
const D1;
for D2, SB;
where D2: Dim, SB: Storage<T, D2>;
@ -149,7 +148,7 @@ add_sub_impl!(Add, add, ClosedAdd;
Self::Output::from(self.coords + right); 'b);
add_sub_impl!(Add, add, ClosedAdd;
(Const<D1>, U1), (D2, U1) -> (Const<D1>)
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1)
const D1;
for D2, SB;
where D2: Dim, SB: Storage<T, D2>;

View File

@ -1,6 +1,7 @@
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use num::Zero;
use std::fmt;
use std::hash::{Hash, Hasher};
#[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write};
@ -26,12 +27,27 @@ use crate::geometry::{Point3, Rotation};
/// A quaternion. See the type alias `UnitQuaternion = Unit<Quaternion>` for a quaternion
/// that may be used as a rotation.
#[repr(C)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Quaternion<T: Scalar> {
#[derive(Debug, Copy, Clone)]
pub struct Quaternion<T> {
/// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order.
pub coords: Vector4<T>,
}
impl<T: Scalar + Hash> Hash for Quaternion<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.coords.hash(state)
}
}
impl<T: Scalar + Eq> Eq for Quaternion<T> {}
impl<T: Scalar> PartialEq for Quaternion<T> {
#[inline]
fn eq(&self, right: &Self) -> bool {
self.coords == right.coords
}
}
impl<T: Scalar + Zero> Default for Quaternion<T> {
fn default() -> Self {
Quaternion {

View File

@ -23,12 +23,12 @@ use crate::{Scalar, SimdRealField};
use crate::geometry::{Quaternion, Rotation3, UnitQuaternion};
impl<T: Scalar> Quaternion<T> {
impl<T> Quaternion<T> {
/// Creates a quaternion from a 4D vector. The quaternion scalar part corresponds to the `w`
/// vector component.
#[inline]
#[deprecated(note = "Use `::from` instead.")]
pub fn from_vector(vector: Vector4<T>) -> Self {
// #[deprecated(note = "Use `::from` instead.")] // Don't deprecate because this one can be a const-fn.
pub const fn from_vector(vector: Vector4<T>) -> Self {
Self { coords: vector }
}
@ -46,8 +46,8 @@ impl<T: Scalar> Quaternion<T> {
/// assert_eq!(*q.as_vector(), Vector4::new(2.0, 3.0, 4.0, 1.0));
/// ```
#[inline]
pub fn new(w: T, i: T, j: T, k: T) -> Self {
Self::from(Vector4::new(i, j, k, w))
pub const fn new(w: T, i: T, j: T, k: T) -> Self {
Self::from_vector(Vector4::new(i, j, k, w))
}
/// Cast the components of `self` to another type.
@ -61,6 +61,7 @@ impl<T: Scalar> Quaternion<T> {
/// ```
pub fn cast<To: Scalar>(self) -> Quaternion<To>
where
T: Scalar,
To: SupersetOf<T>,
{
crate::convert(self)

View File

@ -4,9 +4,7 @@ use std::ops::{Div, DivAssign, Mul, MulAssign};
use simba::scalar::{ClosedAdd, ClosedMul};
use simba::simd::SimdRealField;
use crate::base::allocator::Allocator;
use crate::base::dimension::{U1, U2, U3};
use crate::base::{Const, DefaultAllocator, SVector, Scalar};
use crate::base::{SVector, Scalar};
use crate::geometry::{
AbstractRotation, Isometry, Point, Rotation, Similarity, Translation, UnitComplex,

View File

@ -4,7 +4,7 @@ use std::ops::{Div, DivAssign, Index, IndexMut, Mul, MulAssign};
use simba::scalar::{ClosedAdd, ClosedMul, RealField, SubsetOf};
use crate::base::allocator::Allocator;
use crate::base::dimension::{DimNameAdd, DimNameSum, U1, U4};
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
use crate::geometry::{
@ -110,7 +110,8 @@ md_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategory;
where Const<D>: DimNameAdd<U1>, C: TCategory,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: SVector<T, D>, Output = SVector<T, D>;
[val val] => &self * &rhs;
[ref val] => self * &rhs;
@ -137,7 +138,8 @@ md_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategory;
where Const<D>: DimNameAdd<U1>, C: TCategory,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: Point<T, D>, Output = Point<T, D>;
[val val] => &self * &rhs;
[ref val] => self * &rhs;
@ -166,7 +168,8 @@ md_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
const D;
for CA, CB;
where Const<D>: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: TCategory;
where Const<D>: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: TCategory,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, CA, D>, rhs: Transform<T, CB, D>, Output = Transform<T, CA::Representative, D>;
[val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.into_inner());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.into_inner());
@ -176,11 +179,13 @@ md_impl_all!(
// Transform × Rotation
md_impl_all!(
Mul, mul where T: RealField;
Mul, mul
where T: RealField;
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, Const<D>)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: Rotation<T, D>, Output = Transform<T, C::Representative, D>;
[val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
@ -194,7 +199,8 @@ md_impl_all!(
(Const<D>, Const<D>), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Rotation<T, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
@ -236,7 +242,8 @@ md_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
const D;
for C, R;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: Isometry<T, R, D>, Output = Transform<T, C::Representative, D>;
[val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
@ -250,7 +257,8 @@ md_impl_all!(
(Const<D>, U1), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
const D;
for C, R;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Isometry<T, R, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
@ -264,7 +272,8 @@ md_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
const D;
for C, R;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: Similarity<T, R, D>, Output = Transform<T, C::Representative, D>;
[val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
@ -278,7 +287,8 @@ md_impl_all!(
(Const<D>, U1), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
const D;
for C, R;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Similarity<T, R, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
@ -300,7 +310,8 @@ md_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: Translation<T, D>, Output = Transform<T, C::Representative, D>;
[val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
@ -314,7 +325,8 @@ md_impl_all!(
(Const<D>, U1), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Translation<T, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
@ -328,7 +340,8 @@ md_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
const D;
for CA, CB;
where Const<D>: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: SubTCategoryOf<TProjective>;
where Const<D>: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: SubTCategoryOf<TProjective>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, CA, D>, rhs: Transform<T, CB, D>, Output = Transform<T, CA::Representative, D>;
[val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
[ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
@ -342,7 +355,8 @@ md_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, Const<D>)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: Rotation<T, D>, Output = Transform<T, C::Representative, D>;
[val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
[ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
@ -356,7 +370,8 @@ md_impl_all!(
(Const<D>, Const<D>), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Rotation<T, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
[val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
[ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
@ -452,7 +467,8 @@ md_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: Translation<T, D>, Output = Transform<T, C::Representative, D>;
[val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
[ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
@ -466,7 +482,8 @@ md_impl_all!(
(Const<D>, U1), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Translation<T, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
[val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
[ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
@ -480,7 +497,8 @@ md_assign_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
const D;
for CA, CB;
where Const<D>: DimNameAdd<U1>, CA: TCategory, CB: SubTCategoryOf<CA>;
where Const<D>: DimNameAdd<U1>, CA: TCategory, CB: SubTCategoryOf<CA>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, CA, D>, rhs: Transform<T, CB, D>;
[val] => *self.matrix_mut_unchecked() *= rhs.into_inner();
[ref] => *self.matrix_mut_unchecked() *= rhs.matrix();
@ -492,7 +510,8 @@ md_assign_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
const D;
for C, R;
where Const<D>: DimNameAdd<U1>, C: TCategory, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >;
where Const<D>: DimNameAdd<U1>, C: TCategory, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: Similarity<T, R, D>;
[val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
[ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
@ -504,7 +523,8 @@ md_assign_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
const D;
for C, R;
where Const<D>: DimNameAdd<U1>, C: TCategory, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >;
where Const<D>: DimNameAdd<U1>, C: TCategory, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: Isometry<T, R, D>;
[val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
[ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
@ -524,7 +544,8 @@ md_assign_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategory;
where Const<D>: DimNameAdd<U1>, C: TCategory,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: Translation<T, D>;
[val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
[ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
@ -536,7 +557,8 @@ md_assign_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, Const<D>)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategory;
where Const<D>: DimNameAdd<U1>, C: TCategory,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: Rotation<T, D>;
[val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
[ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
@ -560,7 +582,8 @@ md_assign_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
const D;
for CA, CB;
where Const<D>: DimNameAdd<U1>, CA: SuperTCategoryOf<CB>, CB: SubTCategoryOf<TProjective>;
where Const<D>: DimNameAdd<U1>, CA: SuperTCategoryOf<CB>, CB: SubTCategoryOf<TProjective>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, CA, D>, rhs: Transform<T, CB, D>;
[val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
[ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.clone().inverse() };
@ -593,7 +616,8 @@ md_assign_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategory;
where Const<D>: DimNameAdd<U1>, C: TCategory,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: Translation<T, D>;
[val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
[ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
@ -605,7 +629,8 @@ md_assign_impl_all!(
(DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, Const<D>)
const D;
for C;
where Const<D>: DimNameAdd<U1>, C: TCategory;
where Const<D>: DimNameAdd<U1>, C: TCategory,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, C, D>, rhs: Rotation<T, D>;
[val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
[ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };

View File

@ -23,7 +23,7 @@ use crate::geometry::Point;
/// A translation.
#[repr(C)]
#[derive(Debug)]
pub struct Translation<T: Scalar, const D: usize> {
pub struct Translation<T, const D: usize> {
/// The translation coordinates, i.e., how much is added to a point's coordinates when it is
/// translated.
pub vector: SVector<T, D>,

View File

@ -93,15 +93,15 @@ where
*/
macro_rules! componentwise_constructors_impl(
($($doc: expr; $D: expr, $($args: ident:$irow: expr),*);* $(;)*) => {$(
impl<T: Scalar> Translation<T, $D>
impl<T> Translation<T, $D>
{
#[doc = "Initializes this translation from its components."]
#[doc = "# Example\n```"]
#[doc = $doc]
#[doc = "```"]
#[inline]
pub fn new($($args: T),*) -> Self {
Self::from(SVector::<T, $D>::new($($args),*))
pub const fn new($($args: T),*) -> Self {
Self { vector: SVector::<T, $D>::new($($args),*) }
}
}
)*}

View File

@ -2,37 +2,36 @@ use std::ops::{Div, DivAssign, Mul, MulAssign};
use simba::scalar::{ClosedAdd, ClosedSub};
use crate::base::allocator::{Allocator, SameShapeAllocator};
use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use crate::base::dimension::U1;
use crate::base::{Const, DefaultAllocator, Scalar};
use crate::base::{Const, Scalar};
use crate::geometry::{Point, Translation};
// Translation × Translation
add_sub_impl!(Mul, mul, ClosedAdd;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: &'a Translation<T, D>, right: &'b Translation<T, D>, Output = Translation<T, D>;
#[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(&self.vector + &right.vector) };
'a, 'b);
add_sub_impl!(Mul, mul, ClosedAdd;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: &'a Translation<T, D>, right: Translation<T, D>, Output = Translation<T, D>;
#[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(&self.vector + right.vector) };
'a);
add_sub_impl!(Mul, mul, ClosedAdd;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: Translation<T, D>, right: &'b Translation<T, D>, Output = Translation<T, D>;
#[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector + &right.vector) };
'b);
add_sub_impl!(Mul, mul, ClosedAdd;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: Translation<T, D>, right: Translation<T, D>, Output = Translation<T, D>;
#[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector + right.vector) }; );
@ -40,28 +39,28 @@ add_sub_impl!(Mul, mul, ClosedAdd;
// Translation ÷ Translation
// TODO: instead of calling inverse explicitly, could we just add a `mul_tr` or `mul_inv` method?
add_sub_impl!(Div, div, ClosedSub;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: &'a Translation<T, D>, right: &'b Translation<T, D>, Output = Translation<T, D>;
#[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(&self.vector - &right.vector) };
'a, 'b);
add_sub_impl!(Div, div, ClosedSub;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: &'a Translation<T, D>, right: Translation<T, D>, Output = Translation<T, D>;
#[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(&self.vector - right.vector) };
'a);
add_sub_impl!(Div, div, ClosedSub;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: Translation<T, D>, right: &'b Translation<T, D>, Output = Translation<T, D>;
#[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector - &right.vector) };
'b);
add_sub_impl!(Div, div, ClosedSub;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: Translation<T, D>, right: Translation<T, D>, Output = Translation<T, D>;
#[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector - right.vector) }; );
@ -70,28 +69,28 @@ add_sub_impl!(Div, div, ClosedSub;
// TODO: we don't handle properly non-zero origins here. Do we want this to be the intended
// behavior?
add_sub_impl!(Mul, mul, ClosedAdd;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: &'a Translation<T, D>, right: &'b Point<T, D>, Output = Point<T, D>;
#[allow(clippy::suspicious_arithmetic_impl)] { right + &self.vector };
'a, 'b);
add_sub_impl!(Mul, mul, ClosedAdd;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: &'a Translation<T, D>, right: Point<T, D>, Output = Point<T, D>;
#[allow(clippy::suspicious_arithmetic_impl)] { right + &self.vector };
'a);
add_sub_impl!(Mul, mul, ClosedAdd;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: Translation<T, D>, right: &'b Point<T, D>, Output = Point<T, D>;
#[allow(clippy::suspicious_arithmetic_impl)] { right + self.vector };
'b);
add_sub_impl!(Mul, mul, ClosedAdd;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>)
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
const D; for; where;
self: Translation<T, D>, right: Point<T, D>, Output = Point<T, D>;
#[allow(clippy::suspicious_arithmetic_impl)] { right + self.vector }; );

View File

@ -7,9 +7,7 @@ use alga::linear::{
ProjectiveTransformation, Rotation, Similarity, Transformation,
};
use crate::base::allocator::Allocator;
use crate::base::dimension::U2;
use crate::base::{DefaultAllocator, Vector2};
use crate::base::Vector2;
use crate::geometry::{Point2, UnitComplex};
/*
@ -59,10 +57,7 @@ impl_structures!(
AbstractGroup<Multiplicative>
);
impl<T: RealField + simba::scalar::RealField> Transformation<Point2<T>> for UnitComplex<T>
where
DefaultAllocator: Allocator<T, U2>,
{
impl<T: RealField + simba::scalar::RealField> Transformation<Point2<T>> for UnitComplex<T> {
#[inline]
fn transform_point(&self, pt: &Point2<T>) -> Point2<T> {
self.transform_point(pt)
@ -74,9 +69,8 @@ where
}
}
impl<T: RealField + simba::scalar::RealField> ProjectiveTransformation<Point2<T>> for UnitComplex<T>
where
DefaultAllocator: Allocator<T, U2>,
impl<T: RealField + simba::scalar::RealField> ProjectiveTransformation<Point2<T>>
for UnitComplex<T>
{
#[inline]
fn inverse_transform_point(&self, pt: &Point2<T>) -> Point2<T> {
@ -89,10 +83,7 @@ where
}
}
impl<T: RealField + simba::scalar::RealField> AffineTransformation<Point2<T>> for UnitComplex<T>
where
DefaultAllocator: Allocator<T, U2>,
{
impl<T: RealField + simba::scalar::RealField> AffineTransformation<Point2<T>> for UnitComplex<T> {
type Rotation = Self;
type NonUniformScaling = Id;
type Translation = Id;
@ -133,10 +124,7 @@ where
}
}
impl<T: RealField + simba::scalar::RealField> Similarity<Point2<T>> for UnitComplex<T>
where
DefaultAllocator: Allocator<T, U2>,
{
impl<T: RealField + simba::scalar::RealField> Similarity<Point2<T>> for UnitComplex<T> {
type Scaling = Id;
#[inline]
@ -158,16 +146,13 @@ where
macro_rules! marker_impl(
($($Trait: ident),*) => {$(
impl<T: RealField + simba::scalar::RealField> $Trait<Point2<T>> for UnitComplex<T>
where DefaultAllocator: Allocator<T, U2> { }
{ }
)*}
);
marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation);
impl<T: RealField + simba::scalar::RealField> Rotation<Point2<T>> for UnitComplex<T>
where
DefaultAllocator: Allocator<T, U2>,
{
impl<T: RealField + simba::scalar::RealField> Rotation<Point2<T>> for UnitComplex<T> {
#[inline]
fn powf(&self, n: T) -> Option<Self> {
Some(self.powf(n))