From: mpv Date: Fri, 23 Sep 2016 07:43:24 +0000 (+0300) Subject: Fix for the issue #1755 : for now the sketch solver receives all modified entities... X-Git-Tag: V_2.5.1~9 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=b12bbd2a734142a2596a91c729b6670060b6b7e9;p=modules%2Fshaper.git Fix for the issue #1755 : for now the sketch solver receives all modified entities at once, not one by one, that caused problems. --- diff --git a/src/Config/Config_Translator.cpp b/src/Config/Config_Translator.cpp index 058acfca3..cbc1a2776 100644 --- a/src/Config/Config_Translator.cpp +++ b/src/Config/Config_Translator.cpp @@ -11,6 +11,10 @@ #include #include +#ifdef WIN32 +#pragma warning(disable : 4996) // for sprintf +#endif + /** * \class Config_TSReader * \ingroup Config diff --git a/src/Events/Events_InfoMessage.cpp b/src/Events/Events_InfoMessage.cpp index 18d38a95c..e2a4d9882 100644 --- a/src/Events/Events_InfoMessage.cpp +++ b/src/Events/Events_InfoMessage.cpp @@ -6,6 +6,9 @@ #include "Events_InfoMessage.h" +#ifdef WIN32 +#pragma warning(disable : 4996) // for sprintf +#endif void Events_InfoMessage::addParameter(double theParam) { diff --git a/src/Events/Events_Listener.cpp b/src/Events/Events_Listener.cpp index 1d55bb955..158446b12 100644 --- a/src/Events/Events_Listener.cpp +++ b/src/Events/Events_Listener.cpp @@ -5,3 +5,33 @@ // Author: Mikhail PONIKAROV #include +#include +#include + +void Events_Listener::groupWhileFlush(const std::shared_ptr& theMessage) { + std::shared_ptr aGroup = + std::dynamic_pointer_cast(theMessage); + if (aGroup) { + std::map >::iterator aMyGroup = myGroups.find( + aGroup->eventID().eventText()); + if (aMyGroup == myGroups.end()) { // create a new group of messages for accumulation + myGroups[aGroup->eventID().eventText()] = aGroup->newEmpty(); + aMyGroup = myGroups.find(aGroup->eventID().eventText()); + } + std::shared_ptr aStored = + std::dynamic_pointer_cast(aMyGroup->second); + aStored->Join(aGroup); + //std::cout<<"Add to group "<eventID().eventText()< >::iterator aMyGroup = + myGroups.find(theID.eventText()); + if (aMyGroup != myGroups.end()) { + std::shared_ptr aMessage = aMyGroup->second; + myGroups.erase(aMyGroup); + processEvent(aMessage); + } +} diff --git a/src/Events/Events_Listener.h b/src/Events/Events_Listener.h index 90dedcdfd..74aac5483 100644 --- a/src/Events/Events_Listener.h +++ b/src/Events/Events_Listener.h @@ -9,8 +9,10 @@ #include #include +#include class Events_Message; +class Events_ID; /**\class Events_Listener * \ingroup EventsLoop @@ -19,12 +21,26 @@ class Events_Message; * If some object wants to listen some events it must inherit * this class and register in the Loop. */ -class EVENTS_EXPORT Events_Listener -{ +class Events_Listener { + /// map from event ID to groupped messages (for flush for groupMessages=true listeners) + std::map > myGroups; public: //! This method is called by loop when the event is started to process. - virtual void processEvent(const std::shared_ptr& theMessage) = 0; + EVENTS_EXPORT virtual void processEvent(const std::shared_ptr& theMessage) = 0; + + //! Listener that needs mostly grouped messages received returns true in this method. + //! In this case during the message is flushed, all the new messages are grouped, not sended + //! immideately and then sent in the end of flush. + EVENTS_EXPORT virtual bool groupMessages() {return false;} + +protected: + //! Allows to group messages while they are flushed (for flush for groupMessages=true listeners) + void groupWhileFlush(const std::shared_ptr& theMessage); + //! Sends myGroups on flush finish + EVENTS_EXPORT void flushGrouped(const Events_ID& theID); + + friend class Events_Loop; }; #endif diff --git a/src/Events/Events_Loop.cpp b/src/Events/Events_Loop.cpp index e68798aa4..8e026f733 100644 --- a/src/Events/Events_Loop.cpp +++ b/src/Events/Events_Loop.cpp @@ -39,13 +39,26 @@ Events_ID Events_Loop::eventByName(const char* theName) return Events_ID(aResult); } +void Events_Loop::sendProcessEvent(const std::shared_ptr& theMessage, + std::list& theListeners, const bool theFlushedNow) +{ + for (list::iterator aL = theListeners.begin(); aL != theListeners.end(); aL++) { + if (theFlushedNow && (*aL)->groupMessages()) { + (*aL)->groupWhileFlush(theMessage); + } else { + (*aL)->processEvent(theMessage); + } + } +} + void Events_Loop::send(const std::shared_ptr& theMessage, bool isGroup) { if (myImmediateListeners.find(theMessage->eventID().eventText()) != myImmediateListeners.end()) { myImmediateListeners[theMessage->eventID().eventText()]->processEvent(theMessage); } // if it is grouped message, just accumulate it - if (isGroup && myFlushed.find(theMessage->eventID().myID) == myFlushed.end()) { + bool isFlushedNow = myFlushed.find(theMessage->eventID().myID) != myFlushed.end(); + if (isGroup && !isFlushedNow) { std::shared_ptr aGroup = std::dynamic_pointer_cast(theMessage); if (aGroup) { @@ -61,23 +74,19 @@ void Events_Loop::send(const std::shared_ptr& theMessage, bool i return; } } - + // send map > >::iterator aFindID = myListeners.find( theMessage->eventID().eventText()); if (aFindID != myListeners.end()) { map >::iterator aFindSender = aFindID->second.find( theMessage->sender()); if (aFindSender != aFindID->second.end()) { - list& aListeners = aFindSender->second; - for (list::iterator aL = aListeners.begin(); aL != aListeners.end(); aL++) - (*aL)->processEvent(theMessage); + sendProcessEvent(theMessage, aFindSender->second, isFlushedNow && isGroup); } if (theMessage->sender()) { // also call for NULL senders registered aFindSender = aFindID->second.find(NULL); if (aFindSender != aFindID->second.end()) { - list& aListeners = aFindSender->second; - for (list::iterator aL = aListeners.begin(); aL != aListeners.end(); aL++) - (*aL)->processEvent(theMessage); + sendProcessEvent(theMessage, aFindSender->second, isFlushedNow && isGroup); } } } @@ -173,11 +182,28 @@ void Events_Loop::flush(const Events_ID& theID) myGroups.erase(aMyGroup); send(aGroup, false); - if (!aWasFlushed) + if (!aWasFlushed) { // TODO: Stabilization fix. Check later. if(myFlushed.find(theID.myID) != myFlushed.end()) { myFlushed.erase(myFlushed.find(theID.myID)); + } else { + bool aProblem = true; + } + } + // send accumulated messages to "groupListeners" + map > >::iterator aFindID = myListeners.find( + theID.eventText()); + if (aFindID != myListeners.end()) { + map >::iterator aFindSender = aFindID->second.begin(); + for(; aFindSender != aFindID->second.end(); aFindSender++) { + list::iterator aListener = aFindSender->second.begin(); + for(; aListener != aFindSender->second.end(); aListener++) { + if ((*aListener)->groupMessages()) { + (*aListener)->flushGrouped(theID); + } + } } + } } } diff --git a/src/Events/Events_Loop.h b/src/Events/Events_Loop.h index 0d1f729bd..b095cc4fc 100644 --- a/src/Events/Events_Loop.h +++ b/src/Events/Events_Loop.h @@ -34,7 +34,7 @@ class Events_Loop /// map from event ID to listeners which must process message without waiting for flush std::map myImmediateListeners; - /// map from event ID to groupped messages (accumulated on flush) + /// map from event ID to groupped messages (accumulated for flush) std::map > myGroups; ///< set of messages that are flushed right now, so they are not grouped @@ -93,6 +93,13 @@ class Events_Loop EVENTS_EXPORT bool isFlushed(const Events_ID& theID); //! Sets the flag that the event is flished right now EVENTS_EXPORT void setFlushed(const Events_ID& theID, const bool theValue); + +private: + //! Calls "processEvent" for the given listeners. + //! If theFlushedNow for grouped listeners is stores message in listeners. + void sendProcessEvent(const std::shared_ptr& theMessage, + std::list& theListeners, const bool theFlushedNow); + }; #endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp b/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp index 18b4be1ac..e5147561b 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp @@ -811,7 +811,7 @@ bool FeaturesPlugin_ValidatorConcealedResult::isValid(const AttributePtr& theAtt std::list > aResults; ModelAPI_Tools::getConcealedResults(aRefFeature, aResults); - int aConcealedResults = aResults.size(); + size_t aConcealedResults = aResults.size(); if (!aConcealedResults && !theArguments.empty()) { // find if these results are touched by the feature in another attribute std::list::const_iterator anIt = theArguments.begin(); diff --git a/src/InitializationPlugin/InitializationPlugin_Plugin.h b/src/InitializationPlugin/InitializationPlugin_Plugin.h index c44c7a43f..64d4c951f 100644 --- a/src/InitializationPlugin/InitializationPlugin_Plugin.h +++ b/src/InitializationPlugin/InitializationPlugin_Plugin.h @@ -15,16 +15,17 @@ * It's aim is to fulfill the newly created documents with the "origin" * construction point (0,0,0) and base planes (x0y, z0y, x0z) */ -class INITIALIZATIONPLUGIN_EXPORT InitializationPlugin_Plugin : public Events_Listener +class InitializationPlugin_Plugin : public Events_Listener { public: /// Creates plug-in and registers it in the Event Loop - InitializationPlugin_Plugin(); + INITIALIZATIONPLUGIN_EXPORT InitializationPlugin_Plugin(); /// Destructs the plugin - virtual ~InitializationPlugin_Plugin() {} + INITIALIZATIONPLUGIN_EXPORT virtual ~InitializationPlugin_Plugin() {} /// Process the ModelAPI_DocumentCreatedMessage to fulfill a document /// from the message with origin and planes - virtual void processEvent(const std::shared_ptr& theMessage); + INITIALIZATIONPLUGIN_EXPORT virtual void processEvent( + const std::shared_ptr& theMessage); protected: /// Creates a plane by given parameters A, B, C diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index f38510369..64b5ca6de 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -436,9 +436,11 @@ bool Model_AttributeSelection::update() if (aContext->groupName() == ModelAPI_ResultBody::group()) { // body: just a named shape, use selection mechanism from OCCT TNaming_Selector aSelector(aSelLab); + TopoDS_Shape anOldShape = aSelector.NamedShape()->Get(); bool aResult = aSelector.Solve(scope()) == Standard_True; aResult = setInvalidIfFalse(aSelLab, aResult); // must be before sending of updated attribute (1556) - owner()->data()->sendAttributeUpdated(this); + if (!anOldShape.IsEqual(aSelector.NamedShape()->Get())) // send updated if shape is changed + owner()->data()->sendAttributeUpdated(this); return aResult; } else if (aContext->groupName() == ModelAPI_ResultConstruction::group()) { // construction: identification by the results indexes, recompute faces and diff --git a/src/Model/Model_Objects.h b/src/Model/Model_Objects.h index 72c85936b..d51c39ba8 100644 --- a/src/Model/Model_Objects.h +++ b/src/Model/Model_Objects.h @@ -222,7 +222,6 @@ class Model_Objects friend class Model_AttributeReference; friend class Model_AttributeRefAttr; friend class Model_AttributeRefList; - friend class Model_AttributeRefList; friend class Model_SelectionNaming; }; diff --git a/src/Model/Model_Update.cpp b/src/Model/Model_Update.cpp index f4e189731..bb00695b2 100755 --- a/src/Model/Model_Update.cpp +++ b/src/Model/Model_Update.cpp @@ -119,7 +119,7 @@ bool Model_Update::addModified(FeaturePtr theFeature, FeaturePtr theReason) { if (myModified.find(theFeature) != myModified.end()) { if (theReason.get()) { #ifdef DEB_UPDATE - std::cout<<"*** Add already modified "<name()<<" reason "<name()<name()<<" reason "<name()<name()<<" reason "<name()<name()<name()<<" reason "<name()<name()<data()->execState() == ModelAPI_StateDone) @@ -150,7 +151,7 @@ bool Model_Update::addModified(FeaturePtr theFeature, FeaturePtr theReason) { else return true; // do not need iteration deeply if it is already marked as modified or so #ifdef DEB_UPDATE - std::cout<<"*** Set modified state "<name()<name()< aMsg(new Events_Message(anID, this)); + Events_Loop::loop()->send(aMsg); } if (!aIsModified) { // no modification is needed diff --git a/src/ModelAPI/ModelAPI_Events.h b/src/ModelAPI/ModelAPI_Events.h index 3aa459424..0ba832111 100644 --- a/src/ModelAPI/ModelAPI_Events.h +++ b/src/ModelAPI/ModelAPI_Events.h @@ -63,6 +63,9 @@ static const char * EVENT_ORDER_UPDATED = "OrderUpdated"; /// Event ID that informs that some object has changed the stability static const char * EVENT_STABILITY_CHANGED = "StabilityChanged"; +/// Event ID that the sketch is prepared and all grouped messages for the solver may be flushed +static const char * EVENT_SKETCH_PREPARED = "SketchPrepared"; + /// Message that feature was changed (used for Object Browser update): moved, updated and deleted class MODELAPI_EXPORT ModelAPI_ObjectUpdatedMessage : public Events_MessageGroup { diff --git a/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp b/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp index 976988cde..bcecd78f4 100755 --- a/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp +++ b/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp @@ -21,6 +21,10 @@ #include #include +#ifdef WIN32 +#pragma warning(disable : 4996) // for sprintf +#endif + namespace ModelGeomAlgo_Point2D { std::shared_ptr getPointOfRefAttr(ModelAPI_Feature* theFeature, const std::string& theAttribute, diff --git a/src/PartSetPlugin/PartSetPlugin_Plugin.h b/src/PartSetPlugin/PartSetPlugin_Plugin.h index 834c7c8a3..b86081714 100644 --- a/src/PartSetPlugin/PartSetPlugin_Plugin.h +++ b/src/PartSetPlugin/PartSetPlugin_Plugin.h @@ -20,21 +20,21 @@ * \ingroup Plugins * \brief The main class for management the part set operations as plugin. */ -class PARTSETPLUGIN_EXPORT PartSetPlugin_Plugin : public ModelAPI_Plugin, +class PartSetPlugin_Plugin : public ModelAPI_Plugin, public Events_Listener { public: /// Creates the feature object of this plugin by the feature string ID - virtual FeaturePtr createFeature(std::string theFeatureID); + PARTSETPLUGIN_EXPORT virtual FeaturePtr createFeature(std::string theFeatureID); /// Is needed for python wrapping by swig - PartSetPlugin_Plugin(); + PARTSETPLUGIN_EXPORT PartSetPlugin_Plugin(); //! Redefinition of Events_Listener method - virtual void processEvent(const std::shared_ptr& theMessage); + PARTSETPLUGIN_EXPORT virtual void processEvent(const std::shared_ptr& theMessage); //! Performs the chenges of enabled/disabled state in the toolbar //! due to the current state of the application. - std::shared_ptr getFeaturesState(); + PARTSETPLUGIN_EXPORT std::shared_ptr getFeaturesState(); }; #endif diff --git a/src/SketchPlugin/SketchPlugin_Plugin.h b/src/SketchPlugin/SketchPlugin_Plugin.h index 3b9de25ef..822eeea51 100644 --- a/src/SketchPlugin/SketchPlugin_Plugin.h +++ b/src/SketchPlugin/SketchPlugin_Plugin.h @@ -17,16 +17,18 @@ * \ingroup Plugins * \brief Interface common for any plugin: allows to use plugin by the plugins manager. */ -class SKETCHPLUGIN_EXPORT SketchPlugin_Plugin : public ModelAPI_Plugin, public Events_Listener +class SketchPlugin_Plugin : public ModelAPI_Plugin, public Events_Listener { public: /// Creates the feature object of this plugin by the feature string ID - virtual FeaturePtr createFeature(std::string theFeatureID); + SKETCHPLUGIN_EXPORT virtual FeaturePtr createFeature(std::string theFeatureID); + + /// Constructor that registers features and other plugin elements. + SKETCHPLUGIN_EXPORT SketchPlugin_Plugin(); - public: - SketchPlugin_Plugin(); //! Redefinition of Events_Listener method - virtual void processEvent(const std::shared_ptr& theMessage); + SKETCHPLUGIN_EXPORT virtual void processEvent(const std::shared_ptr& theMessage); + protected: //! Returns the state of the feature in the WorkBench: enabled or disabled for the moment. std::shared_ptr getFeaturesState( diff --git a/src/SketchSolver/SketchSolver_Manager.cpp b/src/SketchSolver/SketchSolver_Manager.cpp index 3a8f8ea86..847607325 100644 --- a/src/SketchSolver/SketchSolver_Manager.cpp +++ b/src/SketchSolver/SketchSolver_Manager.cpp @@ -79,12 +79,13 @@ SketchSolver_Manager::SketchSolver_Manager() // Register in event loop Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED)); - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + Events_Loop::loop()->registerListener(this, anUpdateEvent); Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED)); Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED)); Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_FAILED)); Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_REPAIRED)); + Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SKETCH_PREPARED)); } SketchSolver_Manager::~SketchSolver_Manager() @@ -102,6 +103,11 @@ BuilderPtr SketchSolver_Manager::builder() return myBuilder; } +bool SketchSolver_Manager::groupMessages() +{ + return true; +} + // ============================================================================ // Function: processEvent // Purpose: listen the event loop and process the message @@ -109,7 +115,15 @@ BuilderPtr SketchSolver_Manager::builder() void SketchSolver_Manager::processEvent( const std::shared_ptr& theMessage) { + static const Events_ID aSketchPreparedEvent = Events_Loop::eventByName(EVENT_SKETCH_PREPARED); + // sketch is prepared for resolve: all the needed events are collected and must be processed by the solver + if (theMessage->eventID() == aSketchPreparedEvent) { + flushGrouped(anUpdateEvent); + return; + } + checkConflictingConstraints(theMessage); + if (myIsComputed) return; myIsComputed = true; @@ -118,7 +132,7 @@ void SketchSolver_Manager::processEvent( bool hasProperFeature = false; if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED) - || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED) + || theMessage->eventID() == anUpdateEvent || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) { std::shared_ptr anUpdateMsg = std::dynamic_pointer_cast(theMessage); @@ -169,6 +183,9 @@ void SketchSolver_Manager::processEvent( // Features may be updated => now send events, but for all changed at once if (isUpdateFlushed) allowSendUpdate(); + + myIsComputed = false; + // send update for movement in any case if (needToUpdate || isMovedEvt) Events_Loop::loop()->flush(anUpdateEvent); @@ -215,11 +232,11 @@ void SketchSolver_Manager::processEvent( if (!aGroupsToResolve.empty()) resolveConstraints(aGroupsToResolve); } + myIsComputed = false; } if (hasProperFeature) degreesOfFreedom(); - myIsComputed = false; } void SketchSolver_Manager::checkConflictingConstraints(const std::shared_ptr& theMessage) diff --git a/src/SketchSolver/SketchSolver_Manager.h b/src/SketchSolver/SketchSolver_Manager.h index c0866c558..51581b987 100644 --- a/src/SketchSolver/SketchSolver_Manager.h +++ b/src/SketchSolver/SketchSolver_Manager.h @@ -41,6 +41,12 @@ public: */ virtual void processEvent(const std::shared_ptr& theMessage); + /** + * The solver needs all the updated objects are transfered in one group, not one by one. + * This iscreases performance and avoids problems in resolve of only part of the made updates. + */ + virtual bool groupMessages(); + /// \brief Initialize builder for solver's data structure entities /// \param theBuilder [in] solver's specific builder SKETCHSOLVER_EXPORT void setBuilder(BuilderPtr theBuilder); diff --git a/src/XAO/XAO_Field.hxx b/src/XAO/XAO_Field.hxx index 67f32cf6f..33adeeb25 100644 --- a/src/XAO/XAO_Field.hxx +++ b/src/XAO/XAO_Field.hxx @@ -140,7 +140,7 @@ namespace XAO * Gets the number of the steps. * @return the number of steps. */ - const int countSteps() const { return m_steps.size(); } + const int countSteps() const { return int(m_steps.size()); } /** * Gets the name of a component. diff --git a/src/XAO/XAO_Group.hxx b/src/XAO/XAO_Group.hxx index 4f0115403..7dfd6f0c5 100644 --- a/src/XAO/XAO_Group.hxx +++ b/src/XAO/XAO_Group.hxx @@ -93,7 +93,7 @@ namespace XAO */ const int count() const { - return m_elements.size(); + return int(m_elements.size()); } /**