~ubuntu-branches/ubuntu/utopic/minieigen/utopic-proposed

« back to all changes in this revision

Viewing changes to minieigen/visitors.hpp

  • Committer: Package Import Robot
  • Author(s): Anton Gladky, b285b23
  • Date: 2014-03-28 17:50:30 UTC
  • mfrom: (4.1.11 sid)
  • Revision ID: package-import@ubuntu.com-20140328175030-m63oavfy8k13kudg
Tags: 0.41~dfsg~bzr51-2
[b285b23] Fix autotest. Thanks to Martin Pitt <mpitt@debian.org>

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#pragma once
 
2
#include"common.hpp"
 
3
// classes dealing with exposing actual types, with many switches inside depending on template arguments
 
4
 
 
5
// methods common for vectors and matrices
 
6
template<typename MatrixBaseT>
 
7
class MatrixBaseVisitor: public py::def_visitor<MatrixBaseVisitor<MatrixBaseT> >{
 
8
        typedef typename MatrixBaseT::Scalar Scalar;
 
9
        public:
 
10
        template<class PyClass>
 
11
        void visit(PyClass& cl) const {
 
12
                cl
 
13
                .def(py::init<MatrixBaseT>(py::arg("other")))
 
14
                .def("__neg__",&MatrixBaseVisitor::__neg__)
 
15
                .def("__add__",&MatrixBaseVisitor::__add__).def("__iadd__",&MatrixBaseVisitor::__iadd__)
 
16
                .def("__sub__",&MatrixBaseVisitor::__sub__).def("__isub__",&MatrixBaseVisitor::__isub__)
 
17
                .def("__eq__",&MatrixBaseVisitor::__eq__).def("__ne__",&MatrixBaseVisitor::__ne__)
 
18
                .def("__mul__",&MatrixBaseVisitor::__mul__scalar<long>)
 
19
                .def("__imul__",&MatrixBaseVisitor::__imul__scalar<long>)
 
20
                .def("__rmul__",&MatrixBaseVisitor::__rmul__scalar<long>)
 
21
                .def("rows",&MatrixBaseT::rows,"Number of rows.")
 
22
                .def("cols",&MatrixBaseT::cols,"Number of columns.")
 
23
                ;
 
24
                visit_if_float<Scalar,PyClass>(cl);
 
25
                visit_fixed_or_dynamic<MatrixBaseT,PyClass>(cl);
 
26
 
 
27
                // reductions
 
28
                cl
 
29
                .def("sum",&MatrixBaseT::sum,"Sum of all elements.")
 
30
                .def("maxAbsCoeff",&MatrixBaseVisitor::maxAbsCoeff,"Maximum absolute value over all elements.")
 
31
                ;
 
32
        };
 
33
        private:
 
34
        template<class PyClass> static string name(PyClass& cl){ return py::extract<string>(cl.attr("__name__"))(); }
 
35
        // for dynamic matrices/vectors
 
36
        template<typename MatrixBaseT2, class PyClass> static void visit_fixed_or_dynamic(PyClass& cl, typename boost::enable_if_c<MatrixBaseT2::RowsAtCompileTime==Eigen::Dynamic>::type* dummy = 0){
 
37
                //std::cerr<<"MatrixBaseVisitor: dynamic MatrixBaseT for "<<name(cl)<<std::endl;
 
38
                ;
 
39
        }
 
40
        // for static matrices/vectors
 
41
        template<typename MatrixBaseT2, class PyClass> static void visit_fixed_or_dynamic(PyClass& cl, typename boost::disable_if_c<MatrixBaseT2::RowsAtCompileTime==Eigen::Dynamic>::type* dummy = 0){
 
42
                //std::cerr<<"MatrixBaseVisitor: fixed MatrixBaseT for "<<name(cl)<<std::endl;
 
43
                cl
 
44
                .add_static_property("Ones",&MatrixBaseVisitor::Ones)
 
45
                .add_static_property("Zero",&MatrixBaseVisitor::Zero)
 
46
                .def("Random",&MatrixBaseVisitor::Random,"Return an object where all elements are randomly set to values between 0 and 1.").staticmethod("Random")
 
47
                .add_static_property("Identity",&MatrixBaseVisitor::Identity)
 
48
                ;
 
49
        }
 
50
        template<typename Scalar, class PyClass> static void visit_if_float(PyClass& cl, typename boost::enable_if<boost::is_integral<Scalar> >::type* dummy = 0){ /* do nothing */ }
 
51
        template<typename Scalar, class PyClass> static void visit_if_float(PyClass& cl, typename boost::disable_if<boost::is_integral<Scalar> >::type* dummy = 0){
 
52
                // operations with other scalars (Scalar is the floating type, long is the python integer type)
 
53
                cl
 
54
                .def("__mul__",&MatrixBaseVisitor::__mul__scalar<Scalar>)
 
55
                .def("__rmul__",&MatrixBaseVisitor::__rmul__scalar<Scalar>)
 
56
                .def("__imul__",&MatrixBaseVisitor::__imul__scalar<Scalar>)
 
57
                .def("__div__",&MatrixBaseVisitor::__div__scalar<long>)
 
58
                .def("__idiv__",&MatrixBaseVisitor::__idiv__scalar<long>)
 
59
                .def("__div__",&MatrixBaseVisitor::__div__scalar<Scalar>)
 
60
                .def("__idiv__",&MatrixBaseVisitor::__idiv__scalar<Scalar>)
 
61
                //
 
62
                .def("norm",&MatrixBaseT::norm,"Euclidean norm.")
 
63
                .def("__abs__",&MatrixBaseT::norm)
 
64
                .def("squaredNorm",&MatrixBaseT::squaredNorm,"Square of the Euclidean norm.")
 
65
                .def("normalize",&MatrixBaseT::normalize,"Normalize this object in-place.")
 
66
                .def("normalized",&MatrixBaseT::normalized,"Return normalized copy of this object")
 
67
                .def("pruned",&MatrixBaseVisitor::pruned,py::arg("absTol")=1e-6,"Zero all elements which are greater than *absTol*. Negative zeros are not pruned.")
 
68
                ;
 
69
        }
 
70
        // for fixed-size matrices/vectors only
 
71
        static Scalar maxAbsCoeff(const MatrixBaseT& m){ return m.array().abs().maxCoeff(); }
 
72
        static MatrixBaseT Ones(){ return MatrixBaseT::Ones(); }
 
73
        static MatrixBaseT Zero(){ return MatrixBaseT::Zero(); }
 
74
        static MatrixBaseT Random(){ return MatrixBaseT::Random(); }
 
75
        static MatrixBaseT Identity(){ return MatrixBaseT::Identity(); }
 
76
 
 
77
        static bool __eq__(const MatrixBaseT& a, const MatrixBaseT& b){
 
78
                if(a.rows()!=b.rows() || a.cols()!=b.cols()) return false;
 
79
                return a.cwiseEqual(b).all();
 
80
        }
 
81
        static bool __ne__(const MatrixBaseT& a, const MatrixBaseT& b){ return !__eq__(a,b); }
 
82
        static MatrixBaseT __neg__(const MatrixBaseT& a){ return -a; };
 
83
        static MatrixBaseT __add__(const MatrixBaseT& a, const MatrixBaseT& b){ return a+b; }
 
84
        static MatrixBaseT __sub__(const MatrixBaseT& a, const MatrixBaseT& b){ return a-b; }
 
85
        static MatrixBaseT __iadd__(MatrixBaseT& a, const MatrixBaseT& b){ a+=b; return a; };
 
86
        static MatrixBaseT __isub__(MatrixBaseT& a, const MatrixBaseT& b){ a-=b; return a; };
 
87
 
 
88
        template<typename Scalar2> static MatrixBaseT __mul__scalar(const MatrixBaseT& a, const Scalar2& scalar){ return a*scalar; }
 
89
        template<typename Scalar2> static MatrixBaseT __imul__scalar(MatrixBaseT& a, const Scalar2& scalar){ a*=scalar; return a; }
 
90
        template<typename Scalar2> static MatrixBaseT __rmul__scalar(const MatrixBaseT& a, const Scalar2& scalar){ return a*scalar; }
 
91
        template<typename Scalar2> static MatrixBaseT __div__scalar(const MatrixBaseT& a, const Scalar2& scalar){ return a/scalar; }
 
92
        template<typename Scalar2> static MatrixBaseT __idiv__scalar(MatrixBaseT& a, const Scalar2& scalar){ a/=scalar; return a; }
 
93
 
 
94
        // we want to keep -0 (rather than replacing it by 0), but that does not work for complex numbers
 
95
        // hence two versions
 
96
        template<typename Scalar> static bool prune_element(const Scalar& num, double absTol, typename boost::disable_if<boost::is_complex<Scalar> >::type* dummy=0){ return std::abs(num)<=absTol || num!=-0; }
 
97
        template<typename Scalar> static bool prune_element(const Scalar& num, double absTol, typename boost::enable_if<boost::is_complex<Scalar> >::type* dummy=0){ return std::abs(num)<=absTol; }
 
98
        
 
99
        static MatrixBaseT pruned(const MatrixBaseT& a, double absTol=1e-6){ // typename MatrixBaseT::Scalar absTol=1e-6){
 
100
                MatrixBaseT ret(MatrixBaseT::Zero(a.rows(),a.cols()));
 
101
                for(Index c=0;c<a.cols();c++){ for(Index r=0;r<a.rows();r++){ if(!prune_element(a(c,r),absTol)) ret(c,r)=a(c,r); } }
 
102
                return ret;
 
103
        };
 
104
};
 
