diff --git a/src/Base/MatrixPyImp.cpp b/src/Base/MatrixPyImp.cpp index 8019d9b5d3..de1247d910 100644 --- a/src/Base/MatrixPyImp.cpp +++ b/src/Base/MatrixPyImp.cpp @@ -28,6 +28,7 @@ #include "Base/Matrix.h" // inclusion of the generated files (generated out of MatrixPy.xml) +#include "RotationPy.h" #include "VectorPy.h" #include "GeometryPyCXX.h" #include "QuantityPy.h" @@ -122,17 +123,67 @@ PyObject* MatrixPy::number_subtract_handler(PyObject *self, PyObject *other) PyObject* MatrixPy::number_multiply_handler(PyObject *self, PyObject *other) { - if (!PyObject_TypeCheck(self, &(MatrixPy::Type))) { - PyErr_SetString(PyExc_TypeError, "First arg must be Matrix"); - return 0; - } - if (!PyObject_TypeCheck(other, &(MatrixPy::Type))) { - PyErr_SetString(PyExc_TypeError, "Second arg must be Matrix"); + if (PyObject_TypeCheck(self, &(MatrixPy::Type))) { + Base::Matrix4D a = static_cast(self)->value(); + + if (PyObject_TypeCheck(other, &(VectorPy::Type))) { + auto b = static_cast(other)->value(); + return new VectorPy(a*b); + } + + if (PyObject_TypeCheck(other, &(RotationPy::Type))) { + auto r = static_cast(other)->value(); + Matrix4D b; + r.getValue(b); + return new MatrixPy(a*b); + } + + if (PyObject_TypeCheck(other, &(MatrixPy::Type))) { + Base::Matrix4D b = static_cast(other)->value(); + return new MatrixPy(a*b); + } + + if (PyNumber_Check(other)) { + double v = PyFloat_AsDouble(self); + a.scale(v,v,v); + return new MatrixPy(a); + } + } + + PyErr_SetString(PyExc_NotImplementedError, "Not implemented"); + return 0; +} + +PyObject * MatrixPy::number_power_handler (PyObject* self, PyObject* other, PyObject* arg) +{ + if (!PyObject_TypeCheck(self, &(MatrixPy::Type)) || + +#if PY_MAJOR_VERSION < 3 + !PyInt_Check(other) +#else + !PyLong_Check(other) +#endif + || arg != Py_None + ) + { + PyErr_SetString(PyExc_NotImplementedError, "Not implemented"); return 0; } + Base::Matrix4D a = static_cast(self)->value(); - Base::Matrix4D b = static_cast(other)->value(); - return new MatrixPy(a*b); + + long b = Py::Int(other); + if(!b) + return new MatrixPy(Matrix4D()); + + if(b < 0) { + b = 1+b; + a.inverse(); + } + auto res = a; + for(;b;--b) + res *= a; + return new MatrixPy(res); } PyObject* MatrixPy::richCompare(PyObject *v, PyObject *w, int op) @@ -788,12 +839,6 @@ PyObject * MatrixPy::number_divmod_handler (PyObject* /*self*/, PyObject* /*othe return 0; } -PyObject * MatrixPy::number_power_handler (PyObject* /*self*/, PyObject* /*other*/, PyObject* /*arg*/) -{ - PyErr_SetString(PyExc_NotImplementedError, "Not implemented"); - return 0; -} - PyObject * MatrixPy::number_negative_handler (PyObject* /*self*/) { PyErr_SetString(PyExc_NotImplementedError, "Not implemented"); diff --git a/src/Base/PlacementPy.xml b/src/Base/PlacementPy.xml index 2d68208bcd..0df8551191 100644 --- a/src/Base/PlacementPy.xml +++ b/src/Base/PlacementPy.xml @@ -112,5 +112,11 @@ Placement(Base, Axis, Angle) -- define position and rotation + + + Set/get matrix representation of this placement + + + diff --git a/src/Base/PlacementPyImp.cpp b/src/Base/PlacementPyImp.cpp index 61ed21885a..03f858221b 100644 --- a/src/Base/PlacementPyImp.cpp +++ b/src/Base/PlacementPyImp.cpp @@ -273,6 +273,20 @@ void PlacementPy::setRotation(Py::Object arg) throw Py::TypeError("either Rotation or tuple of four floats expected"); } +Py::Object PlacementPy::getMatrix(void) const +{ + return Py::Matrix(getPlacementPtr()->toMatrix()); +} + +void PlacementPy::setMatrix(Py::Object arg) +{ + Py::Matrix mat; + if (!mat.accepts(arg.ptr())) + throw Py::TypeError("Expect type Matrix"); + mat = arg; + getPlacementPtr()->fromMatrix(mat); +} + PyObject *PlacementPy::getCustomAttributes(const char* attr) const { // for backward compatibility diff --git a/src/Base/Quantity.cpp b/src/Base/Quantity.cpp index 5ab27eed01..1d03a6d7dc 100644 --- a/src/Base/Quantity.cpp +++ b/src/Base/Quantity.cpp @@ -156,7 +156,8 @@ Quantity Quantity::pow(const Quantity &p) const Quantity Quantity::pow(double p) const { return Quantity( - std::pow(this->_Value, p), this->_Unit + std::pow(this->_Value, p), + this->_Unit.pow((short)p) ); } @@ -180,7 +181,7 @@ Quantity& Quantity::operator +=(const Quantity &p) Quantity Quantity::operator -(const Quantity &p) const { if (this->_Unit != p._Unit) - throw Base::UnitsMismatchError("Quantity::operator +(): Unit mismatch in minus operation"); + throw Base::UnitsMismatchError("Quantity::operator -(): Unit mismatch in minus operation"); return Quantity(this->_Value - p._Value,this->_Unit); } diff --git a/src/Base/QuantityPyImp.cpp b/src/Base/QuantityPyImp.cpp index e83de390d1..4f9d568975 100644 --- a/src/Base/QuantityPyImp.cpp +++ b/src/Base/QuantityPyImp.cpp @@ -290,15 +290,12 @@ PyObject* QuantityPy::number_add_handler(PyObject *self, PyObject *other) return 0; } - try { + PY_TRY { Base::Quantity *a = static_cast(self)->getQuantityPtr(); Base::Quantity *b = static_cast(other)->getQuantityPtr(); - return new QuantityPy(new Quantity(*a+*b) ); - } - catch (const Base::Exception& e) { - PyErr_SetString(PyExc_RuntimeError, e.what()); - return 0; - } + Base::Quantity q(*a + *b); // to prevent memory leak in case of exception + return new QuantityPy(new Quantity(q) ); + } PY_CATCH; } PyObject* QuantityPy::number_subtract_handler(PyObject *self, PyObject *other) @@ -313,99 +310,119 @@ PyObject* QuantityPy::number_subtract_handler(PyObject *self, PyObject *other) return 0; } - try { + PY_TRY { Base::Quantity *a = static_cast(self)->getQuantityPtr(); Base::Quantity *b = static_cast(other)->getQuantityPtr(); - return new QuantityPy(new Quantity(*a-*b) ); - } - catch (const Base::Exception& e) { - PyErr_SetString(PyExc_RuntimeError, e.what()); - return 0; - } + Base::Quantity q(*a - *b); // to prevent memory leak in case of exception + return new QuantityPy(new Quantity(q) ); + } PY_CATCH } PyObject* QuantityPy::number_multiply_handler(PyObject *self, PyObject *other) { - if (PyObject_TypeCheck(self, &(QuantityPy::Type))) { - if (PyObject_TypeCheck(other, &(QuantityPy::Type))) { - Base::Quantity *a = static_cast(self) ->getQuantityPtr(); - Base::Quantity *b = static_cast(other)->getQuantityPtr(); - return new QuantityPy(new Quantity(*a * *b) ); - } - else if (PyFloat_Check(other)) { - Base::Quantity *a = static_cast(self) ->getQuantityPtr(); - double b = PyFloat_AsDouble(other); - return new QuantityPy(new Quantity(*a*b) ); - } + PY_TRY { + if (PyObject_TypeCheck(self, &(QuantityPy::Type))) { + if (PyObject_TypeCheck(other, &(QuantityPy::Type))) { + Base::Quantity *a = static_cast(self) ->getQuantityPtr(); + Base::Quantity *b = static_cast(other)->getQuantityPtr(); + Base::Quantity q(*a * *b); + return new QuantityPy(new Quantity(q) ); + } + else if (PyFloat_Check(other)) { + Base::Quantity *a = static_cast(self) ->getQuantityPtr(); + Base::Quantity q(*a * Base::Quantity(PyFloat_AsDouble(other))); + return new QuantityPy(new Quantity(q) ); + } #if PY_MAJOR_VERSION < 3 - else if (PyInt_Check(other)) { - Base::Quantity *a = static_cast(self) ->getQuantityPtr(); - double b = (double)PyInt_AsLong(other); -#else - else if (PyLong_Check(other)) { - Base::Quantity *a = static_cast(self) ->getQuantityPtr(); - double b = (double)PyLong_AsLong(other); + else if (PyInt_Check(other)) { + Base::Quantity *a = static_cast(self) ->getQuantityPtr(); + Base::Quantity q(*a * Base::Quantity(PyInt_AsLong(other))); + return new QuantityPy(new Quantity(q) ); + } #endif - return new QuantityPy(new Quantity(*a*b) ); - } - } - else if (PyObject_TypeCheck(other, &(QuantityPy::Type))) { - if (PyFloat_Check(self)) { - Base::Quantity *a = static_cast(other) ->getQuantityPtr(); - double b = PyFloat_AsDouble(self); - return new QuantityPy(new Quantity(*a*b) ); + else if (PyLong_Check(other)) { + Base::Quantity *a = static_cast(self) ->getQuantityPtr(); + Base::Quantity q(*a * Base::Quantity(PyLong_AsLong(other))); + return new QuantityPy(new Quantity(q) ); + } } + else if (PyObject_TypeCheck(other, &(QuantityPy::Type))) { + if (PyFloat_Check(self)) { + Base::Quantity *a = static_cast(other) ->getQuantityPtr(); + Base::Quantity q(*a * Base::Quantity(PyFloat_AsDouble(self))); + return new QuantityPy(new Quantity(q) ); + } #if PY_MAJOR_VERSION < 3 - else if (PyInt_Check(self)) { - Base::Quantity *a = static_cast(other) ->getQuantityPtr(); - double b = (double)PyInt_AsLong(self); -#else - else if (PyLong_Check(self)) { - Base::Quantity *a = static_cast(other) ->getQuantityPtr(); - double b = (double)PyLong_AsLong(self); + else if (PyInt_Check(self)) { + Base::Quantity *a = static_cast(other) ->getQuantityPtr(); + Base::Quantity q(*a * Base::Quantity(PyInt_AsLong(self))); + return new QuantityPy(new Quantity(q) ); + } #endif - return new QuantityPy(new Quantity(*a*b) ); + else if (PyLong_Check(self)) { + Base::Quantity *a = static_cast(other) ->getQuantityPtr(); + Base::Quantity q(*a * Base::Quantity(PyLong_AsLong(self))); + return new QuantityPy(new Quantity(q) ); + } } - } - - PyErr_SetString(PyExc_TypeError, "A Quantity can only be multiplied by Quantity or number"); - return 0; + PyErr_SetString(PyExc_TypeError, "A Quantity can only be multiplied by Quantity or number"); + return 0; + } PY_CATCH } PyObject * QuantityPy::number_divide_handler (PyObject *self, PyObject *other) { - if (!PyObject_TypeCheck(self, &(QuantityPy::Type))) { - PyErr_SetString(PyExc_TypeError, "First arg must be Quantity"); - return 0; - } - - if (PyObject_TypeCheck(other, &(QuantityPy::Type))) { - Base::Quantity *a = static_cast(self) ->getQuantityPtr(); - Base::Quantity *b = static_cast(other)->getQuantityPtr(); - - return new QuantityPy(new Quantity(*a / *b) ); - } - else if (PyFloat_Check(other)) { - Base::Quantity *a = static_cast(self) ->getQuantityPtr(); - double b = PyFloat_AsDouble(other); - return new QuantityPy(new Quantity(*a / b) ); - } + PY_TRY { + if (PyObject_TypeCheck(self, &(QuantityPy::Type))) { + if (PyObject_TypeCheck(other, &(QuantityPy::Type))) { + Base::Quantity *a = static_cast(self) ->getQuantityPtr(); + Base::Quantity *b = static_cast(other)->getQuantityPtr(); + Base::Quantity q(*a / *b); + return new QuantityPy(new Quantity(q) ); + } + else if (PyFloat_Check(other)) { + Base::Quantity *a = static_cast(self) ->getQuantityPtr(); + Base::Quantity q(*a / Base::Quantity(PyFloat_AsDouble(other))); + return new QuantityPy(new Quantity(q) ); + } #if PY_MAJOR_VERSION < 3 - else if (PyInt_Check(other)) { - Base::Quantity *a = static_cast(self) ->getQuantityPtr(); - double b = (double)PyInt_AsLong(other); - return new QuantityPy(new Quantity(*a / b) ); - } + else if (PyInt_Check(other)) { + Base::Quantity *a = static_cast(self) ->getQuantityPtr(); + Base::Quantity q(*a / Base::Quantity(PyInt_AsLong(other))); + return new QuantityPy(new Quantity(q) ); + } #endif - else if (PyLong_Check(other)) { - Base::Quantity *a = static_cast(self) ->getQuantityPtr(); - double b = (double)PyLong_AsLong(other); - return new QuantityPy(new Quantity(*a / b) ); - } - else { + else if (PyLong_Check(other)) { + Base::Quantity *a = static_cast(self) ->getQuantityPtr(); + Base::Quantity q(*a / Base::Quantity(PyLong_AsLong(other))); + return new QuantityPy(new Quantity(q) ); + } + else { + PyErr_SetString(PyExc_TypeError, "A Quantity can only be divided by Quantity or number"); + return 0; + } + } else if (PyObject_TypeCheck(other, &(QuantityPy::Type))) { + if (PyFloat_Check(self)) { + Base::Quantity *a = static_cast(other) ->getQuantityPtr(); + Base::Quantity q(Base::Quantity(PyFloat_AsDouble(self))/(*a)); + return new QuantityPy(new Quantity(q)); + } +#if PY_MAJOR_VERSION < 3 + else if (PyInt_Check(self)) { + Base::Quantity *a = static_cast(other) ->getQuantityPtr(); + Base::Quantity q(Base::Quantity(PyInt_AsLong(self))/(*a)); + return new QuantityPy(new Quantity(q) ); + } +#endif + else if (PyLong_Check(self)) { + Base::Quantity *a = static_cast(other) ->getQuantityPtr(); + Base::Quantity q(Base::Quantity(PyLong_AsLong(self))/(*a)); + return new QuantityPy(new Quantity(q) ); + } + } PyErr_SetString(PyExc_TypeError, "A Quantity can only be divided by Quantity or number"); return 0; - } + }PY_CATCH } PyObject * QuantityPy::number_remainder_handler (PyObject *self, PyObject *other) @@ -429,10 +446,10 @@ PyObject * QuantityPy::number_remainder_handler (PyObject *self, PyObject *other #if PY_MAJOR_VERSION < 3 else if (PyInt_Check(other)) { d2 = (double)PyInt_AsLong(other); -#else + } +#endif else if (PyLong_Check(other)) { d2 = (double)PyLong_AsLong(other); -#endif } else { PyErr_SetString(PyExc_TypeError, "Expected quantity or number"); @@ -465,32 +482,36 @@ PyObject * QuantityPy::number_power_handler (PyObject *self, PyObject *other, Py return 0; } - if (PyObject_TypeCheck(other, &(QuantityPy::Type))) { - Base::Quantity *a = static_cast(self) ->getQuantityPtr(); - Base::Quantity *b = static_cast(other)->getQuantityPtr(); - - return new QuantityPy(new Quantity(a->pow(*b))); - } - else if (PyFloat_Check(other)) { - Base::Quantity *a = static_cast(self) ->getQuantityPtr(); - double b = PyFloat_AsDouble(other); - return new QuantityPy(new Quantity(a->pow(b)) ); - } + PY_TRY { + if (PyObject_TypeCheck(other, &(QuantityPy::Type))) { + Base::Quantity *a = static_cast(self) ->getQuantityPtr(); + Base::Quantity *b = static_cast(other)->getQuantityPtr(); + Base::Quantity q(a->pow(*b)); // to prevent memory leak in case of exception + + return new QuantityPy(new Quantity(q)); + } + else if (PyFloat_Check(other)) { + Base::Quantity *a = static_cast(self) ->getQuantityPtr(); + double b = PyFloat_AsDouble(other); + return new QuantityPy(new Quantity(a->pow(b)) ); + } #if PY_MAJOR_VERSION < 3 - else if (PyInt_Check(other)) { - Base::Quantity *a = static_cast(self) ->getQuantityPtr(); - double b = (double)PyInt_AsLong(other); -#else - else if (PyLong_Check(other)) { - Base::Quantity *a = static_cast(self) ->getQuantityPtr(); - double b = (double)PyLong_AsLong(other); + else if (PyInt_Check(other)) { + Base::Quantity *a = static_cast(self) ->getQuantityPtr(); + double b = (double)PyInt_AsLong(other); + return new QuantityPy(new Quantity(a->pow(b))); + } #endif - return new QuantityPy(new Quantity(a->pow(b))); - } - else { - PyErr_SetString(PyExc_TypeError, "Expected quantity or number"); - return 0; - } + else if (PyLong_Check(other)) { + Base::Quantity *a = static_cast(self) ->getQuantityPtr(); + double b = (double)PyLong_AsLong(other); + return new QuantityPy(new Quantity(a->pow(b))); + } + else { + PyErr_SetString(PyExc_TypeError, "Expected quantity or number"); + return 0; + } + }PY_CATCH } int QuantityPy::number_nonzero_handler (PyObject *self) diff --git a/src/Base/VectorPyImp.cpp b/src/Base/VectorPyImp.cpp index d153f4e168..19b0684be6 100644 --- a/src/Base/VectorPyImp.cpp +++ b/src/Base/VectorPyImp.cpp @@ -32,6 +32,8 @@ // inclusion of the generated files (generated out of VectorPy.xml) #include "GeometryPyCXX.h" #include "VectorPy.h" +#include "MatrixPy.h" +#include "RotationPy.h" #include "VectorPy.cpp" using namespace Base; @@ -142,11 +144,24 @@ PyObject* VectorPy::number_multiply_handler(PyObject *self, PyObject *other) { if (PyObject_TypeCheck(self, &(VectorPy::Type))) { Base::Vector3d a = static_cast(self) ->value(); + + if (PyObject_TypeCheck(other, &MatrixPy::Type)) { + Base::Matrix4D b = static_cast(other)->value(); + b.scale(a); + return new MatrixPy(b); + } + + if (PyObject_TypeCheck(other, &RotationPy::Type)) { + Base::Rotation b = static_cast(other)->value(); + return new VectorPy(b.multVec(a)); + } + if (PyObject_TypeCheck(other, &(VectorPy::Type))) { Base::Vector3d b = static_cast(other)->value(); Py::Float mult(a * b); return Py::new_reference_to(mult); } + else if (PyFloat_Check(other)) { double b = PyFloat_AsDouble(other); return new VectorPy(a * b); @@ -162,7 +177,7 @@ PyObject* VectorPy::number_multiply_handler(PyObject *self, PyObject *other) return new VectorPy(a * (double)b); } else { - PyErr_SetString(PyExc_TypeError, "A Vector can only be multiplied by Vector or number"); + PyErr_SetString(PyExc_NotImplementedError, "Not implemented"); return 0; } } @@ -704,6 +719,14 @@ PyObject * VectorPy::number_divide_handler (PyObject* self, PyObject* other) PyObject * VectorPy::number_remainder_handler (PyObject* self, PyObject* other) { + if (PyObject_TypeCheck(self, &(VectorPy::Type)) && + PyObject_TypeCheck(other, &(VectorPy::Type))) + { + Base::Vector3d a = static_cast(self) ->value(); + Base::Vector3d b = static_cast(other) ->value(); + return new VectorPy(a % b); + } + PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for %%: '%s' and '%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); return 0;