diff --git a/src/Mod/Path/App/CommandPy.xml b/src/Mod/Path/App/CommandPy.xml index 14e6df4109..1588b9dbe1 100644 --- a/src/Mod/Path/App/CommandPy.xml +++ b/src/Mod/Path/App/CommandPy.xml @@ -43,7 +43,7 @@ pairs, or a placement, or a vector - toGCode(): returns a GCode representation of the command + setFromGCode(): sets the path from the contents of the given GCode string @@ -51,5 +51,8 @@ pairs, or a placement, or a vector transform(Placement): returns a copy of this command transformed by the given placement + + mutable Py::Dict parameters_copy_dict; + diff --git a/src/Mod/Path/App/CommandPyImp.cpp b/src/Mod/Path/App/CommandPyImp.cpp index 98dc904264..88bd30fce5 100644 --- a/src/Mod/Path/App/CommandPyImp.cpp +++ b/src/Mod/Path/App/CommandPyImp.cpp @@ -56,6 +56,11 @@ std::string CommandPy::representation(void) const return str.str(); } +// +// Py::Dict parameters_copy_dict is now a class member to avoid delete/create/copy on every read access from python code +// Now the pre-filled Py::Dict is returned which is more consistent with normal python behaviour. +// It should be cleared whenever the c++ Parameters object is changed eg setParameters() or other objects invalidate its content, eg setPlacement() +// https://forum.freecadweb.org/viewtopic.php?f=15&t=50583 PyObject *CommandPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper { @@ -117,6 +122,7 @@ int CommandPy::PyInit(PyObject* args, PyObject* kwd) } getCommandPtr()->Parameters[ckey]=cvalue; } + parameters_copy_dict.clear(); return 0; } PyErr_Clear(); // set by PyArg_ParseTuple() @@ -157,11 +163,13 @@ void CommandPy::setName(Py::String arg) Py::Dict CommandPy::getParameters(void) const { - Py::Dict dict; - for(std::map::iterator i = getCommandPtr()->Parameters.begin(); i != getCommandPtr()->Parameters.end(); ++i) { - dict.setItem(i->first, Py::Float(i->second)); + // dict now a class member , https://forum.freecadweb.org/viewtopic.php?f=15&t=50583 + if (parameters_copy_dict.length()==0) { + for(std::map::iterator i = getCommandPtr()->Parameters.begin(); i != getCommandPtr()->Parameters.end(); ++i) { + parameters_copy_dict.setItem(i->first, Py::Float(i->second)); + } } - return dict; + return parameters_copy_dict; } void CommandPy::setParameters(Py::Dict arg) @@ -200,6 +208,7 @@ void CommandPy::setParameters(Py::Dict arg) throw Py::TypeError("The dictionary can only contain number values"); } getCommandPtr()->Parameters[ckey]=cvalue; + parameters_copy_dict.clear(); } } @@ -224,6 +233,7 @@ PyObject* CommandPy::setFromGCode(PyObject *args) std::string gcode(pstr); try { getCommandPtr()->setFromGCode(gcode); + parameters_copy_dict.clear(); } catch (const Base::Exception& e) { PyErr_SetString(PyExc_ValueError, e.what()); @@ -249,6 +259,7 @@ void CommandPy::setPlacement(Py::Object arg) Py::Type PlacementType(pyType.o); if(arg.isType(PlacementType)) { getCommandPtr()->setFromPlacement( *static_cast((*arg))->getPlacementPtr() ); + parameters_copy_dict.clear(); } else throw Py::TypeError("Argument must be a placement"); } @@ -259,6 +270,7 @@ PyObject* CommandPy::transform(PyObject *args) if ( PyArg_ParseTuple(args, "O!", &(Base::PlacementPy::Type), &placement) ) { Base::PlacementPy *p = static_cast(placement); Path::Command trCmd = getCommandPtr()->transform( *p->getPlacementPtr() ); + parameters_copy_dict.clear(); return new CommandPy(new Path::Command(trCmd)); } else throw Py::TypeError("Argument must be a placement"); @@ -302,6 +314,7 @@ int CommandPy::setCustomAttributes(const char* attr, PyObject* obj) return 0; } getCommandPtr()->Parameters[satt]=cvalue; + parameters_copy_dict.clear(); return 1; } }