105
 
 
106
template<typename VectorT>
 
107
class VectorVisitor: public py::def_visitor<VectorVisitor<VectorT> >{
 
108
        friend class def_visitor_access;
 
109
        typedef typename VectorT::Scalar Scalar;
 
110
        typedef Eigen::Matrix<Scalar,VectorT::RowsAtCompileTime,VectorT::RowsAtCompileTime> CompatMatrixT;
 
111
        typedef Eigen::Matrix<Scalar,2,1> CompatVec2;
 
112
        typedef Eigen::Matrix<Scalar,3,1> CompatVec3;
 
113
        typedef Eigen::Matrix<Scalar,6,1> CompatVec6;
 
114
        typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> CompatVecX;
 
115
        enum{Dim=VectorT::RowsAtCompileTime};
 
116
        public:
 
117
        template<class PyClass>
 
118
        void visit(PyClass& cl) const {
 
119
                MatrixBaseVisitor<VectorT>().visit(cl);
 
120
                cl
 
121
                .def_pickle(VectorPickle())
 
122
                .def("__setitem__",&VectorVisitor::set_item)
 
123
                .def("__getitem__",&VectorVisitor::get_item)
 
124
                .def("__str__",&VectorVisitor::__str__).def("__repr__",&VectorVisitor::__str__)
 
125
                .def("dot",&VectorVisitor::dot,py::arg("other"),"Dot product with *other*.")
 
126
                .def("outer",&VectorVisitor::outer,py::arg("other"),"Outer product with *other*.")
 
127
                .def("asDiagonal",&VectorVisitor::asDiagonal,"Return diagonal matrix with this vector on the diagonal.")
 
128
                ;
 
129
 
 
130
                visit_fixed_or_dynamic<VectorT,PyClass>(cl);
 
131
 
 
132
                visit_special_sizes<VectorT,PyClass>(cl);
 
133
        };
 
134
        private:
 
135
        // for dynamic vectors
 
136
        template<typename VectorT2, class PyClass> static void visit_fixed_or_dynamic(PyClass& cl, typename boost::enable_if_c<VectorT2::RowsAtCompileTime==Eigen::Dynamic>::type* dummy = 0){
 
137
                //std::cerr<<"VectorVisitor: dynamic vector for "<<name()<<std::endl;
 
138
                cl
 
139
                .def("__len__",&VectorVisitor::dyn__len__)
 
140
                .def("resize",&VectorVisitor::resize)
 
141
                .def("Unit",&VectorVisitor::dyn_Unit).staticmethod("Unit")
 
142
                .def("Ones",&VectorVisitor::dyn_Ones).staticmethod("Ones")
 
143
                .def("Zero",&VectorVisitor::dyn_Zero).staticmethod("Zero")
 
144
                .def("Random",&VectorVisitor::dyn_Random,py::arg("len"),"Return vector of given length with all elements set to values between 0 and 1 randomly.").staticmethod("Random")
 
145
                ;
 
146
        }
 
147
        // for fixed-size vectors
 
148
        template<typename VectorT2, class PyClass> static void visit_fixed_or_dynamic(PyClass& cl, typename boost::disable_if_c<VectorT2::RowsAtCompileTime==Eigen::Dynamic>::type* dummy = 0){
 
149
                //std::cerr<<"VectorVisitor: fixed vector for "<<name()<<std::endl;
 
150
                cl.def("__len__",&VectorVisitor::__len__).staticmethod("__len__")
 
151
                .def("Unit",&VectorVisitor::Unit).staticmethod("Unit")
 
152
                ;
 
153
        }
 
154
 
 
155
        // handle specific sizes of vectors separately
 
156
 
 
157
        // 2-vector
 
158
        template<typename VectorT2, class PyClass> static void visit_special_sizes(PyClass& cl, typename boost::enable_if_c<VectorT2::RowsAtCompileTime==2>::type* dummy=0){
 
159
                cl
 
160
                .def(py::init<typename VectorT2::Scalar,typename VectorT2::Scalar>((py::arg("x"),py::arg("y"))))
 
161
                .add_static_property("UnitX",&VectorVisitor::Vec2_UnitX)
 
162
                .add_static_property("UnitY",&VectorVisitor::Vec2_UnitY)
 
163
                ;
 
164
        }
 
165
        static CompatVec2 Vec2_UnitX(){ return CompatVec2::UnitX(); }
 
166
        static CompatVec2 Vec2_UnitY(){ return CompatVec2::UnitY(); }
 
167
 
 
168
        // 3-vector
 
169
        template<typename VectorT2, class PyClass> static void visit_special_sizes(PyClass& cl, typename boost::enable_if_c<VectorT2::RowsAtCompileTime==3>::type* dummy=0){
 
170
                cl
 
171
                .def(py::init<typename VectorT2::Scalar,typename VectorT2::Scalar,typename VectorT2::Scalar>((py::arg("x"),py::arg("y"),py::arg("z"))))
 
172
                .def("cross",&VectorVisitor::cross) // cross-product only meaningful for 3-sized vectors
 
173
                .add_static_property("UnitX",&VectorVisitor::Vec3_UnitX)
 
174
                .add_static_property("UnitY",&VectorVisitor::Vec3_UnitY)
 
175
                .add_static_property("UnitZ",&VectorVisitor::Vec3_UnitZ)
 
176
                // swizzles
 
177
                .def("xy",&VectorVisitor::Vec3_xy).def("yx",&VectorVisitor::Vec3_yx).def("xz",&VectorVisitor::Vec3_xz).def("zx",&VectorVisitor::Vec3_zx).def("yz",&VectorVisitor::Vec3_yz).def("zy",&VectorVisitor::Vec3_zy)
 
178
                ;
 
179
        }
 
180
        static CompatVec3 cross(const CompatVec3& self, const CompatVec3& other){ return self.cross(other); }
 
181
        static CompatVec3 Vec3_UnitX(){ return CompatVec3::UnitX(); }
 
182
        static CompatVec3 Vec3_UnitY(){ return CompatVec3::UnitY(); }
 
183
        static CompatVec3 Vec3_UnitZ(){ return CompatVec3::UnitZ(); }
 
184
 
 
185
        static CompatVec2 Vec3_xy(const CompatVec3& v){ return CompatVec2(v[0],v[1]); }
 
186
        static CompatVec2 Vec3_yx(const CompatVec3& v){ return CompatVec2(v[1],v[0]); }
 
187
        static CompatVec2 Vec3_xz(const CompatVec3& v){ return CompatVec2(v[0],v[2]); }
 
188
        static CompatVec2 Vec3_zx(const CompatVec3& v){ return CompatVec2(v[2],v[0]); }
 
189
        static CompatVec2 Vec3_yz(const CompatVec3& v){ return CompatVec2(v[1],v[2]); }
 
190
        static CompatVec2 Vec3_zy(const CompatVec3& v){ return CompatVec2(v[2],v[1]); }
 
191
        
 
192
        // 6-vector
 
193
        template<typename VectorT2, class PyClass> static void visit_special_sizes(PyClass& cl, typename boost::enable_if_c<VectorT2::RowsAtCompileTime==6>::type* dummy=0){
 
194
                cl
 
195
                .def("__init__",py::make_constructor(&VectorVisitor::Vec6_fromElements,py::default_call_policies(),(py::arg("v0"),py::arg("v1"),py::arg("v2"),py::arg("v3"),py::arg("v4"),py::arg("v5"))))
 
196
                .def("__init__",py::make_constructor(&VectorVisitor::Vec6_fromHeadTail,py::default_call_policies(),(py::arg("head"),py::arg("tail"))))
 
197
                .def("head",&VectorVisitor::Vec6_head).def("tail",&VectorVisitor::Vec6_tail)
 
198
                ;
 
199
        }
 
200
        // only used with dim==6
 
201
        static CompatVec6* Vec6_fromElements(const Scalar& v0, const Scalar& v1, const Scalar& v2, const Scalar& v3, const Scalar& v4, const Scalar& v5){ CompatVec6* v(new CompatVec6); (*v)<<v0,v1,v2,v3,v4,v5; return v; }
 
202
        static CompatVec6* Vec6_fromHeadTail(const CompatVec3& head, const CompatVec3& tail){ CompatVec6* v(new CompatVec6); (*v)<<head,tail; return v; }
 
203
        static CompatVec3 Vec6_head(const CompatVec6& v){ return v.template head<3>(); }
 
204
        static CompatVec3 Vec6_tail(const CompatVec6& v){ return v.template tail<3>(); }
 
205
 
 
206
        // ctor for dynamic vectors
 
207
        template<typename VectorT2, class PyClass> static void visit_special_sizes(PyClass& cl, typename boost::enable_if_c<VectorT2::RowsAtCompileTime==Eigen::Dynamic>::type* dummy=0){
 
208
                cl
 
209
                .def("__init__",py::make_constructor(&VecX_fromList,py::default_call_policies(),(py::arg("vv"))))
 
210
                ;
 
211
        }
 
212
        static CompatVecX* VecX_fromList(const std::vector<Scalar>& ii){ CompatVecX* v(new CompatVecX(ii.size())); for(size_t i=0; i<ii.size(); i++) (*v)[i]=ii[i]; return v; }
 
213
 
 
214
 
 
215
        static VectorT dyn_Ones(Index size){ return VectorT::Ones(size); }
 
216
        static VectorT dyn_Zero(Index size){ return VectorT::Zero(size); }
 
217
        static VectorT dyn_Random(Index size){ return VectorT::Random(size); }
 
218
        static VectorT Unit(Index ix){ IDX_CHECK(ix,(Index)Dim); return VectorT::Unit(ix); }
 
219
        static VectorT dyn_Unit(Index size,Index ix){ IDX_CHECK(ix,size); return VectorT::Unit(size,ix); }
 
220
        static bool dyn(){ return Dim==Eigen::Dynamic; }
 
221
        static Index __len__(){ assert(!dyn()); return Dim; }
 
222
        static Index dyn__len__(const VectorT& self){ return self.size(); }
 
223
        static void resize(VectorT& self, Index size){ self.resize(size); }
 
224
        static Scalar dot(const VectorT& self, const VectorT& other){ return self.dot(other); }
 
225
        static CompatMatrixT outer(const VectorT& self, const VectorT& other){ return self*other.transpose(); }
 
226
        static CompatMatrixT asDiagonal(const VectorT& self){ return self.asDiagonal(); }
 
227
        static Scalar get_item(const VectorT& self, Index ix){ IDX_CHECK(ix,dyn()?(Index)self.size():(Index)Dim); return self[ix]; }
 
228
        static void set_item(VectorT& self, Index ix, Scalar value){ IDX_CHECK(ix,dyn()?(Index)self.size():(Index)Dim); self[ix]=value; }
 
229
        struct VectorPickle: py::pickle_suite{
 
230
                static py::tuple getinitargs(const VectorT& x){
 
231
                        // if this fails, add supported size to the switch below
 
232
                        BOOST_STATIC_ASSERT(Dim==2 || Dim==3 || Dim==6 || Dim==Eigen::Dynamic);
 
233
                        switch((Index)Dim){
 
234
                                case 2: return py::make_tuple(x[0],x[1]);
 
235
                                case 3: return py::make_tuple(x[0],x[1],x[2]);
 
236
                                case 6: return py::make_tuple(x[0],x[1],x[2],x[3],x[4],x[5]);
 
237
                                default: return py::make_tuple(py::list(x));
 
238
                        }
 
239
                };
 
240
        };
 
241
        public:
 
242
        static string __str__(const py::object& obj){
 
243
                std::ostringstream oss;
 
244
                const VectorT& self=py::extract<VectorT>(obj)();
 
245
                bool list=(Dim==Eigen::Dynamic && self.size()>0);
 
246
                oss<<object_class_name(obj)<<(list?"([":"(");
 
247
                Vector_data_stream(self,oss);
 
248
                oss<<(list?"])":")");
 
249
                return oss.str();
 
250
        };
 
251
 
 
252
        // not sure why this must be templated now?!
 
253
        template<typename VectorType>
 
254
        static void Vector_data_stream(const VectorType& self, std::ostringstream& oss, int pad=0){
 
255
                for(Index i=0; i<self.size(); i++) oss<<(i==0?"":(((i%3)!=0 || pad>0)?",":", "))<<num_to_string(self.row(i/self.cols())[i%self.cols()],/*pad*/pad);
 
256
        }
 
257
};
 
