Base: improve base python object number protocol

This commit is contained in:
Zheng, Lei
2019-08-25 16:16:18 +08:00
committed by wmayer
parent daf96d29fd
commit 1efadc928e
6 changed files with 233 additions and 123 deletions

View File

@@ -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<MatrixPy*>(self)->value();
if (PyObject_TypeCheck(other, &(VectorPy::Type))) {
auto b = static_cast<VectorPy*>(other)->value();
return new VectorPy(a*b);
}
if (PyObject_TypeCheck(other, &(RotationPy::Type))) {
auto r = static_cast<RotationPy*>(other)->value();
Matrix4D b;
r.getValue(b);
return new MatrixPy(a*b);
}
if (PyObject_TypeCheck(other, &(MatrixPy::Type))) {
Base::Matrix4D b = static_cast<MatrixPy*>(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<MatrixPy*>(self)->value();
Base::Matrix4D b = static_cast<MatrixPy*>(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");

View File

@@ -112,5 +112,11 @@ Placement(Base, Axis, Angle) -- define position and rotation
</Documentation>
<Parameter Name="Rotation" Type="Object" />
</Attribute>
<Attribute Name="Matrix" ReadOnly="false">
<Documentation>
<UserDocu>Set/get matrix representation of this placement</UserDocu>
</Documentation>
<Parameter Name="Matrix" Type="Object" />
</Attribute>
</PythonExport>
</GenerateModel>

View File

@@ -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

View File

@@ -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);
}

View File

@@ -290,15 +290,12 @@ PyObject* QuantityPy::number_add_handler(PyObject *self, PyObject *other)
return 0;
}
try {
PY_TRY {
Base::Quantity *a = static_cast<QuantityPy*>(self)->getQuantityPtr();
Base::Quantity *b = static_cast<QuantityPy*>(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<QuantityPy*>(self)->getQuantityPtr();
Base::Quantity *b = static_cast<QuantityPy*>(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<QuantityPy*>(self) ->getQuantityPtr();
Base::Quantity *b = static_cast<QuantityPy*>(other)->getQuantityPtr();
return new QuantityPy(new Quantity(*a * *b) );
}
else if (PyFloat_Check(other)) {
Base::Quantity *a = static_cast<QuantityPy*>(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<QuantityPy*>(self) ->getQuantityPtr();
Base::Quantity *b = static_cast<QuantityPy*>(other)->getQuantityPtr();
Base::Quantity q(*a * *b);
return new QuantityPy(new Quantity(q) );
}
else if (PyFloat_Check(other)) {
Base::Quantity *a = static_cast<QuantityPy*>(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<QuantityPy*>(self) ->getQuantityPtr();
double b = (double)PyInt_AsLong(other);
#else
else if (PyLong_Check(other)) {
Base::Quantity *a = static_cast<QuantityPy*>(self) ->getQuantityPtr();
double b = (double)PyLong_AsLong(other);
else if (PyInt_Check(other)) {
Base::Quantity *a = static_cast<QuantityPy*>(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<QuantityPy*>(other) ->getQuantityPtr();
double b = PyFloat_AsDouble(self);
return new QuantityPy(new Quantity(*a*b) );
else if (PyLong_Check(other)) {
Base::Quantity *a = static_cast<QuantityPy*>(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<QuantityPy*>(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<QuantityPy*>(other) ->getQuantityPtr();
double b = (double)PyInt_AsLong(self);
#else
else if (PyLong_Check(self)) {
Base::Quantity *a = static_cast<QuantityPy*>(other) ->getQuantityPtr();
double b = (double)PyLong_AsLong(self);
else if (PyInt_Check(self)) {
Base::Quantity *a = static_cast<QuantityPy*>(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<QuantityPy*>(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<QuantityPy*>(self) ->getQuantityPtr();
Base::Quantity *b = static_cast<QuantityPy*>(other)->getQuantityPtr();
return new QuantityPy(new Quantity(*a / *b) );
}
else if (PyFloat_Check(other)) {
Base::Quantity *a = static_cast<QuantityPy*>(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<QuantityPy*>(self) ->getQuantityPtr();
Base::Quantity *b = static_cast<QuantityPy*>(other)->getQuantityPtr();
Base::Quantity q(*a / *b);
return new QuantityPy(new Quantity(q) );
}
else if (PyFloat_Check(other)) {
Base::Quantity *a = static_cast<QuantityPy*>(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<QuantityPy*>(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<QuantityPy*>(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<QuantityPy*>(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<QuantityPy*>(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<QuantityPy*>(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<QuantityPy*>(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<QuantityPy*>(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<QuantityPy*>(self) ->getQuantityPtr();
Base::Quantity *b = static_cast<QuantityPy*>(other)->getQuantityPtr();
return new QuantityPy(new Quantity(a->pow(*b)));
}
else if (PyFloat_Check(other)) {
Base::Quantity *a = static_cast<QuantityPy*>(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<QuantityPy*>(self) ->getQuantityPtr();
Base::Quantity *b = static_cast<QuantityPy*>(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<QuantityPy*>(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<QuantityPy*>(self) ->getQuantityPtr();
double b = (double)PyInt_AsLong(other);
#else
else if (PyLong_Check(other)) {
Base::Quantity *a = static_cast<QuantityPy*>(self) ->getQuantityPtr();
double b = (double)PyLong_AsLong(other);
else if (PyInt_Check(other)) {
Base::Quantity *a = static_cast<QuantityPy*>(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<QuantityPy*>(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)

View File

@@ -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<VectorPy*>(self) ->value();
if (PyObject_TypeCheck(other, &MatrixPy::Type)) {
Base::Matrix4D b = static_cast<MatrixPy*>(other)->value();
b.scale(a);
return new MatrixPy(b);
}
if (PyObject_TypeCheck(other, &RotationPy::Type)) {
Base::Rotation b = static_cast<RotationPy*>(other)->value();
return new VectorPy(b.multVec(a));
}
if (PyObject_TypeCheck(other, &(VectorPy::Type))) {
Base::Vector3d b = static_cast<VectorPy*>(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<VectorPy*>(self) ->value();
Base::Vector3d b = static_cast<VectorPy*>(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;