]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SketchSolver_Group.cpp
Salome HOME
Do not recalculate constraints if there are invalid features (issue #874)
[modules/shaper.git] / src / SketchSolver / SketchSolver_Group.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    SketchSolver_Group.cpp
4 // Created: 27 May 2014
5 // Author:  Artem ZHIDKOV
6
7 #include "SketchSolver_Group.h"
8
9 #include <SketchSolver_Builder.h>
10 #include <SketchSolver_Constraint.h>
11 #include <SketchSolver_ConstraintCoincidence.h>
12 #include <SketchSolver_Error.h>
13
14 #include <Events_Error.h>
15 #include <Events_Loop.h>
16 #include <GeomAPI_XY.h>
17 #include <GeomAPI_Dir2d.h>
18 #include <GeomAPI_Pnt2d.h>
19 #include <GeomDataAPI_Dir.h>
20 #include <GeomDataAPI_Point.h>
21 #include <GeomDataAPI_Point2D.h>
22 #include <ModelAPI_AttributeDouble.h>
23 #include <ModelAPI_Document.h>
24 #include <ModelAPI_Events.h>
25 #include <ModelAPI_ResultConstruction.h>
26 #include <ModelAPI_Session.h>
27 #include <ModelAPI_Validator.h>
28
29 #include <SketchPlugin_Constraint.h>
30 #include <SketchPlugin_ConstraintEqual.h>
31 #include <SketchPlugin_ConstraintFillet.h>
32 #include <SketchPlugin_ConstraintLength.h>
33 #include <SketchPlugin_ConstraintCoincidence.h>
34 #include <SketchPlugin_ConstraintMirror.h>
35 #include <SketchPlugin_ConstraintRigid.h>
36 #include <SketchPlugin_ConstraintTangent.h>
37 #include <SketchPlugin_Feature.h>
38 #include <SketchPlugin_MultiRotation.h>
39 #include <SketchPlugin_MultiTranslation.h>
40
41 #include <SketchPlugin_Arc.h>
42 #include <SketchPlugin_Circle.h>
43 #include <SketchPlugin_Line.h>
44 #include <SketchPlugin_Point.h>
45 #include <SketchPlugin_Sketch.h>
46
47 #include <math.h>
48 #include <assert.h>
49
50
51 /// \brief This class is used to give unique index to the groups
52 class GroupIndexer
53 {
54 public:
55   /// \brief Return vacant index
56   static Slvs_hGroup NEW_GROUP() { return ++myGroupIndex; }
57   /// \brief Removes the index
58   static void REMOVE_GROUP(const Slvs_hGroup& theIndex) {
59     if (myGroupIndex == theIndex)
60       myGroupIndex--;
61   }
62
63 private:
64   GroupIndexer() {};
65
66   static Slvs_hGroup myGroupIndex; ///< index of the group
67 };
68
69 Slvs_hGroup GroupIndexer::myGroupIndex = 0;
70
71
72 static void sendMessage(const char* theMessageName)
73 {
74   std::shared_ptr<Events_Message> aMessage = std::shared_ptr<Events_Message>(
75       new Events_Message(Events_Loop::eventByName(theMessageName)));
76   Events_Loop::loop()->send(aMessage);
77 }
78
79
80
81 // ========================================================
82 // =========  SketchSolver_Group  ===============
83 // ========================================================
84
85 SketchSolver_Group::SketchSolver_Group(
86     std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
87     : myID(GroupIndexer::NEW_GROUP()),
88       myPrevSolved(true)
89 {
90   // Initialize workplane
91   myWorkplaneID = SLVS_E_UNKNOWN;
92 #ifndef NDEBUG
93   assert(addWorkplane(theWorkplane));
94 #else
95   addWorkplane(theWorkplane);
96 #endif
97 }
98
99 SketchSolver_Group::~SketchSolver_Group()
100 {
101   myConstraints.clear();
102   GroupIndexer::REMOVE_GROUP(myID);
103 }
104
105 // ============================================================================
106 //  Function: isBaseWorkplane
107 //  Class:    SketchSolver_Group
108 //  Purpose:  verify the group is based on the given workplane
109 // ============================================================================
110 bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const
111 {
112   return theWorkplane == mySketch;
113 }
114
115 // ============================================================================
116 //  Function: isInteract
117 //  Class:    SketchSolver_Group
118 //  Purpose:  verify are there any entities in the group used by given constraint
119 // ============================================================================
120 bool SketchSolver_Group::isInteract(
121     std::shared_ptr<SketchPlugin_Feature> theFeature) const
122 {
123   // Empty group interacts with everything
124   if (isEmpty()) return true;
125   ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
126   if (aConstraint)
127     return myFeatureStorage->isInteract(aConstraint);
128   return myFeatureStorage->isInteract(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
129 }
130
131 // ============================================================================
132 //  Function: getFeatureId
133 //  Class:    SketchSolver_Group
134 //  Purpose:  Find the identifier of the feature, if it already exists in the group
135 // ============================================================================
136 Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const
137 {
138   Slvs_hEntity aResult = SLVS_E_UNKNOWN;
139   if (!myFeatureStorage)
140     return aResult;
141   std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theFeature);
142   if (aConstraints.empty())
143     return aResult;
144   std::set<ConstraintPtr>::iterator aConstrIter = aConstraints.begin();
145   for (; aConstrIter != aConstraints.end(); aConstrIter++) {
146     ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstrIter);
147     if (aCIter == myConstraints.end())
148       continue;
149     aResult = aCIter->second->getId(theFeature);
150     if (aResult != SLVS_E_UNKNOWN)
151       return aResult;
152   }
153   return SLVS_E_UNKNOWN;
154 }
155
156 // ============================================================================
157 //  Function: getAttributeId
158 //  Class:    SketchSolver_Group
159 //  Purpose:  Find the identifier of the attribute, if it already exists in the group
160 // ============================================================================
161 Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const
162 {
163   Slvs_hEntity aResult = SLVS_E_UNKNOWN;
164   if (!myFeatureStorage)
165     return aResult;
166   std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theAttribute);
167   if (aConstraints.empty())
168     return aResult;
169   std::set<ConstraintPtr>::iterator aConstrIter = aConstraints.begin();
170   for (; aConstrIter != aConstraints.end(); aConstrIter++) {
171     ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstrIter);
172     if (aCIter == myConstraints.end())
173       continue;
174     aResult = aCIter->second->getId(theAttribute);
175     if (aResult != SLVS_E_UNKNOWN)
176       return aResult;
177   }
178   return SLVS_E_UNKNOWN;
179 }
180
181 // ============================================================================
182 //  Function: changeConstraint
183 //  Class:    SketchSolver_Group
184 //  Purpose:  create/update the constraint in the group
185 // ============================================================================
186 bool SketchSolver_Group::changeConstraint(
187     std::shared_ptr<SketchPlugin_Constraint> theConstraint)
188 {
189   // There is no workplane yet, something wrong
190   if (myWorkplaneID == SLVS_E_UNKNOWN)
191     return false;
192
193   if (!theConstraint)
194     return false;
195
196   if (!checkFeatureValidity(theConstraint))
197     return false;
198
199   bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end();
200   if (isNewConstraint) {
201     // Add constraint to the current group
202     SolverConstraintPtr aConstraint =
203         SketchSolver_Builder::getInstance()->createConstraint(theConstraint);
204     if (!aConstraint)
205       return false;
206     aConstraint->setGroup(this);
207     aConstraint->setStorage(myStorage);
208     if (!aConstraint->error().empty()) {
209       if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
210         return false; // some attribute are not initialized yet, don't show message
211       Events_Error::send(aConstraint->error(), this);
212     }
213
214     // Additional verification of coincidence of several points
215     if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
216       ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
217       for (; aCIter != myConstraints.end(); aCIter++) {
218         std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoincidence =
219           std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aCIter->second);
220         if (!aCoincidence)
221           continue;
222         std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoinc2 =
223           std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aConstraint);
224         if (aCoincidence != aCoinc2 && aCoincidence->isCoincide(aCoinc2)) {
225           aCoinc2->attach(aCoincidence);
226           // update other coincidences
227           ConstraintConstraintMap::iterator anIt = aCIter;
228           for (++anIt; anIt != myConstraints.end(); ++anIt)
229             if (anIt->second == aCIter->second)
230               anIt->second = aCoinc2;
231           aCIter->second = aCoinc2;
232         }
233       }
234     }
235     myConstraints[theConstraint] = aConstraint;
236   }
237   else
238     myConstraints[theConstraint]->update();
239
240   // Fix base features for fillet
241   if (isNewConstraint && theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
242     std::list<AttributePtr> anAttrList =
243         theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
244     std::list<AttributePtr>::iterator anAttrIter = anAttrList.begin();
245     for (; anAttrIter != anAttrList.end(); anAttrIter++) {
246       AttributeRefAttrPtr aRefAttr =
247           std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
248       if (!aRefAttr || !aRefAttr->isObject())
249         continue;
250       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
251       SolverConstraintPtr aConstraint =
252           SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
253       if (!aConstraint)
254         continue;
255       aConstraint->setGroup(this);
256       aConstraint->setStorage(myStorage);
257       setTemporary(aConstraint);
258     }
259   }
260   // Fix mirror line
261   if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
262     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
263         theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_A()));
264     if (aRefAttr && aRefAttr->isObject()) {
265       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
266       if (aFeature) {
267         SolverConstraintPtr aConstraint =
268             SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
269         if (aConstraint) {
270           aConstraint->setGroup(this);
271           aConstraint->setStorage(myStorage);
272           setTemporary(aConstraint);
273         }
274       }
275     }
276   }
277
278   if (!myFeatureStorage)
279     myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
280   myFeatureStorage->changeConstraint(theConstraint);
281
282   return true;
283 }
284
285
286 bool SketchSolver_Group::updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
287 {
288   if (!checkFeatureValidity(theFeature))
289     return false;
290
291   std::set<ConstraintPtr> aConstraints =
292       myFeatureStorage->getConstraints(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
293   if (aConstraints.empty())
294     return false;
295   std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
296   std::set<SolverConstraintPtr> aPostponed; // postponed constraints Multi-Rotation and Multi-Translation
297   for (; aCIter != aConstraints.end(); aCIter++) {
298     ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter);
299     if (aSolConIter == myConstraints.end() || !aSolConIter->first->data() ||
300         !aSolConIter->first->data()->isValid())
301       continue;
302     myFeatureStorage->changeFeature(theFeature, aSolConIter->first);
303
304     if (aSolConIter->first->getKind() == SketchPlugin_MultiRotation::ID() ||
305         aSolConIter->first->getKind() == SketchPlugin_MultiTranslation::ID()) {
306       aPostponed.insert(aSolConIter->second);
307       continue;
308     }
309     aSolConIter->second->addFeature(theFeature);
310     aSolConIter->second->update();
311   }
312
313   // Update postponed constraints
314   std::set<SolverConstraintPtr>::iterator aSCIter = aPostponed.begin();
315   for (; aSCIter != aPostponed.end(); ++aSCIter) {
316     (*aSCIter)->addFeature(theFeature);
317     (*aSCIter)->update();
318   }
319   return true;
320 }
321
322 void SketchSolver_Group::moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
323 {
324   // Firstly, create temporary rigid constraint
325   SolverConstraintPtr aConstraint =
326       SketchSolver_Builder::getInstance()->createMovementConstraint(theFeature);
327   if (!aConstraint)
328     return;
329   aConstraint->setGroup(this);
330   aConstraint->setStorage(myStorage);
331   if (aConstraint->error().empty())
332     setTemporary(aConstraint);
333   // Secondly, update the feature
334   updateFeature(theFeature);
335 }
336
337 // ============================================================================
338 //  Function: fixFeaturesList
339 //  Class:    SketchSolver_Group
340 //  Purpose:  Apply temporary rigid constraints for the list of features
341 // ============================================================================
342 void SketchSolver_Group::fixFeaturesList(AttributeRefListPtr theList)
343 {
344   std::list<ObjectPtr> aList = theList->list();
345   std::list<ObjectPtr>::iterator anIt = aList.begin();
346   std::list<FeaturePtr> aFeatures;
347   // Sort features, at begining there are features used by Equal constraint
348   for (; anIt != aList.end(); anIt++) {
349     if (!(*anIt))
350       continue;
351     FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
352     std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(aFeature);
353     std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
354     for (; aCIter != aConstraints.end(); aCIter++)
355       if ((*aCIter)->getKind() == SketchPlugin_ConstraintEqual::ID())
356         break;
357     if (aCIter != aConstraints.end())
358       aFeatures.push_front(aFeature);
359     else
360       aFeatures.push_back(aFeature);
361   }
362
363   std::list<FeaturePtr>::iterator aFeatIter = aFeatures.begin();
364   for (; aFeatIter != aFeatures.end(); aFeatIter++) {
365     SolverConstraintPtr aConstraint =
366         SketchSolver_Builder::getInstance()->createRigidConstraint(*aFeatIter);
367     if (!aConstraint)
368       continue;
369     aConstraint->setGroup(this);
370     aConstraint->setStorage(myStorage);
371     setTemporary(aConstraint);
372   }
373 }
374
375 // ============================================================================
376 //  Function: addWorkplane
377 //  Class:    SketchSolver_Group
378 //  Purpose:  create workplane for the group
379 // ============================================================================
380 bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch)
381 {
382   if (myWorkplaneID != SLVS_E_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID())
383     return false;  // the workplane already exists or the function parameter is not Sketch
384
385   mySketch = theSketch;
386   updateWorkplane();
387   return true;
388 }
389
390 // ============================================================================
391 //  Function: updateWorkplane
392 //  Class:    SketchSolver_Group
393 //  Purpose:  update parameters of workplane
394 // ============================================================================
395 bool SketchSolver_Group::updateWorkplane()
396 {
397   if (!myStorage) // Create storage if not exists
398     myStorage = StoragePtr(new SketchSolver_Storage);
399   SketchSolver_Builder* aBuilder = SketchSolver_Builder::getInstance();
400
401   std::vector<Slvs_Entity> anEntities;
402   std::vector<Slvs_Param> aParams;
403   if (!aBuilder->createWorkplane(mySketch, anEntities, aParams))
404     return false;
405
406   if (myWorkplaneID == SLVS_E_UNKNOWN) {
407     myWorkplaneID = anEntities.back().h;
408     // Add new workplane elements
409     std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
410     for (; aParIter != aParams.end(); aParIter++) {
411       aParIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
412       aParIter->group = myID;
413       aParIter->h = myStorage->addParameter(*aParIter);
414     }
415     std::vector<Slvs_Entity>::iterator anEntIter = anEntities.begin();
416     for (; anEntIter != anEntities.end(); anEntIter++) {
417       anEntIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
418       anEntIter->group = myID;
419       anEntIter->wrkpl = myWorkplaneID;
420       for (int i = 0; i < 4; i++)
421         if (anEntIter->param[i] != SLVS_E_UNKNOWN)
422           anEntIter->param[i] = aParams[anEntIter->param[i]-1].h;
423       for (int i = 0; i < 4; i++)
424         if (anEntIter->point[i] != SLVS_E_UNKNOWN)
425           anEntIter->point[i] = anEntities[anEntIter->point[i]-1].h;
426       anEntIter->h = myStorage->addEntity(*anEntIter);
427     }
428   } else {
429     // Update existent workplane
430     const Slvs_Entity& aWP = myStorage->getEntity(myWorkplaneID);
431     const Slvs_Entity& anOrigin = myStorage->getEntity(aWP.point[0]);
432     const Slvs_Entity& aNormal = myStorage->getEntity(aWP.normal);
433     // Get parameters and update them
434     Slvs_hParam aWPParams[7] = {
435         anOrigin.param[0], anOrigin.param[1], anOrigin.param[2],
436         aNormal.param[0], aNormal.param[1], aNormal.param[2], aNormal.param[3]
437       };
438     std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
439     for (int i = 0; aParIter != aParams.end(); aParIter++, i++) {
440       Slvs_Param aParam = myStorage->getParameter(aWPParams[i]);
441       aParam.val = aParIter->val;
442       myStorage->updateParameter(aParam);
443     }
444   }
445   return myWorkplaneID > 0;
446 }
447
448 // ============================================================================
449 //  Function: resolveConstraints
450 //  Class:    SketchSolver_Group
451 //  Purpose:  solve the set of constraints for the current group
452 // ============================================================================
453 bool SketchSolver_Group::resolveConstraints()
454 {
455   bool aResolved = false;
456   if (myStorage->isNeedToResolve() && !isEmpty()) {
457     myConstrSolver.setGroupID(myID);
458     myStorage->initializeSolver(myConstrSolver);
459
460     int aResult = SLVS_RESULT_OKAY;
461     try {
462       if (myStorage->hasDuplicatedConstraint())
463         aResult = SLVS_RESULT_INCONSISTENT;
464       else {
465         // To avoid overconstraint situation, we will remove temporary constraints one-by-one
466         // and try to find the case without overconstraint
467         bool isLastChance = false;
468         int aNbTemp = myStorage->numberTemporary();
469         while (true) {
470           aResult = myConstrSolver.solve();
471           if (aResult == SLVS_RESULT_OKAY || isLastChance)
472             break;
473           if (aNbTemp <= 0) {
474             // try to update parameters and resolve once again
475             ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin();
476             for (; aConstrIt != myConstraints.end(); ++aConstrIt)
477               aConstrIt->second->update();
478             isLastChance = true;
479           } else
480             aNbTemp = myStorage->deleteTemporaryConstraint();
481           myStorage->initializeSolver(myConstrSolver);
482         }
483       }
484     } catch (...) {
485       Events_Error::send(SketchSolver_Error::SOLVESPACE_CRASH(), this);
486       if (myPrevSolved) {
487         sendMessage(EVENT_SOLVER_FAILED);
488         myPrevSolved = false;
489       }
490       return false;
491     }
492     if (aResult == SLVS_RESULT_OKAY) {  // solution succeeded, store results into correspondent attributes
493       myFeatureStorage->blockEvents(true);
494       ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
495       for (; aConstrIter != myConstraints.end(); aConstrIter++)
496         aConstrIter->second->refresh();
497       myFeatureStorage->blockEvents(false);
498       if (!myPrevSolved) {
499         sendMessage(EVENT_SOLVER_REPAIRED);
500         myPrevSolved = true;
501       }
502     } else if (!myConstraints.empty()) {
503       Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
504       if (myPrevSolved) {
505         sendMessage(EVENT_SOLVER_FAILED);
506         myPrevSolved = false;
507       }
508     }
509
510     aResolved = true;
511   }
512   removeTemporaryConstraints();
513   myStorage->setNeedToResolve(false);
514   return aResolved;
515 }
516
517 // ============================================================================
518 //  Function: mergeGroups
519 //  Class:    SketchSolver_Group
520 //  Purpose:  append specified group to the current group
521 // ============================================================================
522 void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
523 {
524   // If specified group is empty, no need to merge
525   if (theGroup.isEmpty())
526     return;
527   if (!myFeatureStorage)
528     myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
529
530   std::vector<ConstraintPtr> aComplexConstraints;
531   ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
532   // append simple constraints
533   for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++)
534     if (isComplexConstraint(aConstrIter->first))
535       aComplexConstraints.push_back(aConstrIter->first);
536     else
537       changeConstraint(aConstrIter->first);
538   // append complex constraints
539   std::vector<ConstraintPtr>::iterator aComplexIter = aComplexConstraints.begin();
540   for (; aComplexIter != aComplexConstraints.end(); aComplexIter++)
541       changeConstraint(*aComplexIter);
542 }
543
544 // ============================================================================
545 //  Function: splitGroup
546 //  Class:    SketchSolver_Group
547 //  Purpose:  divide the group into several subgroups
548 // ============================================================================
549 void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
550 {
551   // Obtain constraints, which should be separated
552   FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage);
553   std::vector<ConstraintPtr> anUnusedConstraints;
554   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
555   for ( ; aCIter != myConstraints.end(); aCIter++) {
556     std::list<ConstraintPtr> aBaseConstraints = aCIter->second->constraints();
557     std::list<ConstraintPtr>::iterator anIter = aBaseConstraints.begin();
558     for (; anIter != aBaseConstraints.end(); anIter++)
559       if (aNewFeatStorage->isInteract(*anIter)) {
560         aNewFeatStorage->changeConstraint(*anIter);
561       } else
562         anUnusedConstraints.push_back(*anIter);
563   }
564
565   // Check the unused constraints once again, because they may become interacted with new storage since adding constraints
566   std::vector<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
567   while (aUnuseIt != anUnusedConstraints.end()) {
568     if (aNewFeatStorage->isInteract(*aUnuseIt)) {
569       size_t aShift = aUnuseIt - anUnusedConstraints.begin();
570       anUnusedConstraints.erase(aUnuseIt);
571       aUnuseIt = anUnusedConstraints.begin() + aShift;
572       continue;
573     }
574     aUnuseIt++;
575   }
576
577   std::vector<SketchSolver_Group*>::iterator aCutsIter;
578   aUnuseIt = anUnusedConstraints.begin();
579   for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) {
580     // Remove unused constraints
581     removeConstraint(*aUnuseIt);
582     // Try to append constraint to already existent group
583     for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); aCutsIter++)
584       if ((*aCutsIter)->isInteract(*aUnuseIt)) {
585         (*aCutsIter)->changeConstraint(*aUnuseIt);
586         break;
587       }
588     if (aCutsIter == theCuts.end()) {
589       // Add new group
590       SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch);
591       aGroup->changeConstraint(*aUnuseIt);
592       theCuts.push_back(aGroup);
593     }
594   }
595 }
596
597 // ============================================================================
598 //  Function: isConsistent
599 //  Class:    SketchSolver_Group
600 //  Purpose:  search removed entities and constraints
601 // ============================================================================
602 bool SketchSolver_Group::isConsistent()
603 {
604   if (!myFeatureStorage) // no one constraint is initialized yet
605     return true;
606
607   bool aResult = myFeatureStorage->isConsistent();
608   if (!aResult) {
609     // remove invalid entities
610     std::set<ConstraintPtr> anInvalidConstraints;
611     ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
612     for (; aCIter != myConstraints.end(); ++aCIter) {
613       if (!aCIter->first->data() || !aCIter->first->data()->isValid())
614         anInvalidConstraints.insert(aCIter->first);
615     }
616     std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
617     for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
618       removeConstraint(*aRemoveIt);
619   }
620   return aResult;
621 }
622
623 // ============================================================================
624 //  Function: removeTemporaryConstraints
625 //  Class:    SketchSolver_Group
626 //  Purpose:  remove all transient SLVS_C_WHERE_DRAGGED constraints after
627 //            resolving the set of constraints
628 // ============================================================================
629 void SketchSolver_Group::removeTemporaryConstraints()
630 {
631   myTempConstraints.clear();
632   while (myStorage->numberTemporary())
633     myStorage->deleteTemporaryConstraint();
634   // Clean lists of removed entities in the storage
635   std::set<Slvs_hParam> aRemPar;
636   std::set<Slvs_hEntity> aRemEnt;
637   std::set<Slvs_hConstraint> aRemCon;
638   myStorage->getRemoved(aRemPar, aRemEnt, aRemCon);
639   myStorage->setNeedToResolve(false);
640 }
641
642 // ============================================================================
643 //  Function: removeConstraint
644 //  Class:    SketchSolver_Group
645 //  Purpose:  remove constraint and all unused entities
646 // ============================================================================
647 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
648 {
649   bool isFullyRemoved = true;
650   myFeatureStorage->removeConstraint(theConstraint);
651   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
652   for (; aCIter != myConstraints.end(); aCIter++)
653     if (aCIter->second->hasConstraint(theConstraint)) {
654       if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed
655         isFullyRemoved = false;
656       break;
657     }
658   if (aCIter == myConstraints.end())
659     return;
660
661   if (isFullyRemoved)
662     myConstraints.erase(aCIter);
663   else if (aCIter != myConstraints.end() &&
664            aCIter->first->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
665     // Update multicoincidence
666     std::list<ConstraintPtr> aMultiCoinc;
667     SolverConstraintPtr aCoincidence = aCIter->second;
668     while (aCIter != myConstraints.end()) {
669       if (aCIter->second != aCoincidence) {
670         ++aCIter;
671         continue;
672       }
673       if (aCIter->first != theConstraint)
674         aMultiCoinc.push_back(aCIter->first);
675       aCIter->second->remove(aCIter->first);
676       ConstraintConstraintMap::iterator aRemoveIt = aCIter++;
677       myConstraints.erase(aRemoveIt);
678     }
679
680     std::list<ConstraintPtr>::iterator anIt = aMultiCoinc.begin();
681     for (; anIt != aMultiCoinc.end(); ++anIt)
682       changeConstraint(*anIt);
683   }
684 }
685
686 // ============================================================================
687 //  Function: isComplexConstraint
688 //  Class:    SketchSolver_Group
689 //  Purpose:  verifies the constraint is complex, i.e. it needs another constraints to be created before
690 // ============================================================================
691 bool SketchSolver_Group::isComplexConstraint(FeaturePtr theConstraint)
692 {
693   return theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID() ||
694          theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID() ||
695          theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID();
696 }
697
698 // ============================================================================
699 //  Function: setTemporary
700 //  Class:    SketchSolver_Group
701 //  Purpose:  append given constraint to th group of temporary constraints
702 // ============================================================================
703 void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
704 {
705   theConstraint->makeTemporary();
706   myTempConstraints.insert(theConstraint);
707 }
708
709
710 // ============================================================================
711 //  Function: checkFeatureValidity
712 //  Class:    SketchSolver_Group
713 //  Purpose:  verifies is the feature valid
714 // ============================================================================
715 bool SketchSolver_Group::checkFeatureValidity(FeaturePtr theFeature)
716 {
717   if (!theFeature || !theFeature->data()->isValid())
718     return true;
719
720   SessionPtr aMgr = ModelAPI_Session::get();
721   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
722   return aFactory->validate(theFeature);
723 }
724