1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
20 #include "SketchSolver_Manager.h"
21 #include "SketchSolver_Error.h"
23 #include <Events_Loop.h>
24 #include <ModelAPI_Events.h>
25 #include <ModelAPI_ResultConstruction.h>
26 #include <ModelAPI_Session.h>
27 #include <ModelAPI_Validator.h>
28 #include <SketchPlugin_Sketch.h>
30 /// Global constraint manager object
31 static SketchSolver_Manager* myManager = SketchSolver_Manager::instance();
33 /// \brief Verifies is the feature valid
34 static bool isFeatureValid(FeaturePtr theFeature)
36 if (!theFeature || !theFeature->data() || !theFeature->data()->isValid())
39 SessionPtr aMgr = ModelAPI_Session::get();
40 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
41 return aFactory->validate(theFeature);
46 // ========================================================
47 // ========= SketchSolver_Manager ===============
48 // ========================================================
49 SketchSolver_Manager* SketchSolver_Manager::instance()
51 static SketchSolver_Manager* mySelf = 0; // Self pointer to implement singleton functionality
53 mySelf = new SketchSolver_Manager();
57 SketchSolver_Manager::SketchSolver_Manager()
62 // Register in event loop
63 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
64 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
65 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
66 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
68 ////Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_FAILED));
69 ////Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_REPAIRED));
70 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SKETCH_PREPARED));
73 SketchSolver_Manager::~SketchSolver_Manager()
78 bool SketchSolver_Manager::groupMessages()
83 // ============================================================================
84 // Function: processEvent
85 // Purpose: listen the event loop and process the message
86 // ============================================================================
87 void SketchSolver_Manager::processEvent(
88 const std::shared_ptr<Events_Message>& theMessage)
90 bool needToResolve = false;
91 bool isUpdateFlushed = false;
92 bool isMovedEvt = false;
94 static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
95 static const Events_ID aSketchPreparedEvent = Events_Loop::eventByName(EVENT_SKETCH_PREPARED);
96 // sketch is prepared for resolve: all the needed events
97 // are collected and must be processed by the solver
98 if (theMessage->eventID() == aSketchPreparedEvent) {
99 flushGrouped(anUpdateEvent);
100 needToResolve = true;
107 if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
108 || theMessage->eventID() == anUpdateEvent
109 || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
110 std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
111 std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
112 std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
114 isUpdateFlushed = stopSendUpdate();
116 isMovedEvt = theMessage->eventID()
117 == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
119 // Shows that the message has at least one feature applicable for solver
120 bool hasProperFeature = false;
122 // update sketch features only
123 std::set<ObjectPtr>::iterator aFeatIter;
124 for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
125 std::shared_ptr<SketchPlugin_Feature> aFeature =
126 std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
127 if (!aFeature || aFeature->isMacro())
130 hasProperFeature = updateFeature(aFeature, isMovedEvt) || hasProperFeature;
133 if (isMovedEvt && hasProperFeature)
134 needToResolve = true;
136 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
137 std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
138 std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
139 const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
141 // Find SketchPlugin_Sketch::ID() in groups.
142 // The constraint groups should be updated when an object removed from Sketch
143 std::set<std::string>::const_iterator aFGrIter;
144 for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
145 if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 ||
146 aFGrIter->compare(ModelAPI_Feature::group()) == 0)
149 if (aFGrIter != aFeatureGroups.end()) {
150 std::list<SketchGroupPtr>::iterator aGroupIter = myGroups.begin();
151 while (aGroupIter != myGroups.end()) {
152 if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed
153 std::list<SketchGroupPtr>::iterator aRemoveIt = aGroupIter++;
154 myGroups.erase(aRemoveIt);
158 (*aGroupIter)->repairConsistency();
162 myIsComputed = false;
165 // resolve constraints if needed
166 bool needToUpdate = needToResolve && resolveConstraints();
167 releaseFeaturesIfEventsBlocked();
169 // Features may be updated => now send events, but for all changed at once
173 myIsComputed = false;
175 // send update for movement in any case
176 if (needToUpdate || isMovedEvt)
177 Events_Loop::loop()->flush(anUpdateEvent);
180 // ============================================================================
181 // Function: changeConstraintOrEntity
182 // Purpose: create/update the constraint or the feature and place it into appropriate group
183 // ============================================================================
184 bool SketchSolver_Manager::updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature,
187 // Check feature validity and find a group to place it.
188 // If the feature is not valid, the returned group will be empty.
189 // This will protect to deal with wrong (not fully initialized) features.
190 SketchGroupPtr aGroup = findGroup(theFeature);
193 aGroup->blockEvents(true);
195 std::shared_ptr<SketchPlugin_Constraint> aConstraint =
196 std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
200 isOk = aGroup->changeConstraint(aConstraint);
202 isOk = aGroup->moveFeature(theFeature);
204 isOk = aGroup->updateFeature(theFeature);
208 // ============================================================================
209 // Function: findGroup
210 // Purpose: search groups of entities interacting with given feature
211 // ============================================================================
212 SketchGroupPtr SketchSolver_Manager::findGroup(
213 std::shared_ptr<SketchPlugin_Feature> theFeature)
215 if (!isFeatureValid(theFeature))
216 return SketchGroupPtr(); // do not process wrong features
218 // Obtain sketch, containing the feature
219 CompositeFeaturePtr aSketch;
220 const std::set<AttributePtr>& aRefsList = theFeature->data()->refsToMe();
221 std::set<AttributePtr>::const_iterator aRefIt = aRefsList.begin();
222 for (; aRefIt != aRefsList.end(); ++aRefIt) {
223 FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
224 if (anOwner && anOwner->getKind() == SketchPlugin_Sketch::ID()) {
225 aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(anOwner);
231 return SketchGroupPtr(); // not a sketch's feature
233 std::list<SketchGroupPtr>::const_iterator aGroupIt;
234 for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); ++aGroupIt)
235 if ((*aGroupIt)->getWorkplane() == aSketch)
238 // group for the sketch does not created yet
239 SketchGroupPtr aNewGroup = SketchGroupPtr(new SketchSolver_Group(aSketch));
240 myGroups.push_back(aNewGroup);
244 // ============================================================================
245 // Function: resolveConstraints
246 // Purpose: change entities according to available constraints
247 // ============================================================================
248 bool SketchSolver_Manager::resolveConstraints()
250 bool needToUpdate = false;
251 std::list<SketchGroupPtr>::const_iterator aGroupIter = myGroups.begin();
252 for (; aGroupIter != myGroups.end(); ++aGroupIter) {
253 if ((*aGroupIter)->resolveConstraints())
259 void SketchSolver_Manager::releaseFeaturesIfEventsBlocked() const
261 std::list<SketchGroupPtr>::const_iterator aGroupIter = myGroups.begin();
262 for (; aGroupIter != myGroups.end(); ++aGroupIter)
263 (*aGroupIter)->blockEvents(false);
266 bool SketchSolver_Manager::stopSendUpdate() const
268 static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
269 // to avoid redisplay of each segment on update by solver one by one in the viewer
270 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
271 if (isUpdateFlushed) {
272 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
274 return isUpdateFlushed;
277 void SketchSolver_Manager::allowSendUpdate() const
279 Events_Loop::loop()->setFlushed(Events_Loop::eventByName(EVENT_OBJECT_UPDATED), true);