]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SketchSolver_ConstraintManager.cpp
Salome HOME
41de682cb5f7b27f40d08449843be79b0d8f7b42
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintManager.cpp
1 // File:    SketchSolver_ConstraintManager.cpp
2 // Created: 08 May 2014
3 // Author:  Artem ZHIDKOV
4
5 #include "SketchSolver_ConstraintManager.h"
6
7 #include <Events_Loop.h>
8 #include <ModelAPI_AttributeDouble.h>
9 #include <ModelAPI_AttributeRefList.h>
10 #include <ModelAPI_Data.h>
11 #include <ModelAPI_Events.h>
12
13 #include <SketchPlugin_Constraint.h>
14
15 #include <SketchPlugin_Arc.h>
16 #include <SketchPlugin_Circle.h>
17 #include <SketchPlugin_Line.h>
18 #include <SketchPlugin_Point.h>
19 #include <SketchPlugin_Sketch.h>
20
21
22 // Initialization of constraint manager self pointer
23 SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
24
25 /// Global constraint manager object
26 SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance();
27
28
29 // ========================================================
30 // ========= SketchSolver_ConstraintManager ===============
31 // ========================================================
32 SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance()
33 {
34   if (!_self)
35     _self = new SketchSolver_ConstraintManager();
36   return _self;
37 }
38
39 SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
40 {
41   myGroups.clear();
42
43   // Register in event loop
44   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
45   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
46   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
47   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
48 }
49
50 SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
51 {
52   myGroups.clear();
53 }
54
55 // ============================================================================
56 //  Function: processEvent
57 //  Class:    SketchSolver_PluginManager
58 //  Purpose:  listen the event loop and process the message
59 // ============================================================================
60 void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessage)
61 {
62   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED) ||
63       theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED) || 
64       theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED))
65   {
66     const ModelAPI_ObjectUpdatedMessage* anUpdateMsg = 
67       dynamic_cast<const ModelAPI_ObjectUpdatedMessage*>(theMessage);
68     std::set< ObjectPtr > aFeatures = anUpdateMsg->features();
69
70     bool isModifiedEvt = 
71       theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
72     if (!isModifiedEvt)
73     {
74       std::set< ObjectPtr >::iterator aFeatIter;
75       for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++)
76       {
77         FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFeatIter);
78         // Only sketches and constraints can be added by Create event
79         const std::string& aFeatureKind = aFeature->getKind();
80         if (aFeatureKind.compare(SKETCH_KIND) == 0)
81         {
82           boost::shared_ptr<SketchPlugin_Feature> aSketch =
83             boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
84           if (aSketch)
85             changeWorkplane(aSketch);
86           continue;
87         }
88         boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
89           boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aFeature);
90         if (aConstraint)
91           changeConstraint(aConstraint);
92         else
93         {
94           // Sketch plugin features can be only updated
95           boost::shared_ptr<SketchPlugin_Feature> aFeature =
96             boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
97           if (aFeature)
98             updateEntity(aFeature);
99         }
100       }
101     }
102
103     // Solve the set of constraints
104     resolveConstraints();
105   }
106   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED))
107   {
108     const ModelAPI_ObjectDeletedMessage* aDeleteMsg = 
109       dynamic_cast<const ModelAPI_ObjectDeletedMessage*>(theMessage);
110     const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
111
112     // Find SKETCH_KIND in groups. The constraint groups should be updated when an object removed from Sketch
113     std::set<std::string>::const_iterator aFGrIter;
114     for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
115       if (aFGrIter->compare(SKETCH_KIND) == 0)
116         break;
117     
118     if (aFGrIter != aFeatureGroups.end())
119     {
120       std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
121       std::vector<SketchSolver_ConstraintGroup*> aSeparatedGroups;
122       while (aGroupIter != myGroups.end())
123       {
124         if (!(*aGroupIter)->isWorkplaneValid())
125         { // the group should be removed
126           delete *aGroupIter;
127           int aShift = aGroupIter - myGroups.begin();
128           myGroups.erase(aGroupIter);
129           aGroupIter = myGroups.begin() + aShift;
130           continue;
131         }
132         if ((*aGroupIter)->updateGroup())
133         { // some constraints were removed, try to split the group
134           (*aGroupIter)->splitGroup(aSeparatedGroups);
135         }
136         aGroupIter++;
137       }
138       if (aSeparatedGroups.size() > 0)
139         myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
140     }
141   }
142 }
143
144 // ============================================================================
145 //  Function: changeWorkplane
146 //  Class:    SketchSolver_PluginManager
147 //  Purpose:  update workplane by given parameters of the sketch
148 // ============================================================================
149 bool SketchSolver_ConstraintManager::changeWorkplane(boost::shared_ptr<SketchPlugin_Feature> theSketch)
150 {
151   bool aResult = true; // changed when a workplane wrongly updated
152   bool isUpdated = false;
153   // Try to update specified workplane in all groups
154   std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
155   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
156     if ((*aGroupIter)->isBaseWorkplane(theSketch))
157     {
158       isUpdated = true;
159       if (!(*aGroupIter)->updateWorkplane())
160         aResult = false;
161     }
162   // If the workplane is not updated, so this is a new workplane
163   if (!isUpdated)
164   {
165     SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch);
166     // Verify that the group is created successfully
167     if (!aNewGroup->isBaseWorkplane(theSketch))
168     {
169       delete aNewGroup;
170       return false;
171     }
172     myGroups.push_back(aNewGroup);
173   }
174   return aResult;
175 }
176
177 // ============================================================================
178 //  Function: changeConstraint
179 //  Class:    SketchSolver_PluginManager
180 //  Purpose:  create/update the constraint and place it into appropriate group
181 // ============================================================================
182 bool SketchSolver_ConstraintManager::changeConstraint(
183               boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
184 {
185   // Search the groups which this constraint touches
186   std::set<Slvs_hGroup> aGroups;
187   findGroups(theConstraint, aGroups);
188
189   // Process the groups list
190   if (aGroups.size() == 0)
191   { // There are no groups applicable for this constraint => create new one
192     boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
193     if (!aWP) return false;
194     SketchSolver_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP);
195     if (!aGroup->changeConstraint(theConstraint))
196     {
197       delete aGroup;
198       return false;
199     }
200     myGroups.push_back(aGroup);
201     return true;
202   }
203   else if (aGroups.size() == 1)
204   { // Only one group => add constraint into it
205     Slvs_hGroup aGroupId = *(aGroups.begin());
206     std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
207     for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
208       if ((*aGroupIter)->getId() == aGroupId)
209         return (*aGroupIter)->changeConstraint(theConstraint);
210   }
211   else if (aGroups.size() > 1)
212   { // Several groups applicable for this constraint => need to merge them
213     std::set<Slvs_hGroup>::const_iterator aGroupsIter = aGroups.begin();
214
215     // Search first group
216     std::vector<SketchSolver_ConstraintGroup*>::iterator aFirstGroupIter;
217     for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
218       if ((*aFirstGroupIter)->getId() == *aGroupsIter)
219         break;
220     if (aFirstGroupIter == myGroups.end())
221       return false;
222
223     // Append other groups to the first one
224     std::vector<SketchSolver_ConstraintGroup*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
225     for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++)
226     {
227       for ( ; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
228         if ((*anOtherGroupIter)->getId() == *aGroupsIter)
229           break;
230       if (anOtherGroupIter == myGroups.end())
231       { // Group disappears
232         anOtherGroupIter = aFirstGroupIter + 1;
233         continue;
234       }
235
236       (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
237       int aShiftFirst = aFirstGroupIter - myGroups.begin();
238       int aShiftOther = anOtherGroupIter - myGroups.begin();
239       delete *anOtherGroupIter;
240       myGroups.erase(anOtherGroupIter);
241       aFirstGroupIter  = myGroups.begin() + aShiftFirst;
242       anOtherGroupIter = myGroups.begin() + aShiftOther;
243     }
244
245     return (*aFirstGroupIter)->changeConstraint(theConstraint);
246   }
247
248   // Something goes wrong
249   return false;
250 }
251
252 // ============================================================================
253 //  Function: updateEntity
254 //  Class:    SketchSolver_PluginManager
255 //  Purpose:  update any element on the sketch, which is used by constraints
256 // ============================================================================
257 void SketchSolver_ConstraintManager::updateEntity(boost::shared_ptr<SketchPlugin_Feature> theFeature)
258 {
259   // Create list of attributes depending on type of the feature
260   std::vector<std::string> anAttrList;
261   const std::string& aFeatureKind = theFeature->getKind();
262   // Point
263   if (aFeatureKind.compare(SKETCH_POINT_KIND) == 0)
264     anAttrList.push_back(POINT_ATTR_COORD);
265   // Line
266   else if (aFeatureKind.compare(SKETCH_LINE_KIND) == 0)
267   {
268     anAttrList.push_back(LINE_ATTR_START);
269     anAttrList.push_back(LINE_ATTR_END);
270   }
271   // Circle
272   else if (aFeatureKind.compare(SKETCH_CIRCLE_KIND) == 0)
273   {
274     anAttrList.push_back(CIRCLE_ATTR_CENTER);
275     anAttrList.push_back(CIRCLE_ATTR_RADIUS);
276   }
277   // Arc
278   else if (aFeatureKind.compare(SKETCH_ARC_KIND) == 0)
279   {
280     anAttrList.push_back(ARC_ATTR_CENTER);
281     anAttrList.push_back(ARC_ATTR_START);
282     anAttrList.push_back(ARC_ATTR_END);
283   }
284   /// \todo Other types of features should be implemented
285
286   // Check changing of feature's attributes (go through the groups and search usage of the attributes)
287   std::vector<std::string>::const_iterator anAttrIter;
288   for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++)
289   {
290     std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
291     for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
292     {
293       if ((*aGroupIter)->isEmpty()) 
294         continue;
295       boost::shared_ptr<ModelAPI_Attribute> anAttribute =
296         boost::dynamic_pointer_cast<ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
297       (*aGroupIter)->updateEntityIfPossible(anAttribute);
298     }
299   }
300
301   std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
302   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
303     if (!(*aGroupIter)->isEmpty())
304       (*aGroupIter)->updateRelatedConstraints(theFeature);
305 }
306
307
308 // ============================================================================
309 //  Function: findGroups
310 //  Class:    SketchSolver_PluginManager
311 //  Purpose:  search groups of entities interacting with given constraint
312 // ============================================================================
313 void SketchSolver_ConstraintManager::findGroups(
314               boost::shared_ptr<SketchPlugin_Constraint> theConstraint,
315               std::set<Slvs_hGroup>&                     theGroupIDs) const
316 {
317   boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
318
319   SketchSolver_ConstraintGroup* anEmptyGroup = 0; // appropriate empty group for specified constraint
320   std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
321   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
322     if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theConstraint))
323     {
324       if (!(*aGroupIter)->isEmpty())
325         theGroupIDs.insert((*aGroupIter)->getId());
326       else if (!anEmptyGroup)
327         anEmptyGroup = *aGroupIter;
328     }
329
330   // When only empty group is found, use it
331   if (anEmptyGroup && theGroupIDs.empty())
332     theGroupIDs.insert(anEmptyGroup->getId());
333 }
334
335 // ============================================================================
336 //  Function: findWorkplaneForConstraint
337 //  Class:    SketchSolver_PluginManager
338 //  Purpose:  search workplane containing given constraint
339 // ============================================================================
340 boost::shared_ptr<SketchPlugin_Feature> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
341               boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
342 {
343   // Already verified workplanes
344   std::set< boost::shared_ptr<SketchPlugin_Feature> > aVerified;
345
346   std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
347   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
348   {
349     boost::shared_ptr<SketchPlugin_Feature> aWP = (*aGroupIter)->getWorkplane();
350     if (aVerified.find(aWP) != aVerified.end())
351       continue;
352
353     boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures =
354       boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aWP->data()->attribute(SKETCH_ATTR_FEATURES));
355     std::list< FeaturePtr > aFeaturesList = aWPFeatures->list();
356     std::list< FeaturePtr >::const_iterator anIter;
357     for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
358       if (*anIter == theConstraint)
359         return aWP; // workplane is found
360     aVerified.insert(aWP);
361   }
362
363   return boost::shared_ptr<SketchPlugin_Feature>();
364 }
365
366 // ============================================================================
367 //  Function: resolveConstraints
368 //  Class:    SketchSolver_PluginManager
369 //  Purpose:  change entities according to available constraints
370 // ============================================================================
371 void SketchSolver_ConstraintManager::resolveConstraints()
372 {
373   std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
374   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
375     (*aGroupIter)->resolveConstraints();
376
377   // Features may be updated => send events
378   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
379 }
380