From 332f6b9a2a68158cf49feab94e21dd384d144b37 Mon Sep 17 00:00:00 2001 From: mpv Date: Wed, 23 Nov 2016 12:39:26 +0300 Subject: [PATCH] Issue #1806 : evaluation of expressions if no parameters defined. Now the python interpreter is loaded in Initialization plugin and accessible for any expression evaluation even if no parameters were created. --- src/InitializationPlugin/CMakeLists.txt | 20 +- .../InitializationPlugin_EvalListener.cpp | 210 ++++++++++++++++++ .../InitializationPlugin_EvalListener.h | 51 +++++ .../InitializationPlugin_Plugin.cpp | 4 + .../InitializationPlugin_Plugin.h | 6 +- .../InitializationPlugin_PyInterp.cpp} | 24 +- .../InitializationPlugin_PyInterp.h} | 18 +- src/ModelAPI/ModelAPI_Events.cpp | 108 +++++++-- src/ModelAPI/ModelAPI_Events.h | 104 +++++++++ src/ParametersPlugin/CMakeLists.txt | 15 +- .../ParametersPlugin_EvalListener.cpp | 132 +---------- .../ParametersPlugin_EvalListener.h | 10 - .../ParametersPlugin_Parameter.cpp | 87 +++----- .../ParametersPlugin_Parameter.h | 5 - 14 files changed, 540 insertions(+), 254 deletions(-) create mode 100644 src/InitializationPlugin/InitializationPlugin_EvalListener.cpp create mode 100644 src/InitializationPlugin/InitializationPlugin_EvalListener.h rename src/{ParametersPlugin/ParametersPlugin_PyInterp.cpp => InitializationPlugin/InitializationPlugin_PyInterp.cpp} (87%) rename src/{ParametersPlugin/ParametersPlugin_PyInterp.h => InitializationPlugin/InitializationPlugin_PyInterp.h} (74%) diff --git a/src/InitializationPlugin/CMakeLists.txt b/src/InitializationPlugin/CMakeLists.txt index 7967fcc67..e5b0ce86b 100644 --- a/src/InitializationPlugin/CMakeLists.txt +++ b/src/InitializationPlugin/CMakeLists.txt @@ -1,36 +1,44 @@ - INCLUDE(Common) +INCLUDE(FindPython) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Events ${PROJECT_SOURCE_DIR}/src/Config ${PROJECT_SOURCE_DIR}/src/ModelAPI ${PROJECT_SOURCE_DIR}/src/GeomAPI + ${PROJECT_SOURCE_DIR}/src/GeomDataAPI + ${PROJECT_SOURCE_DIR}/src/ParametersPlugin + ${SUIT_INCLUDE} + ${PYTHON_INCLUDE_DIR} ) SET(PROJECT_HEADERS InitializationPlugin.h InitializationPlugin_Plugin.h - #InitializationPlugin_OriginPlanesFeature.h + InitializationPlugin_EvalListener.h + InitializationPlugin_PyInterp.h ) SET(PROJECT_SOURCES InitializationPlugin_Plugin.cpp - #InitializationPlugin_OriginPlanesFeature.cpp + InitializationPlugin_EvalListener.cpp + InitializationPlugin_PyInterp.cpp ) -#SET(XML_RESOURCES -#) +MESSAGE(STATUS "PYTHON_LIBRARIES (ParametersPlugin): ${PYTHON_LIBRARIES}") SET(PROJECT_LIBRARIES Events Config ModelAPI + ${PyInterp} + ${PYTHON_LIBRARIES} ) -ADD_DEFINITIONS(-DINITIALIZATIONPLUGIN_EXPORTS) +ADD_DEFINITIONS(-DINITIALIZATIONPLUGIN_EXPORTS -DHAVE_DEBUG_PYTHON) ADD_LIBRARY(InitializationPlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES}) TARGET_LINK_LIBRARIES(InitializationPlugin ${PROJECT_LIBRARIES}) INSTALL(TARGETS InitializationPlugin DESTINATION ${SHAPER_INSTALL_PLUGIN_FILES}) #INSTALL(FILES ${XML_RESOURCES} DESTINATION plugins) + diff --git a/src/InitializationPlugin/InitializationPlugin_EvalListener.cpp b/src/InitializationPlugin/InitializationPlugin_EvalListener.cpp new file mode 100644 index 000000000..86d457a73 --- /dev/null +++ b/src/InitializationPlugin/InitializationPlugin_EvalListener.cpp @@ -0,0 +1,210 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> +/* + * InitializationPlugin_EvalListener.cpp + * + * Created on: Apr 28, 2015 + * Author: sbh + */ + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +//------------------------------------------------------------------------------ +// Tools + +std::string toStdString(double theValue) +{ + std::ostringstream sstream; + sstream << theValue; + size_t aPos = sstream.str().find("."); + std::string aPnt = ""; + if (aPos == std::string::npos) + aPnt = "."; + return sstream.str() + aPnt; +} + +std::set toSet(const std::list& theContainer) +{ + return std::set(theContainer.begin(), theContainer.end()); +} + +//------------------------------------------------------------------------------ + +InitializationPlugin_EvalListener::InitializationPlugin_EvalListener() +{ + Events_Loop* aLoop = Events_Loop::loop(); + + aLoop->registerListener(this, ModelAPI_AttributeEvalMessage::eventId(), NULL, true); + aLoop->registerListener(this, ModelAPI_ParameterEvalMessage::eventId(), NULL, true); + aLoop->registerListener(this, ModelAPI_ComputePositionsMessage::eventId(), NULL, true); + + myInterp = std::shared_ptr(new InitializationPlugin_PyInterp()); + myInterp->initialize(); +} + +InitializationPlugin_EvalListener::~InitializationPlugin_EvalListener() +{ +} + +void InitializationPlugin_EvalListener::processEvent( + const std::shared_ptr& theMessage) +{ + if (!theMessage.get()) + return; + + if (theMessage->eventID() == ModelAPI_AttributeEvalMessage::eventId()) { + processEvaluationEvent(theMessage); + } else if (theMessage->eventID() == ModelAPI_ParameterEvalMessage::eventId()) { + std::shared_ptr aMsg = + std::dynamic_pointer_cast(theMessage); + FeaturePtr aParam = aMsg->parameter(); + std::string anExp = aParam->string(ParametersPlugin_Parameter::EXPRESSION_ID())->value(); + std::string anError; + std::list > aParamsList; + double aResult = evaluate(aParam, anExp, anError, aParamsList, true); + aMsg->setResults(aParamsList, aResult, anError); + } else if (theMessage->eventID() == ModelAPI_ComputePositionsMessage::eventId()) { + std::shared_ptr aMsg = + std::dynamic_pointer_cast(theMessage); + aMsg->setPositions(myInterp->positions(aMsg->expression(), aMsg->parameter())); + } +} + +double InitializationPlugin_EvalListener::evaluate(FeaturePtr theParameter, + const std::string& theExpression, std::string& theError, + std::list >& theParamsList, + const bool theIsParameter) +{ + std::list anExprParams = myInterp->compile(theExpression); + // find expression's params in the model + std::list aContext; + std::list::iterator it = anExprParams.begin(); + for ( ; it != anExprParams.end(); it++) { + double aValue; + ResultParameterPtr aParamRes; + // If variable does not exist python interpreter will generate an error. It is OK. + // But due to the issue 1479 it should not check the history position of parameters relatively + // to feature that contains expression + if (!ModelAPI_Tools::findVariable(theIsParameter ? theParameter : FeaturePtr(), + *it, aValue, aParamRes, theParameter->document())) + continue; + + if (theIsParameter) + theParamsList.push_back(aParamRes); + aContext.push_back(*it + "=" + toStdString(aValue)); + } + myInterp->extendLocalContext(aContext); + double result = myInterp->evaluate(theExpression, theError); + myInterp->clearLocalContext(); + return result; +} + +void InitializationPlugin_EvalListener::processEvaluationEvent( + const std::shared_ptr& theMessage) +{ + std::shared_ptr aMessage = + std::dynamic_pointer_cast(theMessage); + + std::list > aParamsList; + FeaturePtr aParamFeature = + std::dynamic_pointer_cast(aMessage->attribute()->owner()); + if (aMessage->attribute()->attributeType() == ModelAPI_AttributeInteger::typeId()) { + AttributeIntegerPtr anAttribute = + std::dynamic_pointer_cast(aMessage->attribute()); + std::string anError; + int aValue = (int)evaluate(aParamFeature, anAttribute->text(), anError, aParamsList); + bool isValid = anError.empty(); + if (isValid) + anAttribute->setCalculatedValue(aValue); + anAttribute->setUsedParameters(isValid ? + toSet(myInterp->compile(anAttribute->text())) : std::set()); + anAttribute->setExpressionInvalid(!isValid); + anAttribute->setExpressionError(anAttribute->text().empty() ? "" : anError); + } else + if (aMessage->attribute()->attributeType() == ModelAPI_AttributeDouble::typeId()) { + AttributeDoublePtr anAttribute = + std::dynamic_pointer_cast(aMessage->attribute()); + std::string anError; + double aValue = evaluate(aParamFeature, anAttribute->text(), anError, aParamsList); + bool isValid = anError.empty(); + if (isValid) + anAttribute->setCalculatedValue(aValue); + anAttribute->setUsedParameters(isValid ? + toSet(myInterp->compile(anAttribute->text())) : std::set()); + anAttribute->setExpressionInvalid(!isValid); + anAttribute->setExpressionError(anAttribute->text().empty() ? "" : anError); + } else + if (aMessage->attribute()->attributeType() == GeomDataAPI_Point::typeId()) { + AttributePointPtr anAttribute = + std::dynamic_pointer_cast(aMessage->attribute()); + std::string aText[] = { + anAttribute->textX(), + anAttribute->textY(), + anAttribute->textZ() + }; + double aCalculatedValue[] = { + anAttribute->x(), + anAttribute->y(), + anAttribute->z() + }; + for (int i = 0; i < 3; ++i) { + std::string anError; + double aValue = evaluate(aParamFeature, aText[i], anError, aParamsList); + bool isValid = anError.empty(); + if (isValid) aCalculatedValue[i] = aValue; + anAttribute->setUsedParameters(i, + isValid ? toSet(myInterp->compile(aText[i])) : std::set()); + anAttribute->setExpressionInvalid(i, !isValid); + anAttribute->setExpressionError(i, aText[i].empty() ? "" : anError); + } + anAttribute->setCalculatedValue(aCalculatedValue[0], + aCalculatedValue[1], + aCalculatedValue[2]); + } else + if (aMessage->attribute()->attributeType() == GeomDataAPI_Point2D::typeId()) { + AttributePoint2DPtr anAttribute = + std::dynamic_pointer_cast(aMessage->attribute()); + std::string aText[] = { + anAttribute->textX(), + anAttribute->textY() + }; + double aCalculatedValue[] = { + anAttribute->x(), + anAttribute->y() + }; + for (int i = 0; i < 2; ++i) { + std::string anError; + double aValue = evaluate(aParamFeature, aText[i], anError, aParamsList); + bool isValid = anError.empty(); + if (isValid) aCalculatedValue[i] = aValue; + anAttribute->setUsedParameters(i, + isValid ? toSet(myInterp->compile(aText[i])) : std::set()); + anAttribute->setExpressionInvalid(i, !isValid); + anAttribute->setExpressionError(i, aText[i].empty() ? "" : anError); + } + anAttribute->setCalculatedValue(aCalculatedValue[0], + aCalculatedValue[1]); + } +} diff --git a/src/InitializationPlugin/InitializationPlugin_EvalListener.h b/src/InitializationPlugin/InitializationPlugin_EvalListener.h new file mode 100644 index 000000000..9ddb19dda --- /dev/null +++ b/src/InitializationPlugin/InitializationPlugin_EvalListener.h @@ -0,0 +1,51 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> +/* + * InitializationPlugin_EvalListener.h + * + * Created on: Apr 28, 2015 + * Author: sbh + */ + +#ifndef SRC_INITIALIZATIONPLUGIN_EVALLISTENER_H_ +#define SRC_INITIALIZATIONPLUGIN_EVALLISTENER_H_ + +#include +#include + +class ModelAPI_Attribute; +class ModelAPI_Document; +class ModelAPI_Feature; +class ModelAPI_ResultParameter; +class InitializationPlugin_Parameter; +class InitializationPlugin_PyInterp; + +/** + * \class InitializationPlugin_EvalListener + * \ingroup Plugins + * \brief Class which process the events from the event loop. + */ +class InitializationPlugin_EvalListener : public Events_Listener +{ + public: + INITIALIZATIONPLUGIN_EXPORT InitializationPlugin_EvalListener(); + INITIALIZATIONPLUGIN_EXPORT virtual ~InitializationPlugin_EvalListener(); + + /// Reimplemented from Events_Listener::processEvent(). + INITIALIZATIONPLUGIN_EXPORT + virtual void processEvent(const std::shared_ptr& theMessage); + + protected: + /// Evaluates theExpression and returns its value. + double evaluate(std::shared_ptr theParameter, + const std::string& theExpression, std::string& theError, + std::list >& theParamsList, + const bool theIsParameter = false); + + /// Processes Evaluation event. + void processEvaluationEvent(const std::shared_ptr& theMessage); + + private: + std::shared_ptr myInterp; +}; + +#endif /* SRC_INITIALIZATIONPLUGIN_INITIALIZATIONPLUGIN_EVALLISTENER_H_ */ diff --git a/src/InitializationPlugin/InitializationPlugin_Plugin.cpp b/src/InitializationPlugin/InitializationPlugin_Plugin.cpp index ee76b04d2..5367ef276 100644 --- a/src/InitializationPlugin/InitializationPlugin_Plugin.cpp +++ b/src/InitializationPlugin/InitializationPlugin_Plugin.cpp @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -25,6 +26,9 @@ InitializationPlugin_Plugin::InitializationPlugin_Plugin() Events_Loop* aLoop = Events_Loop::loop(); const Events_ID kDocCreatedEvent = ModelAPI_DocumentCreatedMessage::eventId(); aLoop->registerListener(this, kDocCreatedEvent, NULL, true); + + myEvalListener = + std::shared_ptr(new InitializationPlugin_EvalListener()); } void InitializationPlugin_Plugin::processEvent(const std::shared_ptr& theMessage) diff --git a/src/InitializationPlugin/InitializationPlugin_Plugin.h b/src/InitializationPlugin/InitializationPlugin_Plugin.h index 6f06f059f..52d5cc3e9 100644 --- a/src/InitializationPlugin/InitializationPlugin_Plugin.h +++ b/src/InitializationPlugin/InitializationPlugin_Plugin.h @@ -4,11 +4,12 @@ #define INITIALIZATIONPLUGIN_PLUGIN_H_ #include - #include #include +class InitializationPlugin_EvalListener; + /**\class InitializationPlugin_Plugin * \ingroup Plugins * This class is represents a plugin. @@ -51,6 +52,9 @@ class InitializationPlugin_Plugin : public Events_Listener /// \param theZ - Z of direction point FeaturePtr createAxis(DocumentPtr theDoc, FeaturePtr theOrigin, double theX, double theY, double theZ); + + private: + std::shared_ptr myEvalListener; }; #endif diff --git a/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp b/src/InitializationPlugin/InitializationPlugin_PyInterp.cpp similarity index 87% rename from src/ParametersPlugin/ParametersPlugin_PyInterp.cpp rename to src/InitializationPlugin/InitializationPlugin_PyInterp.cpp index a513b1070..ac32047ac 100644 --- a/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp +++ b/src/InitializationPlugin/InitializationPlugin_PyInterp.cpp @@ -1,22 +1,22 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D /* - * ParametersPlugin_PyInterp.cpp + * InitializationPlugin_PyInterp.cpp * * Created on: Apr 2, 2015 * Author: sbh */ -#include +#include #include #include -ParametersPlugin_PyInterp::ParametersPlugin_PyInterp() +InitializationPlugin_PyInterp::InitializationPlugin_PyInterp() : PyInterp_Interp() { } -ParametersPlugin_PyInterp::~ParametersPlugin_PyInterp() +InitializationPlugin_PyInterp::~InitializationPlugin_PyInterp() { } @@ -31,7 +31,7 @@ const char* aSearchCode = "FindName(name).visit(ast.parse(expression))"; std::list > -ParametersPlugin_PyInterp::positions(const std::string& theExpression, +InitializationPlugin_PyInterp::positions(const std::string& theExpression, const std::string& theName) { PyLockWrapper lck; // Acquire GIL until the end of the method @@ -71,7 +71,7 @@ ParametersPlugin_PyInterp::positions(const std::string& theExpression, } -std::list ParametersPlugin_PyInterp::compile(const std::string& theExpression) +std::list InitializationPlugin_PyInterp::compile(const std::string& theExpression) { PyLockWrapper lck; // Acquire GIL until the end of the method std::list aResult; @@ -110,7 +110,7 @@ std::list ParametersPlugin_PyInterp::compile(const std::string& the return aResult; } -void ParametersPlugin_PyInterp::extendLocalContext(const std::list& theParameters) +void InitializationPlugin_PyInterp::extendLocalContext(const std::list& theParameters) { PyLockWrapper lck; // Acquire GIL until the end of the method if (theParameters.empty()) @@ -122,13 +122,13 @@ void ParametersPlugin_PyInterp::extendLocalContext(const std::list& } } -void ParametersPlugin_PyInterp::clearLocalContext() +void InitializationPlugin_PyInterp::clearLocalContext() { PyLockWrapper lck; PyDict_Clear(_local_context); } -double ParametersPlugin_PyInterp::evaluate(const std::string& theExpression, std::string& theError) +double InitializationPlugin_PyInterp::evaluate(const std::string& theExpression, std::string& theError) { PyLockWrapper lck; // Acquire GIL until the end of the method PyCompilerFlags aFlags = {CO_FUTURE_DIVISION}; @@ -164,7 +164,7 @@ double ParametersPlugin_PyInterp::evaluate(const std::string& theExpression, std return result; } -std::string ParametersPlugin_PyInterp::errorMessage() +std::string InitializationPlugin_PyInterp::errorMessage() { std::string aPyError; if (PyErr_Occurred()) { @@ -181,7 +181,7 @@ std::string ParametersPlugin_PyInterp::errorMessage() return aPyError; } -bool ParametersPlugin_PyInterp::initContext() +bool InitializationPlugin_PyInterp::initContext() { PyObject *m = PyImport_AddModule("__main__"); // interpreter main module (module context) if(!m){ @@ -196,7 +196,7 @@ bool ParametersPlugin_PyInterp::initContext() return PyRun_SimpleString("from math import *") == 0; } -void ParametersPlugin_PyInterp::closeContext() +void InitializationPlugin_PyInterp::closeContext() { Py_XDECREF(_local_context); PyInterp_Interp::closeContext(); diff --git a/src/ParametersPlugin/ParametersPlugin_PyInterp.h b/src/InitializationPlugin/InitializationPlugin_PyInterp.h similarity index 74% rename from src/ParametersPlugin/ParametersPlugin_PyInterp.h rename to src/InitializationPlugin/InitializationPlugin_PyInterp.h index 6f4a30467..5e4b67163 100644 --- a/src/ParametersPlugin/ParametersPlugin_PyInterp.h +++ b/src/InitializationPlugin/InitializationPlugin_PyInterp.h @@ -1,31 +1,31 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> /* - * ParametersPlugin_PyInterp.h + * InitializationPlugin_PyInterp.h * * Created on: Apr 2, 2015 * Author: sbh */ -#ifndef PARAMETERSPLUGIN_PYINTERP_H_ -#define PARAMETERSPLUGIN_PYINTERP_H_ +#ifndef INITIALIZATIONPLUGIN_PYINTERP_H_ +#define INITIALIZATIONPLUGIN_PYINTERP_H_ #include -#include +#include #include #include #include /** - * \class ParametersPlugin_PyInterp + * \class InitializationPlugin_PyInterp * \ingroup Plugins * \brief Helper class for using Python interpreter. */ -class PARAMETERSPLUGIN_EXPORT ParametersPlugin_PyInterp : public PyInterp_Interp +class INITIALIZATIONPLUGIN_EXPORT InitializationPlugin_PyInterp : public PyInterp_Interp { public: - ParametersPlugin_PyInterp(); - virtual ~ParametersPlugin_PyInterp(); + InitializationPlugin_PyInterp(); + virtual ~InitializationPlugin_PyInterp(); /// Returns a list of positions for theName in theExpression. std::list > positions(const std::string& theExpression, @@ -48,4 +48,4 @@ class PARAMETERSPLUGIN_EXPORT ParametersPlugin_PyInterp : public PyInterp_Interp virtual void closeContext(); }; -#endif /* PARAMETERSPLUGIN_PYINTERP_H_ */ +#endif /* INITIALIZATIONPLUGIN_PYINTERP_H_ */ diff --git a/src/ModelAPI/ModelAPI_Events.cpp b/src/ModelAPI/ModelAPI_Events.cpp index 1cdf80511..9284b18af 100644 --- a/src/ModelAPI/ModelAPI_Events.cpp +++ b/src/ModelAPI/ModelAPI_Events.cpp @@ -97,17 +97,13 @@ std::list ModelAPI_FeatureStateMessage::features() const } -ModelAPI_DocumentCreatedMessage::ModelAPI_DocumentCreatedMessage(const Events_ID theID, - const void* theSender) +ModelAPI_DocumentCreatedMessage::ModelAPI_DocumentCreatedMessage( + const Events_ID theID, const void* theSender) : Events_Message(theID, theSender) -{ - -} +{} ModelAPI_DocumentCreatedMessage::~ModelAPI_DocumentCreatedMessage() -{ - -} +{} DocumentPtr ModelAPI_DocumentCreatedMessage::document() const { @@ -119,28 +115,110 @@ void ModelAPI_DocumentCreatedMessage::setDocument(DocumentPtr theDocument) myDocument = theDocument; } -ModelAPI_AttributeEvalMessage::ModelAPI_AttributeEvalMessage(const Events_ID theID, - const void* theSender) +ModelAPI_AttributeEvalMessage::ModelAPI_AttributeEvalMessage( + const Events_ID theID, const void* theSender) : Events_Message(theID, theSender) +{} + +ModelAPI_AttributeEvalMessage::~ModelAPI_AttributeEvalMessage() +{} + +AttributePtr ModelAPI_AttributeEvalMessage::attribute() const +{ + return myAttribute; +} + +void ModelAPI_AttributeEvalMessage::setAttribute(AttributePtr theAttribute) { + myAttribute = theAttribute; +} +ModelAPI_ParameterEvalMessage::ModelAPI_ParameterEvalMessage( + const Events_ID theID, const void* theSender) + : Events_Message(theID, theSender), myIsProcessed(false) +{} + +ModelAPI_ParameterEvalMessage::~ModelAPI_ParameterEvalMessage() +{} + +FeaturePtr ModelAPI_ParameterEvalMessage::parameter() const +{ + return myParam; } -ModelAPI_AttributeEvalMessage::~ModelAPI_AttributeEvalMessage() +void ModelAPI_ParameterEvalMessage::setParameter(FeaturePtr theParam) { + myParam = theParam; +} +void ModelAPI_ParameterEvalMessage::setResults( + const std::list >& theParamsList, + const double theResult, const std::string& theError) +{ + myParamsList = theParamsList; + myResult = theResult; + myError = theError; + myIsProcessed = true; } -AttributePtr ModelAPI_AttributeEvalMessage::attribute() const +bool ModelAPI_ParameterEvalMessage::isProcessed() { - return myAttribute; + return myIsProcessed; } -void ModelAPI_AttributeEvalMessage::setAttribute(AttributePtr theDocument) +const std::list >& + ModelAPI_ParameterEvalMessage::params() const { - myAttribute = theDocument; + return myParamsList; } +const double& ModelAPI_ParameterEvalMessage::result() const +{ + return myResult; +} + +const std::string& ModelAPI_ParameterEvalMessage::error() const +{ + return myError; +} + +ModelAPI_ComputePositionsMessage::ModelAPI_ComputePositionsMessage( + const Events_ID theID, const void* theSender) + : Events_Message(theID, theSender) +{} + +ModelAPI_ComputePositionsMessage::~ModelAPI_ComputePositionsMessage() +{} + +const std::string& ModelAPI_ComputePositionsMessage::expression() const +{ + return myExpression; +} + +const std::string& ModelAPI_ComputePositionsMessage::parameter() const +{ + return myParamName; +} + +void ModelAPI_ComputePositionsMessage::set( + const std::string& theExpression, const std::string& theParameter) +{ + myExpression = theExpression; + myParamName = theParameter; +} + +void ModelAPI_ComputePositionsMessage::setPositions( + const std::list >& thePositions) +{ + myPositions = thePositions; +} + +const std::list >& ModelAPI_ComputePositionsMessage::positions() const +{ + return myPositions; +} + + ModelAPI_ObjectRenamedMessage::ModelAPI_ObjectRenamedMessage(const Events_ID theID, const void* theSender) : Events_Message(theID, theSender) diff --git a/src/ModelAPI/ModelAPI_Events.h b/src/ModelAPI/ModelAPI_Events.h index f162734b1..92d200599 100644 --- a/src/ModelAPI/ModelAPI_Events.h +++ b/src/ModelAPI/ModelAPI_Events.h @@ -21,6 +21,7 @@ class ModelAPI_Document; +class ModelAPI_ResultParameter; /// Event ID that feature is created (comes with ModelAPI_ObjectUpdatedMessage) static const char * EVENT_OBJECT_CREATED = "ObjectCreated"; @@ -247,6 +248,109 @@ class ModelAPI_AttributeEvalMessage : public Events_Message MODELAPI_EXPORT void setAttribute(AttributePtr theAttribute); }; +/// Message that parameter feature expression should be evaluated: value and error producing +class ModelAPI_ParameterEvalMessage : public Events_Message +{ + FeaturePtr myParam; ///< parameters that should be evaluated + bool myIsProcessed; ///< true if results were set + /// result of processing, list of parameters in expression found + std::list > myParamsList; + double myResult; ///< result of processing, the computed value of the expression + std::string myError; ///< error of processing, empty if there is no error + + public: + /// Static. Returns EventID of the message. + MODELAPI_EXPORT static Events_ID& eventId() + { + static const char * MY_PARAMETER_EVALUATION_EVENT_ID("ParameterEvaluationRequest"); + static Events_ID anId = Events_Loop::eventByName(MY_PARAMETER_EVALUATION_EVENT_ID); + return anId; + } + + /// Useful method that creates and sends the event. + /// Returns the message, processed, with the resulting fields filled. + MODELAPI_EXPORT static std::shared_ptr + send(FeaturePtr theParameter, const void* theSender) + { + std::shared_ptr aMessage = + std::shared_ptr( + new ModelAPI_ParameterEvalMessage(eventId(), theSender)); + aMessage->setParameter(theParameter); + Events_Loop::loop()->send(aMessage); + return aMessage; + } + + /// Creates an empty message + MODELAPI_EXPORT ModelAPI_ParameterEvalMessage(const Events_ID theID, const void* theSender = 0); + /// The virtual destructor + MODELAPI_EXPORT virtual ~ModelAPI_ParameterEvalMessage(); + + /// Returns a parameter stored in the message + MODELAPI_EXPORT FeaturePtr parameter() const; + /// Sets a parameter to the message + MODELAPI_EXPORT void setParameter(FeaturePtr theParam); + /// Sets the results of processing + MODELAPI_EXPORT void setResults( + const std::list >& theParamsList, + const double theResult, const std::string& theError); + /// Returns true if the expression is processed + MODELAPI_EXPORT bool isProcessed(); + /// Returns the results of processing: list of parameters found in the expression + MODELAPI_EXPORT const std::list >& params() const; + /// Returns the expression result + MODELAPI_EXPORT const double& result() const; + /// Returns the interpreter error (empty if no error) + MODELAPI_EXPORT const std::string& error() const; +}; + + +/// Message to ask compute the positions of parameters in the expression +class ModelAPI_ComputePositionsMessage : public Events_Message +{ + std::string myExpression; ///< the expression string + std::string myParamName; ///< name of the parameter to be searched + std::list > myPositions; ///< computation result: start-end position indices + +public: + /// Static. Returns EventID of the message. + MODELAPI_EXPORT static Events_ID& eventId() + { + static const char * MY_COMPUTE_POSITIOND_EVENT_ID("ComputePositionsRequest"); + static Events_ID anId = Events_Loop::eventByName(MY_COMPUTE_POSITIOND_EVENT_ID); + return anId; + } + + /// Useful method that creates and sends the AttributeEvalMessage event + /// Returns the message, processed, with the resulting fields filled + MODELAPI_EXPORT static std::shared_ptr + send(const std::string& theExpression, const std::string& theParameter, const void* theSender) + { + std::shared_ptr aMessage = + std::shared_ptr( + new ModelAPI_ComputePositionsMessage(eventId(), theSender)); + aMessage->set(theExpression, theParameter); + Events_Loop::loop()->send(aMessage); + return aMessage; + } + + /// Creates an empty message + MODELAPI_EXPORT ModelAPI_ComputePositionsMessage( + const Events_ID theID, const void* theSender = 0); + /// The virtual destructor + MODELAPI_EXPORT virtual ~ModelAPI_ComputePositionsMessage(); + + /// Returns an expression stored in the message + MODELAPI_EXPORT const std::string& expression() const; + /// Returns a parameter name stored in the message + MODELAPI_EXPORT const std::string& parameter() const; + /// Sets an expression and parameter needed for computation + MODELAPI_EXPORT void set(const std::string& theExpression, const std::string& theParameter); + /// Sets the results of processing + MODELAPI_EXPORT void setPositions(const std::list >& thePositions); + /// Returns the results of processing: position start and end indices + MODELAPI_EXPORT const std::list >& positions() const; +}; + /// Message that the object is renamed class ModelAPI_ObjectRenamedMessage : public Events_Message { diff --git a/src/ParametersPlugin/CMakeLists.txt b/src/ParametersPlugin/CMakeLists.txt index d1cdf512e..d57d1d4ec 100644 --- a/src/ParametersPlugin/CMakeLists.txt +++ b/src/ParametersPlugin/CMakeLists.txt @@ -1,5 +1,4 @@ INCLUDE(Common) -INCLUDE(FindPython) INCLUDE(UnitTest) SET(CMAKE_AUTOMOC ON) @@ -7,9 +6,8 @@ SET(PROJECT_HEADERS ParametersPlugin.h ParametersPlugin_Plugin.h ParametersPlugin_Parameter.h - ParametersPlugin_PyInterp.h + ParametersPlugin_EvalListener.h ParametersPlugin_Validators.h - ParametersPlugin_EvalListener.h ParametersPlugin_WidgetCreator.h ParametersPlugin_ParametersMgr.h ParametersPlugin_WidgetParamsMgr.h @@ -18,9 +16,8 @@ SET(PROJECT_HEADERS SET(PROJECT_SOURCES ParametersPlugin_Plugin.cpp ParametersPlugin_Parameter.cpp - ParametersPlugin_PyInterp.cpp + ParametersPlugin_EvalListener.cpp ParametersPlugin_Validators.cpp - ParametersPlugin_EvalListener.cpp ParametersPlugin_WidgetCreator.cpp ParametersPlugin_ParametersMgr.cpp ParametersPlugin_WidgetParamsMgr.cpp @@ -36,24 +33,18 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Events ${PROJECT_SOURCE_DIR}/src/GeomAPI ${PROJECT_SOURCE_DIR}/src/GeomDataAPI ${PROJECT_SOURCE_DIR}/src/ModuleBase - ${SUIT_INCLUDE} - ${PYTHON_INCLUDE_DIR} ${CAS_INCLUDE_DIRS} ) -MESSAGE(STATUS "PYTHON_LIBRARIES (ParametersPlugin): ${PYTHON_LIBRARIES}") - SET(PROJECT_LIBRARIES Events Config ModelAPI ModuleBase - ${PyInterp} - ${PYTHON_LIBRARIES} ${QT_LIBRARIES} ) -ADD_DEFINITIONS(-DPARAMETERSPLUGIN_EXPORTS -DHAVE_DEBUG_PYTHON ${CAS_DEFINITIONS}) +ADD_DEFINITIONS(-DPARAMETERSPLUGIN_EXPORTS ${CAS_DEFINITIONS}) SET(TEXT_RESOURCES ParametersPlugin_msg_ru.ts diff --git a/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp b/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp index dbd603f19..f028edefc 100644 --- a/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp +++ b/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp @@ -10,7 +10,6 @@ #include #include -#include #include @@ -59,16 +58,12 @@ ParametersPlugin_EvalListener::ParametersPlugin_EvalListener() Events_Loop* aLoop = Events_Loop::loop(); Events_ID anEvents_IDs[] = { - ModelAPI_AttributeEvalMessage::eventId(), ModelAPI_ObjectRenamedMessage::eventId(), ModelAPI_ReplaceParameterMessage::eventId() }; for (int i = 0; i < sizeof(anEvents_IDs)/sizeof(anEvents_IDs[0]); ++i) aLoop->registerListener(this, anEvents_IDs[i], NULL, true); - - myInterp = std::shared_ptr(new ParametersPlugin_PyInterp()); - myInterp->initialize(); } ParametersPlugin_EvalListener::~ParametersPlugin_EvalListener() @@ -81,132 +76,13 @@ void ParametersPlugin_EvalListener::processEvent( if (!theMessage.get()) return; - const Events_ID kEvaluationEvent = ModelAPI_AttributeEvalMessage::eventId(); const Events_ID kObjectRenamedEvent = ModelAPI_ObjectRenamedMessage::eventId(); const Events_ID kReplaceParameterEvent = ModelAPI_ReplaceParameterMessage::eventId(); - if (theMessage->eventID() == kEvaluationEvent) { - processEvaluationEvent(theMessage); - } else if (theMessage->eventID() == kObjectRenamedEvent) { + if (theMessage->eventID() == kObjectRenamedEvent) { processObjectRenamedEvent(theMessage); } else if (theMessage->eventID() == kReplaceParameterEvent) { processReplaceParameterEvent(theMessage); - } else { - Events_InfoMessage("ParametersPlugin_EvalListener", - "ParametersPlugin python interpreter, unhandled message caught: ") - .arg(theMessage->eventID().eventText()).send(); - } -} - -double ParametersPlugin_EvalListener::evaluate(FeaturePtr theParameter, - const std::string& theExpression, std::string& theError) -{ - std::list anExprParams = myInterp->compile(theExpression); - // find expression's params in the model - std::list aContext; - std::list::iterator it = anExprParams.begin(); - for ( ; it != anExprParams.end(); it++) { - double aValue; - ResultParameterPtr aParamRes; - // If variable does not exist python interpreter will generate an error. It is OK. - // But due to the issue 1479 it should not check the history position of parameters relatively - // to feature that contains expression - if (!ModelAPI_Tools::findVariable(/*theParameter*/ FeaturePtr(), - *it, aValue, aParamRes, theParameter->document())) - continue; - - aContext.push_back(*it + "=" + toStdString(aValue)); - } - myInterp->extendLocalContext(aContext); - double result = myInterp->evaluate(theExpression, theError); - myInterp->clearLocalContext(); - return result; -} - -void ParametersPlugin_EvalListener::processEvaluationEvent( - const std::shared_ptr& theMessage) -{ - std::shared_ptr aMessage = - std::dynamic_pointer_cast(theMessage); - - FeaturePtr aParamFeature = - std::dynamic_pointer_cast(aMessage->attribute()->owner()); - if (aMessage->attribute()->attributeType() == ModelAPI_AttributeInteger::typeId()) { - AttributeIntegerPtr anAttribute = - std::dynamic_pointer_cast(aMessage->attribute()); - std::string anError; - int aValue = (int)evaluate(aParamFeature, anAttribute->text(), anError); - bool isValid = anError.empty(); - if (isValid) - anAttribute->setCalculatedValue(aValue); - anAttribute->setUsedParameters(isValid ? - toSet(myInterp->compile(anAttribute->text())) : std::set()); - anAttribute->setExpressionInvalid(!isValid); - anAttribute->setExpressionError(anAttribute->text().empty() ? "" : anError); - } else - if (aMessage->attribute()->attributeType() == ModelAPI_AttributeDouble::typeId()) { - AttributeDoublePtr anAttribute = - std::dynamic_pointer_cast(aMessage->attribute()); - std::string anError; - double aValue = evaluate(aParamFeature, anAttribute->text(), anError); - bool isValid = anError.empty(); - if (isValid) - anAttribute->setCalculatedValue(aValue); - anAttribute->setUsedParameters(isValid ? - toSet(myInterp->compile(anAttribute->text())) : std::set()); - anAttribute->setExpressionInvalid(!isValid); - anAttribute->setExpressionError(anAttribute->text().empty() ? "" : anError); - } else - if (aMessage->attribute()->attributeType() == GeomDataAPI_Point::typeId()) { - AttributePointPtr anAttribute = - std::dynamic_pointer_cast(aMessage->attribute()); - std::string aText[] = { - anAttribute->textX(), - anAttribute->textY(), - anAttribute->textZ() - }; - double aCalculatedValue[] = { - anAttribute->x(), - anAttribute->y(), - anAttribute->z() - }; - for (int i = 0; i < 3; ++i) { - std::string anError; - double aValue = evaluate(aParamFeature, aText[i], anError); - bool isValid = anError.empty(); - if (isValid) aCalculatedValue[i] = aValue; - anAttribute->setUsedParameters(i, - isValid ? toSet(myInterp->compile(aText[i])) : std::set()); - anAttribute->setExpressionInvalid(i, !isValid); - anAttribute->setExpressionError(i, aText[i].empty() ? "" : anError); - } - anAttribute->setCalculatedValue(aCalculatedValue[0], - aCalculatedValue[1], - aCalculatedValue[2]); - } else - if (aMessage->attribute()->attributeType() == GeomDataAPI_Point2D::typeId()) { - AttributePoint2DPtr anAttribute = - std::dynamic_pointer_cast(aMessage->attribute()); - std::string aText[] = { - anAttribute->textX(), - anAttribute->textY() - }; - double aCalculatedValue[] = { - anAttribute->x(), - anAttribute->y() - }; - for (int i = 0; i < 2; ++i) { - std::string anError; - double aValue = evaluate(aParamFeature, aText[i], anError); - bool isValid = anError.empty(); - if (isValid) aCalculatedValue[i] = aValue; - anAttribute->setUsedParameters(i, - isValid ? toSet(myInterp->compile(aText[i])) : std::set()); - anAttribute->setExpressionInvalid(i, !isValid); - anAttribute->setExpressionError(i, aText[i].empty() ? "" : anError); - } - anAttribute->setCalculatedValue(aCalculatedValue[0], - aCalculatedValue[1]); } } @@ -217,8 +93,10 @@ std::string ParametersPlugin_EvalListener::renameInPythonExpression( { std::string anExpressionString = theExpression; - std::list > aPositions = - myInterp->positions(anExpressionString, theOldName); + // ask interpreter to compute the positions in the expression + std::shared_ptr aMsg = + ModelAPI_ComputePositionsMessage::send(theExpression, theOldName, this); + const std::list >& aPositions = aMsg->positions(); if (aPositions.empty()) return anExpressionString; diff --git a/src/ParametersPlugin/ParametersPlugin_EvalListener.h b/src/ParametersPlugin/ParametersPlugin_EvalListener.h index 440904783..e16ca0237 100644 --- a/src/ParametersPlugin/ParametersPlugin_EvalListener.h +++ b/src/ParametersPlugin/ParametersPlugin_EvalListener.h @@ -17,7 +17,6 @@ class ModelAPI_Document; class ModelAPI_Feature; class ModelAPI_ResultParameter; class ParametersPlugin_Parameter; -class ParametersPlugin_PyInterp; /** * \class ParametersPlugin_EvalListener @@ -35,12 +34,6 @@ class ParametersPlugin_EvalListener : public Events_Listener virtual void processEvent(const std::shared_ptr& theMessage); protected: - /// Evaluates theExpression and returns its value. - double evaluate(std::shared_ptr theParameter, - const std::string& theExpression, std::string& theError); - - /// Processes Evaluation event. - void processEvaluationEvent(const std::shared_ptr& theMessage); /// Processes ObjectRenamed event. void processObjectRenamedEvent(const std::shared_ptr& theMessage); /// Processes ReplaceParameter event. @@ -62,9 +55,6 @@ class ParametersPlugin_EvalListener : public Events_Listener void renameInDependents(std::shared_ptr theResultParameter, const std::string& theOldName, const std::string& theNewName); - - private: - std::shared_ptr myInterp; }; #endif /* SRC_PARAMETERSPLUGIN_PARAMETERSPLUGIN_EVALLISTENER_H_ */ diff --git a/src/ParametersPlugin/ParametersPlugin_Parameter.cpp b/src/ParametersPlugin/ParametersPlugin_Parameter.cpp index 4428be15b..075b5eab4 100644 --- a/src/ParametersPlugin/ParametersPlugin_Parameter.cpp +++ b/src/ParametersPlugin/ParametersPlugin_Parameter.cpp @@ -7,7 +7,6 @@ #include #include "ParametersPlugin_Parameter.h" -#include #include #include @@ -16,14 +15,13 @@ #include #include #include +#include #include #include ParametersPlugin_Parameter::ParametersPlugin_Parameter() { - myInterp = std::shared_ptr(new ParametersPlugin_PyInterp()); - myInterp->initialize(); } ParametersPlugin_Parameter::~ParametersPlugin_Parameter() @@ -97,63 +95,38 @@ void ParametersPlugin_Parameter::execute() double ParametersPlugin_Parameter::evaluate(const std::string& theExpression, std::string& theError) { - std::list anExprParams = myInterp->compile(theExpression); - // find expression's params in the model - std::list aContext; - std::list::iterator it = anExprParams.begin(); - std::list aParamsList; - for ( ; it != anExprParams.end(); it++) { - std::string& aVariableName = *it; - - // Parameter with the same name should be searched in the parent document. - // For the PartSet assume that the parameter is absent. - // Currently there is no way to get parent document, so we get PartSet for all. - DocumentPtr aDocument = document(); - if (data()->name() == aVariableName) { - if (aDocument == ModelAPI_Session::get()->moduleDocument()) - continue; - aDocument = ModelAPI_Session::get()->moduleDocument(); + FeaturePtr aMyPtr = std::dynamic_pointer_cast(data()->owner()); + std::shared_ptr aProcessMessage = + ModelAPI_ParameterEvalMessage::send(aMyPtr, this); + + double aResult = 0; + if (aProcessMessage->isProcessed()) { + const std::list& aParamsList = aProcessMessage->params(); + aResult = aProcessMessage->result(); + theError = aProcessMessage->error(); + // compare the list of parameters to store if changed + AttributeRefListPtr aParams = reflist(ARGUMENTS_ID()); + bool aDifferent = aParams->size() != aParamsList.size(); + if (!aDifferent) { + std::list::const_iterator aNewIter = aParamsList.begin(); + std::list anOldList = aParams->list(); + std::list::const_iterator anOldIter = anOldList.begin(); + for(; !aDifferent && aNewIter != aParamsList.end(); aNewIter++, anOldIter++) { + if (*aNewIter != *anOldIter) + aDifferent = true; + } } - - double aValue; - ResultParameterPtr aParamRes; - if (!ModelAPI_Tools::findVariable(std::dynamic_pointer_cast(data()->owner()), - aVariableName, aValue, aParamRes, aDocument)) continue; - aParamsList.push_back(aParamRes); - - std::ostringstream sstream; - sstream << aValue; - std::string aParamValue = sstream.str(); - size_t aPos = aParamValue.find("."); - std::string aPnt = ""; - if (aPos == std::string::npos) - aPnt = "."; - aContext.push_back(*it + "=" + aParamValue + aPnt); - } - // compare the list of parameters to store if changed - AttributeRefListPtr aParams = reflist(ARGUMENTS_ID()); - bool aDifferent = aParams->size() != aParamsList.size(); - if (!aDifferent) { - std::list::iterator aNewIter = aParamsList.begin(); - std::list anOldList = aParams->list(); - std::list::iterator anOldIter = anOldList.begin(); - for(; !aDifferent && aNewIter != aParamsList.end(); aNewIter++, anOldIter++) { - if (*aNewIter != *anOldIter) - aDifferent = true; + if (aDifferent) { + aParams->clear(); + std::list::const_iterator aNewIter = aParamsList.begin(); + for(; aNewIter != aParamsList.end(); aNewIter++) { + aParams->append(*aNewIter); + } } + } else { // error: python interpreter is not active + theError = "Python interpreter is not available"; } - if (aDifferent) { - aParams->clear(); - std::list::iterator aNewIter = aParamsList.begin(); - for(; aNewIter != aParamsList.end(); aNewIter++) { - aParams->append(*aNewIter); - } - } - - myInterp->extendLocalContext(aContext); - double result = myInterp->evaluate(theExpression, theError); - myInterp->clearLocalContext(); - return result; + return aResult; } bool ParametersPlugin_Parameter::isPreviewNeeded() const diff --git a/src/ParametersPlugin/ParametersPlugin_Parameter.h b/src/ParametersPlugin/ParametersPlugin_Parameter.h index 50be185b2..5f2689c5f 100644 --- a/src/ParametersPlugin/ParametersPlugin_Parameter.h +++ b/src/ParametersPlugin/ParametersPlugin_Parameter.h @@ -12,8 +12,6 @@ #include -class ParametersPlugin_PyInterp; - /** * \class ParametersPlugin_Parameter * \ingroup Plugins @@ -94,9 +92,6 @@ class ParametersPlugin_Parameter : public ModelAPI_Feature void updateName(); /// Updates expression of the parameter bool updateExpression(); - - private: - std::shared_ptr myInterp; }; #endif -- 2.39.2