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_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));
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_OBJECT_CREATED) ||
63 theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED) ||
64 theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED))
66 const ModelAPI_ObjectUpdatedMessage* anUpdateMsg =
67 dynamic_cast<const ModelAPI_ObjectUpdatedMessage*>(theMessage);
68 std::set< ObjectPtr > aFeatures = anUpdateMsg->features();
71 theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
74 std::set< ObjectPtr >::iterator aFeatIter;
75 for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++)
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(SKETCH_KIND) == 0)
83 boost::shared_ptr<SketchPlugin_Feature> aSketch =
84 boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
86 changeWorkplane(aSketch);
89 boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
90 boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aFeature);
92 changeConstraint(aConstraint);
95 // Sketch plugin features can be only updated
96 boost::shared_ptr<SketchPlugin_Feature> aSFeature =
97 boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
99 updateEntity(aSFeature);
104 // Solve the set of constraints
105 resolveConstraints();
107 else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED))
109 const ModelAPI_ObjectDeletedMessage* aDeleteMsg =
110 dynamic_cast<const ModelAPI_ObjectDeletedMessage*>(theMessage);
111 const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
113 // Find SKETCH_KIND 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(SKETCH_KIND) == 0)
119 if (aFGrIter != aFeatureGroups.end())
121 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
122 std::vector<SketchSolver_ConstraintGroup*> aSeparatedGroups;
123 while (aGroupIter != myGroups.end())
125 if (!(*aGroupIter)->isWorkplaneValid())
126 { // the group should be removed
128 int aShift = aGroupIter - myGroups.begin();
129 myGroups.erase(aGroupIter);
130 aGroupIter = myGroups.begin() + aShift;
133 if ((*aGroupIter)->updateGroup())
134 { // some constraints were removed, try to split the group
135 (*aGroupIter)->splitGroup(aSeparatedGroups);
139 if (aSeparatedGroups.size() > 0)
140 myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
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)
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))
160 if (!(*aGroupIter)->updateWorkplane())
163 // If the workplane is not updated, so this is a new workplane
166 SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch);
167 // Verify that the group is created successfully
168 if (!aNewGroup->isBaseWorkplane(theSketch))
173 myGroups.push_back(aNewGroup);
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)
186 // Search the groups which this constraint touches
187 std::set<Slvs_hGroup> aGroups;
188 findGroups(theConstraint, aGroups);
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))
201 myGroups.push_back(aGroup);
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);
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();
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)
221 if (aFirstGroupIter == myGroups.end())
224 // Append other groups to the first one
225 std::vector<SketchSolver_ConstraintGroup*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
226 for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++)
228 for ( ; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
229 if ((*anOtherGroupIter)->getId() == *aGroupsIter)
231 if (anOtherGroupIter == myGroups.end())
232 { // Group disappears
233 anOtherGroupIter = aFirstGroupIter + 1;
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;
246 return (*aFirstGroupIter)->changeConstraint(theConstraint);
249 // Something goes wrong
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)
260 // Create list of attributes depending on type of the feature
261 std::vector<std::string> anAttrList;
262 const std::string& aFeatureKind = theFeature->getKind();
264 if (aFeatureKind.compare(SKETCH_POINT_KIND) == 0)
265 anAttrList.push_back(POINT_ATTR_COORD);
267 else if (aFeatureKind.compare(SKETCH_LINE_KIND) == 0)
269 anAttrList.push_back(LINE_ATTR_START);
270 anAttrList.push_back(LINE_ATTR_END);
273 else if (aFeatureKind.compare(SKETCH_CIRCLE_KIND) == 0)
275 anAttrList.push_back(CIRCLE_ATTR_CENTER);
276 anAttrList.push_back(CIRCLE_ATTR_RADIUS);
279 else if (aFeatureKind.compare(SKETCH_ARC_KIND) == 0)
281 anAttrList.push_back(ARC_ATTR_CENTER);
282 anAttrList.push_back(ARC_ATTR_START);
283 anAttrList.push_back(ARC_ATTR_END);
285 /// \todo Other types of features should be implemented
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++)
291 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
292 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
294 if ((*aGroupIter)->isEmpty())
296 boost::shared_ptr<ModelAPI_Attribute> anAttribute =
297 boost::dynamic_pointer_cast<ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
298 (*aGroupIter)->updateEntityIfPossible(anAttribute);
302 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
303 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
304 if (!(*aGroupIter)->isEmpty())
305 (*aGroupIter)->updateRelatedConstraints(theFeature);
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
318 boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
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))
325 if (!(*aGroupIter)->isEmpty())
326 theGroupIDs.insert((*aGroupIter)->getId());
327 else if (!anEmptyGroup)
328 anEmptyGroup = *aGroupIter;
331 // When only empty group is found, use it
332 if (anEmptyGroup && theGroupIDs.empty())
333 theGroupIDs.insert(anEmptyGroup->getId());
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
344 // Already verified workplanes
345 std::set< boost::shared_ptr<SketchPlugin_Feature> > aVerified;
347 std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
348 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
350 boost::shared_ptr<SketchPlugin_Feature> aWP = (*aGroupIter)->getWorkplane();
351 if (aVerified.find(aWP) != aVerified.end())
354 boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures =
355 boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aWP->data()->attribute(SKETCH_ATTR_FEATURES));
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);
364 return boost::shared_ptr<SketchPlugin_Feature>();
367 // ============================================================================
368 // Function: resolveConstraints
369 // Class: SketchSolver_PluginManager
370 // Purpose: change entities according to available constraints
371 // ============================================================================
372 void SketchSolver_ConstraintManager::resolveConstraints()
374 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
375 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
376 (*aGroupIter)->resolveConstraints();
378 // Features may be updated => send events
379 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));