From 44354b808becee9c68b55a7ab3aaedf516cb5a56 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Sun, 29 Sep 2019 17:38:07 +0800 Subject: [PATCH] App: add Expression built-in function mscale/minvert/create mscale(matrix,vector|tuple) for scaling matrix minvert(matrix|placement|rotation) for inverting matrix, placement or rotation create(type,arg...) for creating Python object of given type (currently only support 'matrix', 'placement', 'rotation', 'vector' --- src/App/Expression.cpp | 94 ++++++++++++++++++++++++++++++++++++++ src/App/ExpressionParser.h | 3 ++ 2 files changed, 97 insertions(+) diff --git a/src/App/Expression.cpp b/src/App/Expression.cpp index 12a2e57c1d..efe4acf815 100644 --- a/src/App/Expression.cpp +++ b/src/App/Expression.cpp @@ -30,6 +30,8 @@ # pragma clang diagnostic ignored "-Wdelete-non-virtual-dtor" #endif +#include + #include #include "Base/Exception.h" #include @@ -39,6 +41,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -1771,6 +1777,7 @@ FunctionExpression::FunctionExpression(const DocumentObject *_owner, Function _f case TRUNC: case CEIL: case FLOOR: + case MINVERT: if (args.size() != 1) EXPR_THROW("Invalid number of arguments: exactly one required."); break; @@ -1791,6 +1798,8 @@ FunctionExpression::FunctionExpression(const DocumentObject *_owner, Function _f case COUNT: case MIN: case MAX: + case CREATE: + case MSCALE: if (args.size() == 0) EXPR_THROW("Invalid number of arguments: at least one required."); break; @@ -2039,11 +2048,87 @@ Py::Object FunctionExpression::evaluate(const Expression *expr, int f, const std for(auto &arg : args) tuple.setItem(i++,arg->getPyValue()); return tuple; + } else if (f == MSCALE) { + if(args.size() < 2) + _EXPR_THROW("Function requires at least two arguments.",expr); + Py::Object pymat = args[0]->getPyValue(); + Py::Object pyscale; + if(PyObject_TypeCheck(pymat.ptr(),&Base::MatrixPy::Type)) { + if(args.size() == 2) { + Py::Object obj = args[1]->getPyValue(); + if(obj.isSequence() && PySequence_Size(obj.ptr())==3) + pyscale = Py::Tuple(Py::Sequence(obj)); + } else if(args.size() == 4) { + Py::Tuple tuple(3); + tuple.setItem(0,args[1]->getPyValue()); + tuple.setItem(1,args[2]->getPyValue()); + tuple.setItem(2,args[3]->getPyValue()); + pyscale = tuple; + } + } + if(!pyscale.isNone()) { + Base::Vector3d vec; + if (!PyArg_ParseTuple(pyscale.ptr(), "ddd", &vec.x,&vec.y,&vec.z)) + PyErr_Clear(); + else { + auto mat = static_cast(pymat.ptr())->value(); + mat.scale(vec); + return Py::Object(new Base::MatrixPy(mat)); + } + } + _EXPR_THROW("Function requires arguments to be either " + "(matrix,vector) or (matrix,number,number,number).", expr); } if(args.empty()) _EXPR_THROW("Function requires at least one argument.",expr); + if (f == MINVERT) { + Py::Object pyobj = args[0]->getPyValue(); + Py::Tuple args; + if (PyObject_TypeCheck(pyobj.ptr(),&Base::MatrixPy::Type)) { + auto m = static_cast(pyobj.ptr())->value(); + if (fabs(m.determinant()) <= DBL_EPSILON) + _EXPR_THROW("Cannot invert singular matrix.",expr); + m.inverseGauss(); + return Py::Object(new Base::MatrixPy(m)); + + } else if (PyObject_TypeCheck(pyobj.ptr(),&Base::PlacementPy::Type)) { + const auto &pla = *static_cast(pyobj.ptr())->getPlacementPtr(); + return Py::Object(new Base::PlacementPy(pla.inverse())); + + } else if (PyObject_TypeCheck(pyobj.ptr(),&Base::RotationPy::Type)) { + const auto &rot = *static_cast(pyobj.ptr())->getRotationPtr(); + return Py::Object(new Base::RotationPy(rot.inverse())); + } + _EXPR_THROW("Function requires the first argument to be either Matrix, Placement or Rotation.",expr); + + } else if (f == CREATE) { + Py::Object pytype = args[0]->getPyValue(); + if(!pytype.isString()) + _EXPR_THROW("Function requires the first argument to be a string.",expr); + std::string type(pytype.as_string()); + Py::Object res; + if(boost::iequals(type,"matrix")) + res = Py::Object(new Base::MatrixPy(Base::Matrix4D())); + else if(boost::iequals(type,"vector")) + res = Py::Object(new Base::VectorPy(Base::Vector3d())); + else if(boost::iequals(type,"placement")) + res = Py::Object(new Base::PlacementPy(Base::Placement())); + else if(boost::iequals(type,"rotation")) + res = Py::Object(new Base::RotationPy(Base::Rotation())); + else + _EXPR_THROW("Unknown type '" << type << "'.",expr); + if(args.size()>1) { + Py::Tuple tuple(args.size()-1); + for(unsigned i=1;igetPyValue()); + Py::Dict dict; + PyObjectBase::__PyInit(res.ptr(),tuple.ptr(),dict.ptr()); + } + return res; + } + Py::Object e1 = args[0]->getPyValue(); Quantity v1 = pyToQuantity(e1,expr,"Invalid first argument."); Py::Object e2; @@ -2368,6 +2453,12 @@ void FunctionExpression::_toString(std::ostream &ss, bool persistent,int) const ss << "list("; break;; case TUPLE: ss << "tuple("; break;; + case MSCALE: + ss << "mscale("; break;; + case MINVERT: + ss << "minvert("; break;; + case CREATE: + ss << "create("; break;; default: assert(0); } @@ -3184,6 +3275,9 @@ static void initParser(const App::DocumentObject *owner) registered_functions["cath"] = FunctionExpression::CATH; registered_functions["list"] = FunctionExpression::LIST; registered_functions["tuple"] = FunctionExpression::TUPLE; + registered_functions["mscale"] = FunctionExpression::MSCALE; + registered_functions["minvert"] = FunctionExpression::MINVERT; + registered_functions["create"] = FunctionExpression::CREATE; // Aggregates registered_functions["sum"] = FunctionExpression::SUM; diff --git a/src/App/ExpressionParser.h b/src/App/ExpressionParser.h index 61f6cee3cc..d1b78cfb1f 100644 --- a/src/App/ExpressionParser.h +++ b/src/App/ExpressionParser.h @@ -269,6 +269,9 @@ public: CATH, LIST, TUPLE, + MSCALE, // matrix scale by vector + MINVERT, // invert matrix/placement/rotation + CREATE, // create new object of a given type // Aggregates AGGREGATES,