258
 
 
259
template<typename MatrixT>
 
260
class MatrixVisitor: public py::def_visitor<MatrixVisitor<MatrixT> >{
 
261
        friend class def_visitor_access;
 
262
        typedef typename MatrixT::Scalar Scalar;
 
263
        typedef typename Eigen::Matrix<Scalar,MatrixT::RowsAtCompileTime,1> CompatVectorT;
 
264
        typedef Eigen::Matrix<Scalar,3,3> CompatMat3;
 
265
        typedef Eigen::Matrix<Scalar,3,1> CompatVec3;
 
266
        typedef Eigen::Matrix<Scalar,6,6> CompatMat6;
 
267
        typedef Eigen::Matrix<Scalar,6,1> CompatVec6;
 
268
        typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> CompatMatX;
 
269
        typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> CompatVecX;
 
270
        enum{Dim=MatrixT::RowsAtCompileTime};
 
271
        public:
 
272
        template<class PyClass>
 
273
        void visit(PyClass& cl) const {
 
274
                MatrixBaseVisitor<MatrixT>().visit(cl);
 
275
                cl
 
276
                .def_pickle(MatrixPickle())
 
277
                .def("__init__",py::make_constructor(&MatrixVisitor::fromDiagonal,py::default_call_policies(),(py::arg("diag"))))
 
278
 
 
279
                .def("determinant",&MatrixT::determinant,"Return matrix determinant.")
 
280
                .def("trace",&MatrixT::trace,"Return sum of diagonal elements.")
 
281
                .def("transpose",&MatrixVisitor::transpose,"Return transposed matrix.")
 
282
                .def("diagonal",&MatrixVisitor::diagonal,"Return diagonal as vector.")
 
283
                .def("row",&MatrixVisitor::row,py::arg("row"),"Return row as vector.")
 
284
                .def("col",&MatrixVisitor::col,py::arg("col"),"Return column as vector.")
 
285
                // matrix*matrix product
 
286
                .def("__mul__",&MatrixVisitor::__mul__).def("__imul__",&MatrixVisitor::__imul__)
 
287
                // matrix*vector product
 
288
                .def("__mul__",&MatrixVisitor::__mul__vec).def("__rmul__",&MatrixVisitor::__mul__vec)
 
289
                .def("__setitem__",&MatrixVisitor::set_row).def("__getitem__",&MatrixVisitor::get_row)
 
290
                .def("__setitem__",&MatrixVisitor::set_item).def("__getitem__",&MatrixVisitor::get_item)
 
291
                .def("__str__",&MatrixVisitor::__str__).def("__repr__",&MatrixVisitor::__str__)
 
292
                ;
 
293
                visit_if_float<Scalar,PyClass>(cl);
 
294
                visit_fixed_or_dynamic<MatrixT,PyClass>(cl);
 
295
                visit_special_sizes<MatrixT,PyClass>(cl);
 
296
 
 
297
                //std::cerr<<"MatrixVisitor: "<<name()<<std::endl;
 
298
 
 
299
        }
 
300
        private:
 
301
        // for dynamic matrices
 
302
        template<typename MatrixT2, class PyClass> static void visit_fixed_or_dynamic(PyClass& cl, typename boost::enable_if_c<MatrixT2::RowsAtCompileTime==Eigen::Dynamic>::type* dummy = 0){
 
303
                cl
 
304
                .def("__len__",&MatrixVisitor::dyn__len__)
 
305
                .def("resize",&MatrixVisitor::resize,"Change size of the matrix, keep values of elements which exist in the new matrix",(py::arg("rows"),py::arg("cols")))
 
306
                .def("Ones",&MatrixVisitor::dyn_Ones,(py::arg("rows"),py::arg("cols")),"Create matrix of given dimensions where all elements are set to 1.").staticmethod("Ones")
 
307
                .def("Zero",&MatrixVisitor::dyn_Zero,(py::arg("rows"),py::arg("cols")),"Create zero matrix of given dimensions").staticmethod("Zero")
 
308
                .def("Random",&MatrixVisitor::dyn_Random,(py::arg("rows"),py::arg("cols")),"Create matrix with given dimensions where all elements are set to number between 0 and 1 (uniformly-distributed).").staticmethod("Random")
 
309
                .def("Identity",&MatrixVisitor::dyn_Identity,(py::arg("rank")),"Create identity matrix with given rank (square).").staticmethod("Identity")
 
310
                ;
 
311
        }
 
312
        // for fixed-size matrices
 
313
        template<typename MatrixT2, class PyClass> static void visit_fixed_or_dynamic(PyClass& cl, typename boost::disable_if_c<MatrixT2::RowsAtCompileTime==Eigen::Dynamic>::type* dummy = 0){
 
314
                cl.def("__len__",&MatrixVisitor::__len__).staticmethod("__len__")
 
315
                ;
 
316
        }
 
317
 
 
318
        template<typename Scalar, class PyClass> static void visit_if_float(PyClass& cl, typename boost::enable_if<boost::is_integral<Scalar> >::type* dummy = 0){ /* do nothing */ }
 
319
        template<typename Scalar, class PyClass> static void visit_if_float(PyClass& cl, typename boost::disable_if<boost::is_integral<Scalar> >::type* dummy = 0){
 
320
                cl
 
321
                // matrix-matrix division?!
 
322
                //.def("__div__",&MatrixBaseVisitor::__div__).def("__idiv__",&MatrixBaseVisitor::__idiv__)
 
323
                .def("inverse",&MatrixVisitor::inverse,"Return inverted matrix.");
 
324
                // decompositions are only meaningful on non-complex numbers
 
325
                visit_if_decompositions_meaningful<Scalar,PyClass>(cl);
 
326
        }
 
327
        // for complex numbers, do nothing
 
328
        template<typename Scalar, class PyClass> static void visit_if_decompositions_meaningful(PyClass& cl, typename boost::enable_if<boost::is_complex<Scalar> >::type* dummy = 0){ /* do nothing */ }
 
329
        // for non-complex numbers, define decompositions
 
330
        template<typename Scalar, class PyClass> static void visit_if_decompositions_meaningful(PyClass& cl, typename boost::disable_if<boost::is_complex<Scalar> >::type* dummy = 0){
 
331
                cl
 
332
                .def("jacobiSVD",&MatrixVisitor::jacobiSVD,"Compute SVD decomposition of square matrix, retuns (U,S,V) such that self=U*S*V.transpose()")
 
333
                .def("svd",&MatrixVisitor::jacobiSVD,"Alias for :obj:`jacobiSVD`.")
 
334
                .def("computeUnitaryPositive",&MatrixVisitor::computeUnitaryPositive,"Compute polar decomposition (unitary matrix U and positive semi-definite symmetric matrix P such that self=U*P).")
 
335
                .def("polarDecomposition",&MatrixVisitor::computeUnitaryPositive,"Alias for :obj:`computeUnitaryPositive`.")
 
336
                .def("selfAdjointEigenDecomposition",&MatrixVisitor::selfAdjointEigenDecomposition,"Compute eigen (spectral) decomposition of symmetric matrix, returns (eigVecs,eigVals). eigVecs is orthogonal Matrix3 with columns ar normalized eigenvectors, eigVals is Vector3 with corresponding eigenvalues. self=eigVecs*diag(eigVals)*eigVecs.transpose().")
 
337
                .def("spectralDecomposition",&MatrixVisitor::selfAdjointEigenDecomposition,"Alias for :obj:`selfAdjointEigenDecomposition`.")
 
338
                ;
 
339
        }
 
340
 
 
341
        // handle specific matrix sizes
 
342
        // 3x3
 
343
        template<typename MatT2, class PyClass> static void visit_special_sizes(PyClass& cl, typename boost::enable_if_c<MatT2::RowsAtCompileTime==3>::type* dummy=0){
 
344
                cl
 
345
                .def("__init__",py::make_constructor(&MatrixVisitor::Mat3_fromElements,py::default_call_policies(),(py::arg("m00"),py::arg("m01"),py::arg("m02"),py::arg("m10"),py::arg("m11"),py::arg("m12"),py::arg("m20"),py::arg("m21"),py::arg("m22"))))
 
346
                .def("__init__",py::make_constructor(&MatrixVisitor::Mat3_fromRows,py::default_call_policies(),(py::arg("r0"),py::arg("r1"),py::arg("r2"),py::arg("cols")=false)))
 
347
                ;
 
348
        }
 
349
        static CompatMat3* Mat3_fromElements(const Scalar& m00, const Scalar& m01, const Scalar& m02, const Scalar& m10, const Scalar& m11, const Scalar& m12, const Scalar& m20, const Scalar& m21, const Scalar& m22){ CompatMat3* m(new CompatMat3); (*m)<<m00,m01,m02,m10,m11,m12,m20,m21,m22; return m; }
 
350
        static CompatMat3* Mat3_fromRows(const CompatVec3& l0, const CompatVec3& l1, const CompatVec3& l2, bool cols=false){ CompatMat3* m(new CompatMat3); if(cols){m->col(0)=l0; m->col(1)=l1; m->col(2)=l2; } else {m->row(0)=l0; m->row(1)=l1; m->row(2)=l2;} return m; }
 
351
 
 
352
        // 6x6
 
353
        template<typename MatT2, class PyClass> static void visit_special_sizes(PyClass& cl, typename boost::enable_if_c<MatT2::RowsAtCompileTime==6>::type* dummy=0){
 
354
                cl
 
355
                .def("__init__",py::make_constructor(&MatrixVisitor::Mat6_fromBlocks,py::default_call_policies(),(py::arg("ul"),py::arg("ur"),py::arg("ll"),py::arg("lr"))))
 
356
                .def("__init__",py::make_constructor(&MatrixVisitor::Mat6_fromRows,py::default_call_policies(),(py::arg("l0"),py::arg("l1"),py::arg("l2"),py::arg("l3"),py::arg("l4"),py::arg("l5"),py::arg("cols")=false)))
 
357
                /* 3x3 blocks */
 
358
                        .def("ul",&MatrixVisitor::Mat6_ul,"Return upper-left 3x3 block")
 
359
                        .def("ur",&MatrixVisitor::Mat6_ur,"Return upper-right 3x3 block")
 
360
                        .def("ll",&MatrixVisitor::Mat6_ll,"Return lower-left 3x3 block")
 
361
                        .def("lr",&MatrixVisitor::Mat6_lr,"Return lower-right 3x3 block")
 
362
                ;
 
363
        }
 
364
        static CompatMat6* Mat6_fromBlocks(const CompatMat3& ul, const CompatMat3& ur, const CompatMat3& ll, const CompatMat3& lr){ CompatMat6* m(new CompatMat6); (*m)<<ul,ur,ll,lr; return m; }
 
365
        static CompatMat6* Mat6_fromRows(const CompatVec6& l0, const CompatVec6& l1, const CompatVec6& l2, const CompatVec6& l3, const CompatVec6& l4, const CompatVec6& l5, bool cols=false){ CompatMat6* m(new CompatMat6); if(cols){ m->col(0)=l0; m->col(1)=l1; m->col(2)=l2; m->col(3)=l3; m->col(4)=l4; m->col(5)=l5; } else { m->row(0)=l0; m->row(1)=l1; m->row(2)=l2; m->row(3)=l3; m->row(4)=l4; m->row(5)=l5; } return m; }
 
366
                // see http://stackoverflow.com/questions/20870648/error-in-seemingly-correct-template-code-whats-wrong#20870661
 
367
                // on why the template keyword is needed after the m.
 
368
                static CompatMat3 Mat6_ul(const CompatMat6& m){ return m.template topLeftCorner<3,3>(); }
 
369
                static CompatMat3 Mat6_ur(const CompatMat6& m){ return m.template topRightCorner<3,3>(); }
 
370
                static CompatMat3 Mat6_ll(const CompatMat6& m){ return m.template bottomLeftCorner<3,3>(); }
 
371
                static CompatMat3 Mat6_lr(const CompatMat6& m){ return m.template bottomRightCorner<3,3>(); }
 
372
 
 
373
        // XxX
 
374
        template<typename MatT2, class PyClass> static void visit_special_sizes(PyClass& cl, typename boost::enable_if_c<MatT2::RowsAtCompileTime==Eigen::Dynamic>::type* dummy=0){
 
375
                cl
 
376
                .def("__init__",py::make_constructor(&MatrixVisitor::MatX_fromRows,py::default_call_policies(),(py::arg("r0")=CompatVecX(),py::arg("r1")=CompatVecX(),py::arg("r2")=CompatVecX(),py::arg("r3")=CompatVecX(),py::arg("r4")=CompatVecX(),py::arg("r5")=CompatVecX(),py::arg("r6")=CompatVecX(),py::arg("r7")=CompatVecX(),py::arg("r8")=CompatVecX(),py::arg("r9")=CompatVecX(),py::arg("cols")=false)))
 
377
                .def("__init__",py::make_constructor(&MatrixVisitor::MatX_fromRowSeq,py::default_call_policies(),(py::arg("rows"),py::arg("cols")=false)))
 
378
                ;
 
379
        }
 
380
 
 
381
        static CompatMatX* MatX_fromRows(const CompatVecX& r0, const CompatVecX& r1, const CompatVecX& r2, const CompatVecX& r3, const CompatVecX& r4, const CompatVecX& r5, const CompatVecX& r6, const CompatVecX& r7, const CompatVecX& r8, const CompatVecX& r9, bool setCols){
 
382
                /* check vector dimensions */ CompatVecX rr[]={r0,r1,r2,r3,r4,r5,r6,r7,r8,r9};
 
383
                int cols=-1, rows=-1;
 
384
                for(int i=0; i<10; i++){
 
385
                        if(rows<0 && rr[i].size()==0) rows=i;
 
386
                        if(rows>=0 && rr[i].size()>0) throw std::invalid_argument("Matrix6r: non-empty rows not allowed after first empty row, which marks end of the matrix.");
 
387
                }
 
388
                cols=(rows>0?rr[0].size():0);
 
389
                for(int i=1; i<rows; i++) if(rr[i].size()!=cols) throw std::invalid_argument(("Matrix6: all non-empty rows must have the same length (0th row has "+lexical_cast<string>(rr[0].size())+" items, "+lexical_cast<string>(i)+"th row has "+lexical_cast<string>(rr[i].size())+" items)").c_str());
 
390
                CompatMatX* m;
 
391
                m=setCols?new CompatMatX(cols,rows):new CompatMatX(rows,cols);
 
392
                for(int i=0; i<rows; i++){ if(setCols) m->col(i)=rr[i]; else m->row(i)=rr[i]; }
 
393
                return m;
 
394
        }
 
395
        static CompatMatX* MatX_fromRowSeq(const std::vector<CompatVecX>& rr, bool setCols){
 
396
                int rows=rr.size(),cols=rr.size()>0?rr[0].size():0;
 
397
                for(int i=1; i<rows; i++) if(rr[i].size()!=cols) throw std::invalid_argument(("MatrixX: all rows must have the same length."));
 
398
                CompatMatX* m;
 
399
                m=setCols?new CompatMatX(cols,rows):new CompatMatX(rows,cols);
 
400
                for(int i=0; i<rows; i++){ if(setCols) m->col(i)=rr[i]; else m->row(i)=rr[i]; }
 
401
                return m;
 
402
        };
 
403
 
 
404
 
 
405
        static MatrixT dyn_Ones(Index rows, Index cols){ return MatrixT::Ones(rows,cols); }
 
406
        static MatrixT dyn_Zero(Index rows, Index cols){ return MatrixT::Zero(rows,cols); }
 
407
        static MatrixT dyn_Random(Index rows, Index cols){ return MatrixT::Random(rows,cols); }
 
408
        static MatrixT dyn_Identity(Index rows, Index cols){ return MatrixT::Identity(rows,cols); }
 
409
        static typename MatrixT::Index dyn__len__(MatrixT& a){ return a.rows(); }
 
410
        static typename MatrixT::Index __len__(){ return MatrixT::RowsAtCompileTime; }
 
411
        static MatrixT Identity(){ return MatrixT::Identity(); }
 
412
        static MatrixT transpose(const MatrixT& m){ return m.transpose(); }
 
413
        static CompatVectorT diagonal(const MatrixT& m){ return m.diagonal(); }
 
414
        static MatrixT* fromDiagonal(const CompatVectorT& d){ MatrixT* m(new MatrixT); *m=d.asDiagonal(); return m; }
 
415
        static void resize(MatrixT& self, Index rows, Index cols){ self.resize(rows,cols); }
 
416
        static CompatVectorT get_row(const MatrixT& a, Index ix){ IDX_CHECK(ix,a.rows()); return a.row(ix); }
 
417
        static void set_row(MatrixT& a, Index ix, const CompatVectorT& r){ IDX_CHECK(ix,a.rows()); a.row(ix)=r; }
 
418
        static Scalar get_item(const MatrixT& a, py::tuple _idx){ Index idx[2]; Index mx[2]={a.rows(),a.cols()}; IDX2_CHECKED_TUPLE_INTS(_idx,mx,idx); return a(idx[0],idx[1]); }
 
419
        static void set_item(MatrixT& a, py::tuple _idx, const Scalar& value){ Index idx[2]; Index mx[2]={a.rows(),a.cols()}; IDX2_CHECKED_TUPLE_INTS(_idx,mx,idx); a(idx[0],idx[1])=value; }
 
420
 
 
421
        static MatrixT __imul__(MatrixT& a, const MatrixT& b){ a*=b; return a; };
 
422
        static MatrixT __mul__(const MatrixT& a, const MatrixT& b){ return a*b; }
 
423
        static CompatVectorT __mul__vec(const MatrixT& m, const CompatVectorT& v){ return m*v; }
 
424
        // float matrices only
 
425
        static MatrixT inverse(const MatrixT& m){ return m.inverse(); }
 
426
        static MatrixT __div__(const MatrixT& a, const MatrixT& b){ return a/b; }
 
427
        // static void __idiv__(MatrixT& a, const MatrixT& b){ a/=b; };
 
428
        static CompatVectorT row(const MatrixT& m, Index ix){ IDX_CHECK(ix,m.rows()); return m.row(ix); }
 
429
        static CompatVectorT col(const MatrixT& m, Index ix){ IDX_CHECK(ix,m.cols()); return m.col(ix); }
 
430
 
 
431
        static void ensureSquare(const MatrixT& m){ if(m.rows()!=m.cols()) throw std::runtime_error("Matrix is not square."); }
 
432
        static py::tuple jacobiSVD(const MatrixT& in) {
 
433
                ensureSquare(in);
 
434
                Eigen::JacobiSVD<MatrixT> svd(in, Eigen::ComputeThinU | Eigen::ComputeThinV);
 
435
                return py::make_tuple(svd.matrixU(),svd.matrixV(),MatrixT(svd.singularValues().asDiagonal()));
 
436
        };
 
437
        // polar decomposition
 
438
        static py::tuple computeUnitaryPositive(const MatrixT& in) {
 
439
                ensureSquare(in);
 
440
                Eigen::JacobiSVD<MatrixT> svd(in, Eigen::ComputeThinU | Eigen::ComputeThinV);
 
441
                const MatrixT& u=svd.matrixU(); const MatrixT& v=svd.matrixV();
 
442
                MatrixT s=svd.singularValues().asDiagonal();
 
443
                return py::make_tuple(u*v.transpose(),v*s*v.transpose());
 
444
        }
 
445
        // eigen decomposition
 
446
        static py::tuple selfAdjointEigenDecomposition(const MatrixT& in) {
 
447
                ensureSquare(in);
 
448
                Eigen::SelfAdjointEigenSolver<MatrixT> a(in);
 
449
                return py::make_tuple(a.eigenvectors(),a.eigenvalues());
 
450
        }
 
451
        static bool dyn(){ return Dim==Eigen::Dynamic; }
 
452
        static string __str__(const py::object& obj){
 
453
                std::ostringstream oss;
 
454
                const MatrixT& m=py::extract<MatrixT>(obj)();
 
455
                oss<<object_class_name(obj)<<"(";
 
456
                bool wrap=((dyn() && m.rows()>1) || (!dyn() && m.rows()>3));
 
457
                // non-wrapping fixed-size: flat list of numbers, not rows as tuples (Matrix3)
 
458
                if(!dyn() && !wrap){
 
459
                        VectorVisitor<CompatVectorT>::template Vector_data_stream<MatrixT>(m,oss,/*pad=*/0);
 
460
                } else {
 
461
                        if(wrap) oss<<"\n";
 
462
                        for(Index r=0; r<m.rows(); r++){
 
463
                                oss<<(wrap?"\t":"")<<"(";
 
464
                                VectorVisitor<CompatVectorT>::template Vector_data_stream<CompatVectorT>(m.row(r),oss,/*pad=*/(wrap?7:0));
 
465
                                oss<<")"<<(r<m.rows()-1?",":"")<<(wrap?"\n":"");
 
466
                        }
 
467
                }
 
468
                oss<<")";
 
469
                return oss.str();
 
470
        }
 
471
        struct MatrixPickle: py::pickle_suite{
 
472
                static py::tuple getinitargs(const MatrixT& x){
 
473
                        // if this fails, add supported size to the switch below
 
474
                        BOOST_STATIC_ASSERT(Dim==2 || Dim==3 || Dim==6 || Dim==Eigen::Dynamic);
 
475
                        switch((Index)Dim){
 
476
                                case 2: return py::make_tuple(x(0,0),x(0,1),x(1,0),x(1,1));
 
477
                                case 3: return py::make_tuple(x(0,0),x(0,1),x(0,2),x(1,0),x(1,1),x(1,2),x(2,0),x(2,1),x(2,2));
 
478
                                case 6: return py::make_tuple(x.row(0),x.row(1),x.row(2),x.row(3),x.row(4),x.row(5));
 
479
                                // should return list of rows, which are VectorX
 
480
                                default: return py::make_tuple(py::list(x));
 
481
                        }
 
482
                };
 
483
        };
 
484
};
 
