1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: SketchSolver_Manager.cpp
4 // Created: 08 May 2014
5 // Author: Artem ZHIDKOV
7 #include "SketchSolver_Manager.h"
8 #include "SketchSolver_Error.h"
10 #include <Events_Loop.h>
11 #include <GeomDataAPI_Point2D.h>
12 #include <ModelAPI_Events.h>
13 #include <ModelAPI_ResultConstruction.h>
14 #include <ModelAPI_Session.h>
15 #include <ModelAPI_Validator.h>
16 #include <SketchPlugin_Constraint.h>
17 #include <SketchPlugin_Sketch.h>
19 /// Global constraint manager object
20 static SketchSolver_Manager* myManager = SketchSolver_Manager::instance();
22 /// \brief Verifies is the feature valid
23 static bool isFeatureValid(FeaturePtr theFeature)
25 if (!theFeature || !theFeature->data() || !theFeature->data()->isValid())
28 SessionPtr aMgr = ModelAPI_Session::get();
29 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
30 return aFactory->validate(theFeature);
35 // ========================================================
36 // ========= SketchSolver_Manager ===============
37 // ========================================================
38 SketchSolver_Manager* SketchSolver_Manager::instance()
40 static SketchSolver_Manager* mySelf = 0; // Self pointer to implement singleton functionality
42 mySelf = new SketchSolver_Manager();
46 SketchSolver_Manager::SketchSolver_Manager()
51 // Register in event loop
52 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
53 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
54 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
55 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
57 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SKETCH_PREPARED));
60 SketchSolver_Manager::~SketchSolver_Manager()
65 bool SketchSolver_Manager::groupMessages()
70 // ============================================================================
71 // Function: processEvent
72 // Purpose: listen the event loop and process the message
73 // ============================================================================
74 void SketchSolver_Manager::processEvent(
75 const std::shared_ptr<Events_Message>& theMessage)
77 bool needToResolve = false;
78 bool isUpdateFlushed = false;
79 bool isMovedEvt = false;
81 static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
82 static const Events_ID aSketchPreparedEvent = Events_Loop::eventByName(EVENT_SKETCH_PREPARED);
83 // sketch is prepared for resolve: all the needed events
84 // are collected and must be processed by the solver
85 if (theMessage->eventID() == aSketchPreparedEvent) {
86 flushGrouped(anUpdateEvent);
94 #ifdef SUPPORT_NEW_MOVE
95 if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
96 || theMessage->eventID() == anUpdateEvent) {
98 if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
99 || theMessage->eventID() == anUpdateEvent
100 || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
102 std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
103 std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
104 std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
106 isUpdateFlushed = stopSendUpdate();
108 #ifndef SUPPORT_NEW_MOVE
109 isMovedEvt = theMessage->eventID()
110 == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
112 // Shows that the message has at least one feature applicable for solver
113 bool hasProperFeature = false;
116 // update sketch features only
117 std::set<ObjectPtr>::iterator aFeatIter;
118 for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
119 std::shared_ptr<SketchPlugin_Feature> aFeature =
120 std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
121 if (!aFeature || aFeature->isMacro())
124 #ifdef SUPPORT_NEW_MOVE
125 updateFeature(aFeature);
127 hasProperFeature = updateFeature(aFeature, isMovedEvt) || hasProperFeature;
131 #ifndef SUPPORT_NEW_MOVE
132 if (isMovedEvt && hasProperFeature)
133 needToResolve = true;
136 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
137 std::shared_ptr<ModelAPI_ObjectMovedMessage> aMoveMsg =
138 std::dynamic_pointer_cast<ModelAPI_ObjectMovedMessage>(theMessage);
140 ObjectPtr aMovedObject = aMoveMsg->movedObject();
141 std::shared_ptr<GeomDataAPI_Point2D> aMovedPoint =
142 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aMoveMsg->movedAttribute());
144 const std::shared_ptr<GeomAPI_Pnt2d>& aFrom = aMoveMsg->originalPosition();
145 const std::shared_ptr<GeomAPI_Pnt2d>& aTo = aMoveMsg->currentPosition();
148 FeaturePtr aMovedFeature = ModelAPI_Feature::feature(aMovedObject);
149 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
150 std::dynamic_pointer_cast<SketchPlugin_Feature>(aMovedFeature);
151 if (aSketchFeature && !aSketchFeature->isMacro())
152 needToResolve = moveFeature(aSketchFeature, aFrom, aTo);
153 } else if (aMovedPoint)
154 needToResolve = moveAttribute(aMovedPoint, aFrom, aTo);
157 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
158 std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
159 std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
160 const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
162 // Find SketchPlugin_Sketch::ID() in groups.
163 // The constraint groups should be updated when an object removed from Sketch
164 std::set<std::string>::const_iterator aFGrIter;
165 for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
166 if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 ||
167 aFGrIter->compare(ModelAPI_Feature::group()) == 0)
170 if (aFGrIter != aFeatureGroups.end()) {
171 std::list<SketchGroupPtr>::iterator aGroupIter = myGroups.begin();
172 while (aGroupIter != myGroups.end()) {
173 if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed
174 std::list<SketchGroupPtr>::iterator aRemoveIt = aGroupIter++;
175 myGroups.erase(aRemoveIt);
179 (*aGroupIter)->repairConsistency();
183 myIsComputed = false;
186 // resolve constraints if needed
187 bool needToUpdate = needToResolve && resolveConstraints();
188 releaseFeaturesIfEventsBlocked();
190 // Features may be updated => now send events, but for all changed at once
194 myIsComputed = false;
196 // send update for movement in any case
197 if (needToUpdate || isMovedEvt)
198 Events_Loop::loop()->flush(anUpdateEvent);
201 // ============================================================================
202 // Function: updateFeature
203 // Purpose: create/update constraint or feature in appropriate group
204 // ============================================================================
205 #ifdef SUPPORT_NEW_MOVE
206 bool SketchSolver_Manager::updateFeature(const std::shared_ptr<SketchPlugin_Feature>& theFeature)
208 bool SketchSolver_Manager::updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature,
212 // Check feature validity and find a group to place it.
213 // If the feature is not valid, the returned group will be empty.
214 // This will protect to deal with wrong (not fully initialized) features.
215 SketchGroupPtr aGroup = findGroup(theFeature);
218 aGroup->blockEvents(true);
220 std::shared_ptr<SketchPlugin_Constraint> aConstraint =
221 std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
225 isOk = aGroup->changeConstraint(aConstraint);
226 #ifndef SUPPORT_NEW_MOVE
228 isOk = aGroup->moveFeature(theFeature);
231 isOk = aGroup->updateFeature(theFeature);
235 #ifdef SUPPORT_NEW_MOVE
236 // ============================================================================
237 // Function: moveFeature
238 // Purpose: move given feature in appropriate group
239 // ============================================================================
240 bool SketchSolver_Manager::moveFeature(
241 const std::shared_ptr<SketchPlugin_Feature>& theMovedFeature,
242 const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
243 const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
245 SketchGroupPtr aGroup = findGroup(theMovedFeature);
249 aGroup->blockEvents(true);
250 return aGroup->moveFeature(theMovedFeature, theFrom, theTo);
253 // ============================================================================
254 // Function: moveAttribute
255 // Purpose: move given attribute in appropriate group
256 // ============================================================================
257 bool SketchSolver_Manager::moveAttribute(
258 const std::shared_ptr<GeomDataAPI_Point2D>& theMovedAttribute,
259 const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
260 const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
262 FeaturePtr anOwner = ModelAPI_Feature::feature(theMovedAttribute->owner());
263 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
264 std::dynamic_pointer_cast<SketchPlugin_Feature>(anOwner);
265 SketchGroupPtr aGroup;
267 aGroup = findGroup(aSketchFeature);
271 aGroup->blockEvents(true);
272 return aGroup->movePoint(theMovedAttribute, theFrom, theTo);
276 // ============================================================================
277 // Function: findGroup
278 // Purpose: search groups of entities interacting with given feature
279 // ============================================================================
280 SketchGroupPtr SketchSolver_Manager::findGroup(
281 std::shared_ptr<SketchPlugin_Feature> theFeature)
283 if (!isFeatureValid(theFeature))
284 return SketchGroupPtr(); // do not process wrong features
286 // Obtain sketch, containing the feature
287 CompositeFeaturePtr aSketch;
288 const std::set<AttributePtr>& aRefsList = theFeature->data()->refsToMe();
289 std::set<AttributePtr>::const_iterator aRefIt = aRefsList.begin();
290 for (; aRefIt != aRefsList.end(); ++aRefIt) {
291 FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
292 if (anOwner && anOwner->getKind() == SketchPlugin_Sketch::ID()) {
293 aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(anOwner);
299 return SketchGroupPtr(); // not a sketch's feature
301 std::list<SketchGroupPtr>::const_iterator aGroupIt;
302 for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); ++aGroupIt)
303 if ((*aGroupIt)->getWorkplane() == aSketch)
306 // group for the sketch does not created yet
307 SketchGroupPtr aNewGroup = SketchGroupPtr(new SketchSolver_Group(aSketch));
308 myGroups.push_back(aNewGroup);
312 // ============================================================================
313 // Function: resolveConstraints
314 // Purpose: change entities according to available constraints
315 // ============================================================================
316 bool SketchSolver_Manager::resolveConstraints()
318 bool needToUpdate = false;
319 std::list<SketchGroupPtr>::const_iterator aGroupIter = myGroups.begin();
320 for (; aGroupIter != myGroups.end(); ++aGroupIter) {
321 if ((*aGroupIter)->resolveConstraints())
327 void SketchSolver_Manager::releaseFeaturesIfEventsBlocked() const
329 std::list<SketchGroupPtr>::const_iterator aGroupIter = myGroups.begin();
330 for (; aGroupIter != myGroups.end(); ++aGroupIter)
331 (*aGroupIter)->blockEvents(false);
334 bool SketchSolver_Manager::stopSendUpdate() const
336 static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
337 // to avoid redisplay of each segment on update by solver one by one in the viewer
338 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
339 if (isUpdateFlushed) {
340 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
342 return isUpdateFlushed;
345 void SketchSolver_Manager::allowSendUpdate() const
347 Events_Loop::loop()->setFlushed(Events_Loop::eventByName(EVENT_OBJECT_UPDATED), true);