From cfc9d853e3a377c7ff62be3e4ab056c420aaa4ef Mon Sep 17 00:00:00 2001 From: Owen Thompson Date: Thu, 9 Apr 2020 22:04:53 -0400 Subject: [PATCH] Implemented all tests transferable to the 2x2 matrix case from 3x3. Added needed functionality to ensure boost::python worked for testing. Signed-off-by: Owen Thompson --- PyIlmBase/PyImath/CMakeLists.txt | 1 + PyIlmBase/PyImath/PyImathMatrix.h | 45 ++ PyIlmBase/PyImath/PyImathMatrix22.cpp | 734 ++++++++++++++++++++++++++ PyIlmBase/PyImath/PyImathVec2Impl.h | 20 + PyIlmBase/PyImath/imathmodule.cpp | 11 +- PyIlmBase/PyImathTest/pyImathTest.in | 424 ++++++++++++++- 6 files changed, 1227 insertions(+), 8 deletions(-) create mode 100644 PyIlmBase/PyImath/PyImathMatrix22.cpp diff --git a/PyIlmBase/PyImath/CMakeLists.txt b/PyIlmBase/PyImath/CMakeLists.txt index a1c0971b..55c3a2a0 100644 --- a/PyIlmBase/PyImath/CMakeLists.txt +++ b/PyIlmBase/PyImath/CMakeLists.txt @@ -17,6 +17,7 @@ pyilmbase_define_module(imath PyImathFixedArray.cpp PyImathFrustum.cpp PyImathLine.cpp + PyImathMatrix22.cpp PyImathMatrix33.cpp PyImathMatrix44.cpp PyImathPlane.cpp diff --git a/PyIlmBase/PyImath/PyImathMatrix.h b/PyIlmBase/PyImath/PyImathMatrix.h index f7c61991..09ae3e32 100644 --- a/PyIlmBase/PyImath/PyImathMatrix.h +++ b/PyIlmBase/PyImath/PyImathMatrix.h @@ -43,10 +43,14 @@ namespace PyImath { +template boost::python::class_ > register_Matrix22(); template boost::python::class_ > register_Matrix33(); template boost::python::class_ > register_Matrix44(); template boost::python::class_ > > register_M44Array(); template boost::python::class_ > > register_M33Array(); +template boost::python::class_ > > register_M22Array(); +typedef FixedArray > M22fArray; +typedef FixedArray > M22dArray; typedef FixedArray > M33fArray; typedef FixedArray > M33dArray; typedef FixedArray > M44fArray; @@ -61,6 +65,13 @@ typedef FixedArray > M44dArray; // have these properties, so we define a companion class here. // The template argument, T, is the element type (e.g.,float, double). +template +class M22 { + public: + static PyObject * wrap (const IMATH_NAMESPACE::Matrix22 &m); + static int convert (PyObject *p, IMATH_NAMESPACE::Matrix22 *m); +}; + template class M33 { public: @@ -75,6 +86,15 @@ class M44 { static int convert (PyObject *p, IMATH_NAMESPACE::Matrix44 *m); }; +template +PyObject * +M22::wrap (const IMATH_NAMESPACE::Matrix22 &m) +{ + typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Matrix22 >::type converter; + PyObject *p = converter (m); + return p; +} + template PyObject * M33::wrap (const IMATH_NAMESPACE::Matrix33 &m) @@ -93,6 +113,29 @@ M44::wrap (const IMATH_NAMESPACE::Matrix44 &m) return p; } +template +int +M22::convert (PyObject *p, IMATH_NAMESPACE::Matrix22 *m) +{ + boost::python::extract extractorMf (p); + if (extractorMf.check()) + { + IMATH_NAMESPACE::M22f e = extractorMf(); + m->setValue (e); + return 1; + } + + boost::python::extract extractorMd (p); + if (extractorMd.check()) + { + IMATH_NAMESPACE::M22d e = extractorMd(); + m->setValue (e); + return 1; + } + + return 0; +} + template int M33::convert (PyObject *p, IMATH_NAMESPACE::Matrix33 *m) @@ -174,6 +217,8 @@ jacobiEigensolve(const Matrix& m) return boost::python::make_tuple (Q, S); } +typedef M22 M22f; +typedef M22 M22d; typedef M33 M33f; typedef M33 M33d; diff --git a/PyIlmBase/PyImath/PyImathMatrix22.cpp b/PyIlmBase/PyImath/PyImathMatrix22.cpp new file mode 100644 index 00000000..e31f742f --- /dev/null +++ b/PyIlmBase/PyImath/PyImathMatrix22.cpp @@ -0,0 +1,734 @@ +/////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 1998-2011, Industrial Light & Magic, a division of Lucas +// Digital Ltd. LLC +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Industrial Light & Magic nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////// + +#define BOOST_PYTHON_MAX_ARITY 17 + +#include "PyImathMatrix.h" +#include "PyImathExport.h" +#include "PyImathDecorators.h" +#include +#include +#include +#include +#include +#include +#include +#include "PyImath.h" +#include "PyImathVec.h" +#include "PyImathMathExc.h" +#include +#include +#include + +namespace PyImath { + +template<> const char *PyImath::M22fArray::name() { return "M22fArray"; } +template<> const char *PyImath::M22dArray::name() { return "M22dArray"; } + +using namespace boost::python; +using namespace IMATH_NAMESPACE; + +template +struct MatrixRow { + explicit MatrixRow(T *data) : _data(data) {} + T & operator [] (int i) { return _data[i]; } + T *_data; + + static const char *name; + static void register_class() + { + typedef PyImath::StaticFixedArray MatrixRow_helper; + class_ matrixRow_class(name,no_init); + matrixRow_class + .def("__len__", MatrixRow_helper::len) + .def("__getitem__", MatrixRow_helper::getitem,return_value_policy()) + .def("__setitem__", MatrixRow_helper::setitem) + ; + } +}; + +template <> const char *MatrixRow::name = "M22fRow"; +template <> const char *MatrixRow::name = "M22dRow"; + + +template +struct IndexAccessMatrixRow { + typedef MatrixRow result_type; + static MatrixRow apply(Container &c, int i) { return MatrixRow(c[i]); } +}; + +template struct Matrix22Name { static const char *value; }; +template<> const char *Matrix22Name::value = "M22f"; +template<> const char *Matrix22Name::value = "M22d"; + +template +static std::string Matrix22_str(const Matrix22 &v) +{ + std::stringstream stream; + stream << Matrix22Name::value << "("; + for (int row = 0; row < 2; row++) + { + stream << "("; + for (int col = 0; col < 2; col++) + { + stream << v[row][col]; + stream << (col != 1 ? ", " : ""); + } + stream << ")" << (row != 1 ? ", " : ""); + } + stream << ")"; + return stream.str(); +} + +// Non-specialized repr is same as str +template +static std::string Matrix22_repr(const Matrix22 &v) +{ + return Matrix22_str(v); +} + +// Specialization for float to full precision +template <> +std::string Matrix22_repr(const Matrix22 &v) +{ + return (boost::format("%s((%.9g, %.9g), (%.9g, %.9g))") + % Matrix22Name::value + % v[0][0] % v[0][1] + % v[1][0] % v[1][1]).str(); +} + +// Specialization for double to full precision +template <> +std::string Matrix22_repr(const Matrix22 &v) +{ + return (boost::format("%s((%.17g, %.17g), (%.17g, %.17g))") + % Matrix22Name::value + % v[0][0] % v[0][1] + % v[1][0] % v[1][1]).str(); +} + +template +static const Matrix22 & +invert22 (Matrix22 &m, bool singExc = true) +{ + MATH_EXC_ON; + return m.invert(singExc); +} + +template +static Matrix22 +inverse22 (Matrix22 &m, bool singExc = true) +{ + MATH_EXC_ON; + return m.inverse(singExc); +} + +template +static const Matrix22 & +iadd22(Matrix22 &m, const Matrix22 &m2) +{ + MATH_EXC_ON; + Matrix22 m3; + m3.setValue (m2); + return m += m3; +} + +template +static const Matrix22 & +iadd22T(Matrix22 &mat, T a) +{ + MATH_EXC_ON; + return mat += a; +} + +template +static Matrix22 +add22(Matrix22 &m, const Matrix22 &m2) +{ + MATH_EXC_ON; + return m + m2; +} + +template +static const Matrix22 & +isub22(Matrix22 &m, const Matrix22 &m2) +{ + MATH_EXC_ON; + Matrix22 m3; + m3.setValue (m2); + return m -= m3; +} + +template +static const Matrix22 & +isub22T(Matrix22 &mat, T a) +{ + MATH_EXC_ON; + return mat -= a; +} + +template +static Matrix22 +sub22(Matrix22 &m, const Matrix22 &m2) +{ + MATH_EXC_ON; + return m - m2; +} + +template +static const Matrix22 & +negate22 (Matrix22 &m) +{ + MATH_EXC_ON; + return m.negate(); +} + +template +static Matrix22 +neg22 (Matrix22 &m) +{ + MATH_EXC_ON; + return -m; +} + +template +static const Matrix22 & +imul22T(Matrix22 &m, const T &t) +{ + MATH_EXC_ON; + return m *= t; +} + +template +static Matrix22 +mul22T(Matrix22 &m, const T &t) +{ + MATH_EXC_ON; + return m * t; +} + +template +static Matrix22 +rmul22T(Matrix22 &m, const T &t) +{ + MATH_EXC_ON; + return t * m; +} + +template +static const Matrix22 & +idiv22T(Matrix22 &m, const T &t) +{ + MATH_EXC_ON; + return m /= t; +} + +template +static Matrix22 +div22T(Matrix22 &m, const T &t) +{ + MATH_EXC_ON; + return m / t; +} + +template +void +outerProduct22(Matrix22 &mat, const Vec2 &a, const Vec2 &b) +{ + MATH_EXC_ON; + mat = IMATH_NAMESPACE::outerProduct(a,b); +} + +template +static void +multDirMatrix22(Matrix22 &mat, const Vec2 &src, Vec2 &dst) +{ + MATH_EXC_ON; + mat.multDirMatrix(src, dst); +} + +template +static Vec2 +multDirMatrix22_return_value(Matrix22 &mat, const Vec2 &src) +{ + MATH_EXC_ON; + Vec2 dst; + mat.multDirMatrix(src, dst); + return dst; +} + +template +static FixedArray > +multDirMatrix22_array(Matrix22 &mat, const FixedArray >&src) +{ + MATH_EXC_ON; + size_t len = src.len(); + FixedArray > dst(len); + for (size_t i=0; i +static const Matrix22 & +rotate22(Matrix22 &mat, const T &r) +{ + MATH_EXC_ON; + return mat.rotate(r); +} + +template +static void +extractEuler(Matrix22 &mat, Vec2 &dstObj) +{ + MATH_EXC_ON; + T dst; + IMATH_NAMESPACE::extractEuler(mat, dst); + dstObj.setValue(dst, T (0)); +} + +template +static const Matrix22 & +scaleSc22(Matrix22 &mat, const T &s) +{ + MATH_EXC_ON; + Vec2 sVec(s, s); + return mat.scale(sVec); +} + +template +static const Matrix22 & +scaleV22(Matrix22 &mat, const Vec2 &s) +{ + MATH_EXC_ON; + return mat.scale(s); +} + +template +static const Matrix22 & +scale22Tuple(Matrix22 &mat, const tuple &t) +{ + MATH_EXC_ON; + if(t.attr("__len__")() == 2) + { + Vec2 s; + s.x = extract(t[0]); + s.y = extract(t[1]); + + return mat.scale(s); + } + else + THROW(IEX_NAMESPACE::LogicExc, "m.scale needs tuple of length 2"); +} + +template +static const Matrix22 & +setRotation22(Matrix22 &mat, const T &r) +{ + MATH_EXC_ON; + return mat.setRotation(r); +} + +template +static const Matrix22 & +setScaleSc22(Matrix22 &mat, const T &s) +{ + MATH_EXC_ON; + Vec2 sVec(s, s); + return mat.setScale(sVec); +} + +template +static const Matrix22 & +setScaleV22(Matrix22 &mat, const Vec2 &s) +{ + MATH_EXC_ON; + return mat.setScale(s); +} + +template +static const Matrix22 & +setScale22Tuple(Matrix22 &mat, const tuple &t) +{ + MATH_EXC_ON; + if(t.attr("__len__")() == 2) + { + Vec2 s; + s.x = extract(t[0]); + s.y = extract(t[1]); + + return mat.setScale(s); + } + else + THROW(IEX_NAMESPACE::LogicExc, "m.setScale needs tuple of length 2"); +} + +template +static void +setValue22(Matrix22 &mat, const Matrix22 &value) +{ + MATH_EXC_ON; + mat.setValue(value); +} + +template +static Matrix22 +subtractTL22(Matrix22 &mat, T a) +{ + MATH_EXC_ON; + Matrix22 m(mat.x); + for(int i = 0; i < 2; ++i) + for(int j = 0; j < 2; ++j) + m.x[i][j] -= a; + + return m; +} + +template +static Matrix22 +subtractTR22(Matrix22 &mat, T a) +{ + MATH_EXC_ON; + Matrix22 m(mat.x); + for(int i = 0; i < 2; ++i) + for(int j = 0; j < 2; ++j) + m.x[i][j] = a - m.x[i][j]; + + return m; +} + + +template +static Matrix22 +add22T(Matrix22 &mat, T a) +{ + MATH_EXC_ON; + Matrix22 m(mat.x); + for(int i = 0; i < 2; ++i) + for(int j = 0; j < 2; ++j) + m.x[i][j] += a; + + return m; +} + +template +static Matrix22 +mul22(Matrix22 &mat1, Matrix22 &mat2) +{ + MATH_EXC_ON; + Matrix22 mat2T; + mat2T.setValue (mat2); + return mat1 * mat2T; +} + +template +static Matrix22 +rmul22(Matrix22 &mat2, Matrix22 &mat1) +{ + MATH_EXC_ON; + Matrix22 mat1T; + mat1T.setValue (mat1); + return mat1T * mat2; +} + +template +static const Matrix22 & +imul22(Matrix22 &mat1, Matrix22 &mat2) +{ + MATH_EXC_ON; + Matrix22 mat2T; + mat2T.setValue (mat2); + return mat1 *= mat2T; +} + +template +static bool +lessThan22(Matrix22 &mat1, const Matrix22 &mat2) +{ + for(int i = 0; i < 2; ++i){ + for(int j = 0; j < 2; ++j){ + if(mat1[i][j] > mat2[i][j]){ + return false; + } + } + } + + return (mat1 != mat2); +} + +template +static bool +lessThanEqual22(Matrix22 &mat1, const Matrix22 &mat2) +{ + for(int i = 0; i < 2; ++i){ + for(int j = 0; j < 2; ++j){ + if(mat1[i][j] > mat2[i][j]){ + return false; + } + } + } + + return true; +} + +template +static bool +greaterThan22(Matrix22 &mat1, const Matrix22 &mat2) +{ + for(int i = 0; i < 2; ++i){ + for(int j = 0; j < 2; ++j){ + if(mat1[i][j] < mat2[i][j]){ + std::cout << mat1[i][j] << " " << mat2[i][j] << std::endl; + return false; + } + } + } + + return (mat1 != mat2); +} + +template +static bool +greaterThanEqual22(Matrix22 &mat1, const Matrix22 &mat2) +{ + for(int i = 0; i < 2; ++i){ + for(int j = 0; j < 2; ++j){ + if(mat1[i][j] < mat2[i][j]){ + return false; + } + } + } + + return true; +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(invert22_overloads, invert22, 1, 2); +BOOST_PYTHON_FUNCTION_OVERLOADS(inverse22_overloads, inverse22, 1, 2); +BOOST_PYTHON_FUNCTION_OVERLOADS(outerProduct22_overloads, outerProduct22, 3, 3); + +template +static Matrix22 * Matrix2_tuple_constructor(const tuple &t0, const tuple &t1) +{ + if(t0.attr("__len__")() == 2 && t1.attr("__len__")() == 2) + { + return new Matrix22(extract(t0[0]), extract(t0[1]), + extract(t1[0]), extract(t1[1])); + } + else + THROW(IEX_NAMESPACE::LogicExc, "Matrix22 takes 2 tuples of length 2"); +} + +template +static Matrix22 *Matrix2_matrix_constructor(const Matrix22 &mat) +{ + Matrix22 *m = new Matrix22; + + for(int i = 0; i < 2; ++i) + for(int j = 0; j < 2; ++j) + m->x[i][j] = T (mat.x[i][j]); + + return m; +} + +template +class_ > +register_Matrix22() +{ + typedef PyImath::StaticFixedArray,T,2,IndexAccessMatrixRow,T,2> > Matrix22_helper; + + MatrixRow::register_class(); + class_ > matrix22_class(Matrix22Name::value, Matrix22Name::value,init >("copy construction")); + matrix22_class + .def(init<>("initialize to identity")) + .def(init("initialize all entries to a single value")) + .def(init("make from components")) + .def("__init__", make_constructor(Matrix2_tuple_constructor)) + .def("__init__", make_constructor(Matrix2_matrix_constructor)) + .def("__init__", make_constructor(Matrix2_matrix_constructor)) + + //.def_readwrite("x00", &Matrix22::x[0][0]) + //.def_readwrite("x01", &Matrix22::x[0][1]) + //.def_readwrite("x02", &Matrix22::x[0][2]) + //.def_readwrite("x10", &Matrix22::x[1][0]) + //.def_readwrite("x11", &Matrix22::x[1][1]) + //.def_readwrite("x12", &Matrix22::x[1][2]) + //.def_readwrite("x20", &Matrix22::x[2][0]) + //.def_readwrite("x21", &Matrix22::x[2][1]) + //.def_readwrite("x22", &Matrix22::x[2][2]) + .def("baseTypeEpsilon", &Matrix22::baseTypeEpsilon,"baseTypeEpsilon() epsilon value of the base type of the vector") + .staticmethod("baseTypeEpsilon") + .def("baseTypeMax", &Matrix22::baseTypeMax,"baseTypeMax() max value of the base type of the vector") + .staticmethod("baseTypeMax") + .def("baseTypeMin", &Matrix22::baseTypeMin,"baseTypeMin() min value of the base type of the vector") + .staticmethod("baseTypeMin") + .def("baseTypeSmallest", &Matrix22::baseTypeSmallest,"baseTypeSmallest() smallest value of the base type of the vector") + .staticmethod("baseTypeSmallest") + .def("equalWithAbsError", &Matrix22::equalWithAbsError,"m1.equalWithAbsError(m2,e) true if the elements " + "of v1 and v2 are the same with an absolute error of no more than e, " + "i.e., abs(m1[i] - m2[i]) <= e") + .def("equalWithRelError", &Matrix22::equalWithRelError,"m1.equalWithAbsError(m2,e) true if the elements " + "of m1 and m2 are the same with an absolute error of no more than e, " + "i.e., abs(m1[i] - m2[i]) <= e * abs(m1[i])") + // need a different version for matrix data access + .def("__len__", Matrix22_helper::len) + .def("__getitem__", Matrix22_helper::getitem) + //.def("__setitem__", Matrix22_helper::setitem) + .def("makeIdentity",&Matrix22::makeIdentity,"makeIdentity() make this matrix the identity matrix") + .def("transpose",&Matrix22::transpose,return_internal_reference<>(),"transpose() transpose this matrix") + .def("transposed",&Matrix22::transposed,"transposed() return a transposed copy of this matrix") + .def("invert",&invert22,invert22_overloads("invert() invert this matrix")[return_internal_reference<>()]) + .def("inverse",&inverse22,inverse22_overloads("inverse() return an inverted copy of this matrix")) + .def("determinant",&Matrix22::determinant,"determinant() return the determinant of this matrix") + .def(self == self) // NOSONAR - suppress SonarCloud bug report. + .def(self != self) // NOSONAR - suppress SonarCloud bug report. + .def("__iadd__", &iadd22,return_internal_reference<>()) + .def("__iadd__", &iadd22,return_internal_reference<>()) + .def("__iadd__", &iadd22T,return_internal_reference<>()) + .def("__add__", &add22) + .def("__isub__", &isub22,return_internal_reference<>()) + .def("__isub__", &isub22,return_internal_reference<>()) + .def("__isub__", &isub22T,return_internal_reference<>()) + .def("__sub__", &sub22) + .def("negate",&negate22,return_internal_reference<>(),"negate() negate all entries in this matrix") + .def("__neg__", &neg22) + .def("__imul__", &imul22T,return_internal_reference<>()) + .def("__mul__", &mul22T) + .def("__rmul__", &rmul22T) + .def("__idiv__", &idiv22T,return_internal_reference<>()) + .def("__itruediv__", &idiv22T,return_internal_reference<>()) + .def("__div__", &div22T) + .def("__truediv__", &div22T) + .def("__add__", &add22T) + .def("__radd__", &add22T) + .def("__sub__", &subtractTL22) + .def("__rsub__", &subtractTR22) + .def("__mul__", &mul22) + .def("__mul__", &mul22) + .def("__rmul__", &rmul22) + .def("__rmul__", &rmul22) + .def("__imul__", &imul22,return_internal_reference<>()) + .def("__imul__", &imul22,return_internal_reference<>()) + .def("__lt__", &lessThan22) + .def("__le__", &lessThanEqual22) + .def("__gt__", &greaterThan22) + .def("__ge__", &greaterThanEqual22) + //.def(self_ns::str(self)) + .def("__str__",&Matrix22_str) + .def("__repr__",&Matrix22_repr) + + .def("extractEuler", &extractEuler, + "M.extractEuler(r) -- extracts the " + "rotation component of M into r. " + "Assumes that M contains no shear or " + "non-uniform scaling; results are " + "meaningless if it does.") + + .def("multDirMatrix", &multDirMatrix22, "mult matrix") + .def("multDirMatrix", &multDirMatrix22_return_value, "mult matrix") + .def("multDirMatrix", &multDirMatrix22_array, "mult matrix") + .def("multDirMatrix", &multDirMatrix22, "mult matrix") + .def("multDirMatrix", &multDirMatrix22_return_value, "mult matrix") + .def("multDirMatrix", &multDirMatrix22_array, "mult matrix") + + .def("rotate", &rotate22, return_internal_reference<>(),"rotate matrix") + + .def("scale", &scaleSc22, return_internal_reference<>(),"scale matrix") + .def("scale", &scaleV22, return_internal_reference<>(),"scale matrix") + .def("scale", &scale22Tuple, return_internal_reference<>(),"scale matrix") + + .def("setRotation", &setRotation22, return_internal_reference<>(),"setRotation()") + .def("setScale", &setScaleSc22, return_internal_reference<>(),"setScale()") + .def("setScale", &setScaleV22, return_internal_reference<>(),"setScale()") + .def("setScale", &setScale22Tuple, return_internal_reference<>(),"setScale()") + + .def("setValue", &setValue22, "setValue()") + ; + + decoratecopy(matrix22_class); + + return matrix22_class; +/* + const Matrix22 & operator = (const Matrix22 &v); + const Matrix22 & operator = (T a); + T * getValue (); + const T * getValue () const; + template void getValue (Matrix22 &v) const; + template Matrix22 & setValue (const Matrix22 &v); + template Matrix22 & setTheMatrix (const Matrix22 &v); + template void multVecMatrix(const Vec2 &src, Vec2 &dst) const; + template void multDirMatrix(const Vec2 &src, Vec2 &dst) const; + template const Matrix22 & setRotation (S r); + template const Matrix22 & rotate (S r); + const Matrix22 & setScale (T s); + template const Matrix22 & setScale (const Vec2 &s); + template const Matrix22 & scale (const Vec2 &s); + template const Matrix22 & setTranslation (const Vec2 &t); + Vec2 translation () const; + template const Matrix22 & translate (const Vec2 &t); + template const Matrix22 & setShear (const S &h); + template const Matrix22 & setShear (const Vec2 &h); + template const Matrix22 & shear (const S &xy); + template const Matrix22 & shear (const Vec2 &h); +*/ +} + +template +static void +setM22ArrayItem(FixedArray > &ma, + Py_ssize_t index, + const IMATH_NAMESPACE::Matrix22 &m) +{ + ma[ma.canonical_index(index)] = m; +} + +template +class_ > > +register_M22Array() +{ + class_ > > matrixArray_class = FixedArray >::register_("Fixed length array of IMATH_NAMESPACE::Matrix22"); + matrixArray_class + .def("__setitem__", &setM22ArrayItem) + ; + return matrixArray_class; +} + +template PYIMATH_EXPORT class_ > register_Matrix22(); +template PYIMATH_EXPORT class_ > register_Matrix22(); + +template PYIMATH_EXPORT class_ > > register_M22Array(); +template PYIMATH_EXPORT class_ > > register_M22Array(); + + +template<> PYIMATH_EXPORT IMATH_NAMESPACE::Matrix22 FixedArrayDefaultValue >::value() { return IMATH_NAMESPACE::Matrix22(); } +template<> PYIMATH_EXPORT IMATH_NAMESPACE::Matrix22 FixedArrayDefaultValue >::value() { return IMATH_NAMESPACE::Matrix22(); } +} diff --git a/PyIlmBase/PyImath/PyImathVec2Impl.h b/PyIlmBase/PyImath/PyImathVec2Impl.h index 1a04c40f..6624e2bd 100644 --- a/PyIlmBase/PyImath/PyImathVec2Impl.h +++ b/PyIlmBase/PyImath/PyImathVec2Impl.h @@ -405,6 +405,14 @@ Vec2_imulT(IMATH_NAMESPACE::Vec2 &v, T t) return v *= t; } +template +static Vec2 +Vec2_mulM22 (Vec2 &v, const Matrix22 &m) +{ + MATH_EXC_ON; + return v * m; +} + template static Vec2 Vec2_mulM33 (Vec2 &v, const Matrix33 &m) @@ -571,6 +579,14 @@ Vec2_mulTuple(const Vec2 &v, BoostPyType t) return w; } +template +static const Vec2 & +Vec2_imulM22 (Vec2 &v, const Matrix22 &m) +{ + MATH_EXC_ON; + return v *= m; +} + template static const Vec2 & Vec2_imulM33 (Vec2 &v, const Matrix33 &m) @@ -1003,8 +1019,12 @@ register_Vec2() .def("__imul__", &Vec2_imulV,return_internal_reference<>()) .def("__imul__", &Vec2_imulT,return_internal_reference<>()) .def(self * self) + .def("__mul__", &Vec2_mulM22) + .def("__mul__", &Vec2_mulM22) .def("__mul__", &Vec2_mulM33) .def("__mul__", &Vec2_mulM33) + .def("__imul__", &Vec2_imulM22, return_internal_reference<>()) + .def("__imul__", &Vec2_imulM22, return_internal_reference<>()) .def("__imul__", &Vec2_imulM33, return_internal_reference<>()) .def("__imul__", &Vec2_imulM33, return_internal_reference<>()) .def(self / self) // NOSONAR - suppress SonarCloud bug report. diff --git a/PyIlmBase/PyImath/imathmodule.cpp b/PyIlmBase/PyImath/imathmodule.cpp index e853c8c9..ff0c34d3 100644 --- a/PyIlmBase/PyImath/imathmodule.cpp +++ b/PyIlmBase/PyImath/imathmodule.cpp @@ -310,15 +310,17 @@ BOOST_PYTHON_MODULE(imath) class_ > b3d_class = register_BoxArray(); // - // Matrix33/44 + // Matrix22/33/44 // + register_Matrix22(); + register_Matrix22(); register_Matrix33(); register_Matrix33(); register_Matrix44(); register_Matrix44(); // - // M33/44Array + // M22/M33/44Array // class_ > m44d_class = register_M44Array(); class_ > m44f_class = register_M44Array(); @@ -330,6 +332,11 @@ BOOST_PYTHON_MODULE(imath) add_explicit_construction_from_type< IMATH_NAMESPACE::Matrix33 >(m33d_class); add_explicit_construction_from_type< IMATH_NAMESPACE::Matrix33 > (m33f_class); + class_ > m22d_class = register_M22Array(); + class_ > m22f_class = register_M22Array(); + add_explicit_construction_from_type< IMATH_NAMESPACE::Matrix22 >(m22d_class); + add_explicit_construction_from_type< IMATH_NAMESPACE::Matrix22 > (m22f_class); + // // String Array // diff --git a/PyIlmBase/PyImathTest/pyImathTest.in b/PyIlmBase/PyImathTest/pyImathTest.in index 7745fd31..6796c2d2 100755 --- a/PyIlmBase/PyImathTest/pyImathTest.in +++ b/PyIlmBase/PyImathTest/pyImathTest.in @@ -1,12 +1,14 @@ #!/usr/bin/env python2 -from imath import * -from math import sqrt, pi, sin, cos import math -import string, traceback, sys -import iex import random +import string +import sys +import traceback +from math import cos, pi, sin, sqrt +import iex +from imath import * testList = [] @@ -4783,6 +4785,340 @@ def testShearConversions (): testList.append (('testShearConversions',testShearConversions)) +# ------------------------------------------------------------------------- +# Tests for M22x + +def testM22x (Mat, Vec): + + # Constructors (and element access). + + m = Mat() + assert m[0][0] == 1 and m[0][1] == 0 and \ + m[1][0] == 0 and m[1][1] == 1 + + m = Mat(1) + assert m[0][0] == 1 and m[0][1] == 1 and \ + m[1][0] == 1 and m[1][1] == 1 + + m = Mat((0, 1), (2, 3)) + assert m[0][0] == 0 and m[0][1] == 1 and \ + m[1][0] == 2 and m[1][1] == 3 + + + m = Mat(0, 1, 2, 3) + assert m[0][0] == 0 and m[0][1] == 1 and \ + m[1][0] == 2 and m[1][1] == 3 + + # Repr. + + m = Mat(0/9., 1/9., 2/9., 3/9.) + assert m == eval(repr(m)) + + # Sequence length. + + m = Mat() + assert len(m) == 2 + + # Element setting. + + m = Mat() + m[0][0] = 10 + m[1][1] = 11 + assert m[0][0] == 10 and m[1][1] == 11 + + try: + m[-4][0] = 0 # This should raise an exception. + except: + pass + else: + assert 0 # We shouldn't get here. + + try: + v[3][0] = 0 # This should raise an exception. + except: + pass + else: + assert 0 # We shouldn't get here. + + try: + m[0][-4] = 0 # This should raise an exception. + except: + pass + else: + assert 0 # We shouldn't get here. + + try: + v[0][3] = 0 # This should raise an exception. + except: + pass + else: + assert 0 # We shouldn't get here. + + try: + v[1] = (1,2,3) # This should raise an exception. + except: + pass + else: + assert 0 # We shouldn't get here. + + # Assignment. + + m1 = Mat(1) + + m2 = m1 + assert m2[0][0] == 1 and m2[0][1] == 1 and \ + m2[1][0] == 1 and m2[1][1] == 1 + + m1[0][0] = 2 + assert m2[0][0] == 2 and m2[0][1] == 1 and \ + m2[1][0] == 1 and m2[1][1] == 1 + + # Identity. + + m = Mat(2) + + m.makeIdentity() + assert m[0][0] == 1 and m[0][1] == 0 and \ + m[1][0] == 0 and m[1][1] == 1 + + # Comparison operators. + + m1 = Mat() + m1[1][1] = 2 + m2 = Mat() + m2[1][1] = 2 + m3 = Mat() + m3[1][1] = 3 + + assert m1 == m2 + assert m1 != m3 + assert not (m1 < m2) + assert m1 < m3 + assert m1 <= m2 + assert m1 <= m3 + assert not (m3 <= m1) + assert not (m2 > m1) + assert m3 > m1 + assert m2 >= m1 + assert m3 >= m1 + assert not (m1 >= m3) + + # Epsilon equality. + + e = 0.005 + m1 = Mat(1) + m2 = Mat(1 + e) + + assert m1.equalWithAbsError(m2, e) + assert m2.equalWithAbsError(m1, e) + + e = 0.003 + m1 = Mat(10) + m2 = Mat(10 + 10 * e) + + assert m1.equalWithRelError(m2, e) + assert m2.equalWithRelError(m1, e) + + # Addition. + + m1 = Mat(1) + m2 = Mat(2) + + assert m1 + m2 == Mat(3) + assert m2 + m1 == m1 + m2 + assert m1 + 1 == Mat(2) + assert 1 + m1 == m1 + 1 + + # Subtraction and negation. + + m1 = Mat(2) + m2 = Mat(3) + + assert m2 - m1 == Mat(1) + assert m1 - 1 == Mat(1) + assert 1 - m1 == - (m1 - 1) + assert m1.negate() == Mat(-2) + + # Multiplication. + + m1 = Mat(1) + # (Scales by (3, 4).) + m2 = Mat() + m2[0][0] = 3 + m2[1][1] = 4 + v = Vec(1, 2) + + assert m1 * 2 == Mat(2) + assert m1 * 2 == 2 * m1 + assert m1 * m2 == Mat((3,4),(3,4)) + assert v * m2 == Vec(3, 8) + try: + m1 * v # This should raise an exception. + except: + pass + else: + assert 0 # We shouldn't get here. + + m2f = M22f() + m2f[0][0] = 1 + m2f[1][1] = 2 + v = Vec(1, 2) + v *= m2f + assert v == Vec(1, 4) + + m2d = M22d() + m2d[0][0] = 1 + m2d[1][1] = 2 + v = Vec(1, 2) + v *= m2d + assert v == Vec(1, 4) + + # (Rotates by 45 degrees.) + m3 = Mat() + m3[0][0] = 0 + m3[0][1] = 1 + m3[1][0] = -1 + m3[1][1] = 0 + m4 = m3 * Mat() + v1 = Vec(1, 0) + v2 = Vec() + + m4.multDirMatrix(v1,v2) + assert v2.equalWithAbsError((0, 1), v2.baseTypeEpsilon()) + v2 = m4.multDirMatrix(v1) + assert v2.equalWithAbsError((0, 1), v2.baseTypeEpsilon()) + v1a = V2fArray(1) + v1a[:] = V2f(v1) + v2a = m4.multDirMatrix(v1a) + assert v2a[0].equalWithAbsError((0, 1), v2a[0].baseTypeEpsilon()) + v1a = V2dArray(1) + v1a[:] = V2d(v1) + v2a = m4.multDirMatrix(v1a) + assert v2a[0].equalWithAbsError((0, 1), v2a[0].baseTypeEpsilon()) + + # Division. + + m = Mat(4) + + assert m / 2 == Mat(2) + try: + 4 / m # This should raise an exception. + except: + pass + else: + assert 0 # We shouldn't get here. + + # Transpose. + + m = Mat(1, 2, 3, 4) + + assert m.transpose() == Mat(1, 3, 2, 4) + m.transposed() + assert m == Mat(1, 3, 2, 4) + + # Invert. + + m1 = Mat() + m1[0][0] = 1 + m1[1][1] = 2 + + m1I = m1.inverse() + assert m1 * m1I == Mat() + + m2 = Mat(m1) + m2.invert() + assert m1 * m2 == Mat() + + # Rotation (in radians). + + v1 = Vec(1, 0) + + m = Mat() + m.setRotation(-pi / 2) + + v2 = v1 * m + assert v2.equalWithAbsError((0, -1), v2.baseTypeEpsilon()) + + m.rotate(-pi / 2) + + v2 = v1 * m + assert v2.equalWithAbsError((-1, 0), v2.baseTypeEpsilon()) + + # Scaling. + + v1 = Vec(1, 2) + + m = Mat() + m.setScale(2) + + v2 = v1 * m + assert v2.equalWithAbsError((2, 4), v2.baseTypeEpsilon()) + + m.scale(3) + + v2 = v1 * m + assert v2.equalWithAbsError((6, 12), v2.baseTypeEpsilon()) + + m = Mat() + m.setScale((1, 2)) + + v2 = v1 * m + assert v2.equalWithAbsError((1, 4), v2.baseTypeEpsilon()) + + m.scale((2, 3)) + + v2 = v1 * m + assert v2.equalWithAbsError((2, 12), v2.baseTypeEpsilon()) + + # It is not essential for correctness that the following exceptions + # occur. Instead, these tests merely document the way the Python + # wrappings currently work. + try: + m.setScale(1, 2) # This should raise an exception. + except: + pass + else: + assert 0 # We shouldn't get here. + + m = Mat() + a = pi/4 + # (Rotation by -a around Z axis.) + m[0][0] = cos(a) + m[0][1] = -sin(a) + m[1][0] = sin(a) + m[1][1] = cos(a) + v = Vec() + + m.extractEuler(v) + assert v.equalWithAbsError((-a, 0), v.baseTypeEpsilon()) + + # Determinants (by building a random singular value decomposition) + + u = Mat() + v = Mat() + s = Mat() + + u.setRotation( random.random() ) + v.setRotation( random.random() ) + s[0][0] = random.random() + s[1][1] = random.random() + + c = u * s * v.transpose() + assert abs(c.determinant() - s[0][0]*s[1][1]) <= u.baseTypeEpsilon() + + + print ("ok") + return + +def testM22 (): + + print ("M22f") + testM22x (M22f, V2f) + print ("M22d") + testM22x (M22d, V2d) + +testList.append (('testM22',testM22)) + # ------------------------------------------------------------------------- # Tests for M33x @@ -6166,6 +6502,54 @@ testList.append (('testM44',testM44)) # ------------------------------------------------------------------------- # Tests for Mat --> Mat conversions +def testM22xConversions (Mat): + + # Assignment + + m1 = Mat(0,1, 2,3) + + m2 = M22f (m1) + assert m2[0][0] == 0 and m2[0][1] == 1 + + m2 = M22d (m1) + assert m2[0][0] == 0 and m2[0][1] == 1 + + # The += operator + + m2 = Mat(0,1, 2,3) + m2 += M22f (m1) + assert m2[0][0] == 0 and m2[0][1] == 2 + + m2 = Mat(0,1, 2,3) + m2 += M22d (m1) + assert m2[0][0] == 0 and m2[0][1] == 2 + + # The -= operator + + m2 = Mat(0,1, 2,3) + m2 -= M22f (m1) + assert m2[0][0] == 0 and m2[0][1] == 0 + + m2 = Mat(0,1, 2,3) + m2 -= M22d (m1) + assert m2[0][0] == 0 and m2[0][1] == 0 + + # The *= operator + + m2 = Mat(0,1, 2,3) + m2 *= M22f (m1) + assert m2[0][0] == 0*0 + 1*2 + assert m2[0][1] == 0*1 + 1*3 + + m2 = Mat(0,1, 2,3) + m2 *= M22d (m1) + assert m2[0][0] == 0*0 + 1*2 + assert m2[0][1] == 0*1 + 1*3 + + print ("ok") + return + + def testM33xConversions (Mat): # Assignment @@ -6262,8 +6646,7 @@ def testM44xConversions (Mat): return -def testM33xM44xConversion (MatA, MatB): - +def testInvalidConversion (MatA, MatB): try: m = MatA(); m1 = MatB (m); # This should raise an exception. @@ -6273,8 +6656,25 @@ def testM33xM44xConversion (MatA, MatB): assert 0 # We shouldn't get here. +def testM33xM44xConversion (MatA, MatB): + testInvalidConversion (MatA, MatB) + + +def testM22xM33xConversion (MatA, MatB): + testInvalidConversion (MatA, MatB) + + +def testM22xM44xConversion (MatA, MatB): + testInvalidConversion (MatA, MatB) + + def testMatConversions (): + print ("M22f") + testM22xConversions (M22f) + print ("M22d") + testM22xConversions (M22d) + print ("M33f") testM33xConversions (M33f) print ("M33d") @@ -6287,6 +6687,13 @@ def testMatConversions (): print ("invalid conversions") # Deliberatly not exhaustive, just representative. + + testM22xM33xConversion (M22f, M33d) + testM22xM33xConversion (M33f, M22d) + + testM22xM44xConversion (M22f, M44d) + testM22xM44xConversion (M44f, M22d) + testM33xM44xConversion (M33f, M44d) testM33xM44xConversion (M44f, M33d) @@ -8366,6 +8773,11 @@ def testMatrixArray (): testMxArray (M33fArray, M33f) print ("M33dArray") testMxArray (M33dArray, M33d) + print ("M22fArray") + testMxArray (M22fArray, M22f) + print ("M22dArray") + testMxArray (M22dArray, M22d) + testList.append(("testMatrixArray",testMatrixArray))