1 // File: SketchSolver_ConstraintManager.cpp
2 // Created: 08 May 2014
3 // Author: Artem ZHIDKOV
5 #include "SketchSolver_ConstraintManager.h"
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>
13 #include <SketchPlugin_Constraint.h>
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>
22 // Initialization of constraint manager self pointer
23 SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
25 /// Global constraint manager object
26 SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance();
29 // ========================================================
30 // ========= SketchSolver_ConstraintManager ===============
31 // ========================================================
32 SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance()
35 _self = new SketchSolver_ConstraintManager();
39 SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
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));
50 SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
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)
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))
66 const Model_FeatureUpdatedMessage* anUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
67 std::set< boost::shared_ptr<ModelAPI_Feature> > aFeatures = anUpdateMsg->features();
69 bool isModifiedEvt = theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_MOVED);
72 std::set< boost::shared_ptr<ModelAPI_Feature> >::iterator aFeatIter;
73 for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++)
75 // Only sketches and constraints can be added by Create event
76 const std::string& aFeatureKind = (*aFeatIter)->getKind();
77 if (aFeatureKind.compare("Sketch") == 0)
79 boost::shared_ptr<SketchPlugin_Feature> aSketch =
80 boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
82 changeWorkplane(aSketch);
85 boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
86 boost::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFeatIter);
88 changeConstraint(aConstraint);
91 // Sketch plugin features can be only updated
92 boost::shared_ptr<SketchPlugin_Feature> aFeature =
93 boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
95 updateEntity(aFeature);
100 // Solve the set of constraints
101 resolveConstraints();
103 else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED))
105 const Model_FeatureDeletedMessage* aDeleteMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
106 const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
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)
114 if (aFGrIter != aFeatureGroups.end())
116 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
117 std::vector<SketchSolver_ConstraintGroup*> aSeparatedGroups;
118 while (aGroupIter != myGroups.end())
120 if (!(*aGroupIter)->isWorkplaneValid())
121 { // the group should be removed
123 int aShift = aGroupIter - myGroups.begin();
124 myGroups.erase(aGroupIter);
125 aGroupIter = myGroups.begin() + aShift;
128 if ((*aGroupIter)->updateGroup())
129 { // some constraints were removed, try to split the group
130 (*aGroupIter)->splitGroup(aSeparatedGroups);
134 if (aSeparatedGroups.size() > 0)
135 myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
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)
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))
155 if (!(*aGroupIter)->updateWorkplane())
158 // If the workplane is not updated, so this is a new workplane
161 SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch);
162 // Verify that the group is created successfully
163 if (!aNewGroup->isBaseWorkplane(theSketch))
168 myGroups.push_back(aNewGroup);
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)
181 // Search the groups which this constraint touches
182 std::set<Slvs_hGroup> aGroups;
183 findGroups(theConstraint, aGroups);
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))
196 myGroups.push_back(aGroup);
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);
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();
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)
216 if (aFirstGroupIter == myGroups.end())
219 // Append other groups to the first one
220 std::vector<SketchSolver_ConstraintGroup*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
221 for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++)
223 for ( ; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
224 if ((*anOtherGroupIter)->getId() == *aGroupsIter)
226 if (anOtherGroupIter == myGroups.end())
227 { // Group disappears
228 anOtherGroupIter = aFirstGroupIter + 1;
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;
241 return (*aFirstGroupIter)->changeConstraint(theConstraint);
244 // Something goes wrong
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)
255 // Create list of attributes depending on type of the feature
256 std::vector<std::string> anAttrList;
257 const std::string& aFeatureKind = theFeature->getKind();
259 if (aFeatureKind.compare("SketchPoint") == 0)
260 anAttrList.push_back(POINT_ATTR_COORD);
262 else if (aFeatureKind.compare("SketchLine") == 0)
264 anAttrList.push_back(LINE_ATTR_START);
265 anAttrList.push_back(LINE_ATTR_END);
268 else if (aFeatureKind.compare("SketchCircle") == 0)
270 anAttrList.push_back(CIRCLE_ATTR_CENTER);
271 anAttrList.push_back(CIRCLE_ATTR_RADIUS);
274 else if (aFeatureKind.compare("SketchArc") == 0)
276 anAttrList.push_back(ARC_ATTR_CENTER);
277 anAttrList.push_back(ARC_ATTR_START);
278 anAttrList.push_back(ARC_ATTR_END);
280 /// \todo Other types of features should be implemented
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++)
286 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
287 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
289 if ((*aGroupIter)->isEmpty())
291 boost::shared_ptr<ModelAPI_Attribute> anAttribute =
292 boost::dynamic_pointer_cast<ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
293 (*aGroupIter)->updateEntityIfPossible(anAttribute);
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
308 boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
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))
315 if (!(*aGroupIter)->isEmpty())
316 theGroupIDs.insert((*aGroupIter)->getId());
317 else if (!anEmptyGroup)
318 anEmptyGroup = *aGroupIter;
321 // When only empty group is found, use it
322 if (anEmptyGroup && theGroupIDs.empty())
323 theGroupIDs.insert(anEmptyGroup->getId());
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
334 // Already verified workplanes
335 std::set< boost::shared_ptr<SketchPlugin_Feature> > aVerified;
337 std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
338 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
340 boost::shared_ptr<SketchPlugin_Feature> aWP = (*aGroupIter)->getWorkplane();
341 if (aVerified.find(aWP) != aVerified.end())
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);
354 return boost::shared_ptr<SketchPlugin_Feature>();
357 // ============================================================================
358 // Function: resolveConstraints
359 // Class: SketchSolver_PluginManager
360 // Purpose: change entities according to available constraints
361 // ============================================================================
362 void SketchSolver_ConstraintManager::resolveConstraints()
364 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
365 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
366 (*aGroupIter)->resolveConstraints();
368 // Features may be updated => send events
369 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));