mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-04-19 08:09:36 +08:00
Cross product for vectors of size 2. Fixes #1037
This commit is contained in:
parent
8588d8c74b
commit
6431dfdb50
@ -387,20 +387,9 @@ template<typename Derived> class MatrixBase
|
||||
|
||||
/////////// Geometry module ///////////
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
/// \internal helper struct to form the return type of the cross product
|
||||
template<typename OtherDerived> struct cross_product_return_type {
|
||||
typedef typename ScalarBinaryOpTraits<typename internal::traits<Derived>::Scalar,typename internal::traits<OtherDerived>::Scalar>::ReturnType Scalar;
|
||||
typedef Matrix<Scalar,MatrixBase::RowsAtCompileTime,MatrixBase::ColsAtCompileTime> type;
|
||||
};
|
||||
#endif // EIGEN_PARSED_BY_DOXYGEN
|
||||
template<typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
inline typename cross_product_return_type<OtherDerived>::type
|
||||
#else
|
||||
inline PlainObject
|
||||
#endif
|
||||
inline typename internal::cross_impl<Derived, OtherDerived>::return_type
|
||||
cross(const MatrixBase<OtherDerived>& other) const;
|
||||
|
||||
template<typename OtherDerived>
|
||||
|
@ -270,8 +270,10 @@ template<typename VectorsType, typename CoeffsType, int Side=OnTheLeft> class Ho
|
||||
template<typename Scalar> class JacobiRotation;
|
||||
|
||||
// Geometry module:
|
||||
namespace internal {
|
||||
template<typename Derived, typename OtherDerived, int Size = MatrixBase<Derived>::SizeAtCompileTime> struct cross_impl;
|
||||
}
|
||||
template<typename Derived, int Dim_> class RotationBase;
|
||||
template<typename Lhs, typename Rhs> class Cross;
|
||||
template<typename Derived> class QuaternionBase;
|
||||
template<typename Scalar> class Rotation2D;
|
||||
template<typename Scalar> class AngleAxis;
|
||||
|
@ -15,39 +15,83 @@
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Vector3 version (default)
|
||||
template<typename Derived, typename OtherDerived, int Size>
|
||||
struct cross_impl
|
||||
{
|
||||
typedef typename ScalarBinaryOpTraits<typename internal::traits<Derived>::Scalar,typename internal::traits<OtherDerived>::Scalar>::ReturnType Scalar;
|
||||
typedef Matrix<Scalar,MatrixBase<Derived>::RowsAtCompileTime,MatrixBase<Derived>::ColsAtCompileTime> return_type;
|
||||
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
|
||||
return_type run(const MatrixBase<Derived>& first, const MatrixBase<OtherDerived>& second)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Derived,3)
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,3)
|
||||
|
||||
// Note that there is no need for an expression here since the compiler
|
||||
// optimize such a small temporary very well (even within a complex expression)
|
||||
typename internal::nested_eval<Derived,2>::type lhs(first.derived());
|
||||
typename internal::nested_eval<OtherDerived,2>::type rhs(second.derived());
|
||||
return return_type(
|
||||
numext::conj(lhs.coeff(1) * rhs.coeff(2) - lhs.coeff(2) * rhs.coeff(1)),
|
||||
numext::conj(lhs.coeff(2) * rhs.coeff(0) - lhs.coeff(0) * rhs.coeff(2)),
|
||||
numext::conj(lhs.coeff(0) * rhs.coeff(1) - lhs.coeff(1) * rhs.coeff(0))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Vector2 version
|
||||
template<typename Derived, typename OtherDerived>
|
||||
struct cross_impl<Derived, OtherDerived, 2>
|
||||
{
|
||||
typedef typename ScalarBinaryOpTraits<typename internal::traits<Derived>::Scalar,typename internal::traits<OtherDerived>::Scalar>::ReturnType Scalar;
|
||||
typedef Scalar return_type;
|
||||
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
|
||||
return_type run(const MatrixBase<Derived>& first, const MatrixBase<OtherDerived>& second)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Derived,2);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,2);
|
||||
typename internal::nested_eval<Derived,2>::type lhs(first.derived());
|
||||
typename internal::nested_eval<OtherDerived,2>::type rhs(second.derived());
|
||||
return numext::conj(lhs.coeff(0) * rhs.coeff(1) - lhs.coeff(1) * rhs.coeff(0));
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
/** \geometry_module \ingroup Geometry_Module
|
||||
*
|
||||
* \returns the cross product of \c *this and \a other
|
||||
* \returns the cross product of \c *this and \a other. This is either a scalar for size-2 vectors or a size-3 vector for size-3 vectors.
|
||||
*
|
||||
* Here is a very good explanation of cross-product: http://xkcd.com/199/
|
||||
* This method is implemented for two different cases: between vectors of fixed size 2 and between vectors of fixed size 3.
|
||||
*
|
||||
* With complex numbers, the cross product is implemented as
|
||||
* \f$ (\mathbf{a}+i\mathbf{b}) \times (\mathbf{c}+i\mathbf{d}) = (\mathbf{a} \times \mathbf{c} - \mathbf{b} \times \mathbf{d}) - i(\mathbf{a} \times \mathbf{d} - \mathbf{b} \times \mathbf{c})\f$
|
||||
* For vectors of size 3, the output is simply the traditional cross product.
|
||||
*
|
||||
* For vectors of size 2, the output is a scalar.
|
||||
* Given vectors \f$ v = \begin{bmatrix} v_1 & v_2 \end{bmatrix} \f$ and \f$ w = \begin{bmatrix} w_1 & w_2 \end{bmatrix} \f$,
|
||||
* the result is simply \f$ v\times w = \overline{v_1 w_2 - v_2 w_1} = \text{conj}\left|\begin{smallmatrix} v_1 & w_1 \\ v_2 & w_2 \end{smallmatrix}\right| \f$;
|
||||
* or, to put it differently, it is the third coordinate of the cross product of \f$ \begin{bmatrix} v_1 & v_2 & v_3 \end{bmatrix} \f$ and \f$ \begin{bmatrix} w_1 & w_2 & w_3 \end{bmatrix} \f$.
|
||||
* For real-valued inputs, the result can be interpreted as the signed area of a parallelogram spanned by the two vectors.
|
||||
*
|
||||
* \note With complex numbers, the cross product is implemented as
|
||||
* \f$ (\mathbf{a}+i\mathbf{b}) \times (\mathbf{c}+i\mathbf{d}) = (\mathbf{a} \times \mathbf{c} - \mathbf{b} \times \mathbf{d}) - i(\mathbf{a} \times \mathbf{d} + \mathbf{b} \times \mathbf{c})\f$
|
||||
*
|
||||
* \sa MatrixBase::cross3()
|
||||
*/
|
||||
template<typename Derived>
|
||||
template<typename OtherDerived>
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
|
||||
typename MatrixBase<Derived>::template cross_product_return_type<OtherDerived>::type
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
typename internal::cross_impl<Derived, OtherDerived>::return_type
|
||||
#else
|
||||
typename MatrixBase<Derived>::PlainObject
|
||||
inline std::conditional_t<SizeAtCompileTime==2, Scalar, PlainObject>
|
||||
#endif
|
||||
MatrixBase<Derived>::cross(const MatrixBase<OtherDerived>& other) const
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Derived,3)
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,3)
|
||||
|
||||
// Note that there is no need for an expression here since the compiler
|
||||
// optimize such a small temporary very well (even within a complex expression)
|
||||
typename internal::nested_eval<Derived,2>::type lhs(derived());
|
||||
typename internal::nested_eval<OtherDerived,2>::type rhs(other.derived());
|
||||
return typename cross_product_return_type<OtherDerived>::type(
|
||||
numext::conj(lhs.coeff(1) * rhs.coeff(2) - lhs.coeff(2) * rhs.coeff(1)),
|
||||
numext::conj(lhs.coeff(2) * rhs.coeff(0) - lhs.coeff(0) * rhs.coeff(2)),
|
||||
numext::conj(lhs.coeff(0) * rhs.coeff(1) - lhs.coeff(1) * rhs.coeff(0))
|
||||
);
|
||||
return internal::cross_impl<Derived, OtherDerived>::run(*this, other);
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
@ -367,7 +367,8 @@ vec2 = vec1.normalized(); vec1.normalize(); // inplace \endcode
|
||||
<tr class="alt"><td>
|
||||
\link MatrixBase::cross() cross product \endlink \matrixworld</td><td>\code
|
||||
#include <Eigen/Geometry>
|
||||
vec3 = vec1.cross(vec2);\endcode</td></tr>
|
||||
v3c = v3a.cross(v3b); // size-3 vectors
|
||||
scalar = v2a.cross(v2b); // size-2 vectors \endcode</td></tr>
|
||||
</table>
|
||||
|
||||
<a href="#" class="top">top</a>
|
||||
|
@ -158,7 +158,7 @@ For dot product and cross product, you need the \link MatrixBase::dot() dot()\en
|
||||
\verbinclude tut_arithmetic_dot_cross.out
|
||||
</td></tr></table>
|
||||
|
||||
Remember that cross product is only for vectors of size 3. Dot product is for vectors of any sizes.
|
||||
Cross product is defined in Eigen not only for vectors of size 3 but also for those of size 2, check \link MatrixBase::cross() the doc\endlink for details. Dot product is for vectors of any sizes.
|
||||
When using complex numbers, Eigen's dot product is conjugate-linear in the first variable and linear in the
|
||||
second variable.
|
||||
|
||||
|
@ -9,5 +9,10 @@ int main()
|
||||
std::cout << "Dot product: " << v.dot(w) << std::endl;
|
||||
double dp = v.adjoint()*w; // automatic conversion of the inner product to a scalar
|
||||
std::cout << "Dot product via a matrix product: " << dp << std::endl;
|
||||
|
||||
std::cout << "Cross product:\n" << v.cross(w) << std::endl;
|
||||
Eigen::Vector2d v2(1,2);
|
||||
Eigen::Vector2d w2(0,1);
|
||||
double cp = v2.cross(w2); // returning a scalar between size-2 vectors
|
||||
std::cout << "Cross product for 2D vectors: " << cp << std::endl;
|
||||
}
|
||||
|
@ -78,6 +78,36 @@ template<typename Scalar> void orthomethods_3()
|
||||
VERIFY_IS_APPROX(v2.cross(v1), rv1.cross(v1));
|
||||
}
|
||||
|
||||
template<typename Scalar> void orthomethods_2()
|
||||
{
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar,2,1> Vector2;
|
||||
typedef Matrix<Scalar,3,1> Vector3;
|
||||
|
||||
Vector3 v30 = Vector3::Random(),
|
||||
v31 = Vector3::Random();
|
||||
Vector2 v20 = v30.template head<2>();
|
||||
Vector2 v21 = v31.template head<2>();
|
||||
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(v20.cross(v20), Scalar(1));
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(v21.cross(v21), Scalar(1));
|
||||
VERIFY_IS_APPROX(v20.cross(v21), v30.cross(v31).z());
|
||||
|
||||
Vector2 v20Rot90(numext::conj(-v20.y()), numext::conj(v20.x()));
|
||||
VERIFY_IS_APPROX(v20.cross( v20Rot90), v20.squaredNorm());
|
||||
VERIFY_IS_APPROX(v20.cross(-v20Rot90), -v20.squaredNorm());
|
||||
Vector2 v21Rot90(numext::conj(-v21.y()), numext::conj(v21.x()));
|
||||
VERIFY_IS_APPROX(v21.cross( v21Rot90), v21.squaredNorm());
|
||||
VERIFY_IS_APPROX(v21.cross(-v21Rot90), -v21.squaredNorm());
|
||||
|
||||
// check mixed product
|
||||
typedef Matrix<RealScalar, 2, 1> RealVector2;
|
||||
RealVector2 rv21 = RealVector2::Random();
|
||||
v21 = rv21.template cast<Scalar>();
|
||||
VERIFY_IS_APPROX(v20.cross(v21), v20.cross(rv21));
|
||||
VERIFY_IS_APPROX(v21.cross(v20), rv21.cross(v20));
|
||||
}
|
||||
|
||||
template<typename Scalar, int Size> void orthomethods(int size=Size)
|
||||
{
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
@ -119,6 +149,9 @@ template<typename Scalar, int Size> void orthomethods(int size=Size)
|
||||
EIGEN_DECLARE_TEST(geo_orthomethods)
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
CALL_SUBTEST_1( orthomethods_2<float>() );
|
||||
CALL_SUBTEST_2( orthomethods_2<double>() );
|
||||
CALL_SUBTEST_4( orthomethods_2<std::complex<double> >() );
|
||||
CALL_SUBTEST_1( orthomethods_3<float>() );
|
||||
CALL_SUBTEST_2( orthomethods_3<double>() );
|
||||
CALL_SUBTEST_4( orthomethods_3<std::complex<double> >() );
|
||||
|
Loading…
x
Reference in New Issue
Block a user