Salome HOME
Fix compilation error on Linux. Part V.
[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_Constraint.h>
10 #include <SketchSolver_ConstraintCoincidence.h>
11 #include <SketchSolver_ConstraintMulti.h>
12 #include <SketchSolver_Error.h>
13 ////#include <SketchSolver_Builder.h>
14 #include <SketchSolver_Manager.h>
15
16 #include <Events_Error.h>
17 #include <Events_Loop.h>
18 ////#include <GeomAPI_XY.h>
19 ////#include <GeomAPI_Dir2d.h>
20 ////#include <GeomAPI_Pnt2d.h>
21 ////#include <GeomDataAPI_Dir.h>
22 ////#include <GeomDataAPI_Point.h>
23 ////#include <GeomDataAPI_Point2D.h>
24 ////#include <ModelAPI_AttributeDouble.h>
25 #include <ModelAPI_AttributeString.h>
26 ////#include <ModelAPI_Document.h>
27 #include <ModelAPI_Events.h>
28 ////#include <ModelAPI_ResultConstruction.h>
29 #include <ModelAPI_Session.h>
30 #include <ModelAPI_Validator.h>
31 ////
32 ////#include <SketchPlugin_Constraint.h>
33 #include <SketchPlugin_ConstraintAngle.h>
34 #include <SketchPlugin_ConstraintCoincidence.h>
35 #include <SketchPlugin_ConstraintDistance.h>
36 #include <SketchPlugin_ConstraintEqual.h>
37 #include <SketchPlugin_ConstraintHorizontal.h>
38 #include <SketchPlugin_ConstraintLength.h>
39 #include <SketchPlugin_ConstraintFillet.h>
40 #include <SketchPlugin_ConstraintMirror.h>
41 #include <SketchPlugin_ConstraintParallel.h>
42 #include <SketchPlugin_ConstraintPerpendicular.h>
43 #include <SketchPlugin_ConstraintRadius.h>
44 #include <SketchPlugin_ConstraintRigid.h>
45 #include <SketchPlugin_ConstraintTangent.h>
46 #include <SketchPlugin_ConstraintVertical.h>
47 ////#include <SketchPlugin_Feature.h>
48 #include <SketchPlugin_MultiRotation.h>
49 #include <SketchPlugin_MultiTranslation.h>
50 ////#include <SketchPlugin_Sketch.h>
51 ////
52 ////#include <SketchPlugin_Arc.h>
53 ////#include <SketchPlugin_Circle.h>
54 ////#include <SketchPlugin_Line.h>
55 ////#include <SketchPlugin_Point.h>
56 ////#include <SketchPlugin_Sketch.h>
57
58 #include <math.h>
59 #include <assert.h>
60
61
62 /// \brief This class is used to give unique index to the groups
63 class GroupIndexer
64 {
65 public:
66   /// \brief Return vacant index
67   static GroupID NEW_GROUP() { return ++myGroupIndex; }
68   /// \brief Removes the index
69   static void REMOVE_GROUP(const GroupID& theIndex) {
70     if (myGroupIndex == theIndex)
71       myGroupIndex--;
72   }
73
74 private:
75   GroupIndexer() {};
76
77   static GroupID myGroupIndex; ///< index of the group
78 };
79
80 GroupID GroupIndexer::myGroupIndex = GID_OUTOFGROUP;
81
82
83 static void sendMessage(const char* theMessageName)
84 {
85   std::shared_ptr<Events_Message> aMessage = std::shared_ptr<Events_Message>(
86       new Events_Message(Events_Loop::eventByName(theMessageName)));
87   Events_Loop::loop()->send(aMessage);
88 }
89
90
91
92 // ========================================================
93 // =========  SketchSolver_Group  ===============
94 // ========================================================
95
96 SketchSolver_Group::SketchSolver_Group(
97     std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
98     : myID(GroupIndexer::NEW_GROUP()),
99       myPrevSolved(true)
100 {
101   // Initialize workplane
102   myWorkplaneID = EID_UNKNOWN;
103   addWorkplane(theWorkplane);
104 }
105
106 SketchSolver_Group::~SketchSolver_Group()
107 {
108   myConstraints.clear();
109   GroupIndexer::REMOVE_GROUP(myID);
110 }
111
112 // ============================================================================
113 //  Function: isBaseWorkplane
114 //  Class:    SketchSolver_Group
115 //  Purpose:  verify the group is based on the given workplane
116 // ============================================================================
117 bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const
118 {
119   return theWorkplane == mySketch;
120 }
121
122 // ============================================================================
123 //  Function: isInteract
124 //  Class:    SketchSolver_Group
125 //  Purpose:  verify are there any entities in the group used by given constraint
126 // ============================================================================
127 bool SketchSolver_Group::isInteract(FeaturePtr theFeature) const
128 {
129   // Empty group interacts with everything
130   if (isEmpty())
131     return true;
132   // Check interaction with the storage
133   return myStorage->isInteract(theFeature);
134 }
135
136 // ============================================================================
137 //  Function: changeConstraint
138 //  Class:    SketchSolver_Group
139 //  Purpose:  create/update the constraint in the group
140 // ============================================================================
141 bool SketchSolver_Group::changeConstraint(
142     std::shared_ptr<SketchPlugin_Constraint> theConstraint)
143 {
144   // There is no workplane yet, something wrong
145   if (myWorkplaneID == EID_UNKNOWN)
146     return false;
147
148   if (!theConstraint || !theConstraint->data())
149     return false;
150
151   if (!checkFeatureValidity(theConstraint))
152     return false;
153
154   BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
155
156   bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end();
157   if (isNewConstraint) {
158     // Add constraint to the current group
159     SolverConstraintPtr aConstraint = aBuilder->createConstraint(theConstraint);
160     if (!aConstraint)
161       return false;
162     aConstraint->process(myStorage, getId(), getWorkplaneId());
163     if (!aConstraint->error().empty()) {
164       if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
165         return false; // some attribute are not initialized yet, don't show message
166       Events_Error::send(aConstraint->error(), this);
167     }
168
169 ////    // Additional verification of coincidence of several points
170 ////    if (aConstraint->getType() == CONSTRAINT_PT_PT_COINCIDENT) {
171 ////      bool hasMultiCoincidence = false;
172 ////      std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoincidence =
173 ////          std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aConstraint);
174 ////
175 ////      ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
176 ////      for (; aCIter != myConstraints.end(); ++aCIter) {
177 ////        if (aCIter->second->getType() != CONSTRAINT_PT_PT_COINCIDENT)
178 ////          continue;
179 ////
180 ////        std::shared_ptr<SketchSolver_ConstraintCoincidence> aCurCoinc =
181 ////          std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aCIter->second);
182 ////        if (aCoincidence != aCurCoinc && aCurCoinc->isCoincide(aCoincidence)) {
183 ////          aCoincidence->attach(aCurCoinc);
184 ////////          // update other coincidences
185 ////////          ConstraintConstraintMap::iterator anIt = aCIter;
186 ////////          for (++anIt; anIt != myConstraints.end(); ++anIt)
187 ////////            if (anIt->second == aCIter->second)
188 ////////              anIt->second = aCoincidence;
189 ////          aCIter->second = aCoincidence;
190 ////          hasMultiCoincidence = true;
191 ////        }
192 ////      }
193 ////
194 ////      if (hasMultiCoincidence)
195 ////        notifyMultiConstraints();
196 ////    }
197     myConstraints[theConstraint] = aConstraint;
198   }
199   else
200     myConstraints[theConstraint]->update();
201
202 ////  // Fix base features for fillet
203 ////  if (isNewConstraint && theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
204 ////    std::list<AttributePtr> anAttrList =
205 ////        theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
206 ////    std::list<AttributePtr>::iterator anAttrIter = anAttrList.begin();
207 ////    for (; anAttrIter != anAttrList.end(); anAttrIter++) {
208 ////      AttributeRefAttrPtr aRefAttr =
209 ////          std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
210 ////      if (!aRefAttr || !aRefAttr->isObject())
211 ////        continue;
212 ////      FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
213 ////      SolverConstraintPtr aConstraint = aBuilder->createRigidConstraint(aFeature);
214 ////      if (!aConstraint)
215 ////        continue;
216 ////      aConstraint->setGroup(this);
217 ////      aConstraint->setStorage(myStorage);
218 ////      setTemporary(aConstraint);
219 ////    }
220 ////  }
221
222   // Fix mirror line
223   if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
224     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
225         theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_A()));
226     if (aRefAttr && aRefAttr->isObject()) {
227       std::shared_ptr<SketchPlugin_Feature> aFeature =
228           std::dynamic_pointer_cast<SketchPlugin_Feature>(
229           ModelAPI_Feature::feature(aRefAttr->object()));
230       if (aFeature) {
231         SolverConstraintPtr aConstraint = aBuilder->createFixedConstraint(aFeature);
232         if (aConstraint) {
233           aConstraint->process(myStorage, getId(), getWorkplaneId());
234           setTemporary(aConstraint);
235         }
236       }
237     }
238   }
239
240 ////  // Check the attributes of constraint are given by parametric expression
241 ////  std::list<AttributePtr> anAttributes =
242 ////      theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
243 ////  std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
244 ////  for (; anAttrIt != anAttributes.end(); ++anAttrIt) {
245 ////    AttributeRefAttrPtr aRefAttr =
246 ////        std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIt);
247 ////    if (!aRefAttr)
248 ////      continue;
249 ////
250 ////    std::shared_ptr<GeomDataAPI_Point2D> aPoint;
251 ////    if (aRefAttr->isObject()) {
252 ////      FeaturePtr aFeat = ModelAPI_Feature::feature(aRefAttr->object());
253 ////      if (aFeat->getKind() != SketchPlugin_Point::ID())
254 ////        continue;
255 ////      aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
256 ////          aFeat->attribute(SketchPlugin_Point::COORD_ID()));
257 ////    } else
258 ////      aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
259 ////
260 ////    if (!aPoint || (aPoint->textX().empty() && aPoint->textY().empty()))
261 ////      continue;
262 ////
263 ////    std::map<AttributePtr, SolverConstraintPtr>::iterator aFound =
264 ////        myParametricConstraints.find(aPoint);
265 ////    if (aFound == myParametricConstraints.end()) {
266 ////      SolverConstraintPtr aConstraint = aBuilder->createParametricConstraint(aPoint);
267 ////      if (!aConstraint)
268 ////        continue;
269 ////      aConstraint->setGroup(this);
270 ////      aConstraint->setStorage(myStorage);
271 ////      myParametricConstraints[aPoint] = aConstraint;
272 ////    } else
273 ////      aFound->second->update();
274 ////  }
275
276   return true;
277 }
278
279
280 void SketchSolver_Group::updateConstraints()
281 {
282   std::set<SolverConstraintPtr> aPostponed; // postponed constraints Multi-Rotation and Multi-Translation
283
284   ConstraintConstraintMap::iterator anIt = myConstraints.begin();
285   for (; anIt != myConstraints.end(); ++anIt) {
286     if (myChangedConstraints.find(anIt->first) == myChangedConstraints.end())
287       continue;
288     if (anIt->first->getKind() == SketchPlugin_MultiRotation::ID() ||
289         anIt->first->getKind() == SketchPlugin_MultiTranslation::ID())
290       aPostponed.insert(anIt->second);
291     else
292       anIt->second->update();
293   }
294
295   // Update postponed constraints
296   std::set<SolverConstraintPtr>::iterator aSCIter = aPostponed.begin();
297   for (; aSCIter != aPostponed.end(); ++aSCIter)
298     (*aSCIter)->update();
299
300   myChangedConstraints.clear();
301 }
302
303 bool SketchSolver_Group::updateFeature(FeaturePtr theFeature)
304 {
305   if (!checkFeatureValidity(theFeature))
306     return false;
307
308   bool isUpdated = myStorage->update(theFeature);
309
310 ////  // Search attributes of the feature in the set of parametric constraints and update them
311 ////  std::list<AttributePtr> anAttrList =
312 ////      theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
313 ////  std::list<AttributePtr>::iterator anAttrIt = anAttrList.begin();
314 ////  for (; anAttrIt != anAttrList.end(); ++anAttrIt) {
315 ////    std::map<AttributePtr, SolverConstraintPtr>::iterator aFound =
316 ////        myParametricConstraints.find(*anAttrIt);
317 ////    if (aFound != myParametricConstraints.end())
318 ////      aFound->second->update();
319 ////    else {
320 ////      std::shared_ptr<GeomDataAPI_Point2D> aPoint =
321 ////          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anAttrIt);
322 ////      if (aPoint && (!aPoint->textX().empty() || !aPoint->textY().empty())) {
323 ////        // Create new parametric constraint
324 ////        SolverConstraintPtr aConstraint =
325 ////            SketchSolver_Builder::getInstance()->createParametricConstraint(*anAttrIt);
326 ////        if (!aConstraint)
327 ////          continue;
328 ////        aConstraint->setGroup(this);
329 ////        aConstraint->setStorage(myStorage);
330 ////        myParametricConstraints[*anAttrIt] = aConstraint;
331 ////      }
332 ////    }
333 ////  }
334   return isUpdated;
335 }
336
337 void SketchSolver_Group::moveFeature(FeaturePtr theFeature)
338 {
339   BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
340
341   // Firstly, revert changes in the fixed entities
342   myStorage->refresh(true);
343
344   // Secondly, search attributes of the feature in the list of the Multi constraints and update them
345   ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
346   for (; aCIt != myConstraints.end(); ++aCIt) {
347     if ((aCIt->second->getType() == CONSTRAINT_MULTI_ROTATION ||
348          aCIt->second->getType() == CONSTRAINT_MULTI_TRANSLATION)
349         && aCIt->second->isUsed(theFeature))
350       std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIt->second)->update(true);
351   }
352
353   // Then, create temporary rigid constraint
354   SolverConstraintPtr aConstraint = aBuilder->createMovementConstraint(theFeature);
355   if (!aConstraint)
356     return;
357   aConstraint->process(myStorage, getId(), getWorkplaneId());
358   if (aConstraint->error().empty())
359     setTemporary(aConstraint);
360 }
361
362 // ============================================================================
363 //  Function: addWorkplane
364 //  Class:    SketchSolver_Group
365 //  Purpose:  create workplane for the group
366 // ============================================================================
367 bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch)
368 {
369   if (myWorkplaneID != EID_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID())
370     return false;  // the workplane already exists or the function parameter is not Sketch
371
372   mySketch = theSketch;
373   if (!updateWorkplane()) {
374     mySketch = CompositeFeaturePtr();
375     return false;
376   }
377   return true;
378 }
379
380 // ============================================================================
381 //  Function: updateWorkplane
382 //  Class:    SketchSolver_Group
383 //  Purpose:  update parameters of workplane
384 // ============================================================================
385 bool SketchSolver_Group::updateWorkplane()
386 {
387   BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
388   if (!myStorage) // Create storage if not exists
389     myStorage = aBuilder->createStorage(getId());
390
391   // sketch should be unchanged, set it out of current group
392   bool isUpdated = myStorage->update(FeaturePtr(mySketch), GID_OUTOFGROUP);
393   if (isUpdated) {
394     EntityWrapperPtr anEntity = myStorage->entity(FeaturePtr(mySketch));
395     myWorkplaneID = anEntity->id();
396   }
397   return isUpdated;
398 }
399
400 // ============================================================================
401 //  Function: resolveConstraints
402 //  Class:    SketchSolver_Group
403 //  Purpose:  solve the set of constraints for the current group
404 // ============================================================================
405 bool SketchSolver_Group::resolveConstraints()
406 {
407   if (!myChangedConstraints.empty())
408     updateConstraints();
409
410   bool aResolved = false;
411   bool isGroupEmpty = isEmpty();
412   if (myStorage->isNeedToResolve() && !isGroupEmpty) {
413     if (!mySketchSolver)
414       mySketchSolver = SketchSolver_Manager::instance()->builder()->createSolver();
415
416     mySketchSolver->setGroup(myID);
417     mySketchSolver->calculateFailedConstraints(false);
418     myStorage->initializeSolver(mySketchSolver);
419
420     SketchSolver_SolveStatus aResult = STATUS_OK;
421     try {
422       if (myStorage->hasDuplicatedConstraint())
423         aResult = STATUS_INCONSISTENT;
424       else {
425         // To avoid overconstraint situation, we will remove temporary constraints one-by-one
426         // and try to find the case without overconstraint
427         bool isLastChance = false;
428         size_t aNbTemp = myStorage->nbTemporary();
429         while (true) {
430           aResult = mySketchSolver->solve();
431           if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET || isLastChance)
432             break;
433           if (aNbTemp == 0) {
434             // try to update parameters and resolve once again
435             ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin();
436             for (; aConstrIt != myConstraints.end(); ++aConstrIt)
437               aConstrIt->second->update();
438             isLastChance = true;
439           } else
440             aNbTemp = myStorage->removeTemporary();
441           mySketchSolver->calculateFailedConstraints(true); // something failed => need to find it
442           myStorage->initializeSolver(mySketchSolver);
443         }
444       }
445     } catch (...) {
446 //      Events_Error::send(SketchSolver_Error::SOLVESPACE_CRASH(), this);
447       getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::SOLVESPACE_CRASH());
448       if (myPrevSolved) {
449         // the error message should be changed before sending the message
450         sendMessage(EVENT_SOLVER_FAILED);
451         myPrevSolved = false;
452       }
453       return false;
454     }
455     if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET) {  // solution succeeded, store results into correspondent attributes
456       myStorage->refresh();
457 ////      myFeatureStorage->blockEvents(true);
458 ////      // First refresh parametric constraints to satisfy parameters
459 ////      std::map<AttributePtr, SolverConstraintPtr>::iterator aParIter = myParametricConstraints.begin();
460 ////      for (; aParIter != myParametricConstraints.end(); ++aParIter)
461 ////        aParIter->second->refresh();
462 ////      // Update all other constraints
463 ////      ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
464 ////      for (; aConstrIter != myConstraints.end(); ++aConstrIter)
465 ////        aConstrIter->second->refresh();
466 ////      myFeatureStorage->blockEvents(false);
467       if (!myPrevSolved) {
468         getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue("");
469         // the error message should be changed before sending the message
470         sendMessage(EVENT_SOLVER_REPAIRED);
471         myPrevSolved = true;
472       }
473     } else if (!myConstraints.empty()) {
474 //      Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
475       getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::CONSTRAINTS());
476       if (myPrevSolved) {
477         // the error message should be changed before sending the message
478         sendMessage(EVENT_SOLVER_FAILED);
479         myPrevSolved = false;
480       }
481     }
482
483     aResolved = true;
484   } else if (!isGroupEmpty) {
485 ////    myFeatureStorage->blockEvents(true);
486     // Check there are constraints Fixed. If they exist, update parameters by stored values
487     ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
488     for (; aCIt != myConstraints.end(); ++aCIt)
489       if (aCIt->first->getKind() == SketchPlugin_ConstraintRigid::ID()) {
490 ////        aCIt->second->refresh();
491         aResolved = true;
492         break;
493       }
494 ////     myFeatureStorage->blockEvents(false);
495     if (aCIt != myConstraints.end())
496       myStorage->refresh();
497   }
498   removeTemporaryConstraints();
499   myStorage->setNeedToResolve(false);
500   return aResolved;
501 }
502
503 // ============================================================================
504 //  Function: mergeGroups
505 //  Class:    SketchSolver_Group
506 //  Purpose:  append specified group to the current group
507 // ============================================================================
508 void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
509 {
510   // If specified group is empty, no need to merge
511   if (theGroup.isEmpty())
512     return;
513
514   std::set<ObjectPtr> aConstraints;
515   ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
516   for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++)
517     aConstraints.insert(aConstrIter->first);
518
519   std::list<FeaturePtr> aSortedConstraints = selectApplicableFeatures(aConstraints);
520   std::list<FeaturePtr>::iterator aSCIter = aSortedConstraints.begin();
521   for (; aSCIter != aSortedConstraints.end(); ++aSCIter) {
522     ConstraintPtr aConstr = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aSCIter);
523     if (!aConstr)
524       continue;
525     changeConstraint(aConstr);
526   }
527 }
528
529 // ============================================================================
530 //  Function: splitGroup
531 //  Class:    SketchSolver_Group
532 //  Purpose:  divide the group into several subgroups
533 // ============================================================================
534 void SketchSolver_Group::splitGroup(std::list<SketchSolver_Group*>& theCuts)
535 {
536   // New storage will be used in trimmed way to store the list of constraint interacted together.
537   StoragePtr aNewStorage = SketchSolver_Manager::instance()->builder()->createStorage(getId());
538   std::list<ConstraintWrapperPtr> aDummyVec; // empty vector to avoid creation of solver's constraints
539
540   // Obtain constraints, which should be separated
541   std::list<ConstraintPtr> anUnusedConstraints;
542   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
543   for ( ; aCIter != myConstraints.end(); aCIter++) {
544     if (aNewStorage->isInteract(FeaturePtr(aCIter->first)))
545       aNewStorage->addConstraint(aCIter->first, aDummyVec);
546     else
547       anUnusedConstraints.push_back(aCIter->first);
548   }
549
550   // Check the unused constraints once again, because they may become interacted with new storage since adding constraints
551   std::list<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
552   while (aUnuseIt != anUnusedConstraints.end()) {
553     if (aNewStorage->isInteract(FeaturePtr(*aUnuseIt))) {
554       aNewStorage->addConstraint(*aUnuseIt, aDummyVec);
555       anUnusedConstraints.erase(aUnuseIt);
556       aUnuseIt = anUnusedConstraints.begin();
557       continue;
558     }
559     aUnuseIt++;
560   }
561
562   std::list<SketchSolver_Group*>::iterator aCutsIter;
563   aUnuseIt = anUnusedConstraints.begin();
564   for ( ; aUnuseIt != anUnusedConstraints.end(); ++aUnuseIt) {
565     // Remove unused constraints
566     removeConstraint(*aUnuseIt);
567     // Try to append constraint to already existent group
568     for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); ++aCutsIter)
569       if ((*aCutsIter)->isInteract(*aUnuseIt)) {
570         (*aCutsIter)->changeConstraint(*aUnuseIt);
571         break;
572       }
573     if (aCutsIter == theCuts.end()) {
574       // Add new group
575       SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch);
576       aGroup->changeConstraint(*aUnuseIt);
577       theCuts.push_back(aGroup);
578     } else {
579       // Find other groups interacting with constraint
580       std::list<SketchSolver_Group*>::iterator aBaseGroupIt = aCutsIter;
581       for (++aCutsIter; aCutsIter != theCuts.end(); ++aCutsIter)
582         if ((*aCutsIter)->isInteract(*aUnuseIt)) {
583           (*aBaseGroupIt)->mergeGroups(**aCutsIter);
584           std::list<SketchSolver_Group*>::iterator aRemoveIt = aCutsIter--;
585           theCuts.erase(aRemoveIt);
586         }
587     }
588   }
589 }
590
591 // ============================================================================
592 //  Function: isConsistent
593 //  Class:    SketchSolver_Group
594 //  Purpose:  search removed entities and constraints
595 // ============================================================================
596 bool SketchSolver_Group::isConsistent()
597 {
598   if (isEmpty()) // no one constraint is initialized yet
599     return true;
600
601   // Check the features and constraint is the storage are valid
602   bool aResult = myStorage->isConsistent();
603   if (aResult) {
604     // additional check of consistency of the Fixed constraint,
605     // because they are not added to the storage
606     ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
607     for (; aCIter != myConstraints.end(); ++aCIter)
608       if (aCIter->first->getKind() == SketchPlugin_ConstraintRigid::ID() &&
609          (!aCIter->first->data() || !aCIter->first->data()->isValid())) {
610         aResult = false;
611         break;
612       }
613   }
614   if (!aResult) {
615     // remove invalid constraints
616     std::set<ConstraintPtr> anInvalidConstraints;
617     ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
618     for (; aCIter != myConstraints.end(); ++aCIter) {
619       if (!aCIter->first->data() || !aCIter->first->data()->isValid())
620         anInvalidConstraints.insert(aCIter->first);
621     }
622     std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
623     for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
624       removeConstraint(*aRemoveIt);
625     // remove invalid features
626     myStorage->removeInvalidEntities();
627   }
628   return aResult;
629 }
630
631 // ============================================================================
632 //  Function: removeTemporaryConstraints
633 //  Class:    SketchSolver_Group
634 //  Purpose:  remove all transient SLVS_C_WHERE_DRAGGED constraints after
635 //            resolving the set of constraints
636 // ============================================================================
637 void SketchSolver_Group::removeTemporaryConstraints()
638 {
639   std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
640   for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
641     (*aTmpIt)->remove();
642
643   size_t aNbTemp = myStorage->nbTemporary();
644   if (aNbTemp > 0)
645     myStorage->removeTemporary(aNbTemp);
646 ////  // Clean lists of removed entities in the storage
647 ////  std::set<Slvs_hParam> aRemPar;
648 ////  std::set<Slvs_hEntity> aRemEnt;
649 ////  std::set<Slvs_hConstraint> aRemCon;
650 ////  myStorage->getRemoved(aRemPar, aRemEnt, aRemCon);
651
652   if (!myTempConstraints.empty())
653     myStorage->verifyFixed();
654   myStorage->setNeedToResolve(false);
655   myTempConstraints.clear();
656 }
657
658 // ============================================================================
659 //  Function: removeConstraint
660 //  Class:    SketchSolver_Group
661 //  Purpose:  remove constraint and all unused entities
662 // ============================================================================
663 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
664 {
665   bool isFullyRemoved = true;
666   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
667   for (; aCIter != myConstraints.end(); aCIter++)
668     if (aCIter->first == theConstraint) {
669       if (!aCIter->second->remove()) // the constraint is not fully removed
670         isFullyRemoved = false;
671       break;
672     }
673   if (aCIter == myConstraints.end())
674     return;
675
676 ////  // Remove entities not used by constraints
677 ////  myStorage->removeUnusedEntities();
678
679   if (isFullyRemoved)
680     myConstraints.erase(aCIter);
681   else if (aCIter != myConstraints.end() &&
682            aCIter->first->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
683     // Update multicoincidence
684     std::list<ConstraintPtr> aMultiCoinc;
685     SolverConstraintPtr aCoincidence = aCIter->second;
686     while (aCIter != myConstraints.end()) {
687       if (aCIter->second != aCoincidence) {
688         ++aCIter;
689         continue;
690       }
691       if (aCIter->first != theConstraint)
692         aMultiCoinc.push_back(aCIter->first);
693       aCIter->second->remove();
694       ConstraintConstraintMap::iterator aRemoveIt = aCIter++;
695       myConstraints.erase(aRemoveIt);
696     }
697
698     std::list<ConstraintPtr>::iterator anIt = aMultiCoinc.begin();
699     for (; anIt != aMultiCoinc.end(); ++anIt)
700       changeConstraint(*anIt);
701
702     notifyMultiConstraints();
703   }
704 }
705
706 // ============================================================================
707 //  Function: isComplexConstraint
708 //  Class:    SketchSolver_Group
709 //  Purpose:  verifies the constraint is complex, i.e. it needs another constraints to be created before
710 // ============================================================================
711 bool SketchSolver_Group::isComplexConstraint(FeaturePtr theConstraint)
712 {
713   return theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID() ||
714          theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID() ||
715          theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID();
716 }
717
718 // ============================================================================
719 //  Function: setTemporary
720 //  Class:    SketchSolver_Group
721 //  Purpose:  append given constraint to the group of temporary constraints
722 // ============================================================================
723 void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
724 {
725   theConstraint->makeTemporary();
726   myTempConstraints.insert(theConstraint);
727 }
728
729
730 // ============================================================================
731 //  Function: checkFeatureValidity
732 //  Class:    SketchSolver_Group
733 //  Purpose:  verifies is the feature valid
734 // ============================================================================
735 bool SketchSolver_Group::checkFeatureValidity(FeaturePtr theFeature)
736 {
737   if (!theFeature || !theFeature->data()->isValid())
738     return true;
739
740   SessionPtr aMgr = ModelAPI_Session::get();
741   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
742   return aFactory->validate(theFeature);
743 }
744
745 // ============================================================================
746 //  Function: notifyMultiConstraints
747 //  Class:    SketchSolver_Group
748 //  Purpose:  Update Multi-Translation/-Rotation constraints due to multi coincidence appears/disappears
749 // ============================================================================
750 void SketchSolver_Group::notifyMultiConstraints()
751 {
752 ////  ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
753 ////  for (; aCIter != myConstraints.end(); ++aCIter) {
754 ////    if (aCIter->first->getKind() == SketchPlugin_MultiRotation::ID() ||
755 ////        aCIter->first->getKind() == SketchPlugin_MultiTranslation::ID()) {
756 ////      std::shared_ptr<SketchSolver_ConstraintMulti> aMulti = 
757 ////          std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIter->second);
758 ////      aMulti->checkCoincidence();
759 ////    }
760 ////  }
761 }
762
763
764
765
766 // ===========   Auxiliary functions   ========================================
767 static double featureToVal(FeaturePtr theFeature)
768 {
769   if (theFeature->getKind() == SketchPlugin_Sketch::ID())
770     return 0.0; // sketch
771   ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
772   if (!aConstraint)
773     return 1.0; // features (arc, circle, line, point)
774
775   const std::string& anID = aConstraint->getKind();
776   if (anID == SketchPlugin_ConstraintCoincidence::ID()) {
777     AttributeRefAttrPtr anAttrA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
778         aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
779     AttributeRefAttrPtr anAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
780         aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
781     if (anAttrA && anAttrB && (anAttrA->isObject() || anAttrB->isObject()))
782       return 2.0; // point-on-line and point-on-circle should go before points coincidence constraint
783     return 2.5;
784   }
785   if (anID == SketchPlugin_ConstraintDistance::ID() ||
786       anID == SketchPlugin_ConstraintLength::ID() ||
787       anID == SketchPlugin_ConstraintRadius::ID())
788     return 3.0;
789   if (anID == SketchPlugin_ConstraintAngle::ID())
790     return 3.5;
791   if (anID == SketchPlugin_ConstraintHorizontal::ID() ||
792       anID == SketchPlugin_ConstraintVertical::ID() ||
793       anID == SketchPlugin_ConstraintParallel::ID() ||
794       anID == SketchPlugin_ConstraintPerpendicular::ID())
795     return 4.0;
796   if (anID == SketchPlugin_ConstraintEqual::ID())
797     return 5.0;
798   if (anID == SketchPlugin_ConstraintTangent::ID() ||
799       anID == SketchPlugin_ConstraintMirror::ID())
800     return 6.0;
801   if (anID == SketchPlugin_ConstraintRigid::ID())
802     return 7.0;
803   if (anID == SketchPlugin_MultiRotation::ID() ||
804       anID == SketchPlugin_MultiTranslation::ID())
805     return 8.0;
806
807   // all other constraints are placed between Equal and Tangent constraints
808   return 5.5;
809 }
810
811 static bool isLess(FeaturePtr theFeature1, FeaturePtr theFeature2)
812 {
813   return featureToVal(theFeature1) < featureToVal(theFeature2);
814 }
815
816 std::list<FeaturePtr> SketchSolver_Group::selectApplicableFeatures(const std::set<ObjectPtr>& theObjects)
817 {
818   std::list<FeaturePtr> aResult;
819   std::list<FeaturePtr>::iterator aResIt;
820
821   std::set<ObjectPtr>::const_iterator anObjIter = theObjects.begin();
822   for (; anObjIter != theObjects.end(); ++anObjIter) {
823     // Operate sketch itself and SketchPlugin features only.
824     // Also, the Fillet need to be skipped, because there are several separated constraints composing it.
825     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIter);
826     if (!aFeature)
827       continue;
828     std::shared_ptr<SketchPlugin_Feature> aSketchFeature = 
829         std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
830     if ((aFeature->getKind() != SketchPlugin_Sketch::ID() && !aSketchFeature) ||
831         aFeature->getKind() == SketchPlugin_ConstraintFillet::ID())
832       continue;
833
834     // Find the place where to insert a feature
835     for (aResIt = aResult.begin(); aResIt != aResult.end(); ++aResIt)
836       if (isLess(aFeature, *aResIt))
837         break;
838     aResult.insert(aResIt, aFeature);
839   }
840
841   return aResult;
842 }
843