485
 
 
486
 
 
487
template<typename Box>
 
488
class AabbVisitor: public py::def_visitor<AabbVisitor<Box> >{
 
489
        friend class def_visitor_access;
 
490
        typedef typename Box::VectorType VectorType;
 
491
        typedef typename Box::Scalar Scalar;
 
492
        public:
 
493
        template <class PyClass>
 
494
        void visit(PyClass& cl) const {
 
495
                cl
 
496
                .def(py::init<Box>(py::arg("other")))
 
497
                .def(py::init<VectorType,VectorType>((py::arg("min"),py::arg("max"))))
 
498
                .def_pickle(BoxPickle())
 
499
                .def("volume",&Box::volume)
 
500
                .def("empty",&Box::isEmpty)
 
501
                .def("center",&AabbVisitor::center)
 
502
                .def("sizes",&AabbVisitor::sizes)
 
503
                .def("contains",&AabbVisitor::containsPt)
 
504
                .def("contains",&AabbVisitor::containsBox)
 
505
                // for the "in" operator
 
506
                .def("__contains__",&AabbVisitor::containsPt) 
 
507
                .def("__contains__",&AabbVisitor::containsBox)
 
508
                .def("extend",&AabbVisitor::extendPt)
 
509
                .def("extend",&AabbVisitor::extendBox)
 
510
                .def("clamp",&AabbVisitor::clamp)
 
511
                // return new objects
 
512
                .def("intersection",&Box::intersection)
 
513
                .def("merged",&Box::merged)
 
514
                // those return internal references, which is what we want (FIXME: this is not true, they return copies!!)
 
515
                .add_property("min",&AabbVisitor::min) 
 
516
                .add_property("max",&AabbVisitor::max)
 
517
                .def("__len__",&AabbVisitor::len).staticmethod("__len__")
 
518
                .def("__setitem__",&AabbVisitor::set_item).def("__getitem__",&AabbVisitor::get_item)
 
519
                .def("__setitem__",&AabbVisitor::set_minmax).def("__getitem__",&AabbVisitor::get_minmax)
 
520
                .def("__str__",&AabbVisitor::__str__).def("__repr__",&AabbVisitor::__str__)
 
521
                ;
 
522
        };
 
523
        private:
 
524
        static bool containsPt(const Box& self, const VectorType& pt){ return self.contains(pt); }
 
525
        static bool containsBox(const Box& self, const Box& other){ return self.contains(other); }
 
526
        static void extendPt(Box& self, const VectorType& pt){ self.extend(pt); }
 
527
        static void extendBox(Box& self, const Box& other){ self.extend(other); }
 
528
        static void clamp(Box& self, const Box& other){ self.clamp(other); }
 
529
        static VectorType min(const Box& self){ return self.min(); }
 
530
        static VectorType max(const Box& self){ return self.max(); }
 
531
        static VectorType center(const Box& self){ return self.center(); }
 
532
        static VectorType sizes(const Box& self){ return self.sizes(); }
 
533
        struct BoxPickle: py::pickle_suite{
 
534
                static py::tuple getinitargs(const Box& x){ return py::make_tuple(x.min(),x.max()); }
 
535
        };
 
536
        static Index len(){ return Box::AmbientDimAtCompileTime; }
 
537
        // getters and setters 
 
538
        static Scalar get_item(const Box& self, py::tuple _idx){ Index idx[2]; Index mx[2]={2,Box::AmbientDimAtCompileTime}; IDX2_CHECKED_TUPLE_INTS(_idx,mx,idx); if(idx[0]==0) return self.min()[idx[1]]; return self.max()[idx[1]]; }
 
539
        static void set_item(Box& self, py::tuple _idx, Scalar value){ Index idx[2]; Index mx[2]={2,Box::AmbientDimAtCompileTime}; IDX2_CHECKED_TUPLE_INTS(_idx,mx,idx); if(idx[0]==0) self.min()[idx[1]]=value; else self.max()[idx[1]]=value; }
 
540
        static VectorType get_minmax(const Box& self, Index idx){ IDX_CHECK(idx,2); if(idx==0) return self.min(); return self.max(); }
 
541
        static void set_minmax(Box& self, Index idx, const VectorType& value){ IDX_CHECK(idx,2); if(idx==0) self.min()=value; else self.max()=value; }
 
542
        static string __str__(const py::object& obj){
 
543
                const Box& self=py::extract<Box>(obj)();
 
544
                std::ostringstream oss; oss<<object_class_name(obj)<<"((";
 
545
                VectorVisitor<VectorType>::template Vector_data_stream<VectorType>(self.min(),oss);
 
546
                oss<<"), (";
 
547
                VectorVisitor<VectorType>::template Vector_data_stream<VectorType>(self.max(),oss);
 
548
                oss<<"))";
 
549
                return oss.str();
 
550
        }
 
551
};
 
