1 // File: SketchSolver_ConstraintManager.cpp
2 // Created: 08 May 2014
3 // Author: Artem ZHIDKOV
5 #include "SketchSolver_ConstraintManager.h"
6 #include <SketchSolver_ConstraintGroup.h>
8 #include <Events_Loop.h>
9 #include <ModelAPI_AttributeDouble.h>
10 #include <ModelAPI_AttributeRefList.h>
11 #include <ModelAPI_Data.h>
12 #include <ModelAPI_Events.h>
13 #include <ModelAPI_Object.h>
14 #include <ModelAPI_ResultConstruction.h>
15 #include <ModelAPI_Attribute.h>
17 #include <SketchPlugin_Constraint.h>
19 #include <SketchPlugin_Arc.h>
20 #include <SketchPlugin_Circle.h>
21 #include <SketchPlugin_Line.h>
22 #include <SketchPlugin_Point.h>
23 #include <SketchPlugin_Sketch.h>
24 #include <SketchPlugin_Feature.h>
30 // Initialization of constraint manager self pointer
31 SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
33 /// Global constraint manager object
34 SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance();
36 // ========================================================
37 // ========= SketchSolver_ConstraintManager ===============
38 // ========================================================
39 SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance()
42 _self = new SketchSolver_ConstraintManager();
46 SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
51 // Register in event loop
52 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
53 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
54 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
55 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
58 SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
63 // ============================================================================
64 // Function: processEvent
65 // Class: SketchSolver_Session
66 // Purpose: listen the event loop and process the message
67 // ============================================================================
68 void SketchSolver_ConstraintManager::processEvent(
69 const std::shared_ptr<Events_Message>& theMessage)
73 if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
74 || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)
75 || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
76 std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
77 std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
78 std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
80 bool isMovedEvt = theMessage->eventID()
81 == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
83 std::set<ObjectPtr>::iterator aFeatIter;
84 for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
85 std::shared_ptr<SketchPlugin_Feature> aSFeature =
86 std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
88 updateEntity(aSFeature);
91 std::set<ObjectPtr>::iterator aFeatIter;
92 // iterate sketchers fisrt to create all sketches before (on load may exist several sketches)
93 for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
94 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*aFeatIter);
97 const std::string& aFeatureKind = aFeature->getKind();
98 if (aFeatureKind.compare(SketchPlugin_Sketch::ID()) == 0) {
99 std::shared_ptr<ModelAPI_CompositeFeature> aSketch = std::dynamic_pointer_cast<
100 ModelAPI_CompositeFeature>(aFeature);
101 changeWorkplane(aSketch);
104 // then get anything but not the sketch
105 for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
106 std::shared_ptr<SketchPlugin_Feature> aFeature =
107 std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
110 changeConstraintOrEntity(aFeature);
114 // Solve the set of constraints
115 resolveConstraints();
116 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
117 std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
118 std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
119 const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
121 // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch
122 std::set<std::string>::const_iterator aFGrIter;
123 for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
124 if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 ||
125 aFGrIter->compare(ModelAPI_Feature::group()) == 0)
128 if (aFGrIter != aFeatureGroups.end()) {
129 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
130 std::vector<SketchSolver_ConstraintGroup*> aSeparatedGroups;
131 while (aGroupIter != myGroups.end()) {
132 if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed
134 int aShift = aGroupIter - myGroups.begin();
135 myGroups.erase(aGroupIter);
136 aGroupIter = myGroups.begin() + aShift;
139 if ((*aGroupIter)->updateGroup()) { // some constraints were removed, try to split the group
140 (*aGroupIter)->splitGroup(aSeparatedGroups);
144 if (aSeparatedGroups.size() > 0)
145 myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
150 // ============================================================================
151 // Function: changeWorkplane
152 // Class: SketchSolver_Session
153 // Purpose: update workplane by given parameters of the sketch
154 // ============================================================================
155 bool SketchSolver_ConstraintManager::changeWorkplane(
156 std::shared_ptr<ModelAPI_CompositeFeature> theSketch)
158 bool aResult = true; // changed when a workplane wrongly updated
159 bool isUpdated = false;
160 // Try to update specified workplane in all groups
161 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
162 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
163 if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
165 if (!(*aGroupIter)->updateWorkplane())
168 // If the workplane is not updated, so this is a new workplane
170 SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch);
171 // Verify that the group is created successfully
172 if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) {
176 myGroups.push_back(aNewGroup);
181 // ============================================================================
182 // Function: changeConstraintOrEntity
183 // Class: SketchSolver_Session
184 // Purpose: create/update the constraint or the feature and place it into appropriate group
185 // ============================================================================
186 bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
187 std::shared_ptr<SketchPlugin_Feature> theFeature)
189 // Search the groups which this feature touches
190 std::set<Slvs_hGroup> aGroups;
191 findGroups(theFeature, aGroups);
193 std::shared_ptr<SketchPlugin_Constraint> aConstraint =
194 std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
196 // Process the groups list
197 if (aGroups.size() == 0) {
198 // There are no groups applicable for this constraint => create new one
199 // The group will be created only for constraints, not for features
200 if (!aConstraint) return false;
201 std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(aConstraint);
204 SketchSolver_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP);
205 if (!aGroup->changeConstraint(aConstraint)) {
209 myGroups.push_back(aGroup);
211 } else if (aGroups.size() == 1) { // Only one group => add feature into it
212 Slvs_hGroup aGroupId = *(aGroups.begin());
213 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
214 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
215 if ((*aGroupIter)->getId() == aGroupId) {
216 // If the group is empty, the feature is not added (the constraint only)
217 if (!aConstraint && !(*aGroupIter)->isEmpty())
218 return (*aGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
219 return (*aGroupIter)->changeConstraint(aConstraint);
221 } else if (aGroups.size() > 1) { // Several groups applicable for this feature => need to merge them
222 std::set<Slvs_hGroup>::const_iterator aGroupsIter = aGroups.begin();
224 // Search first group
225 std::vector<SketchSolver_ConstraintGroup*>::iterator aFirstGroupIter;
226 for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
227 if ((*aFirstGroupIter)->getId() == *aGroupsIter)
229 if (aFirstGroupIter == myGroups.end())
232 // Append other groups to the first one
233 std::vector<SketchSolver_ConstraintGroup*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
234 for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
235 for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
236 if ((*anOtherGroupIter)->getId() == *aGroupsIter)
238 if (anOtherGroupIter == myGroups.end()) { // Group disappears
239 anOtherGroupIter = aFirstGroupIter + 1;
243 (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
244 int aShiftFirst = aFirstGroupIter - myGroups.begin();
245 int aShiftOther = anOtherGroupIter - myGroups.begin();
246 delete *anOtherGroupIter;
247 myGroups.erase(anOtherGroupIter);
248 aFirstGroupIter = myGroups.begin() + aShiftFirst;
249 anOtherGroupIter = myGroups.begin() + aShiftOther;
253 return (*aFirstGroupIter)->changeConstraint(aConstraint);
254 return (*aFirstGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
257 // Something goes wrong
261 // ============================================================================
262 // Function: updateEntity
263 // Class: SketchSolver_Session
264 // Purpose: update any element on the sketch, which is used by constraints
265 // ============================================================================
266 void SketchSolver_ConstraintManager::updateEntity(
267 std::shared_ptr<SketchPlugin_Feature> theFeature)
269 // Create list of attributes depending on type of the feature
270 std::vector<std::string> anAttrList;
271 const std::string& aFeatureKind = theFeature->getKind();
273 if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0)
274 anAttrList.push_back(SketchPlugin_Point::COORD_ID());
276 else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
277 anAttrList.push_back(SketchPlugin_Line::START_ID());
278 anAttrList.push_back(SketchPlugin_Line::END_ID());
281 else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
282 anAttrList.push_back(SketchPlugin_Circle::CENTER_ID());
283 anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID());
286 else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
287 anAttrList.push_back(SketchPlugin_Arc::CENTER_ID());
288 anAttrList.push_back(SketchPlugin_Arc::START_ID());
289 anAttrList.push_back(SketchPlugin_Arc::END_ID());
291 /// \todo Other types of features should be implemented
293 // Check changing of feature's attributes (go through the groups and search usage of the attributes)
294 std::vector<std::string>::const_iterator anAttrIter;
295 for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++) {
296 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
297 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
298 if ((*aGroupIter)->isEmpty())
300 std::shared_ptr<ModelAPI_Attribute> anAttribute = std::dynamic_pointer_cast<
301 ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
302 (*aGroupIter)->updateEntityIfPossible(anAttribute);
306 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
307 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
308 if (!(*aGroupIter)->isEmpty())
309 (*aGroupIter)->updateRelatedConstraintsFeature(theFeature);
312 // ============================================================================
313 // Function: findGroups
314 // Class: SketchSolver_Session
315 // Purpose: search groups of entities interacting with given feature
316 // ============================================================================
317 void SketchSolver_ConstraintManager::findGroups(
318 std::shared_ptr<SketchPlugin_Feature> theFeature,
319 std::set<Slvs_hGroup>& theGroupIDs) const
321 std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(theFeature);
323 SketchSolver_ConstraintGroup* anEmptyGroup = 0; // appropriate empty group for specified constraint
324 std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
325 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
326 if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) {
327 if (!(*aGroupIter)->isEmpty())
328 theGroupIDs.insert((*aGroupIter)->getId());
329 else if (!anEmptyGroup)
330 anEmptyGroup = *aGroupIter;
333 // When only empty group is found, use it
334 if (anEmptyGroup && theGroupIDs.empty())
335 theGroupIDs.insert(anEmptyGroup->getId());
338 // ============================================================================
339 // Function: findWorkplane
340 // Class: SketchSolver_Session
341 // Purpose: search workplane containing given feature
342 // ============================================================================
343 std::shared_ptr<ModelAPI_CompositeFeature> SketchSolver_ConstraintManager
344 ::findWorkplane(std::shared_ptr<SketchPlugin_Feature> theFeature) const
346 // Already verified workplanes
347 std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
349 std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
350 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
351 std::shared_ptr<ModelAPI_CompositeFeature> aWP = (*aGroupIter)->getWorkplane();
352 if (aVerified.find(aWP) != aVerified.end())
355 std::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures = std::dynamic_pointer_cast<
356 ModelAPI_AttributeRefList>(aWP->data()->attribute(SketchPlugin_Sketch::FEATURES_ID()));
357 std::list<ObjectPtr> aFeaturesList = aWPFeatures->list();
358 std::list<ObjectPtr>::const_iterator anIter;
359 for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
360 if (*anIter == theFeature)
361 return aWP; // workplane is found
362 aVerified.insert(aWP);
365 return std::shared_ptr<ModelAPI_CompositeFeature>();
368 // ============================================================================
369 // Function: resolveConstraints
370 // Class: SketchSolver_Session
371 // Purpose: change entities according to available constraints
372 // ============================================================================
373 void SketchSolver_ConstraintManager::resolveConstraints()
376 bool needToUpdate = false;
377 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
378 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
379 if ((*aGroupIter)->resolveConstraints())
382 // Features may be updated => send events
384 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
385 myIsComputed = false;