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>
12 #include <ModelAPI_Object.h>
13 #include <ModelAPI_ResultConstruction.h>
15 #include <SketchPlugin_Constraint.h>
17 #include <SketchPlugin_Arc.h>
18 #include <SketchPlugin_Circle.h>
19 #include <SketchPlugin_Line.h>
20 #include <SketchPlugin_Point.h>
21 #include <SketchPlugin_Sketch.h>
25 // Initialization of constraint manager self pointer
26 SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
28 /// Global constraint manager object
29 SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance();
31 // ========================================================
32 // ========= SketchSolver_ConstraintManager ===============
33 // ========================================================
34 SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance()
37 _self = new SketchSolver_ConstraintManager();
41 SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
45 // Register in event loop
46 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
47 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
48 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
49 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
52 SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
57 // ============================================================================
58 // Function: processEvent
59 // Class: SketchSolver_PluginManager
60 // Purpose: listen the event loop and process the message
61 // ============================================================================
62 void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessage)
64 if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
65 || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)
66 || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
67 const ModelAPI_ObjectUpdatedMessage* anUpdateMsg =
68 dynamic_cast<const ModelAPI_ObjectUpdatedMessage*>(theMessage);
69 std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
71 bool isModifiedEvt = theMessage->eventID()
72 == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
74 std::set<ObjectPtr>::iterator aFeatIter;
75 for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
76 FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFeatIter);
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 boost::shared_ptr<SketchPlugin_Feature> aSketch = boost::dynamic_pointer_cast<
83 SketchPlugin_Feature>(aFeature);
85 changeWorkplane(aSketch);
88 boost::shared_ptr<SketchPlugin_Constraint> aConstraint = boost::dynamic_pointer_cast<
89 SketchPlugin_Constraint>(aFeature);
91 changeConstraint(aConstraint);
93 // Sketch plugin features can be only updated
94 boost::shared_ptr<SketchPlugin_Feature> aSFeature = boost::dynamic_pointer_cast<
95 SketchPlugin_Feature>(aFeature);
97 updateEntity(aSFeature);
102 // Solve the set of constraints
103 resolveConstraints();
104 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
105 const ModelAPI_ObjectDeletedMessage* aDeleteMsg =
106 dynamic_cast<const ModelAPI_ObjectDeletedMessage*>(theMessage);
107 const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
109 // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch
110 std::set<std::string>::const_iterator aFGrIter;
111 for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
112 if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0)
115 if (aFGrIter != aFeatureGroups.end()) {
116 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
117 std::vector<SketchSolver_ConstraintGroup*> aSeparatedGroups;
118 while (aGroupIter != myGroups.end()) {
119 if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed
121 int aShift = aGroupIter - myGroups.begin();
122 myGroups.erase(aGroupIter);
123 aGroupIter = myGroups.begin() + aShift;
126 if ((*aGroupIter)->updateGroup()) { // some constraints were removed, try to split the group
127 (*aGroupIter)->splitGroup(aSeparatedGroups);
131 if (aSeparatedGroups.size() > 0)
132 myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
137 // ============================================================================
138 // Function: changeWorkplane
139 // Class: SketchSolver_PluginManager
140 // Purpose: update workplane by given parameters of the sketch
141 // ============================================================================
142 bool SketchSolver_ConstraintManager::changeWorkplane(
143 boost::shared_ptr<SketchPlugin_Feature> theSketch)
145 bool aResult = true; // changed when a workplane wrongly updated
146 bool isUpdated = false;
147 // Try to update specified workplane in all groups
148 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
149 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
150 if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
152 if (!(*aGroupIter)->updateWorkplane())
155 // If the workplane is not updated, so this is a new workplane
157 SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch);
158 // Verify that the group is created successfully
159 if (!aNewGroup->isBaseWorkplane(theSketch)) {
163 myGroups.push_back(aNewGroup);
168 // ============================================================================
169 // Function: changeConstraint
170 // Class: SketchSolver_PluginManager
171 // Purpose: create/update the constraint and place it into appropriate group
172 // ============================================================================
173 bool SketchSolver_ConstraintManager::changeConstraint(
174 boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
176 // Search the groups which this constraint touches
177 std::set<Slvs_hGroup> aGroups;
178 findGroups(theConstraint, aGroups);
180 // Process the groups list
181 if (aGroups.size() == 0) { // There are no groups applicable for this constraint => create new one
182 boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
185 SketchSolver_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP);
186 if (!aGroup->changeConstraint(theConstraint)) {
190 myGroups.push_back(aGroup);
192 } else if (aGroups.size() == 1) { // Only one group => add constraint into it
193 Slvs_hGroup aGroupId = *(aGroups.begin());
194 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
195 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
196 if ((*aGroupIter)->getId() == aGroupId)
197 return (*aGroupIter)->changeConstraint(theConstraint);
198 } else if (aGroups.size() > 1) { // Several groups applicable for this constraint => need to merge them
199 std::set<Slvs_hGroup>::const_iterator aGroupsIter = aGroups.begin();
201 // Search first group
202 std::vector<SketchSolver_ConstraintGroup*>::iterator aFirstGroupIter;
203 for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
204 if ((*aFirstGroupIter)->getId() == *aGroupsIter)
206 if (aFirstGroupIter == myGroups.end())
209 // Append other groups to the first one
210 std::vector<SketchSolver_ConstraintGroup*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
211 for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
212 for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
213 if ((*anOtherGroupIter)->getId() == *aGroupsIter)
215 if (anOtherGroupIter == myGroups.end()) { // Group disappears
216 anOtherGroupIter = aFirstGroupIter + 1;
220 (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
221 int aShiftFirst = aFirstGroupIter - myGroups.begin();
222 int aShiftOther = anOtherGroupIter - myGroups.begin();
223 delete *anOtherGroupIter;
224 myGroups.erase(anOtherGroupIter);
225 aFirstGroupIter = myGroups.begin() + aShiftFirst;
226 anOtherGroupIter = myGroups.begin() + aShiftOther;
229 return (*aFirstGroupIter)->changeConstraint(theConstraint);
232 // Something goes wrong
236 // ============================================================================
237 // Function: updateEntity
238 // Class: SketchSolver_PluginManager
239 // Purpose: update any element on the sketch, which is used by constraints
240 // ============================================================================
241 void SketchSolver_ConstraintManager::updateEntity(
242 boost::shared_ptr<SketchPlugin_Feature> theFeature)
244 // Create list of attributes depending on type of the feature
245 std::vector<std::string> anAttrList;
246 const std::string& aFeatureKind = theFeature->getKind();
248 if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0)
249 anAttrList.push_back(SketchPlugin_Point::COORD_ID());
251 else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
252 anAttrList.push_back(SketchPlugin_Line::START_ID());
253 anAttrList.push_back(SketchPlugin_Line::END_ID());
256 else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
257 anAttrList.push_back(SketchPlugin_Circle::CENTER_ID());
258 anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID());
261 else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
262 anAttrList.push_back(SketchPlugin_Arc::CENTER_ID());
263 anAttrList.push_back(SketchPlugin_Arc::START_ID());
264 anAttrList.push_back(SketchPlugin_Arc::END_ID());
266 /// \todo Other types of features should be implemented
268 // Check changing of feature's attributes (go through the groups and search usage of the attributes)
269 std::vector<std::string>::const_iterator anAttrIter;
270 for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++) {
271 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
272 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
273 if ((*aGroupIter)->isEmpty())
275 boost::shared_ptr<ModelAPI_Attribute> anAttribute = boost::dynamic_pointer_cast<
276 ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
277 (*aGroupIter)->updateEntityIfPossible(anAttribute);
281 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
282 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
283 if (!(*aGroupIter)->isEmpty())
284 (*aGroupIter)->updateRelatedConstraints(theFeature);
287 // ============================================================================
288 // Function: findGroups
289 // Class: SketchSolver_PluginManager
290 // Purpose: search groups of entities interacting with given constraint
291 // ============================================================================
292 void SketchSolver_ConstraintManager::findGroups(
293 boost::shared_ptr<SketchPlugin_Constraint> theConstraint,
294 std::set<Slvs_hGroup>& theGroupIDs) const
296 boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
298 SketchSolver_ConstraintGroup* anEmptyGroup = 0; // appropriate empty group for specified constraint
299 std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
300 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
301 if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theConstraint)) {
302 if (!(*aGroupIter)->isEmpty())
303 theGroupIDs.insert((*aGroupIter)->getId());
304 else if (!anEmptyGroup)
305 anEmptyGroup = *aGroupIter;
308 // When only empty group is found, use it
309 if (anEmptyGroup && theGroupIDs.empty())
310 theGroupIDs.insert(anEmptyGroup->getId());
313 // ============================================================================
314 // Function: findWorkplaneForConstraint
315 // Class: SketchSolver_PluginManager
316 // Purpose: search workplane containing given constraint
317 // ============================================================================
318 boost::shared_ptr<SketchPlugin_Feature> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
319 boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
321 // Already verified workplanes
322 std::set<boost::shared_ptr<SketchPlugin_Feature> > aVerified;
324 std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
325 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
326 boost::shared_ptr<SketchPlugin_Feature> aWP = (*aGroupIter)->getWorkplane();
327 if (aVerified.find(aWP) != aVerified.end())
330 boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures = boost::dynamic_pointer_cast<
331 ModelAPI_AttributeRefList>(aWP->data()->attribute(SketchPlugin_Sketch::FEATURES_ID()));
332 std::list<ObjectPtr> aFeaturesList = aWPFeatures->list();
333 std::list<ObjectPtr>::const_iterator anIter;
334 for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
335 if (*anIter == theConstraint)
336 return aWP; // workplane is found
337 aVerified.insert(aWP);
340 return boost::shared_ptr<SketchPlugin_Feature>();
343 // ============================================================================
344 // Function: resolveConstraints
345 // Class: SketchSolver_PluginManager
346 // Purpose: change entities according to available constraints
347 // ============================================================================
348 void SketchSolver_ConstraintManager::resolveConstraints()
350 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
351 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
352 (*aGroupIter)->resolveConstraints();
354 // Features may be updated => send events
355 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));