1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: SketchSolver_Manager.cpp
4 // Created: 08 May 2014
5 // Author: Artem ZHIDKOV
7 #include "SketchSolver_Manager.h"
9 #include <Events_Loop.h>
10 #include <ModelAPI_AttributeDouble.h>
11 #include <ModelAPI_AttributeRefList.h>
12 #include <ModelAPI_Data.h>
13 #include <ModelAPI_Events.h>
14 #include <ModelAPI_Object.h>
15 #include <ModelAPI_ResultConstruction.h>
16 #include <ModelAPI_Attribute.h>
18 #include <SketchPlugin_Constraint.h>
20 #include <SketchPlugin_Arc.h>
21 #include <SketchPlugin_Circle.h>
22 #include <SketchPlugin_Line.h>
23 #include <SketchPlugin_Point.h>
24 #include <SketchPlugin_Sketch.h>
25 #include <SketchPlugin_Feature.h>
31 static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
33 // Initialization of constraint manager self pointer
34 SketchSolver_Manager* SketchSolver_Manager::mySelf = 0;
36 /// Global constraint manager object
37 SketchSolver_Manager* myManager = SketchSolver_Manager::instance();
40 // ========================================================
41 // ========= SketchSolver_Manager ===============
42 // ========================================================
43 SketchSolver_Manager* SketchSolver_Manager::instance()
46 mySelf = new SketchSolver_Manager();
50 SketchSolver_Manager::SketchSolver_Manager()
55 // Register in event loop
56 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
57 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
58 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
59 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
62 SketchSolver_Manager::~SketchSolver_Manager()
67 void SketchSolver_Manager::setBuilder(BuilderPtr theBuilder)
69 myBuilder = theBuilder;
72 BuilderPtr SketchSolver_Manager::builder()
77 // ============================================================================
78 // Function: processEvent
79 // Purpose: listen the event loop and process the message
80 // ============================================================================
81 void SketchSolver_Manager::processEvent(
82 const std::shared_ptr<Events_Message>& theMessage)
87 if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
88 || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)
89 || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
90 std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
91 std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
92 std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
94 bool isUpdateFlushed = stopSendUpdate();
95 // Shows the message has at least one feature applicable for solver
96 bool hasProperFeature = false;
98 bool isMovedEvt = theMessage->eventID()
99 == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
101 std::set<ObjectPtr>::iterator aFeatIter;
102 for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
103 std::shared_ptr<SketchPlugin_Feature> aSFeature =
104 std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
106 moveEntity(aSFeature);
107 hasProperFeature = true;
111 std::list<FeaturePtr> aSketchFeatures = SketchSolver_Group::selectApplicableFeatures(aFeatures);
112 std::list<FeaturePtr>::iterator aFeatIter = aSketchFeatures.begin();
113 for (; aFeatIter != aSketchFeatures.end(); ++aFeatIter) {
114 if ((*aFeatIter)->getKind() == SketchPlugin_Sketch::ID()) {
115 std::shared_ptr<ModelAPI_CompositeFeature> aSketch =
116 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFeatIter);
117 hasProperFeature = changeWorkplane(aSketch) || hasProperFeature;
120 std::shared_ptr<SketchPlugin_Feature> aFeature =
121 std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
124 hasProperFeature = changeFeature(aFeature) || hasProperFeature;
128 bool needToUpdate = false;
129 // Solve the set of constraints
130 if (hasProperFeature)
131 needToUpdate = resolveConstraints();
133 // Features may be updated => now send events, but for all changed at once
136 // send update for movement in any case
137 if (needToUpdate || isMovedEvt)
138 Events_Loop::loop()->flush(anUpdateEvent);
140 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
141 std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
142 std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
143 const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
145 // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch
146 std::set<std::string>::const_iterator aFGrIter;
147 for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
148 if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 ||
149 aFGrIter->compare(ModelAPI_Feature::group()) == 0)
152 if (aFGrIter != aFeatureGroups.end()) {
153 std::vector<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
154 std::list<SketchSolver_Group*> aSeparatedGroups;
155 while (aGroupIter != myGroups.end()) {
156 if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed
158 int aShift = aGroupIter - myGroups.begin();
159 myGroups.erase(aGroupIter);
160 aGroupIter = myGroups.begin() + aShift;
163 if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group
164 (*aGroupIter)->splitGroup(aSeparatedGroups);
168 if (aSeparatedGroups.size() > 0)
169 myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
172 myIsComputed = false;
175 // ============================================================================
176 // Function: changeWorkplane
177 // Purpose: update workplane by given parameters of the sketch
178 // ============================================================================
179 bool SketchSolver_Manager::changeWorkplane(CompositeFeaturePtr theSketch)
181 bool aResult = true; // changed when a workplane wrongly updated
182 bool isUpdated = false;
183 // Try to update specified workplane in all groups
184 std::vector<SketchSolver_Group*>::iterator aGroupIter;
185 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
186 if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
190 // If the workplane is not updated, so this is a new workplane
192 SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch);
193 // Verify that the group is created successfully
194 if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) {
198 myGroups.push_back(aNewGroup);
203 // ============================================================================
204 // Function: changeConstraintOrEntity
205 // Purpose: create/update the constraint or the feature and place it into appropriate group
206 // ============================================================================
207 bool SketchSolver_Manager::changeFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
209 // Search the groups which this feature touches
210 std::set<GroupID> aGroups;
211 findGroups(theFeature, aGroups);
213 std::shared_ptr<SketchPlugin_Constraint> aConstraint =
214 std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
216 // Process the groups list
217 if (aGroups.size() == 0) {
218 // There are no groups applicable for this constraint => create new one
219 // The group will be created only for constraints, not for features
220 if (!aConstraint) return false;
221 std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(aConstraint);
224 SketchSolver_Group* aGroup = new SketchSolver_Group(aWP);
225 if (!aGroup->changeConstraint(aConstraint)) {
229 myGroups.push_back(aGroup);
231 } else if (aGroups.size() == 1) { // Only one group => add feature into it
232 GroupID aGroupId = *(aGroups.begin());
233 std::vector<SketchSolver_Group*>::iterator aGroupIter;
234 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
235 if ((*aGroupIter)->getId() == aGroupId) {
236 // If the group is empty, the feature is not added (the constraint only)
237 if (!aConstraint && !(*aGroupIter)->isEmpty())
238 return (*aGroupIter)->updateFeature(theFeature);
239 return (*aGroupIter)->changeConstraint(aConstraint);
241 } else if (aGroups.size() > 1) { // Several groups applicable for this feature => need to merge them
242 std::set<GroupID>::const_iterator aGroupsIter = aGroups.begin();
244 // Search first group
245 std::vector<SketchSolver_Group*>::iterator aFirstGroupIter;
246 for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
247 if ((*aFirstGroupIter)->getId() == *aGroupsIter)
249 if (aFirstGroupIter == myGroups.end())
252 // Append other groups to the first one
253 std::vector<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
254 for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
255 for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
256 if ((*anOtherGroupIter)->getId() == *aGroupsIter)
258 if (anOtherGroupIter == myGroups.end()) { // Group disappears
259 anOtherGroupIter = aFirstGroupIter + 1;
263 (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
264 int aShiftFirst = aFirstGroupIter - myGroups.begin();
265 int aShiftOther = anOtherGroupIter - myGroups.begin();
266 delete *anOtherGroupIter;
267 myGroups.erase(anOtherGroupIter);
268 aFirstGroupIter = myGroups.begin() + aShiftFirst;
269 anOtherGroupIter = myGroups.begin() + aShiftOther;
273 (*aFirstGroupIter)->changeConstraint(aConstraint);
275 (*aFirstGroupIter)->updateFeature(theFeature);
276 // groups are merged => need to resolve them
280 // Something goes wrong
284 // ============================================================================
285 // Function: moveEntity
286 // Purpose: update element moved on the sketch, which is used by constraints
287 // ============================================================================
288 void SketchSolver_Manager::moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature)
290 std::vector<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
291 for (; aGroupIt != myGroups.end(); aGroupIt++)
292 if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature))
293 (*aGroupIt)->moveFeature(theFeature);
296 // ============================================================================
297 // Function: findGroups
298 // Purpose: search groups of entities interacting with given feature
299 // ============================================================================
300 void SketchSolver_Manager::findGroups(
301 std::shared_ptr<SketchPlugin_Feature> theFeature,
302 std::set<GroupID>& theGroupIDs) const
304 std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(theFeature);
306 SketchSolver_Group* anEmptyGroup = 0; // appropriate empty group for specified constraint
307 std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
308 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
309 if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) {
310 if (!(*aGroupIter)->isEmpty())
311 theGroupIDs.insert((*aGroupIter)->getId());
312 else if (!anEmptyGroup)
313 anEmptyGroup = *aGroupIter;
316 // When only empty group is found, use it
317 if (anEmptyGroup && theGroupIDs.empty())
318 theGroupIDs.insert(anEmptyGroup->getId());
321 // ============================================================================
322 // Function: findWorkplane
323 // Purpose: search workplane containing given feature
324 // ============================================================================
325 std::shared_ptr<ModelAPI_CompositeFeature> SketchSolver_Manager
326 ::findWorkplane(std::shared_ptr<SketchPlugin_Feature> theFeature) const
328 // Already verified workplanes
329 std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
331 std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
332 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
333 std::shared_ptr<ModelAPI_CompositeFeature> aWP = (*aGroupIter)->getWorkplane();
334 if (aVerified.find(aWP) != aVerified.end())
337 DataPtr aData = aWP->data();
338 if (aData->isValid()) {
339 std::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures = std::dynamic_pointer_cast<
340 ModelAPI_AttributeRefList>(aData->attribute(SketchPlugin_Sketch::FEATURES_ID()));
341 std::list<ObjectPtr> aFeaturesList = aWPFeatures->list();
342 std::list<ObjectPtr>::const_iterator anIter;
343 for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
344 if (*anIter == theFeature)
345 return aWP; // workplane is found
347 aVerified.insert(aWP);
350 return std::shared_ptr<ModelAPI_CompositeFeature>();
353 // ============================================================================
354 // Function: resolveConstraints
355 // Purpose: change entities according to available constraints
356 // ============================================================================
357 bool SketchSolver_Manager::resolveConstraints()
359 bool needToUpdate = false;
360 std::vector<SketchSolver_Group*>::iterator aGroupIter;
361 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
362 if ((*aGroupIter)->resolveConstraints())
367 bool SketchSolver_Manager::stopSendUpdate() const
369 // to avoid redisplay of each segment on update by solver one by one in the viewer
370 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
371 if (isUpdateFlushed) {
372 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
374 return isUpdateFlushed;
377 void SketchSolver_Manager::allowSendUpdate() const
379 Events_Loop::loop()->setFlushed(anUpdateEvent, true);