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 <ModelAPI_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 ModelAPI_FeatureUpdatedMessage* anUpdateMsg =
67 dynamic_cast<const ModelAPI_FeatureUpdatedMessage*>(theMessage);
68 std::set< FeaturePtr > aFeatures = anUpdateMsg->features();
71 theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_MOVED);
74 std::set< FeaturePtr >::iterator aFeatIter;
75 for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++)
77 // Only sketches and constraints can be added by Create event
78 const std::string& aFeatureKind = (*aFeatIter)->getKind();
79 if (aFeatureKind.compare(SketchPlugin_Sketch::ID()) == 0)
81 boost::shared_ptr<SketchPlugin_Feature> aSketch =
82 boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
84 changeWorkplane(aSketch);
87 boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
88 boost::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFeatIter);
90 changeConstraint(aConstraint);
93 // Sketch plugin features can be only updated
94 boost::shared_ptr<SketchPlugin_Feature> aFeature =
95 boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
97 updateEntity(aFeature);
102 // Solve the set of constraints
103 resolveConstraints();
105 else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED))
107 const ModelAPI_FeatureDeletedMessage* aDeleteMsg =
108 dynamic_cast<const ModelAPI_FeatureDeletedMessage*>(theMessage);
109 const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
111 // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch
112 std::set<std::string>::const_iterator aFGrIter;
113 for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
114 if (aFGrIter->compare(SketchPlugin_Sketch::ID()) == 0)
117 if (aFGrIter != aFeatureGroups.end())
119 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
120 std::vector<SketchSolver_ConstraintGroup*> aSeparatedGroups;
121 while (aGroupIter != myGroups.end())
123 if (!(*aGroupIter)->isWorkplaneValid())
124 { // the group should be removed
126 int aShift = aGroupIter - myGroups.begin();
127 myGroups.erase(aGroupIter);
128 aGroupIter = myGroups.begin() + aShift;
131 if ((*aGroupIter)->updateGroup())
132 { // some constraints were removed, try to split the group
133 (*aGroupIter)->splitGroup(aSeparatedGroups);
137 if (aSeparatedGroups.size() > 0)
138 myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
143 // ============================================================================
144 // Function: changeWorkplane
145 // Class: SketchSolver_PluginManager
146 // Purpose: update workplane by given parameters of the sketch
147 // ============================================================================
148 bool SketchSolver_ConstraintManager::changeWorkplane(boost::shared_ptr<SketchPlugin_Feature> theSketch)
150 bool aResult = true; // changed when a workplane wrongly updated
151 bool isUpdated = false;
152 // Try to update specified workplane in all groups
153 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
154 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
155 if ((*aGroupIter)->isBaseWorkplane(theSketch))
158 if (!(*aGroupIter)->updateWorkplane())
161 // If the workplane is not updated, so this is a new workplane
164 SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch);
165 // Verify that the group is created successfully
166 if (!aNewGroup->isBaseWorkplane(theSketch))
171 myGroups.push_back(aNewGroup);
176 // ============================================================================
177 // Function: changeConstraint
178 // Class: SketchSolver_PluginManager
179 // Purpose: create/update the constraint and place it into appropriate group
180 // ============================================================================
181 bool SketchSolver_ConstraintManager::changeConstraint(
182 boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
184 // Search the groups which this constraint touches
185 std::set<Slvs_hGroup> aGroups;
186 findGroups(theConstraint, aGroups);
188 // Process the groups list
189 if (aGroups.size() == 0)
190 { // There are no groups applicable for this constraint => create new one
191 boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
192 if (!aWP) return false;
193 SketchSolver_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP);
194 if (!aGroup->changeConstraint(theConstraint))
199 myGroups.push_back(aGroup);
202 else if (aGroups.size() == 1)
203 { // Only one group => add constraint into it
204 Slvs_hGroup aGroupId = *(aGroups.begin());
205 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
206 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
207 if ((*aGroupIter)->getId() == aGroupId)
208 return (*aGroupIter)->changeConstraint(theConstraint);
210 else if (aGroups.size() > 1)
211 { // Several groups applicable for this constraint => need to merge them
212 std::set<Slvs_hGroup>::const_iterator aGroupsIter = aGroups.begin();
214 // Search first group
215 std::vector<SketchSolver_ConstraintGroup*>::iterator aFirstGroupIter;
216 for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
217 if ((*aFirstGroupIter)->getId() == *aGroupsIter)
219 if (aFirstGroupIter == myGroups.end())
222 // Append other groups to the first one
223 std::vector<SketchSolver_ConstraintGroup*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
224 for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++)
226 for ( ; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
227 if ((*anOtherGroupIter)->getId() == *aGroupsIter)
229 if (anOtherGroupIter == myGroups.end())
230 { // Group disappears
231 anOtherGroupIter = aFirstGroupIter + 1;
235 (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
236 int aShiftFirst = aFirstGroupIter - myGroups.begin();
237 int aShiftOther = anOtherGroupIter - myGroups.begin();
238 delete *anOtherGroupIter;
239 myGroups.erase(anOtherGroupIter);
240 aFirstGroupIter = myGroups.begin() + aShiftFirst;
241 anOtherGroupIter = myGroups.begin() + aShiftOther;
244 return (*aFirstGroupIter)->changeConstraint(theConstraint);
247 // Something goes wrong
251 // ============================================================================
252 // Function: updateEntity
253 // Class: SketchSolver_PluginManager
254 // Purpose: update any element on the sketch, which is used by constraints
255 // ============================================================================
256 void SketchSolver_ConstraintManager::updateEntity(boost::shared_ptr<SketchPlugin_Feature> theFeature)
258 // Create list of attributes depending on type of the feature
259 std::vector<std::string> anAttrList;
260 const std::string& aFeatureKind = theFeature->getKind();
262 if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0)
263 anAttrList.push_back(SketchPlugin_Point::COORD_ID());
265 else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0)
267 anAttrList.push_back(SketchPlugin_Line::START_ID());
268 anAttrList.push_back(SketchPlugin_Line::END_ID());
271 else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0)
273 anAttrList.push_back(SketchPlugin_Circle::CENTER_ID());
274 anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID());
277 else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0)
279 anAttrList.push_back(SketchPlugin_Arc::CENTER_ID());
280 anAttrList.push_back(SketchPlugin_Arc::START_ID());
281 anAttrList.push_back(SketchPlugin_Arc::END_ID());
283 /// \todo Other types of features should be implemented
285 // Check changing of feature's attributes (go through the groups and search usage of the attributes)
286 std::vector<std::string>::const_iterator anAttrIter;
287 for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++)
289 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
290 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
292 if ((*aGroupIter)->isEmpty())
294 boost::shared_ptr<ModelAPI_Attribute> anAttribute =
295 boost::dynamic_pointer_cast<ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
296 (*aGroupIter)->updateEntityIfPossible(anAttribute);
300 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
301 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
302 if (!(*aGroupIter)->isEmpty())
303 (*aGroupIter)->updateRelatedConstraints(theFeature);
307 // ============================================================================
308 // Function: findGroups
309 // Class: SketchSolver_PluginManager
310 // Purpose: search groups of entities interacting with given constraint
311 // ============================================================================
312 void SketchSolver_ConstraintManager::findGroups(
313 boost::shared_ptr<SketchPlugin_Constraint> theConstraint,
314 std::set<Slvs_hGroup>& theGroupIDs) const
316 boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
318 SketchSolver_ConstraintGroup* anEmptyGroup = 0; // appropriate empty group for specified constraint
319 std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
320 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
321 if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theConstraint))
323 if (!(*aGroupIter)->isEmpty())
324 theGroupIDs.insert((*aGroupIter)->getId());
325 else if (!anEmptyGroup)
326 anEmptyGroup = *aGroupIter;
329 // When only empty group is found, use it
330 if (anEmptyGroup && theGroupIDs.empty())
331 theGroupIDs.insert(anEmptyGroup->getId());
334 // ============================================================================
335 // Function: findWorkplaneForConstraint
336 // Class: SketchSolver_PluginManager
337 // Purpose: search workplane containing given constraint
338 // ============================================================================
339 boost::shared_ptr<SketchPlugin_Feature> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
340 boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
342 // Already verified workplanes
343 std::set< boost::shared_ptr<SketchPlugin_Feature> > aVerified;
345 std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
346 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
348 boost::shared_ptr<SketchPlugin_Feature> aWP = (*aGroupIter)->getWorkplane();
349 if (aVerified.find(aWP) != aVerified.end())
352 boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures =
353 boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aWP->data()->attribute(SketchPlugin_Sketch::FEATURES_ID()));
354 std::list< FeaturePtr > aFeaturesList = aWPFeatures->list();
355 std::list< FeaturePtr >::const_iterator anIter;
356 for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
357 if (*anIter == theConstraint)
358 return aWP; // workplane is found
359 aVerified.insert(aWP);
362 return boost::shared_ptr<SketchPlugin_Feature>();
365 // ============================================================================
366 // Function: resolveConstraints
367 // Class: SketchSolver_PluginManager
368 // Purpose: change entities according to available constraints
369 // ============================================================================
370 void SketchSolver_ConstraintManager::resolveConstraints()
372 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
373 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
374 (*aGroupIter)->resolveConstraints();
376 // Features may be updated => send events
377 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));