552
 
 
553
template<typename QuaternionT>
 
554
class QuaternionVisitor:  public py::def_visitor<QuaternionVisitor<QuaternionT> >{
 
555
        typedef typename QuaternionT::Scalar Scalar;
 
556
        typedef Eigen::Matrix<Scalar,3,1> CompatVec3;
 
557
        typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> CompatVecX;
 
558
        typedef Eigen::Matrix<Scalar,3,3> CompatMat3;
 
559
        typedef Eigen::AngleAxis<Scalar> AngleAxisT;
 
560
        public:
 
561
        template<class PyClass>
 
562
        void visit(PyClass& cl) const {
 
563
                cl
 
564
                .def("__init__",py::make_constructor(&QuaternionVisitor::fromAxisAngle,py::default_call_policies(),(py::arg("axis"),py::arg("angle"))))
 
565
                .def("__init__",py::make_constructor(&QuaternionVisitor::fromAngleAxis,py::default_call_policies(),(py::arg("angle"),py::arg("axis"))))
 
566
                .def("__init__",py::make_constructor(&QuaternionVisitor::fromTwoVectors,py::default_call_policies(),(py::arg("u"),py::arg("v"))))
 
567
                .def(py::init<Scalar,Scalar,Scalar,Scalar>((py::arg("w"),py::arg("x"),py::arg("y"),py::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*!"))
 
568
                .def(py::init<CompatMat3>((py::arg("rotMatrix")))) //,"Initialize from given rotation matrix.")
 
569
                .def(py::init<QuaternionT>((py::arg("other"))))
 
570
                .def_pickle(QuaternionPickle())
 
571
                // properties
 
572
                .add_static_property("Identity",&QuaternionVisitor::Identity)
 
573
                // methods
 
574
                .def("setFromTwoVectors",&QuaternionVisitor::setFromTwoVectors,((py::arg("u"),py::arg("v"))))
 
575
                .def("conjugate",&QuaternionT::conjugate)
 
576
                .def("toAxisAngle",&QuaternionVisitor::toAxisAngle)
 
577
                .def("toAngleAxis",&QuaternionVisitor::toAngleAxis)
 
578
                .def("toRotationMatrix",&QuaternionT::toRotationMatrix)
 
579
                .def("toRotationVector",&QuaternionVisitor::toRotationVector)
 
580
                .def("Rotate",&QuaternionVisitor::Rotate,((py::arg("v"))))
 
581
                .def("inverse",&QuaternionT::inverse)
 
582
                .def("norm",&QuaternionT::norm)
 
583
                .def("normalize",&QuaternionT::normalize)
 
584
                .def("normalized",&QuaternionT::normalized)
 
585
                // .def("random",&QuaternionVisitor::random,"Assign random orientation to the quaternion.")
 
586
                // operators
 
587
                .def(py::self * py::self)
 
588
                .def(py::self *= py::self)
 
589
                .def(py::self * py::other<CompatVec3>())
 
590
                .def("__eq__",&QuaternionVisitor::__eq__).def("__ne__",&QuaternionVisitor::__ne__)
 
591
                .def("__sub__",&QuaternionVisitor::__sub__) 
 
592
                // specials
 
593
                .def("__abs__",&QuaternionT::norm)
 
594
                .def("__len__",&QuaternionVisitor::__len__).staticmethod("__len__")
 
595
                .def("__setitem__",&QuaternionVisitor::__setitem__).def("__getitem__",&QuaternionVisitor::__getitem__)
 
596
                .def("__str__",&QuaternionVisitor::__str__).def("__repr__",&QuaternionVisitor::__str__)
 
597
                ;
 
598
        }
 
599
        private:
 
600
        static QuaternionT* fromAxisAngle(const CompatVec3& axis, const Scalar& angle){ return new QuaternionT(AngleAxisT(angle,axis)); }
 
601
        static QuaternionT* fromAngleAxis(const Scalar& angle, const CompatVec3& axis){ return new QuaternionT(AngleAxisT(angle,axis)); }
 
602
        static QuaternionT* fromTwoVectors(const CompatVec3& u, const CompatVec3& v){ QuaternionT* q(new QuaternionT); q->setFromTwoVectors(u,v); return q; }
 
603
 
 
604
        struct QuaternionPickle: py::pickle_suite{static py::tuple getinitargs(const QuaternionT& x){ return py::make_tuple(x.w(),x.x(),x.y(),x.z());} };
 
605
        static QuaternionT Identity(){ return QuaternionT::Identity(); }
 
606
        static Vector3r Rotate(const QuaternionT& self, const Vector3r& u){ return self*u; }
 
607
        static py::tuple toAxisAngle(const QuaternionT& self){ AngleAxisT aa(self); return py::make_tuple(aa.axis(),aa.angle());}
 
608
        static py::tuple toAngleAxis(const QuaternionT& self){ AngleAxisT aa(self); return py::make_tuple(aa.angle(),aa.axis());}
 
609
        static CompatVec3 toRotationVector(const QuaternionT& self){ AngleAxisT aa(self); return aa.angle()*aa.axis();}
 
610
        static void setFromTwoVectors(QuaternionT& self, const Vector3r& u, const Vector3r& v){ self.setFromTwoVectors(u,v); /*return self;*/ }
 
611
 
 
612
        static bool __eq__(const QuaternionT& u, const QuaternionT& v){ return u.x()==v.x() && u.y()==v.y() && u.z()==v.z() && u.w()==v.w(); }
 
613
        static bool __ne__(const QuaternionT& u, const QuaternionT& v){ return !__eq__(u,v); }
 
614
        static CompatVecX __sub__(const QuaternionT& a, const QuaternionT& b){ CompatVecX r(4); r<<a.w()-b.w(),a.x()-b.x(),a.y()-b.y(),a.z()-b.z(); return r; }
 
615
 
 
616
        static Scalar __getitem__(const QuaternionT & self, Index idx){ IDX_CHECK(idx,4); if(idx==0) return self.x(); if(idx==1) return self.y(); if(idx==2) return self.z(); return self.w(); }
 
617
        static void __setitem__(QuaternionT& self, Index idx, Real value){ IDX_CHECK(idx,4); if(idx==0) self.x()=value; else if(idx==1) self.y()=value; else if(idx==2) self.z()=value; else if(idx==3) self.w()=value; }
 
618
        static string __str__(const py::object& obj){
 
619
                const QuaternionT& self=py::extract<QuaternionT>(obj)();
 
620
                AngleAxisT aa(self);
 
621
                return string(object_class_name(obj)+"((")+num_to_string(aa.axis()[0])+","+num_to_string(aa.axis()[1])+","+num_to_string(aa.axis()[2])+"),"+num_to_string(aa.angle())+")";
 
622
        }
 
623
        static Index __len__(){return 4;}
 
624
};
 
625
 
 
626