]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SketchSolver_Manager.cpp
Salome HOME
4973c483de34158cdc68272de55c1fd68297b103
[modules/shaper.git] / src / SketchSolver / SketchSolver_Manager.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    SketchSolver_Manager.cpp
4 // Created: 08 May 2014
5 // Author:  Artem ZHIDKOV
6
7 #include "SketchSolver_Manager.h"
8 #include "SketchSolver_Error.h"
9
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>
18
19 /// Global constraint manager object
20 static SketchSolver_Manager* myManager = SketchSolver_Manager::instance();
21
22 /// \brief Verifies is the feature valid
23 static bool isFeatureValid(FeaturePtr theFeature)
24 {
25   if (!theFeature || !theFeature->data() || !theFeature->data()->isValid())
26     return false;
27
28   SessionPtr aMgr = ModelAPI_Session::get();
29   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
30   return aFactory->validate(theFeature);
31 }
32
33
34
35 // ========================================================
36 // ========= SketchSolver_Manager ===============
37 // ========================================================
38 SketchSolver_Manager* SketchSolver_Manager::instance()
39 {
40   static SketchSolver_Manager* mySelf = 0; // Self pointer to implement singleton functionality
41   if (!mySelf)
42     mySelf = new SketchSolver_Manager();
43   return mySelf;
44 }
45
46 SketchSolver_Manager::SketchSolver_Manager()
47 {
48   myGroups.clear();
49   myIsComputed = false;
50
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));
56
57   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SKETCH_PREPARED));
58 }
59
60 SketchSolver_Manager::~SketchSolver_Manager()
61 {
62   myGroups.clear();
63 }
64
65 bool SketchSolver_Manager::groupMessages()
66 {
67   return true;
68 }
69
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)
76 {
77   bool needToResolve = false;
78   bool isUpdateFlushed = false;
79   bool isMovedEvt = false;
80
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);
87     needToResolve = true;
88   }
89
90   if (myIsComputed)
91     return;
92   myIsComputed = true;
93
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();
99
100     isUpdateFlushed = stopSendUpdate();
101
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())
108         continue;
109
110       updateFeature(aFeature);
111     }
112
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);
116
117     ObjectPtr aMovedObject = aMoveMsg->movedObject();
118     std::shared_ptr<GeomDataAPI_Point2D> aMovedPoint =
119         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aMoveMsg->movedAttribute());
120
121     const std::shared_ptr<GeomAPI_Pnt2d>& aFrom = aMoveMsg->originalPosition();
122     const std::shared_ptr<GeomAPI_Pnt2d>& aTo = aMoveMsg->currentPosition();
123
124     if (aMovedObject) {
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);
132
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();
137
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)
144         break;
145
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);
152           continue;
153         }
154
155         (*aGroupIter)->repairConsistency();
156         ++aGroupIter;
157       }
158     }
159     myIsComputed = false;
160   }
161
162   // resolve constraints if needed
163   bool needToUpdate = needToResolve && resolveConstraints();
164   releaseFeaturesIfEventsBlocked();
165
166   // Features may be updated => now send events, but for all changed at once
167   if (isUpdateFlushed)
168     allowSendUpdate();
169
170   myIsComputed = false;
171
172   // send update for movement in any case
173   if (needToUpdate || isMovedEvt)
174     Events_Loop::loop()->flush(anUpdateEvent);
175 }
176
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)
182 {
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);
187   if (!aGroup)
188     return false;
189   aGroup->blockEvents(true);
190
191   std::shared_ptr<SketchPlugin_Constraint> aConstraint =
192       std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
193
194   bool isOk = false;
195   if (aConstraint)
196     isOk = aGroup->changeConstraint(aConstraint);
197   else
198     isOk = aGroup->updateFeature(theFeature);
199   return isOk;
200 }
201
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)
210 {
211   SketchGroupPtr aGroup = findGroup(theMovedFeature);
212   if (!aGroup)
213     return false;
214
215   aGroup->blockEvents(true);
216   return aGroup->moveFeature(theMovedFeature, theFrom, theTo);
217 }
218
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)
227 {
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;
232   if (aSketchFeature)
233     aGroup = findGroup(aSketchFeature);
234   if (!aGroup) {
235     theMovedAttribute->setValue(theTo);
236     return false;
237   }
238
239   aGroup->blockEvents(true);
240   return aGroup->movePoint(theMovedAttribute, theFrom, theTo);
241 }
242
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)
249 {
250   if (!isFeatureValid(theFeature))
251     return SketchGroupPtr(); // do not process wrong features
252
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);
261       break;
262     }
263   }
264
265   if (!aSketch)
266     return SketchGroupPtr(); // not a sketch's feature
267
268   std::list<SketchGroupPtr>::const_iterator aGroupIt;
269   for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); ++aGroupIt)
270     if ((*aGroupIt)->getWorkplane() == aSketch)
271       return *aGroupIt;
272
273   // group for the sketch does not created yet
274   SketchGroupPtr aNewGroup = SketchGroupPtr(new SketchSolver_Group(aSketch));
275   myGroups.push_back(aNewGroup);
276   return aNewGroup;
277 }
278
279 // ============================================================================
280 //  Function: resolveConstraints
281 //  Purpose:  change entities according to available constraints
282 // ============================================================================
283 bool SketchSolver_Manager::resolveConstraints()
284 {
285   bool needToUpdate = false;
286   std::list<SketchGroupPtr>::const_iterator aGroupIter = myGroups.begin();
287   for (; aGroupIter != myGroups.end(); ++aGroupIter) {
288     if ((*aGroupIter)->resolveConstraints())
289       needToUpdate = true;
290   }
291   return needToUpdate;
292 }
293
294 void SketchSolver_Manager::releaseFeaturesIfEventsBlocked() const
295 {
296   std::list<SketchGroupPtr>::const_iterator aGroupIter = myGroups.begin();
297   for (; aGroupIter != myGroups.end(); ++aGroupIter)
298     (*aGroupIter)->blockEvents(false);
299 }
300
301 bool SketchSolver_Manager::stopSendUpdate() const
302 {
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);
308   }
309   return isUpdateFlushed;
310 }
311
312 void SketchSolver_Manager::allowSendUpdate() const
313 {
314   Events_Loop::loop()->setFlushed(Events_Loop::eventByName(EVENT_OBJECT_UPDATED), true);
315 }