nalgebra/geometry/
reflection.rs

1use crate::base::constraint::{AreMultipliable, DimEq, SameNumberOfRows, ShapeConstraint};
2use crate::base::{Const, Matrix, Unit, Vector};
3use crate::dimension::{Dim, U1};
4use crate::storage::{Storage, StorageMut};
5use simba::scalar::ComplexField;
6
7use crate::geometry::Point;
8
9/// A reflection wrt. a plane.
10pub struct Reflection<T, D, S> {
11    axis: Vector<T, D, S>,
12    bias: T,
13}
14
15impl<T: ComplexField, S: Storage<T, Const<D>>, const D: usize> Reflection<T, Const<D>, S> {
16    /// Creates a new reflection wrt. the plane orthogonal to the given axis and that contains the
17    /// point `pt`.
18    pub fn new_containing_point(axis: Unit<Vector<T, Const<D>, S>>, pt: &Point<T, D>) -> Self {
19        let bias = axis.dotc(&pt.coords);
20        Self::new(axis, bias)
21    }
22}
23
24impl<T: ComplexField, D: Dim, S: Storage<T, D>> Reflection<T, D, S> {
25    /// Creates a new reflection wrt. the plane orthogonal to the given axis and bias.
26    ///
27    /// The bias is the position of the plane on the axis. In particular, a bias equal to zero
28    /// represents a plane that passes through the origin.
29    pub fn new(axis: Unit<Vector<T, D, S>>, bias: T) -> Self {
30        Self {
31            axis: axis.into_inner(),
32            bias,
33        }
34    }
35
36    /// The reflection axis.
37    #[must_use]
38    pub fn axis(&self) -> &Vector<T, D, S> {
39        &self.axis
40    }
41
42    /// The reflection bias.
43    ///
44    /// The bias is the position of the plane on the axis. In particular, a bias equal to zero
45    /// represents a plane that passes through the origin.
46    #[must_use]
47    pub fn bias(&self) -> T {
48        self.bias.clone()
49    }
50
51    // TODO: naming convention: reflect_to, reflect_assign ?
52    /// Applies the reflection to the columns of `rhs`.
53    pub fn reflect<R2: Dim, C2: Dim, S2>(&self, rhs: &mut Matrix<T, R2, C2, S2>)
54    where
55        S2: StorageMut<T, R2, C2>,
56        ShapeConstraint: SameNumberOfRows<R2, D>,
57    {
58        for i in 0..rhs.ncols() {
59            // NOTE: we borrow the column twice here. First it is borrowed immutably for the
60            // dot product, and then mutably. Somehow, this allows significantly
61            // better optimizations of the dot product from the compiler.
62            let m_two: T = crate::convert(-2.0f64);
63            let factor = (self.axis.dotc(&rhs.column(i)) - self.bias.clone()) * m_two;
64            rhs.column_mut(i).axpy(factor, &self.axis, T::one());
65        }
66    }
67
68    // TODO: naming convention: reflect_to, reflect_assign ?
69    /// Applies the reflection to the columns of `rhs`.
70    pub fn reflect_with_sign<R2: Dim, C2: Dim, S2>(&self, rhs: &mut Matrix<T, R2, C2, S2>, sign: T)
71    where
72        S2: StorageMut<T, R2, C2>,
73        ShapeConstraint: SameNumberOfRows<R2, D>,
74    {
75        for i in 0..rhs.ncols() {
76            // NOTE: we borrow the column twice here. First it is borrowed immutably for the
77            // dot product, and then mutably. Somehow, this allows significantly
78            // better optimizations of the dot product from the compiler.
79            let m_two = sign.clone().scale(crate::convert(-2.0f64));
80            let factor = (self.axis.dotc(&rhs.column(i)) - self.bias.clone()) * m_two;
81            rhs.column_mut(i).axpy(factor, &self.axis, sign.clone());
82        }
83    }
84
85    /// Applies the reflection to the rows of `lhs`.
86    pub fn reflect_rows<R2: Dim, C2: Dim, S2, S3>(
87        &self,
88        lhs: &mut Matrix<T, R2, C2, S2>,
89        work: &mut Vector<T, R2, S3>,
90    ) where
91        S2: StorageMut<T, R2, C2>,
92        S3: StorageMut<T, R2>,
93        ShapeConstraint: DimEq<C2, D> + AreMultipliable<R2, C2, D, U1>,
94    {
95        lhs.mul_to(&self.axis, work);
96
97        if !self.bias.is_zero() {
98            work.add_scalar_mut(-self.bias.clone());
99        }
100
101        let m_two: T = crate::convert(-2.0f64);
102        lhs.gerc(m_two, work, &self.axis, T::one());
103    }
104
105    /// Applies the reflection to the rows of `lhs`.
106    pub fn reflect_rows_with_sign<R2: Dim, C2: Dim, S2, S3>(
107        &self,
108        lhs: &mut Matrix<T, R2, C2, S2>,
109        work: &mut Vector<T, R2, S3>,
110        sign: T,
111    ) where
112        S2: StorageMut<T, R2, C2>,
113        S3: StorageMut<T, R2>,
114        ShapeConstraint: DimEq<C2, D> + AreMultipliable<R2, C2, D, U1>,
115    {
116        lhs.mul_to(&self.axis, work);
117
118        if !self.bias.is_zero() {
119            work.add_scalar_mut(-self.bias.clone());
120        }
121
122        let m_two = sign.clone().scale(crate::convert(-2.0f64));
123        lhs.gerc(m_two, work, &self.axis, sign);
124    }
125}