]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SketchSolver_ConstraintManager.cpp
Salome HOME
Merge branch 'master' of newgeom:newgeom.git
[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         if (!aFeature) continue;
79         // Only sketches and constraints can be added by Create event
80         const std::string& aFeatureKind = aFeature->getKind();
81         if (aFeatureKind.compare(SketchPlugin_Sketch::ID()) == 0)
82         {
83           boost::shared_ptr<SketchPlugin_Feature> aSketch =
84             boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
85           if (aSketch)
86             changeWorkplane(aSketch);
87           continue;
88         }
89         boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
90           boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aFeature);
91         if (aConstraint)
92           changeConstraint(aConstraint);
93         else
94         {
95           // Sketch plugin features can be only updated
96           boost::shared_ptr<SketchPlugin_Feature> aSFeature =
97             boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
98           if (aSFeature)
99             updateEntity(aSFeature);
100         }
101       }
102     }
103
104     // Solve the set of constraints
105     resolveConstraints();
106   }
107   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED))
108   {
109     const ModelAPI_ObjectDeletedMessage* aDeleteMsg = 
110       dynamic_cast<const ModelAPI_ObjectDeletedMessage*>(theMessage);
111     const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
112
113     // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch
114     std::set<std::string>::const_iterator aFGrIter;
115     for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
116       if (aFGrIter->compare(SketchPlugin_Sketch::ID()) == 0)
117         break;
118     
119     if (aFGrIter != aFeatureGroups.end())
120     {
121       std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
122       std::vector<SketchSolver_ConstraintGroup*> aSeparatedGroups;
123       while (aGroupIter != myGroups.end())
124       {
125         if (!(*aGroupIter)->isWorkplaneValid())
126         { // the group should be removed
127           delete *aGroupIter;
128           int aShift = aGroupIter - myGroups.begin();
129           myGroups.erase(aGroupIter);
130           aGroupIter = myGroups.begin() + aShift;
131           continue;
132         }
133         if ((*aGroupIter)->updateGroup())
134         { // some constraints were removed, try to split the group
135           (*aGroupIter)->splitGroup(aSeparatedGroups);
136         }
137         aGroupIter++;
138       }
139       if (aSeparatedGroups.size() > 0)
140         myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
141     }
142   }
143 }
144
145 // ============================================================================
146 //  Function: changeWorkplane
147 //  Class:    SketchSolver_PluginManager
148 //  Purpose:  update workplane by given parameters of the sketch
149 // ============================================================================
150 bool SketchSolver_ConstraintManager::changeWorkplane(boost::shared_ptr<SketchPlugin_Feature> theSketch)
151 {
152   bool aResult = true; // changed when a workplane wrongly updated
153   bool isUpdated = false;
154   // Try to update specified workplane in all groups
155   std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
156   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
157     if ((*aGroupIter)->isBaseWorkplane(theSketch))
158     {
159       isUpdated = true;
160       if (!(*aGroupIter)->updateWorkplane())
161         aResult = false;
162     }
163   // If the workplane is not updated, so this is a new workplane
164   if (!isUpdated)
165   {
166     SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch);
167     // Verify that the group is created successfully
168     if (!aNewGroup->isBaseWorkplane(theSketch))
169     {
170       delete aNewGroup;
171       return false;
172     }
173     myGroups.push_back(aNewGroup);
174   }
175   return aResult;
176 }
177
178 // ============================================================================
179 //  Function: changeConstraint
180 //  Class:    SketchSolver_PluginManager
181 //  Purpose:  create/update the constraint and place it into appropriate group
182 // ============================================================================
183 bool SketchSolver_ConstraintManager::changeConstraint(
184               boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
185 {
186   // Search the groups which this constraint touches
187   std::set<Slvs_hGroup> aGroups;
188   findGroups(theConstraint, aGroups);
189
190   // Process the groups list
191   if (aGroups.size() == 0)
192   { // There are no groups applicable for this constraint => create new one
193     boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
194     if (!aWP) return false;
195     SketchSolver_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP);
196     if (!aGroup->changeConstraint(theConstraint))
197     {
198       delete aGroup;
199       return false;
200     }
201     myGroups.push_back(aGroup);
202     return true;
203   }
204   else if (aGroups.size() == 1)
205   { // Only one group => add constraint into it
206     Slvs_hGroup aGroupId = *(aGroups.begin());
207     std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
208     for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
209       if ((*aGroupIter)->getId() == aGroupId)
210         return (*aGroupIter)->changeConstraint(theConstraint);
211   }
212   else if (aGroups.size() > 1)
213   { // Several groups applicable for this constraint => need to merge them
214     std::set<Slvs_hGroup>::const_iterator aGroupsIter = aGroups.begin();
215
216     // Search first group
217     std::vector<SketchSolver_ConstraintGroup*>::iterator aFirstGroupIter;
218     for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
219       if ((*aFirstGroupIter)->getId() == *aGroupsIter)
220         break;
221     if (aFirstGroupIter == myGroups.end())
222       return false;
223
224     // Append other groups to the first one
225     std::vector<SketchSolver_ConstraintGroup*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
226     for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++)
227     {
228       for ( ; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
229         if ((*anOtherGroupIter)->getId() == *aGroupsIter)
230           break;
231       if (anOtherGroupIter == myGroups.end())
232       { // Group disappears
233         anOtherGroupIter = aFirstGroupIter + 1;
234         continue;
235       }
236
237       (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
238       int aShiftFirst = aFirstGroupIter - myGroups.begin();
239       int aShiftOther = anOtherGroupIter - myGroups.begin();
240       delete *anOtherGroupIter;
241       myGroups.erase(anOtherGroupIter);
242       aFirstGroupIter  = myGroups.begin() + aShiftFirst;
243       anOtherGroupIter = myGroups.begin() + aShiftOther;
244     }
245
246     return (*aFirstGroupIter)->changeConstraint(theConstraint);
247   }
248
249   // Something goes wrong
250   return false;
251 }
252
253 // ============================================================================
254 //  Function: updateEntity
255 //  Class:    SketchSolver_PluginManager
256 //  Purpose:  update any element on the sketch, which is used by constraints
257 // ============================================================================
258 void SketchSolver_ConstraintManager::updateEntity(boost::shared_ptr<SketchPlugin_Feature> theFeature)
259 {
260   // Create list of attributes depending on type of the feature
261   std::vector<std::string> anAttrList;
262   const std::string& aFeatureKind = theFeature->getKind();
263   // Point
264   if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0)
265     anAttrList.push_back(SketchPlugin_Point::COORD_ID());
266   // Line
267   else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0)
268   {
269     anAttrList.push_back(SketchPlugin_Line::START_ID());
270     anAttrList.push_back(SketchPlugin_Line::END_ID());
271   }
272   // Circle
273   else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0)
274   {
275     anAttrList.push_back(SketchPlugin_Circle::CENTER_ID());
276     anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID());
277   }
278   // Arc
279   else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0)
280   {
281     anAttrList.push_back(SketchPlugin_Arc::CENTER_ID());
282     anAttrList.push_back(SketchPlugin_Arc::START_ID());
283     anAttrList.push_back(SketchPlugin_Arc::END_ID());
284   }
285   /// \todo Other types of features should be implemented
286
287   // Check changing of feature's attributes (go through the groups and search usage of the attributes)
288   std::vector<std::string>::const_iterator anAttrIter;
289   for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++)
290   {
291     std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
292     for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
293     {
294       if ((*aGroupIter)->isEmpty()) 
295         continue;
296       boost::shared_ptr<ModelAPI_Attribute> anAttribute =
297         boost::dynamic_pointer_cast<ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
298       (*aGroupIter)->updateEntityIfPossible(anAttribute);
299     }
300   }
301
302   std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
303   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
304     if (!(*aGroupIter)->isEmpty())
305       (*aGroupIter)->updateRelatedConstraints(theFeature);
306 }
307
308
309 // ============================================================================
310 //  Function: findGroups
311 //  Class:    SketchSolver_PluginManager
312 //  Purpose:  search groups of entities interacting with given constraint
313 // ============================================================================
314 void SketchSolver_ConstraintManager::findGroups(
315               boost::shared_ptr<SketchPlugin_Constraint> theConstraint,
316               std::set<Slvs_hGroup>&                     theGroupIDs) const
317 {
318   boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
319
320   SketchSolver_ConstraintGroup* anEmptyGroup = 0; // appropriate empty group for specified constraint
321   std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
322   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
323     if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theConstraint))
324     {
325       if (!(*aGroupIter)->isEmpty())
326         theGroupIDs.insert((*aGroupIter)->getId());
327       else if (!anEmptyGroup)
328         anEmptyGroup = *aGroupIter;
329     }
330
331   // When only empty group is found, use it
332   if (anEmptyGroup && theGroupIDs.empty())
333     theGroupIDs.insert(anEmptyGroup->getId());
334 }
335
336 // ============================================================================
337 //  Function: findWorkplaneForConstraint
338 //  Class:    SketchSolver_PluginManager
339 //  Purpose:  search workplane containing given constraint
340 // ============================================================================
341 boost::shared_ptr<SketchPlugin_Feature> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
342               boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
343 {
344   // Already verified workplanes
345   std::set< boost::shared_ptr<SketchPlugin_Feature> > aVerified;
346
347   std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
348   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
349   {
350     boost::shared_ptr<SketchPlugin_Feature> aWP = (*aGroupIter)->getWorkplane();
351     if (aVerified.find(aWP) != aVerified.end())
352       continue;
353
354     boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures =
355       boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aWP->data()->attribute(SketchPlugin_Sketch::FEATURES_ID()));
356     std::list< ObjectPtr >& aFeaturesList = aWPFeatures->list();
357     std::list< ObjectPtr >::const_iterator anIter;
358     for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
359       if (*anIter == theConstraint)
360         return aWP; // workplane is found
361     aVerified.insert(aWP);
362   }
363
364   return boost::shared_ptr<SketchPlugin_Feature>();
365 }
366
367 // ============================================================================
368 //  Function: resolveConstraints
369 //  Class:    SketchSolver_PluginManager
370 //  Purpose:  change entities according to available constraints
371 // ============================================================================
372 void SketchSolver_ConstraintManager::resolveConstraints()
373 {
374   std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
375   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
376     (*aGroupIter)->resolveConstraints();
377
378   // Features may be updated => send events
379   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
380 }
381