1*bf2c3715SXin Li // This file is part of Eigen, a lightweight C++ template library 2*bf2c3715SXin Li // for linear algebra. 3*bf2c3715SXin Li // 4*bf2c3715SXin Li // Copyright (C) 2008 Gael Guennebaud <[email protected]> 5*bf2c3715SXin Li // Copyright (C) 2008 Benoit Jacob <[email protected]> 6*bf2c3715SXin Li // 7*bf2c3715SXin Li // This Source Code Form is subject to the terms of the Mozilla 8*bf2c3715SXin Li // Public License v. 2.0. If a copy of the MPL was not distributed 9*bf2c3715SXin Li // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 10*bf2c3715SXin Li 11*bf2c3715SXin Li #ifndef EIGEN_HYPERPLANE_H 12*bf2c3715SXin Li #define EIGEN_HYPERPLANE_H 13*bf2c3715SXin Li 14*bf2c3715SXin Li namespace Eigen { 15*bf2c3715SXin Li 16*bf2c3715SXin Li /** \geometry_module \ingroup Geometry_Module 17*bf2c3715SXin Li * 18*bf2c3715SXin Li * \class Hyperplane 19*bf2c3715SXin Li * 20*bf2c3715SXin Li * \brief A hyperplane 21*bf2c3715SXin Li * 22*bf2c3715SXin Li * A hyperplane is an affine subspace of dimension n-1 in a space of dimension n. 23*bf2c3715SXin Li * For example, a hyperplane in a plane is a line; a hyperplane in 3-space is a plane. 24*bf2c3715SXin Li * 25*bf2c3715SXin Li * \tparam _Scalar the scalar type, i.e., the type of the coefficients 26*bf2c3715SXin Li * \tparam _AmbientDim the dimension of the ambient space, can be a compile time value or Dynamic. 27*bf2c3715SXin Li * Notice that the dimension of the hyperplane is _AmbientDim-1. 28*bf2c3715SXin Li * 29*bf2c3715SXin Li * This class represents an hyperplane as the zero set of the implicit equation 30*bf2c3715SXin Li * \f$ n \cdot x + d = 0 \f$ where \f$ n \f$ is a unit normal vector of the plane (linear part) 31*bf2c3715SXin Li * and \f$ d \f$ is the distance (offset) to the origin. 32*bf2c3715SXin Li */ 33*bf2c3715SXin Li template <typename _Scalar, int _AmbientDim, int _Options> 34*bf2c3715SXin Li class Hyperplane 35*bf2c3715SXin Li { 36*bf2c3715SXin Li public: 37*bf2c3715SXin Li EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1) 38*bf2c3715SXin Li enum { 39*bf2c3715SXin Li AmbientDimAtCompileTime = _AmbientDim, 40*bf2c3715SXin Li Options = _Options 41*bf2c3715SXin Li }; 42*bf2c3715SXin Li typedef _Scalar Scalar; 43*bf2c3715SXin Li typedef typename NumTraits<Scalar>::Real RealScalar; 44*bf2c3715SXin Li typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 45*bf2c3715SXin Li typedef Matrix<Scalar,AmbientDimAtCompileTime,1> VectorType; 46*bf2c3715SXin Li typedef Matrix<Scalar,Index(AmbientDimAtCompileTime)==Dynamic 47*bf2c3715SXin Li ? Dynamic 48*bf2c3715SXin Li : Index(AmbientDimAtCompileTime)+1,1,Options> Coefficients; 49*bf2c3715SXin Li typedef Block<Coefficients,AmbientDimAtCompileTime,1> NormalReturnType; 50*bf2c3715SXin Li typedef const Block<const Coefficients,AmbientDimAtCompileTime,1> ConstNormalReturnType; 51*bf2c3715SXin Li 52*bf2c3715SXin Li /** Default constructor without initialization */ Hyperplane()53*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline Hyperplane() {} 54*bf2c3715SXin Li 55*bf2c3715SXin Li template<int OtherOptions> Hyperplane(const Hyperplane<Scalar,AmbientDimAtCompileTime,OtherOptions> & other)56*bf2c3715SXin Li EIGEN_DEVICE_FUNC Hyperplane(const Hyperplane<Scalar,AmbientDimAtCompileTime,OtherOptions>& other) 57*bf2c3715SXin Li : m_coeffs(other.coeffs()) 58*bf2c3715SXin Li {} 59*bf2c3715SXin Li 60*bf2c3715SXin Li /** Constructs a dynamic-size hyperplane with \a _dim the dimension 61*bf2c3715SXin Li * of the ambient space */ Hyperplane(Index _dim)62*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline explicit Hyperplane(Index _dim) : m_coeffs(_dim+1) {} 63*bf2c3715SXin Li 64*bf2c3715SXin Li /** Construct a plane from its normal \a n and a point \a e onto the plane. 65*bf2c3715SXin Li * \warning the vector normal is assumed to be normalized. 66*bf2c3715SXin Li */ Hyperplane(const VectorType & n,const VectorType & e)67*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline Hyperplane(const VectorType& n, const VectorType& e) 68*bf2c3715SXin Li : m_coeffs(n.size()+1) 69*bf2c3715SXin Li { 70*bf2c3715SXin Li normal() = n; 71*bf2c3715SXin Li offset() = -n.dot(e); 72*bf2c3715SXin Li } 73*bf2c3715SXin Li 74*bf2c3715SXin Li /** Constructs a plane from its normal \a n and distance to the origin \a d 75*bf2c3715SXin Li * such that the algebraic equation of the plane is \f$ n \cdot x + d = 0 \f$. 76*bf2c3715SXin Li * \warning the vector normal is assumed to be normalized. 77*bf2c3715SXin Li */ Hyperplane(const VectorType & n,const Scalar & d)78*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline Hyperplane(const VectorType& n, const Scalar& d) 79*bf2c3715SXin Li : m_coeffs(n.size()+1) 80*bf2c3715SXin Li { 81*bf2c3715SXin Li normal() = n; 82*bf2c3715SXin Li offset() = d; 83*bf2c3715SXin Li } 84*bf2c3715SXin Li 85*bf2c3715SXin Li /** Constructs a hyperplane passing through the two points. If the dimension of the ambient space 86*bf2c3715SXin Li * is greater than 2, then there isn't uniqueness, so an arbitrary choice is made. 87*bf2c3715SXin Li */ Through(const VectorType & p0,const VectorType & p1)88*bf2c3715SXin Li EIGEN_DEVICE_FUNC static inline Hyperplane Through(const VectorType& p0, const VectorType& p1) 89*bf2c3715SXin Li { 90*bf2c3715SXin Li Hyperplane result(p0.size()); 91*bf2c3715SXin Li result.normal() = (p1 - p0).unitOrthogonal(); 92*bf2c3715SXin Li result.offset() = -p0.dot(result.normal()); 93*bf2c3715SXin Li return result; 94*bf2c3715SXin Li } 95*bf2c3715SXin Li 96*bf2c3715SXin Li /** Constructs a hyperplane passing through the three points. The dimension of the ambient space 97*bf2c3715SXin Li * is required to be exactly 3. 98*bf2c3715SXin Li */ Through(const VectorType & p0,const VectorType & p1,const VectorType & p2)99*bf2c3715SXin Li EIGEN_DEVICE_FUNC static inline Hyperplane Through(const VectorType& p0, const VectorType& p1, const VectorType& p2) 100*bf2c3715SXin Li { 101*bf2c3715SXin Li EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 3) 102*bf2c3715SXin Li Hyperplane result(p0.size()); 103*bf2c3715SXin Li VectorType v0(p2 - p0), v1(p1 - p0); 104*bf2c3715SXin Li result.normal() = v0.cross(v1); 105*bf2c3715SXin Li RealScalar norm = result.normal().norm(); 106*bf2c3715SXin Li if(norm <= v0.norm() * v1.norm() * NumTraits<RealScalar>::epsilon()) 107*bf2c3715SXin Li { 108*bf2c3715SXin Li Matrix<Scalar,2,3> m; m << v0.transpose(), v1.transpose(); 109*bf2c3715SXin Li JacobiSVD<Matrix<Scalar,2,3> > svd(m, ComputeFullV); 110*bf2c3715SXin Li result.normal() = svd.matrixV().col(2); 111*bf2c3715SXin Li } 112*bf2c3715SXin Li else 113*bf2c3715SXin Li result.normal() /= norm; 114*bf2c3715SXin Li result.offset() = -p0.dot(result.normal()); 115*bf2c3715SXin Li return result; 116*bf2c3715SXin Li } 117*bf2c3715SXin Li 118*bf2c3715SXin Li /** Constructs a hyperplane passing through the parametrized line \a parametrized. 119*bf2c3715SXin Li * If the dimension of the ambient space is greater than 2, then there isn't uniqueness, 120*bf2c3715SXin Li * so an arbitrary choice is made. 121*bf2c3715SXin Li */ 122*bf2c3715SXin Li // FIXME to be consistent with the rest this could be implemented as a static Through function ?? Hyperplane(const ParametrizedLine<Scalar,AmbientDimAtCompileTime> & parametrized)123*bf2c3715SXin Li EIGEN_DEVICE_FUNC explicit Hyperplane(const ParametrizedLine<Scalar, AmbientDimAtCompileTime>& parametrized) 124*bf2c3715SXin Li { 125*bf2c3715SXin Li normal() = parametrized.direction().unitOrthogonal(); 126*bf2c3715SXin Li offset() = -parametrized.origin().dot(normal()); 127*bf2c3715SXin Li } 128*bf2c3715SXin Li ~Hyperplane()129*bf2c3715SXin Li EIGEN_DEVICE_FUNC ~Hyperplane() {} 130*bf2c3715SXin Li 131*bf2c3715SXin Li /** \returns the dimension in which the plane holds */ dim()132*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline Index dim() const { return AmbientDimAtCompileTime==Dynamic ? m_coeffs.size()-1 : Index(AmbientDimAtCompileTime); } 133*bf2c3715SXin Li 134*bf2c3715SXin Li /** normalizes \c *this */ normalize(void)135*bf2c3715SXin Li EIGEN_DEVICE_FUNC void normalize(void) 136*bf2c3715SXin Li { 137*bf2c3715SXin Li m_coeffs /= normal().norm(); 138*bf2c3715SXin Li } 139*bf2c3715SXin Li 140*bf2c3715SXin Li /** \returns the signed distance between the plane \c *this and a point \a p. 141*bf2c3715SXin Li * \sa absDistance() 142*bf2c3715SXin Li */ signedDistance(const VectorType & p)143*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline Scalar signedDistance(const VectorType& p) const { return normal().dot(p) + offset(); } 144*bf2c3715SXin Li 145*bf2c3715SXin Li /** \returns the absolute distance between the plane \c *this and a point \a p. 146*bf2c3715SXin Li * \sa signedDistance() 147*bf2c3715SXin Li */ absDistance(const VectorType & p)148*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline Scalar absDistance(const VectorType& p) const { return numext::abs(signedDistance(p)); } 149*bf2c3715SXin Li 150*bf2c3715SXin Li /** \returns the projection of a point \a p onto the plane \c *this. 151*bf2c3715SXin Li */ projection(const VectorType & p)152*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline VectorType projection(const VectorType& p) const { return p - signedDistance(p) * normal(); } 153*bf2c3715SXin Li 154*bf2c3715SXin Li /** \returns a constant reference to the unit normal vector of the plane, which corresponds 155*bf2c3715SXin Li * to the linear part of the implicit equation. 156*bf2c3715SXin Li */ normal()157*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline ConstNormalReturnType normal() const { return ConstNormalReturnType(m_coeffs,0,0,dim(),1); } 158*bf2c3715SXin Li 159*bf2c3715SXin Li /** \returns a non-constant reference to the unit normal vector of the plane, which corresponds 160*bf2c3715SXin Li * to the linear part of the implicit equation. 161*bf2c3715SXin Li */ normal()162*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline NormalReturnType normal() { return NormalReturnType(m_coeffs,0,0,dim(),1); } 163*bf2c3715SXin Li 164*bf2c3715SXin Li /** \returns the distance to the origin, which is also the "constant term" of the implicit equation 165*bf2c3715SXin Li * \warning the vector normal is assumed to be normalized. 166*bf2c3715SXin Li */ offset()167*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline const Scalar& offset() const { return m_coeffs.coeff(dim()); } 168*bf2c3715SXin Li 169*bf2c3715SXin Li /** \returns a non-constant reference to the distance to the origin, which is also the constant part 170*bf2c3715SXin Li * of the implicit equation */ offset()171*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline Scalar& offset() { return m_coeffs(dim()); } 172*bf2c3715SXin Li 173*bf2c3715SXin Li /** \returns a constant reference to the coefficients c_i of the plane equation: 174*bf2c3715SXin Li * \f$ c_0*x_0 + ... + c_{d-1}*x_{d-1} + c_d = 0 \f$ 175*bf2c3715SXin Li */ coeffs()176*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline const Coefficients& coeffs() const { return m_coeffs; } 177*bf2c3715SXin Li 178*bf2c3715SXin Li /** \returns a non-constant reference to the coefficients c_i of the plane equation: 179*bf2c3715SXin Li * \f$ c_0*x_0 + ... + c_{d-1}*x_{d-1} + c_d = 0 \f$ 180*bf2c3715SXin Li */ coeffs()181*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline Coefficients& coeffs() { return m_coeffs; } 182*bf2c3715SXin Li 183*bf2c3715SXin Li /** \returns the intersection of *this with \a other. 184*bf2c3715SXin Li * 185*bf2c3715SXin Li * \warning The ambient space must be a plane, i.e. have dimension 2, so that \c *this and \a other are lines. 186*bf2c3715SXin Li * 187*bf2c3715SXin Li * \note If \a other is approximately parallel to *this, this method will return any point on *this. 188*bf2c3715SXin Li */ intersection(const Hyperplane & other)189*bf2c3715SXin Li EIGEN_DEVICE_FUNC VectorType intersection(const Hyperplane& other) const 190*bf2c3715SXin Li { 191*bf2c3715SXin Li EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 2) 192*bf2c3715SXin Li Scalar det = coeffs().coeff(0) * other.coeffs().coeff(1) - coeffs().coeff(1) * other.coeffs().coeff(0); 193*bf2c3715SXin Li // since the line equations ax+by=c are normalized with a^2+b^2=1, the following tests 194*bf2c3715SXin Li // whether the two lines are approximately parallel. 195*bf2c3715SXin Li if(internal::isMuchSmallerThan(det, Scalar(1))) 196*bf2c3715SXin Li { // special case where the two lines are approximately parallel. Pick any point on the first line. 197*bf2c3715SXin Li if(numext::abs(coeffs().coeff(1))>numext::abs(coeffs().coeff(0))) 198*bf2c3715SXin Li return VectorType(coeffs().coeff(1), -coeffs().coeff(2)/coeffs().coeff(1)-coeffs().coeff(0)); 199*bf2c3715SXin Li else 200*bf2c3715SXin Li return VectorType(-coeffs().coeff(2)/coeffs().coeff(0)-coeffs().coeff(1), coeffs().coeff(0)); 201*bf2c3715SXin Li } 202*bf2c3715SXin Li else 203*bf2c3715SXin Li { // general case 204*bf2c3715SXin Li Scalar invdet = Scalar(1) / det; 205*bf2c3715SXin Li return VectorType(invdet*(coeffs().coeff(1)*other.coeffs().coeff(2)-other.coeffs().coeff(1)*coeffs().coeff(2)), 206*bf2c3715SXin Li invdet*(other.coeffs().coeff(0)*coeffs().coeff(2)-coeffs().coeff(0)*other.coeffs().coeff(2))); 207*bf2c3715SXin Li } 208*bf2c3715SXin Li } 209*bf2c3715SXin Li 210*bf2c3715SXin Li /** Applies the transformation matrix \a mat to \c *this and returns a reference to \c *this. 211*bf2c3715SXin Li * 212*bf2c3715SXin Li * \param mat the Dim x Dim transformation matrix 213*bf2c3715SXin Li * \param traits specifies whether the matrix \a mat represents an #Isometry 214*bf2c3715SXin Li * or a more generic #Affine transformation. The default is #Affine. 215*bf2c3715SXin Li */ 216*bf2c3715SXin Li template<typename XprType> 217*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline Hyperplane& transform(const MatrixBase<XprType>& mat, TransformTraits traits = Affine) 218*bf2c3715SXin Li { 219*bf2c3715SXin Li if (traits==Affine) 220*bf2c3715SXin Li { 221*bf2c3715SXin Li normal() = mat.inverse().transpose() * normal(); 222*bf2c3715SXin Li m_coeffs /= normal().norm(); 223*bf2c3715SXin Li } 224*bf2c3715SXin Li else if (traits==Isometry) 225*bf2c3715SXin Li normal() = mat * normal(); 226*bf2c3715SXin Li else 227*bf2c3715SXin Li { 228*bf2c3715SXin Li eigen_assert(0 && "invalid traits value in Hyperplane::transform()"); 229*bf2c3715SXin Li } 230*bf2c3715SXin Li return *this; 231*bf2c3715SXin Li } 232*bf2c3715SXin Li 233*bf2c3715SXin Li /** Applies the transformation \a t to \c *this and returns a reference to \c *this. 234*bf2c3715SXin Li * 235*bf2c3715SXin Li * \param t the transformation of dimension Dim 236*bf2c3715SXin Li * \param traits specifies whether the transformation \a t represents an #Isometry 237*bf2c3715SXin Li * or a more generic #Affine transformation. The default is #Affine. 238*bf2c3715SXin Li * Other kind of transformations are not supported. 239*bf2c3715SXin Li */ 240*bf2c3715SXin Li template<int TrOptions> 241*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline Hyperplane& transform(const Transform<Scalar,AmbientDimAtCompileTime,Affine,TrOptions>& t, 242*bf2c3715SXin Li TransformTraits traits = Affine) 243*bf2c3715SXin Li { 244*bf2c3715SXin Li transform(t.linear(), traits); 245*bf2c3715SXin Li offset() -= normal().dot(t.translation()); 246*bf2c3715SXin Li return *this; 247*bf2c3715SXin Li } 248*bf2c3715SXin Li 249*bf2c3715SXin Li /** \returns \c *this with scalar type casted to \a NewScalarType 250*bf2c3715SXin Li * 251*bf2c3715SXin Li * Note that if \a NewScalarType is equal to the current scalar type of \c *this 252*bf2c3715SXin Li * then this function smartly returns a const reference to \c *this. 253*bf2c3715SXin Li */ 254*bf2c3715SXin Li template<typename NewScalarType> 255*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline typename internal::cast_return_type<Hyperplane, cast()256*bf2c3715SXin Li Hyperplane<NewScalarType,AmbientDimAtCompileTime,Options> >::type cast() const 257*bf2c3715SXin Li { 258*bf2c3715SXin Li return typename internal::cast_return_type<Hyperplane, 259*bf2c3715SXin Li Hyperplane<NewScalarType,AmbientDimAtCompileTime,Options> >::type(*this); 260*bf2c3715SXin Li } 261*bf2c3715SXin Li 262*bf2c3715SXin Li /** Copy constructor with scalar type conversion */ 263*bf2c3715SXin Li template<typename OtherScalarType,int OtherOptions> Hyperplane(const Hyperplane<OtherScalarType,AmbientDimAtCompileTime,OtherOptions> & other)264*bf2c3715SXin Li EIGEN_DEVICE_FUNC inline explicit Hyperplane(const Hyperplane<OtherScalarType,AmbientDimAtCompileTime,OtherOptions>& other) 265*bf2c3715SXin Li { m_coeffs = other.coeffs().template cast<Scalar>(); } 266*bf2c3715SXin Li 267*bf2c3715SXin Li /** \returns \c true if \c *this is approximately equal to \a other, within the precision 268*bf2c3715SXin Li * determined by \a prec. 269*bf2c3715SXin Li * 270*bf2c3715SXin Li * \sa MatrixBase::isApprox() */ 271*bf2c3715SXin Li template<int OtherOptions> 272*bf2c3715SXin Li EIGEN_DEVICE_FUNC bool isApprox(const Hyperplane<Scalar,AmbientDimAtCompileTime,OtherOptions>& other, const typename NumTraits<Scalar>::Real& prec = NumTraits<Scalar>::dummy_precision()) const 273*bf2c3715SXin Li { return m_coeffs.isApprox(other.m_coeffs, prec); } 274*bf2c3715SXin Li 275*bf2c3715SXin Li protected: 276*bf2c3715SXin Li 277*bf2c3715SXin Li Coefficients m_coeffs; 278*bf2c3715SXin Li }; 279*bf2c3715SXin Li 280*bf2c3715SXin Li } // end namespace Eigen 281*bf2c3715SXin Li 282*bf2c3715SXin Li #endif // EIGEN_HYPERPLANE_H 283