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 if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
95 || theMessage->eventID() == anUpdateEvent) {
96 std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
97 std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
98 std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
100 isUpdateFlushed = stopSendUpdate();
102 // update sketch features only
103 std::set<ObjectPtr>::iterator aFeatIter;
104 for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
105 std::shared_ptr<SketchPlugin_Feature> aFeature =
106 std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
107 if (!aFeature || aFeature->isMacro())
110 updateFeature(aFeature);
113 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
114 std::shared_ptr<ModelAPI_ObjectMovedMessage> aMoveMsg =
115 std::dynamic_pointer_cast<ModelAPI_ObjectMovedMessage>(theMessage);
117 ObjectPtr aMovedObject = aMoveMsg->movedObject();
118 std::shared_ptr<GeomDataAPI_Point2D> aMovedPoint =
119 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aMoveMsg->movedAttribute());
121 const std::shared_ptr<GeomAPI_Pnt2d>& aFrom = aMoveMsg->originalPosition();
122 const std::shared_ptr<GeomAPI_Pnt2d>& aTo = aMoveMsg->currentPosition();
125 FeaturePtr aMovedFeature = ModelAPI_Feature::feature(aMovedObject);
126 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
127 std::dynamic_pointer_cast<SketchPlugin_Feature>(aMovedFeature);
128 if (aSketchFeature && !aSketchFeature->isMacro())
129 needToResolve = moveFeature(aSketchFeature, aFrom, aTo);
130 } else if (aMovedPoint)
131 needToResolve = moveAttribute(aMovedPoint, aFrom, aTo);
133 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
134 std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
135 std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
136 const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
138 // Find SketchPlugin_Sketch::ID() in groups.
139 // The constraint groups should be updated when an object removed from Sketch
140 std::set<std::string>::const_iterator aFGrIter;
141 for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
142 if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 ||
143 aFGrIter->compare(ModelAPI_Feature::group()) == 0)
146 if (aFGrIter != aFeatureGroups.end()) {
147 std::list<SketchGroupPtr>::iterator aGroupIter = myGroups.begin();
148 while (aGroupIter != myGroups.end()) {
149 if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed
150 std::list<SketchGroupPtr>::iterator aRemoveIt = aGroupIter++;
151 myGroups.erase(aRemoveIt);
155 (*aGroupIter)->repairConsistency();
159 myIsComputed = false;
162 // resolve constraints if needed
163 bool needToUpdate = needToResolve && resolveConstraints();
164 releaseFeaturesIfEventsBlocked();
166 // Features may be updated => now send events, but for all changed at once
170 myIsComputed = false;
172 // send update for movement in any case
173 if (needToUpdate || isMovedEvt)
174 Events_Loop::loop()->flush(anUpdateEvent);
177 // ============================================================================
178 // Function: updateFeature
179 // Purpose: create/update constraint or feature in appropriate group
180 // ============================================================================
181 bool SketchSolver_Manager::updateFeature(const std::shared_ptr<SketchPlugin_Feature>& theFeature)
183 // Check feature validity and find a group to place it.
184 // If the feature is not valid, the returned group will be empty.
185 // This will protect to deal with wrong (not fully initialized) features.
186 SketchGroupPtr aGroup = findGroup(theFeature);
189 aGroup->blockEvents(true);
191 std::shared_ptr<SketchPlugin_Constraint> aConstraint =
192 std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
196 isOk = aGroup->changeConstraint(aConstraint);
198 isOk = aGroup->updateFeature(theFeature);
202 // ============================================================================
203 // Function: moveFeature
204 // Purpose: move given feature in appropriate group
205 // ============================================================================
206 bool SketchSolver_Manager::moveFeature(
207 const std::shared_ptr<SketchPlugin_Feature>& theMovedFeature,
208 const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
209 const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
211 SketchGroupPtr aGroup = findGroup(theMovedFeature);
215 aGroup->blockEvents(true);
216 return aGroup->moveFeature(theMovedFeature, theFrom, theTo);
219 // ============================================================================
220 // Function: moveAttribute
221 // Purpose: move given attribute in appropriate group
222 // ============================================================================
223 bool SketchSolver_Manager::moveAttribute(
224 const std::shared_ptr<GeomDataAPI_Point2D>& theMovedAttribute,
225 const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
226 const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
228 FeaturePtr anOwner = ModelAPI_Feature::feature(theMovedAttribute->owner());
229 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
230 std::dynamic_pointer_cast<SketchPlugin_Feature>(anOwner);
231 SketchGroupPtr aGroup;
233 aGroup = findGroup(aSketchFeature);
235 theMovedAttribute->setValue(theTo);
239 aGroup->blockEvents(true);
240 return aGroup->movePoint(theMovedAttribute, theFrom, theTo);
243 // ============================================================================
244 // Function: findGroup
245 // Purpose: search groups of entities interacting with given feature
246 // ============================================================================
247 SketchGroupPtr SketchSolver_Manager::findGroup(
248 std::shared_ptr<SketchPlugin_Feature> theFeature)
250 if (!isFeatureValid(theFeature))
251 return SketchGroupPtr(); // do not process wrong features
253 // Obtain sketch, containing the feature
254 CompositeFeaturePtr aSketch;
255 const std::set<AttributePtr>& aRefsList = theFeature->data()->refsToMe();
256 std::set<AttributePtr>::const_iterator aRefIt = aRefsList.begin();
257 for (; aRefIt != aRefsList.end(); ++aRefIt) {
258 FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
259 if (anOwner && anOwner->getKind() == SketchPlugin_Sketch::ID()) {
260 aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(anOwner);
266 return SketchGroupPtr(); // not a sketch's feature
268 std::list<SketchGroupPtr>::const_iterator aGroupIt;
269 for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); ++aGroupIt)
270 if ((*aGroupIt)->getWorkplane() == aSketch)
273 // group for the sketch does not created yet
274 SketchGroupPtr aNewGroup = SketchGroupPtr(new SketchSolver_Group(aSketch));
275 myGroups.push_back(aNewGroup);
279 // ============================================================================
280 // Function: resolveConstraints
281 // Purpose: change entities according to available constraints
282 // ============================================================================
283 bool SketchSolver_Manager::resolveConstraints()
285 bool needToUpdate = false;
286 std::list<SketchGroupPtr>::const_iterator aGroupIter = myGroups.begin();
287 for (; aGroupIter != myGroups.end(); ++aGroupIter) {
288 if ((*aGroupIter)->resolveConstraints())
294 void SketchSolver_Manager::releaseFeaturesIfEventsBlocked() const
296 std::list<SketchGroupPtr>::const_iterator aGroupIter = myGroups.begin();
297 for (; aGroupIter != myGroups.end(); ++aGroupIter)
298 (*aGroupIter)->blockEvents(false);
301 bool SketchSolver_Manager::stopSendUpdate() const
303 static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
304 // to avoid redisplay of each segment on update by solver one by one in the viewer
305 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
306 if (isUpdateFlushed) {
307 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
309 return isUpdateFlushed;
312 void SketchSolver_Manager::allowSendUpdate() const
314 Events_Loop::loop()->setFlushed(Events_Loop::eventByName(EVENT_OBJECT_UPDATED), true);