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