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"
8 #include "SketchSolver_Error.h"
10 #include <Events_Loop.h>
11 #include <ModelAPI_AttributeDouble.h>
12 #include <ModelAPI_AttributeRefList.h>
13 #include <ModelAPI_Data.h>
14 #include <ModelAPI_Events.h>
15 #include <ModelAPI_Object.h>
16 #include <ModelAPI_ResultConstruction.h>
17 #include <ModelAPI_Attribute.h>
18 #include <ModelAPI_AttributeInteger.h>
19 #include <ModelAPI_AttributeString.h>
21 #include <SketchPlugin_Constraint.h>
22 #include <SketchPlugin_ConstraintAngle.h>
23 #include <SketchPlugin_ConstraintCoincidence.h>
24 #include <SketchPlugin_ConstraintCollinear.h>
25 #include <SketchPlugin_ConstraintDistance.h>
26 #include <SketchPlugin_ConstraintEqual.h>
27 #include <SketchPlugin_ConstraintHorizontal.h>
28 #include <SketchPlugin_ConstraintLength.h>
29 #include <SketchPlugin_ConstraintMiddle.h>
30 #include <SketchPlugin_ConstraintMirror.h>
31 #include <SketchPlugin_ConstraintParallel.h>
32 #include <SketchPlugin_ConstraintPerpendicular.h>
33 #include <SketchPlugin_ConstraintRadius.h>
34 #include <SketchPlugin_ConstraintRigid.h>
35 #include <SketchPlugin_ConstraintTangent.h>
36 #include <SketchPlugin_ConstraintVertical.h>
37 #include <SketchPlugin_MultiRotation.h>
38 #include <SketchPlugin_MultiTranslation.h>
40 #include <SketchPlugin_Arc.h>
41 #include <SketchPlugin_Circle.h>
42 #include <SketchPlugin_Line.h>
43 #include <SketchPlugin_Point.h>
44 #include <SketchPlugin_Sketch.h>
45 #include <SketchPlugin_Feature.h>
53 static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
55 // Initialization of constraint manager self pointer
56 SketchSolver_Manager* SketchSolver_Manager::mySelf = 0;
58 /// Global constraint manager object
59 SketchSolver_Manager* myManager = SketchSolver_Manager::instance();
62 // ========================================================
63 // ========= SketchSolver_Manager ===============
64 // ========================================================
65 SketchSolver_Manager* SketchSolver_Manager::instance()
68 mySelf = new SketchSolver_Manager();
72 SketchSolver_Manager::SketchSolver_Manager()
77 // Register in event loop
78 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
79 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
80 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
81 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
83 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_FAILED));
84 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_REPAIRED));
87 SketchSolver_Manager::~SketchSolver_Manager()
92 void SketchSolver_Manager::setBuilder(BuilderPtr theBuilder)
94 myBuilder = theBuilder;
97 BuilderPtr SketchSolver_Manager::builder()
102 // ============================================================================
103 // Function: processEvent
104 // Purpose: listen the event loop and process the message
105 // ============================================================================
106 void SketchSolver_Manager::processEvent(
107 const std::shared_ptr<Events_Message>& theMessage)
109 checkConflictingConstraints(theMessage);
114 // Shows that the message has at least one feature applicable for solver
115 bool hasProperFeature = false;
117 if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
118 || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)
119 || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
120 std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
121 std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
122 std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
124 bool isUpdateFlushed = stopSendUpdate();
126 bool isMovedEvt = theMessage->eventID()
127 == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
129 std::set<ObjectPtr>::iterator aFeatIter;
130 for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
131 std::shared_ptr<SketchPlugin_Feature> aSFeature =
132 std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
134 moveEntity(aSFeature);
135 hasProperFeature = true;
139 std::list<FeaturePtr> aSketchFeatures = SketchSolver_Group::selectApplicableFeatures(aFeatures);
140 std::list<FeaturePtr>::iterator aFeatIter = aSketchFeatures.begin();
141 for (; aFeatIter != aSketchFeatures.end(); ++aFeatIter) {
142 if ((*aFeatIter)->getKind() == SketchPlugin_Sketch::ID()) {
143 std::shared_ptr<ModelAPI_CompositeFeature> aSketch =
144 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFeatIter);
145 hasProperFeature = changeWorkplane(aSketch) || hasProperFeature;
148 std::shared_ptr<SketchPlugin_Feature> aFeature =
149 std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
152 hasProperFeature = changeFeature(aFeature) || hasProperFeature;
156 bool needToUpdate = false;
157 // Solve the set of constraints
158 if (hasProperFeature)
159 needToUpdate = resolveConstraints();
161 // Features may be updated => now send events, but for all changed at once
164 // send update for movement in any case
165 if (needToUpdate || isMovedEvt)
166 Events_Loop::loop()->flush(anUpdateEvent);
168 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
169 std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
170 std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
171 const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
173 // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch
174 std::set<std::string>::const_iterator aFGrIter;
175 for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
176 if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 ||
177 aFGrIter->compare(ModelAPI_Feature::group()) == 0)
180 if (aFGrIter != aFeatureGroups.end()) {
181 hasProperFeature = true;
182 std::list<SketchSolver_Group*> aGroupsToResolve;
183 std::list<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
184 std::list<SketchSolver_Group*> aSeparatedGroups;
185 while (aGroupIter != myGroups.end()) {
186 if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed
188 std::list<SketchSolver_Group*>::iterator aRemoveIt = aGroupIter++;
189 myGroups.erase(aRemoveIt);
192 if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group
193 (*aGroupIter)->splitGroup(aSeparatedGroups);
194 //if (!(*aGroupIter)->getWorkplane()->string(
195 // SketchPlugin_Sketch::SOLVER_ERROR())->value().empty())
196 aGroupsToResolve.push_back(*aGroupIter);
200 if (aSeparatedGroups.size() > 0) {
201 myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
202 aGroupsToResolve.insert(aGroupsToResolve.end(),
203 aSeparatedGroups.begin(), aSeparatedGroups.end());
206 if (!aGroupsToResolve.empty())
207 resolveConstraints(aGroupsToResolve);
211 if (hasProperFeature)
213 myIsComputed = false;
216 void SketchSolver_Manager::checkConflictingConstraints(const std::shared_ptr<Events_Message>& theMessage)
218 if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_SOLVER_REPAIRED)) {
219 std::shared_ptr<ModelAPI_SolverFailedMessage> aMessage =
220 std::dynamic_pointer_cast<ModelAPI_SolverFailedMessage>(theMessage);
221 std::set<ObjectPtr> aSentObjs = aMessage->objects();
222 if (!aSentObjs.empty()) {
223 // Obtain sketch where the constraints are placed.
224 // It is enough to check only one constraint.
225 CompositeFeaturePtr aSketch;
226 FeaturePtr aConstraint = ModelAPI_Feature::feature(*aSentObjs.begin());
227 std::list<SketchSolver_Group*>::const_iterator aGrIt = myGroups.begin();
228 for (; aGrIt != myGroups.end(); ++aGrIt)
229 if ((*aGrIt)->isInteract(aConstraint)) {
230 aSketch = (*aGrIt)->getWorkplane();
234 // Search failed groups built on the same sketch
236 for (aGrIt = myGroups.begin(); aGrIt != myGroups.end(); ++aGrIt) {
237 SketchSolver_Group* aGroup = *aGrIt;
238 if (aGroup->isBaseWorkplane(aSketch) && aGroup->isFailed() &&
239 !aGroup->isInteract(aConstraint)) {
240 // reset error message on the sketch
241 aGroup->getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(
242 SketchSolver_Error::CONSTRAINTS());
251 // ============================================================================
252 // Function: changeWorkplane
253 // Purpose: update workplane by given parameters of the sketch
254 // ============================================================================
255 bool SketchSolver_Manager::changeWorkplane(CompositeFeaturePtr theSketch)
257 bool aResult = true; // changed when a workplane wrongly updated
258 bool isUpdated = false;
259 // Try to update specified workplane in all groups
260 std::list<SketchSolver_Group*>::iterator aGroupIter;
261 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
262 if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
266 // If the workplane is not updated, so this is a new workplane
268 SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch);
269 // Verify that the group is created successfully
270 if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) {
274 myGroups.push_back(aNewGroup);
279 // ============================================================================
280 // Function: changeConstraintOrEntity
281 // Purpose: create/update the constraint or the feature and place it into appropriate group
282 // ============================================================================
283 bool SketchSolver_Manager::changeFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
285 // Search the groups which this feature touches
286 std::set<GroupID> aGroups;
287 findGroups(theFeature, aGroups);
289 std::shared_ptr<SketchPlugin_Constraint> aConstraint =
290 std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
292 // Process the groups list
293 if (aGroups.size() == 0) {
294 // There are no groups applicable for this constraint => create new one
295 // The group will be created only for constraints, not for features
296 if (!aConstraint) return false;
297 std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(aConstraint);
300 SketchSolver_Group* aGroup = new SketchSolver_Group(aWP);
301 if (!aGroup->changeConstraint(aConstraint)) {
305 myGroups.push_back(aGroup);
307 } else if (aGroups.size() == 1) { // Only one group => add feature into it
308 GroupID aGroupId = *(aGroups.begin());
309 std::list<SketchSolver_Group*>::iterator aGroupIter;
310 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
311 if ((*aGroupIter)->getId() == aGroupId) {
312 // If the group is empty, the feature is not added (the constraint only)
313 if (!aConstraint && !(*aGroupIter)->isEmpty())
314 return (*aGroupIter)->updateFeature(theFeature);
315 return (*aGroupIter)->changeConstraint(aConstraint);
317 } else if (aGroups.size() > 1) { // Several groups applicable for this feature => need to merge them
318 std::set<GroupID>::const_iterator aGroupsIter = aGroups.begin();
320 // Search first group
321 std::list<SketchSolver_Group*>::iterator aFirstGroupIter;
322 for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
323 if ((*aFirstGroupIter)->getId() == *aGroupsIter)
325 if (aFirstGroupIter == myGroups.end())
328 // Append other groups to the first one
329 std::list<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter;
331 for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
332 for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
333 if ((*anOtherGroupIter)->getId() == *aGroupsIter)
335 if (anOtherGroupIter == myGroups.end()) { // Group disappears
336 anOtherGroupIter = aFirstGroupIter;
341 (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
342 std::list<SketchSolver_Group*>::iterator aRemoveIt = anOtherGroupIter++;
344 myGroups.erase(aRemoveIt);
348 (*aFirstGroupIter)->changeConstraint(aConstraint);
350 (*aFirstGroupIter)->updateFeature(theFeature);
351 // groups are merged => need to resolve them
355 // Something goes wrong
359 // ============================================================================
360 // Function: moveEntity
361 // Purpose: update element moved on the sketch, which is used by constraints
362 // ============================================================================
363 void SketchSolver_Manager::moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature)
365 bool isMoved = false;
366 std::list<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
367 for (; aGroupIt != myGroups.end(); aGroupIt++)
368 if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature)) {
369 (*aGroupIt)->moveFeature(theFeature);
373 if (!isMoved && theFeature->getKind() == SketchPlugin_Arc::ID()) {
374 // Workaround to move arc.
375 // If the arc has not been constrained, we will push it into empty group and apply movement.
376 for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); aGroupIt++)
377 if ((*aGroupIt)->isEmpty())
378 (*aGroupIt)->moveFeature(theFeature);
382 // ============================================================================
383 // Function: findGroups
384 // Purpose: search groups of entities interacting with given feature
385 // ============================================================================
386 void SketchSolver_Manager::findGroups(
387 std::shared_ptr<SketchPlugin_Feature> theFeature,
388 std::set<GroupID>& theGroupIDs) const
390 std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(theFeature);
392 SketchSolver_Group* anEmptyGroup = 0; // appropriate empty group for specified constraint
393 std::list<SketchSolver_Group*>::const_iterator aGroupIter;
394 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
395 if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) {
396 if (!(*aGroupIter)->isEmpty())
397 theGroupIDs.insert((*aGroupIter)->getId());
398 else if (!anEmptyGroup)
399 anEmptyGroup = *aGroupIter;
402 // When only empty group is found, use it
403 if (anEmptyGroup && theGroupIDs.empty())
404 theGroupIDs.insert(anEmptyGroup->getId());
407 // ============================================================================
408 // Function: findWorkplane
409 // Purpose: search workplane containing given feature
410 // ============================================================================
411 std::shared_ptr<ModelAPI_CompositeFeature> SketchSolver_Manager
412 ::findWorkplane(std::shared_ptr<SketchPlugin_Feature> theFeature) const
414 // Already verified workplanes
415 std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
417 std::list<SketchSolver_Group*>::const_iterator aGroupIter;
418 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
419 std::shared_ptr<ModelAPI_CompositeFeature> aWP = (*aGroupIter)->getWorkplane();
420 if (aVerified.find(aWP) != aVerified.end())
423 DataPtr aData = aWP->data();
424 if (aData->isValid()) {
425 std::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures = std::dynamic_pointer_cast<
426 ModelAPI_AttributeRefList>(aData->attribute(SketchPlugin_Sketch::FEATURES_ID()));
427 std::list<ObjectPtr> aFeaturesList = aWPFeatures->list();
428 std::list<ObjectPtr>::const_iterator anIter;
429 for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
430 if (*anIter == theFeature)
431 return aWP; // workplane is found
433 aVerified.insert(aWP);
436 return std::shared_ptr<ModelAPI_CompositeFeature>();
439 // ============================================================================
440 // Function: resolveConstraints
441 // Purpose: change entities according to available constraints
442 // ============================================================================
443 bool SketchSolver_Manager::resolveConstraints(const std::list<SketchSolver_Group*>& theGroups)
445 bool needToUpdate = false;
446 const std::list<SketchSolver_Group*>& aGroupsToResolve = theGroups.empty() ? myGroups : theGroups;
447 std::list<SketchSolver_Group*>::const_iterator aGroupIter = aGroupsToResolve.begin();
448 for (; aGroupIter != aGroupsToResolve.end(); aGroupIter++)
449 if ((*aGroupIter)->resolveConstraints())
454 // ============================================================================
455 // Function: degreesOfFreedom
456 // Purpose: calculate DoFs for each sketch
457 // ============================================================================
458 void SketchSolver_Manager::degreesOfFreedom()
460 static std::map<std::string, int> aDoFDelta; // indicates how many DoF adds or decreases a feature
461 static bool isNeedInit = true;
463 aDoFDelta[SketchPlugin_Point::ID()] = 2;
464 aDoFDelta[SketchPlugin_Line::ID()] = 4;
465 aDoFDelta[SketchPlugin_Circle::ID()] = 3;
466 aDoFDelta[SketchPlugin_Arc::ID()] = 5;
468 aDoFDelta[SketchPlugin_ConstraintAngle::ID()] = -1;
469 aDoFDelta[SketchPlugin_ConstraintCollinear::ID()] = -1;
470 aDoFDelta[SketchPlugin_ConstraintDistance::ID()] = -1;
471 aDoFDelta[SketchPlugin_ConstraintEqual::ID()] = -1;
472 aDoFDelta[SketchPlugin_ConstraintHorizontal::ID()] = -1;
473 aDoFDelta[SketchPlugin_ConstraintLength::ID()] = -1;
474 aDoFDelta[SketchPlugin_ConstraintMiddle::ID()] = -1;
475 aDoFDelta[SketchPlugin_ConstraintParallel::ID()] = -1;
476 aDoFDelta[SketchPlugin_ConstraintPerpendicular::ID()] = -1;
477 aDoFDelta[SketchPlugin_ConstraintRadius::ID()] = -1;
478 aDoFDelta[SketchPlugin_ConstraintTangent::ID()] = -1;
479 aDoFDelta[SketchPlugin_ConstraintVertical::ID()] = -1;
484 std::map<CompositeFeaturePtr, int> aSketchDoF;
486 std::list<SketchSolver_Group*>::const_iterator aGroupIt = myGroups.begin();
487 for (; aGroupIt != myGroups.end(); ++aGroupIt) {
488 CompositeFeaturePtr aSketch = (*aGroupIt)->getWorkplane();
489 if (!aSketch->data()->isValid()) {
490 myDoF.erase(aSketch);
494 // check conflicting constraints in the group
495 if ((*aGroupIt)->isFailed())
496 aSketchDoF[aSketch] = -1;
497 // check the sketch is already processed
498 if (aSketchDoF.find(aSketch) != aSketchDoF.end() || aSketchDoF[aSketch] < 0)
501 std::set<AttributePtr> aCoincidentPoints;
503 int aNbSubs = aSketch->numberOfSubs();
504 for (int i = 0; i < aNbSubs; ++i) {
505 FeaturePtr aFeature = aSketch->subFeature(i);
506 // check DoF delta for invariant types
507 std::map<std::string, int>::const_iterator aFound = aDoFDelta.find(aFeature->getKind());
508 if (aFound != aDoFDelta.end()) {
509 aDoF += aFound->second;
513 // DoF delta in specific cases
514 if (aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
515 AttributePtr aCoincPoint[2] = {AttributePtr(), AttributePtr()};
516 for (int j = 0; j < 2; ++j) {
517 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
518 aFeature->attribute(SketchPlugin_Constraint::ATTRIBUTE(j)));
521 bool isPoint = !aRefAttr->isObject();
523 aCoincPoint[j] = aRefAttr->attr();
525 FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object());
526 isPoint = anAttr && anAttr->getKind() == SketchPlugin_Point::ID();
528 aCoincPoint[j] = anAttr->attribute(SketchPlugin_Point::COORD_ID());
531 if (aCoincPoint[0] && aCoincPoint[1]) {
532 // point-point coincidence
533 if (aCoincidentPoints.find(aCoincPoint[0]) == aCoincidentPoints.end() ||
534 aCoincidentPoints.find(aCoincPoint[1]) == aCoincidentPoints.end())
538 for (int j = 0; j < 2; ++j)
540 aCoincidentPoints.insert(aCoincPoint[j]);
542 else if (aFeature->getKind() == SketchPlugin_ConstraintRigid::ID()) {
543 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
544 aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
546 if (!aRefAttr->isObject())
547 aDoF -= 2; // attribute is a point
549 FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object());
551 aDoF -= aDoFDelta[anAttr->getKind()];
554 else if (aFeature->getKind() == SketchPlugin_ConstraintMirror::ID() ||
555 aFeature->getKind() == SketchPlugin_MultiRotation::ID() ||
556 aFeature->getKind() == SketchPlugin_MultiTranslation::ID()) {
558 std::string anAttrName;
559 if (aFeature->getKind() == SketchPlugin_ConstraintMirror::ID())
560 anAttrName = SketchPlugin_Constraint::ENTITY_B();
562 if (aFeature->getKind() == SketchPlugin_MultiRotation::ID())
563 aNbCopies = aFeature->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID())->value() - 1;
564 else if (aFeature->getKind() == SketchPlugin_MultiTranslation::ID())
565 aNbCopies = aFeature->integer(SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID())->value() - 1;
566 anAttrName = SketchPlugin_Constraint::ENTITY_A();
569 AttributeRefListPtr aRefListOfShapes = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
570 aFeature->attribute(anAttrName));
571 std::list<ObjectPtr> anObjList = aRefListOfShapes->list();
572 std::list<ObjectPtr>::const_iterator anObjIt = anObjList.begin();
573 for (; anObjIt != anObjList.end(); ++anObjIt) {
574 FeaturePtr aSub = ModelAPI_Feature::feature(*anObjIt);
575 aDoF -= aDoFDelta[aSub->getKind()] * aNbCopies;
580 aSketchDoF[aSketch] = aDoF;
583 // Check the degrees of freedom are changed
584 std::map<CompositeFeaturePtr, int>::const_iterator aDoFIt = aSketchDoF.begin();
585 std::map<CompositeFeaturePtr, int>::iterator aFound;
586 for (; aDoFIt != aSketchDoF.end(); ++aDoFIt) {
587 if (aDoFIt->second < 0)
588 continue; // conflicting constraints on the current sketch
589 aFound = myDoF.find(aDoFIt->first);
590 if (aFound != myDoF.end() && aFound->second == aDoFIt->second)
591 continue; // nothing is changed
592 myDoF[aDoFIt->first] = aDoFIt->second;
593 // change attribute value
594 std::ostringstream aStream;
595 if (aDoFIt->second == 0)
596 aStream << "Sketch fully fixed (DOF = " << aDoFIt->second << ")";
598 aStream << "DOF (degree of freedom) = " << aDoFIt->second;
599 aDoFIt->first->data()->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aStream.str());
603 bool SketchSolver_Manager::stopSendUpdate() const
605 // to avoid redisplay of each segment on update by solver one by one in the viewer
606 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
607 if (isUpdateFlushed) {
608 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
610 return isUpdateFlushed;
613 void SketchSolver_Manager::allowSendUpdate() const
615 Events_Loop::loop()->setFlushed(anUpdateEvent, true);