diff --git a/src/quaternion.hpp b/src/quaternion.hpp index 97c53d0a632f1a2dc0e1019686198a0515ee7bae..52c68cac23267895b714baa99549bd425ece50eb 100644 --- a/src/quaternion.hpp +++ b/src/quaternion.hpp @@ -28,7 +28,6 @@ namespace eigenpy class ExceptionIndex : public Exception { public: - int index; ExceptionIndex(int index,int imin,int imax) : Exception("") { std::ostringstream oss; oss << "Index " << index << " out of range " << imin << ".."<< imax <<"."; @@ -36,16 +35,6 @@ namespace eigenpy } }; - template<> - struct UnalignedEquivalent<Eigen::Quaterniond> - { -#ifndef EIGENPY_ALIGNED - typedef Eigen::Quaternion<Eigen::Quaterniond::Scalar,Eigen::DontAlign> type; -#else - typedef Eigen::Quaterniond type; -#endif - }; - namespace bp = boost::python; template<typename Quaternion> @@ -53,135 +42,169 @@ namespace eigenpy : public boost::python::def_visitor< QuaternionVisitor<Quaternion> > { typedef Eigen::QuaternionBase<Quaternion> QuaternionBase; - typedef typename eigenpy::UnalignedEquivalent<Quaternion>::type QuaternionUnaligned; typedef typename QuaternionBase::Scalar Scalar; - typedef typename QuaternionUnaligned::Coefficients Coefficients; -#ifndef EIGENPY_ALIGNED - typedef Eigen::Matrix<Scalar,3,1,Eigen::DontAlign> Vector3; - typedef Eigen::Matrix<Scalar,3,3,Eigen::DontAlign> Matrix3; -#else - typedef Eigen::Matrix<Scalar,3,1,0> Vector3; - typedef Eigen::Matrix<Scalar,3,3,0> Matrix3; -#endif + typedef typename Quaternion::Coefficients Coefficients; + typedef Eigen::Matrix<Scalar,3,1> Vector3; + typedef Eigen::Matrix<Scalar,4,1> Vector4; + typedef Eigen::Matrix<Scalar,3,3> Matrix3; - typedef Eigen::AngleAxis<Scalar> AngleAxisUnaligned; + typedef Eigen::AngleAxis<Scalar> AngleAxis; public: - /* Conversion from C++ to Python. */ - static PyObject* convert(Quaternion const& q) - { - QuaternionUnaligned qx = q; - return boost::python::incref(boost::python::object(qx).ptr()); - } - template<class PyClass> void visit(PyClass& cl) const { cl - .def(bp::init<Matrix3>((bp::arg("matrixRotation")),"Initialize from rotation matrix.")) - .def(bp::init<AngleAxisUnaligned>((bp::arg("angleaxis")),"Initialize from angle axis.")) - .def(bp::init<QuaternionUnaligned>((bp::arg("clone")),"Copy constructor.")) - .def("__init__",bp::make_constructor(&QuaternionVisitor::fromTwoVectors, - bp::default_call_policies(), - (bp::arg("u"),bp::arg("v"))),"Initialize from two vector u,v") - .def(bp::init<Scalar,Scalar,Scalar,Scalar> - ((bp::arg("w"),bp::arg("x"),bp::arg("y"),bp::arg("z")), - "Initialize from coefficients.\n\n" - "... note:: The order of coefficients is *w*, *x*, *y*, *z*. " - "The [] operator numbers them differently, 0...4 for *x* *y* *z* *w*!")) - - /* --- Methods --- */ - .def("coeffs",&QuaternionVisitor::coeffs) - .def("matrix",&QuaternionUnaligned::toRotationMatrix) + .def(bp::init<>("Default constructor")) + .def(bp::init<Matrix3>((bp::arg("matrixRotation")),"Initialize from rotation matrix.")) + .def(bp::init<AngleAxis>((bp::arg("angleaxis")),"Initialize from angle axis.")) + .def(bp::init<Quaternion>((bp::arg("clone")),"Copy constructor.")) + .def("__init__",bp::make_constructor(&QuaternionVisitor::fromTwoVectors, + bp::default_call_policies(), + (bp::arg("u"),bp::arg("v"))),"Initialize from two vector u,v") + .def(bp::init<Scalar,Scalar,Scalar,Scalar> + ((bp::arg("w"),bp::arg("x"),bp::arg("y"),bp::arg("z")), + "Initialize from coefficients.\n\n" + "... note:: The order of coefficients is *w*, *x*, *y*, *z*. " + "The [] operator numbers them differently, 0...4 for *x* *y* *z* *w*!")) + + .add_property("x", + (Scalar (Quaternion::*)()const)&Quaternion::x, + &QuaternionVisitor::setCoeff<0>,"The x coefficient.") + .add_property("y", + (Scalar (Quaternion::*)()const)&Quaternion::y, + &QuaternionVisitor::setCoeff<1>,"The y coefficient.") + .add_property("z", + (Scalar (Quaternion::*)()const)&Quaternion::z, + &QuaternionVisitor::setCoeff<2>,"The z coefficient.") + .add_property("w", + (Scalar (Quaternion::*)()const)&Quaternion::w, + &QuaternionVisitor::setCoeff<3>,"The w coefficient.") + + .def("isApprox",(bool (Quaternion::*)(const Quaternion &))&Quaternion::template isApprox<Quaternion>, + "Returns true if *this is approximately equal to other.") + .def("isApprox",(bool (Quaternion::*)(const Quaternion &, const Scalar prec))&Quaternion::template isApprox<Quaternion>, + "Returns true if *this is approximately equal to other, within the precision determined by prec..") + + /* --- Methods --- */ + .def("coeffs",(const Vector4 & (Quaternion::*)()const)&Quaternion::coeffs, + bp::return_value_policy<bp::copy_const_reference>()) + .def("matrix",&Quaternion::matrix,"Returns an equivalent rotation matrix") + .def("toRotationMatrix ",&Quaternion::toRotationMatrix,"Returns an equivalent 3x3 rotation matrix.") + + .def("setFromTwoVectors",&setFromTwoVectors,((bp::arg("a"),bp::arg("b"))),"Set *this to be the quaternion which transform a into b through a rotation." + ,bp::return_self<>()) + .def("conjugate",&Quaternion::conjugate,"Returns the conjugated quaternion. The conjugate of a quaternion represents the opposite rotation.") + .def("inverse",&Quaternion::inverse,"Returns the quaternion describing the inverse rotation.") + .def("setIdentity",&Quaternion::setIdentity,bp::return_self<>(),"Set *this to the idendity rotation.") + .def("norm",&Quaternion::norm,"Returns the norm of the quaternion's coefficients.") + .def("normalize",&Quaternion::normalize,"Normalizes the quaternion *this.") + .def("normalized",&Quaternion::normalized,"Returns a normalized copy of *this.") + .def("squaredNorm",&Quaternion::squaredNorm,"Returns the squared norm of the quaternion's coefficients.") + .def("dot",&Quaternion::template dot<Quaternion>,bp::arg("other"),"Returns the dot product of *this with other" + "Geometrically speaking, the dot product of two unit quaternions corresponds to the cosine of half the angle between the two rotations.") + .def("_transformVector",&Quaternion::_transformVector,bp::arg("vector"),"Rotation of a vector by a quaternion.") + .def("vec",&vec,"Returns a vector expression of the imaginary part (x,y,z).") + .def("angularDistance",&Quaternion::template angularDistance<Quaternion>,"Returns the angle (in radian) between two rotations.") + .def("slerp",&Quaternion::template slerp<Quaternion>,bp::args("t","other"), + "Returns the spherical linear interpolation between the two quaternions *this and other at the parameter t in [0;1].") + + /* --- Operators --- */ + .def(bp::self * bp::self) + .def(bp::self *= bp::self) + .def(bp::self * bp::other<Vector3>()) + .def("__eq__",&QuaternionVisitor::__eq__) + .def("__ne__",&QuaternionVisitor::__ne__) + .def("__abs__",&Quaternion::norm) + .def("__len__",&QuaternionVisitor::__len__).staticmethod("__len__") + .def("__setitem__",&QuaternionVisitor::__setitem__) + .def("__getitem__",&QuaternionVisitor::__getitem__) + .def("assign",&assign<Quaternion>, + bp::arg("quat"),"Set *this from an quaternion quat and returns a reference to *this.",bp::return_self<>()) + .def("assign",(Quaternion & (Quaternion::*)(const AngleAxis &))&Quaternion::operator=, + bp::arg("aa"),"Set *this from an angle-axis aa and returns a reference to *this.",bp::return_self<>()) + .def("__str__",&print) + .def("__repr__",&print) + + .def("FromTwoVectors",&Quaternion::template FromTwoVectors<Vector3,Vector3>, + bp::args("a","b"), + "Returns the quaternion which transform a into b through a rotation.") + .staticmethod("FromTwoVectors") + .def("Identity",&Quaternion::Identity,"Returns a quaternion representing an identity rotation.") + .staticmethod("Identity") - .def("setFromTwoVectors",&QuaternionVisitor::setFromTwoVectors,((bp::arg("u"),bp::arg("v")))) - .def("conjugate",&QuaternionUnaligned::conjugate) - .def("inverse",&QuaternionUnaligned::inverse) - .def("norm",&QuaternionUnaligned::norm) - .def("normalize",&QuaternionUnaligned::normalize) - .def("normalized",&QuaternionUnaligned::normalized) - .def("apply",&QuaternionUnaligned::_transformVector) - - /* --- Operators --- */ - .def(bp::self * bp::self) - .def(bp::self *= bp::self) - .def(bp::self * bp::other<Vector3>()) - .def("__eq__",&QuaternionVisitor::__eq__) - .def("__ne__",&QuaternionVisitor::__ne__) - .def("__abs__",&QuaternionUnaligned::norm) - .def("__len__",&QuaternionVisitor::__len__).staticmethod("__len__") - .def("__setitem__",&QuaternionVisitor::__setitem__) - .def("__getitem__",&QuaternionVisitor::__getitem__) - ; + + ; } private: - - static QuaternionUnaligned* fromTwoVectors(const Vector3& u, const Vector3& v) + + template<int i> + static void setCoeff(Quaternion & self, Scalar value) { self.coeffs()[i] = value; } + + static Quaternion & setFromTwoVectors(Quaternion & self, const Vector3 & a, const Vector3 & b) + { return self.setFromTwoVectors(a,b); } + + template<typename OtherQuat> + static Quaternion & assign(Quaternion & self, const OtherQuat & quat) + { return self = quat; } + + static Quaternion* fromTwoVectors(const Vector3& u, const Vector3& v) { - QuaternionUnaligned* q(new QuaternionUnaligned); q->setFromTwoVectors(u,v); + Quaternion* q(new Quaternion); q->setFromTwoVectors(u,v); return q; } - static Coefficients coeffs(const QuaternionUnaligned& self) - { - return self.coeffs(); - } - - static void setFromTwoVectors(QuaternionUnaligned& self, const Vector3& u, const Vector3& v) - { - self.setFromTwoVectors(u,v); - } - - static bool __eq__(const QuaternionUnaligned& u, const QuaternionUnaligned& v) + static bool __eq__(const Quaternion& u, const Quaternion& v) { return u.isApprox(v,1e-9); } - static bool __ne__(const QuaternionUnaligned& u, const QuaternionUnaligned& v) + + static bool __ne__(const Quaternion& u, const Quaternion& v) { return !__eq__(u,v); } - static double __getitem__(const QuaternionUnaligned & self, int idx) + static Scalar __getitem__(const Quaternion & self, int idx) { - if((idx<0) || (idx>4)) throw eigenpy::ExceptionIndex(idx,0,4); - if(idx==0) return self.x(); - else if(idx==1) return self.y(); - else if(idx==2) return self.z(); - else return self.w(); + if((idx<0) || (idx>=4)) throw eigenpy::ExceptionIndex(idx,0,3); + return self.coeffs()[idx]; } - static void __setitem__(QuaternionUnaligned& self, int idx, double value) + static void __setitem__(Quaternion& self, int idx, const Scalar value) { - if((idx<0) || (idx>4)) throw eigenpy::ExceptionIndex(idx,0,4); - if(idx==0) self.x()=value; - else if(idx==1) self.y()=value; - else if(idx==2) self.z()=value; - else self.w()=value; + if((idx<0) || (idx>=4)) throw eigenpy::ExceptionIndex(idx,0,3); + self.coeffs()[idx] = value; } - static int __len__() { return 4; } + static int __len__() { return 4; } + static Vector3 vec(const Quaternion & self) { return self.vec(); } + + static std::string print(const Quaternion & self) + { + std::stringstream ss; + ss << "(x,y,z,w) = " << self.coeffs().transpose() << std::endl; + + return ss.str(); + } public: static void expose() { - bp::class_<QuaternionUnaligned>("Quaternion", - "Quaternion representing rotation.\n\n" - "Supported operations " - "('q is a Quaternion, 'v' is a Vector3): " - "'q*q' (rotation composition), " - "'q*=q', " - "'q*v' (rotating 'v' by 'q'), " - "'q==q', 'q!=q', 'q[0..3]'.", - bp::init<>()) - .def(QuaternionVisitor<Quaternion>()) - ; + bp::class_<Quaternion>("Quaternion", + "Quaternion representing rotation.\n\n" + "Supported operations " + "('q is a Quaternion, 'v' is a Vector3): " + "'q*q' (rotation composition), " + "'q*=q', " + "'q*v' (rotating 'v' by 'q'), " + "'q==q', 'q!=q', 'q[0..3]'.", + bp::no_init) + .def(QuaternionVisitor<Quaternion>()) + ; -#ifndef EIGENPY_ALIGNED - bp::to_python_converter< Quaternion,QuaternionVisitor<Quaternion> >(); -#endif } };