]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SketchSolver_ConstraintGroup.cpp
Salome HOME
Merge branch 'Dev_1.1.0' of newgeom:newgeom into Dev_1.1.0
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintGroup.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    SketchSolver_ConstraintGroup.cpp
4 // Created: 27 May 2014
5 // Author:  Artem ZHIDKOV
6
7 #include "SketchSolver_ConstraintGroup.h"
8
9 #include <SketchSolver_Constraint.h>
10
11 #include <Events_Error.h>
12 #include <Events_Loop.h>
13 #include <GeomAPI_XY.h>
14 #include <GeomAPI_Pnt2d.h>
15 #include <GeomDataAPI_Dir.h>
16 #include <GeomDataAPI_Point.h>
17 #include <GeomDataAPI_Point2D.h>
18 #include <ModelAPI_AttributeDouble.h>
19 #include <ModelAPI_AttributeRefList.h>
20 #include <ModelAPI_Document.h>
21 #include <ModelAPI_Events.h>
22 #include <ModelAPI_ResultConstruction.h>
23
24 #include <SketchPlugin_Constraint.h>
25 #include <SketchPlugin_ConstraintLength.h>
26 #include <SketchPlugin_ConstraintCoincidence.h>
27 #include <SketchPlugin_ConstraintRigid.h>
28
29 #include <SketchPlugin_Arc.h>
30 #include <SketchPlugin_Circle.h>
31 #include <SketchPlugin_Line.h>
32 #include <SketchPlugin_Point.h>
33 #include <SketchPlugin_Sketch.h>
34
35 #include <math.h>
36 #include <assert.h>
37
38 /// Tolerance for value of parameters
39 const double tolerance = 1.e-10;
40
41 /**
42  * Collects all sketch solver error' codes
43  * as inline static functions
44  */
45  // TODO: Move this class into a separate file
46 class SketchSolver_Error
47 {
48  public:
49   /// The value parameter for the constraint
50   inline static const std::string& CONSTRAINTS()
51   {
52     static const std::string MY_ERROR_VALUE("Conflicting constraints");
53     return MY_ERROR_VALUE;
54   }
55   /// The entities need to have shared point, but they have not
56   inline static const std::string& NO_COINCIDENT_POINTS()
57   {
58     static const std::string MY_ERROR_VALUE("Objects should have coincident point");
59     return MY_ERROR_VALUE;
60   }
61 };
62
63 /// This value is used to give unique index to the groups
64 static Slvs_hGroup myGroupIndexer = 0;
65
66 /** \brief Search the entity/parameter with specified ID in the list of elements
67  *  \param[in] theEntityID unique ID of the element
68  *  \param[in] theEntities list of elements
69  *  \return position of the found element or -1 if the element is not found
70  */
71 template<typename T>
72 static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
73
74 // ========================================================
75 // =========  SketchSolver_ConstraintGroup  ===============
76 // ========================================================
77
78 SketchSolver_ConstraintGroup::SketchSolver_ConstraintGroup(
79     std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
80     : myID(++myGroupIndexer),
81       myParamMaxID(0),
82       myEntityMaxID(0),
83       myConstrMaxID(0),
84       myConstraintMap(),
85       myNeedToSolve(false),
86       myConstrSolver()
87 {
88   myParams.clear();
89   myEntities.clear();
90   myEntOfConstr.clear();
91   myConstraints.clear();
92
93   myTempConstraints.clear();
94   myTempPointWhereDragged.clear();
95   myTempPointWDrgdID = 0;
96
97   // Initialize workplane
98   myWorkplane.h = SLVS_E_UNKNOWN;
99 #ifndef NDEBUG
100   assert(addWorkplane(theWorkplane));
101 #else
102   addWorkplane(theWorkplane);
103 #endif
104 }
105
106 SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
107 {
108   myParams.clear();
109   myEntities.clear();
110   myEntOfConstr.clear();
111   myConstraints.clear();
112   myConstraintMap.clear();
113   myTempConstraints.clear();
114   myTempPointWhereDragged.clear();
115
116   // If the group with maximal identifier is deleted, decrease the indexer
117   if (myID == myGroupIndexer)
118     myGroupIndexer--;
119 }
120
121 // ============================================================================
122 //  Function: isBaseWorkplane
123 //  Class:    SketchSolver_ConstraintGroup
124 //  Purpose:  verify the group is based on the given workplane
125 // ============================================================================
126 bool SketchSolver_ConstraintGroup::isBaseWorkplane(
127     std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane) const
128 {
129   return theWorkplane == mySketch;
130 }
131
132 // ============================================================================
133 //  Function: isInteract
134 //  Class:    SketchSolver_ConstraintGroup
135 //  Purpose:  verify are there any entities in the group used by given constraint
136 // ============================================================================
137 bool SketchSolver_ConstraintGroup::isInteract(
138     std::shared_ptr<SketchPlugin_Feature> theFeature) const
139 {
140   // Check the group is empty
141   if (isEmpty())
142     return true;
143
144   // Check if the feature is already in the group
145   if (myEntityFeatMap.find(theFeature) != myEntityFeatMap.end())
146     return true;
147   std::shared_ptr<SketchPlugin_Constraint> aConstr =
148       std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
149   if (aConstr && myConstraintMap.find(aConstr) != myConstraintMap.end())
150     return true;
151
152   // Go through the attributes and verify if some of them already in the group
153   std::list<std::shared_ptr<ModelAPI_Attribute>> 
154       anAttrList = theFeature->data()->attributes(std::string());
155   std::list<std::shared_ptr<ModelAPI_Attribute>>::const_iterator
156       anAttrIter = anAttrList.begin();
157   for ( ; anAttrIter != anAttrList.end(); anAttrIter++) {
158     std::shared_ptr<ModelAPI_AttributeRefAttr> aCAttrRef =
159         std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
160     if (!aCAttrRef || !aCAttrRef->isObject()) {
161       std::shared_ptr<ModelAPI_Attribute> anAttr = 
162           aCAttrRef ? aCAttrRef->attr() : *anAttrIter;
163       if (myEntityAttrMap.find(anAttr) != myEntityAttrMap.end())
164         return true;
165     } else {
166       ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
167           aCAttrRef->object());
168       if (!aRC)
169         continue;
170       std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
171       FeaturePtr aFeature = aDoc->feature(aRC);
172       if (myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
173         return true;
174       // search attributes of a feature to be parameters of constraint
175       std::list<std::shared_ptr<ModelAPI_Attribute> > aFeatAttrList =
176           aFeature->data()->attributes(std::string());
177       std::list<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aFAIter = aFeatAttrList
178           .begin();
179       for (; aFAIter != aFeatAttrList.end(); aFAIter++)
180         if (myEntityAttrMap.find(*aFAIter) != myEntityAttrMap.end())
181           return true;
182     }
183   }
184
185   // Entities did not found
186   return false;
187 }
188
189 // ============================================================================
190 //  Function: checkConstraintConsistence
191 //  Class:    SketchSolver_ConstraintGroup
192 //  Purpose:  verifies and changes parameters of the constraint
193 // ============================================================================
194 void SketchSolver_ConstraintGroup::checkConstraintConsistence(Slvs_Constraint& theConstraint)
195 {
196   if (theConstraint.type == SLVS_C_PT_LINE_DISTANCE) {
197     // Get constraint parameters and check the sign of constraint value
198
199     // point coordinates
200     int aPtPos = Search(theConstraint.ptA, myEntities);
201     int aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
202     std::shared_ptr<GeomAPI_XY> aPoint(
203         new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
204
205     // line coordinates
206     int aLnPos = Search(theConstraint.entityA, myEntities);
207     aPtPos = Search(myEntities[aLnPos].point[0], myEntities);
208     aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
209     std::shared_ptr<GeomAPI_XY> aStart(
210         new GeomAPI_XY(-myParams[aPtParamPos].val, -myParams[aPtParamPos + 1].val));
211     aPtPos = Search(myEntities[aLnPos].point[1], myEntities);
212     aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
213     std::shared_ptr<GeomAPI_XY> aEnd(
214         new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
215
216     aEnd = aEnd->added(aStart);
217     aPoint = aPoint->added(aStart);
218     if (aPoint->cross(aEnd) * theConstraint.valA < 0.0)
219       theConstraint.valA *= -1.0;
220   }
221 }
222
223 // ============================================================================
224 //  Function: changeConstraint
225 //  Class:    SketchSolver_ConstraintGroup
226 //  Purpose:  create/update the constraint in the group
227 // ============================================================================
228 bool SketchSolver_ConstraintGroup::changeConstraint(
229     std::shared_ptr<SketchPlugin_Constraint> theConstraint)
230 {
231   // There is no workplane yet, something wrong
232   if (myWorkplane.h == SLVS_E_UNKNOWN)
233     return false;
234
235   if (theConstraint && theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID())
236     return changeRigidConstraint(theConstraint);
237
238   // Search this constraint in the current group to update it
239   ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
240   std::vector<Slvs_Constraint>::iterator aConstrIter;
241   if (aConstrMapIter != myConstraintMap.end()) {
242     int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
243     aConstrIter = myConstraints.begin() + aConstrPos;
244   }
245
246   // Get constraint type and verify the constraint parameters are correct
247   SketchSolver_Constraint aConstraint(theConstraint);
248   int aConstrType = aConstraint.getType();
249   if (aConstrType == SLVS_C_UNKNOWN
250       || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
251     return false;
252   const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
253
254   // Create constraint parameters
255   double aDistance = 0.0;  // scalar value of the constraint
256   AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
257       theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE()));
258   if (aDistAttr) {
259     aDistance = aDistAttr->value();
260     // Issue #196: checking the positivity of the distance constraint
261     if (aDistance < tolerance &&
262        (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE))
263       return false;
264     // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
265     if (aConstrType == SLVS_C_DIAMETER)
266       aDistance *= 2.0;
267     if (aConstrMapIter != myConstraintMap.end()
268         && fabs(aConstrIter->valA - aDistance) > tolerance) {
269       myNeedToSolve = true;
270       aConstrIter->valA = aDistance;
271     }
272   }
273
274   size_t aNbTmpConstraints = myTempConstraints.size();
275   Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE];  // parameters of the constraint
276   for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
277     aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
278     std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
279         ModelAPI_AttributeRefAttr>(
280         theConstraint->data()->attribute(aConstraintAttributes[indAttr]));
281     if (!aConstrAttr)
282       continue;
283
284     // Convert the object of the attribute to the feature
285     FeaturePtr aFeature;
286     if (aConstrAttr->isObject() && aConstrAttr->object()) {
287       ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
288           aConstrAttr->object());
289       if (!aRC)
290         continue;
291       std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
292       aFeature = aDoc->feature(aRC);
293     }
294
295     // For the length constraint the start and end points of the line should be added to the entities list instead of line
296     if (aConstrType == SLVS_C_PT_PT_DISTANCE
297         && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0) {
298       Slvs_hEntity aLineEnt = changeEntityFeature(aFeature);
299       int aEntPos = Search(aLineEnt, myEntities);
300       aConstrEnt[indAttr++] = myEntities[aEntPos].point[0];
301       aConstrEnt[indAttr++] = myEntities[aEntPos].point[1];
302       while (indAttr < CONSTRAINT_ATTR_SIZE)
303         aConstrEnt[indAttr++] = 0;
304       break;  // there should be no other entities
305     } else if (aConstrAttr->isObject())
306       aConstrEnt[indAttr] = changeEntityFeature(aFeature);
307     else
308       aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
309   }
310
311   if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
312     // Several points may be coincident, it is not necessary to store all constraints between them.
313     // Try to find sequence of coincident points which connects the points of new constraint
314     if (aConstrType == SLVS_C_POINTS_COINCIDENT) {
315       if (aConstrEnt[0] == aConstrEnt[1])  // no need to add self coincidence
316         return false;
317       if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) {
318         myExtraCoincidence.insert(theConstraint);  // the constraint is stored for further purposes
319         return false;
320       }
321       if (aNbTmpConstraints < myTempConstraints.size()) {
322         // There was added temporary constraint. Check that there is no coincident points which already rigid.
323
324         // Get list of already fixed points
325         std::set<Slvs_hEntity> anAlreadyFixed;
326         std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
327         for (; aCIter != myConstraints.end(); aCIter++)
328           if (aCIter->type == SLVS_C_WHERE_DRAGGED) {
329             std::list<Slvs_hConstraint>::const_iterator aTmpIt = myTempConstraints.begin();
330             for (; aTmpIt != myTempConstraints.end(); aTmpIt++)
331               if (*aTmpIt == aCIter->h)
332                 break;
333             if (aTmpIt == myTempConstraints.end())
334               anAlreadyFixed.insert(aCIter->ptA);
335           }
336
337         std::set<Slvs_hConstraint> aTmpConstrToDelete;
338         std::list<Slvs_hConstraint>::reverse_iterator aTmpIter = myTempConstraints.rbegin();
339         size_t aCurSize = myTempConstraints.size();
340         for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend();
341             aTmpIter++, aCurSize--) {
342           int aConstrPos = Search(*aTmpIter, myConstraints);
343           std::vector<std::set<Slvs_hEntity> >::const_iterator
344             aCoincIter = myCoincidentPoints.begin();
345           for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
346             if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) {
347               std::set<Slvs_hEntity>::const_iterator anIt;
348               for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++)
349                 if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) {
350                   aTmpConstrToDelete.insert(*aTmpIter);
351                   break;
352                 }
353               break;
354             }
355         }
356         if (!aTmpConstrToDelete.empty())
357           removeTemporaryConstraints(aTmpConstrToDelete);
358       }
359     }
360     // For the tangency constraints it is necessary to identify which points of entities are coincident
361     int aSlvsOtherFlag = 0;
362     int aSlvsOther2Flag = 0;
363     if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) {
364       // Search entities used by constraint
365       int anEnt1Pos = Search(aConstrEnt[2], myEntities);
366       int anEnt2Pos = Search(aConstrEnt[3], myEntities);
367       // Obtain start and end points of entities
368       Slvs_hEntity aPointsToFind[4];
369       aPointsToFind[0] = myEntities[anEnt1Pos].point[1];
370       aPointsToFind[1]= myEntities[anEnt1Pos].point[2];
371       bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT);
372       aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1];
373       aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2];
374       // Search coincident points
375       bool isPointFound[4];
376       std::vector<std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
377       for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) {
378         for (int i = 0; i < 4; i++)
379           isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end());
380         if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) {
381           // the arc is tangent by end point
382           if (isPointFound[1]) aSlvsOtherFlag = 1;
383           // the second item is an arc and it is tangent by end point too
384           if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1;
385           break;
386         }
387       }
388       if (aCPIter == myCoincidentPoints.end()) {
389         // There is no coincident points between tangential objects. Generate error message
390         Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
391         return false;
392       }
393     }
394
395     // Create SolveSpace constraint structure
396     Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
397                                                       myWorkplane.h, aDistance, aConstrEnt[0],
398                                                       aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
399     if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag;
400     if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag;
401     myConstraints.push_back(aSlvsConstr);
402     myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aSlvsConstr.h);
403     int aConstrPos = Search(aSlvsConstr.h, myConstraints);
404     aConstrIter = myConstraints.begin() + aConstrPos;
405     myNeedToSolve = true;
406   } else { // Attributes of constraint may be changed => update constraint
407     Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB,
408                                    &aConstrIter->entityA, &aConstrIter->entityB,
409                                    &aConstrIter->entityC, &aConstrIter->entityD};
410     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
411       if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr])
412       {
413         *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr];
414         myNeedToSolve = true;
415       }
416     }
417   }
418
419   // Update flags of entities to be used by constraints
420   for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
421     if (aConstrEnt[indAttr] != 0) {
422       int aPos = Search(aConstrEnt[indAttr], myEntities);
423       myEntOfConstr[aPos] = true;
424       // Sub-entities should be used implcitly
425       Slvs_hEntity* aEntPtr = myEntities[aPos].point;
426       while (*aEntPtr != 0) {
427         aPos = Search(*aEntPtr, myEntities);
428         myEntOfConstr[aPos] = true;
429         aEntPtr++;
430       }
431     }
432
433   checkConstraintConsistence(*aConstrIter);
434   return true;
435 }
436
437 // ============================================================================
438 //  Function: changeRigidConstraint
439 //  Class:    SketchSolver_ConstraintGroup
440 //  Purpose:  create/update the "Rigid" constraint in the group
441 // ============================================================================
442 bool SketchSolver_ConstraintGroup::changeRigidConstraint(
443     std::shared_ptr<SketchPlugin_Constraint> theConstraint)
444 {
445   // Search this constraint in the current group to update it
446   ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
447   std::vector<Slvs_Constraint>::iterator aConstrIter;
448   if (aConstrMapIter != myConstraintMap.end()) {
449     int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
450     aConstrIter = myConstraints.begin() + aConstrPos;
451   }
452
453   // Get constraint type and verify the constraint parameters are correct
454   SketchSolver_Constraint aConstraint(theConstraint);
455   int aConstrType = aConstraint.getType();
456   if (aConstrType == SLVS_C_UNKNOWN
457       || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
458     return false;
459   const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
460
461   Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN;
462   std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
463       ModelAPI_AttributeRefAttr>(
464       theConstraint->data()->attribute(aConstraintAttributes[0]));
465   if (!aConstrAttr)
466     return false;
467
468   // Convert the object of the attribute to the feature
469   FeaturePtr aFeature;
470   if (aConstrAttr->isObject() && aConstrAttr->object()) {
471     ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
472         aConstrAttr->object());
473     if (!aRC)
474       return false;
475     std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
476     aFeature = aDoc->feature(aRC);
477   }
478
479   aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr());
480
481   if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
482     // Check the fixed entity is not a point.
483     std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
484         ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0]));
485     std::shared_ptr<GeomDataAPI_Point> aPoint =
486         std::dynamic_pointer_cast<GeomDataAPI_Point>(aConstrAttr->attr());
487     std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
488         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aConstrAttr->attr());
489     if (aPoint || aPoint2D) {
490       // Create SolveSpace constraint structure
491       Slvs_Constraint aConstraint = Slvs_MakeConstraint(
492           ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
493           aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
494       myConstraints.push_back(aConstraint);
495       myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aConstraint.h);
496       int aConstrPos = Search(aConstraint.h, myConstraints);
497       aConstrIter = myConstraints.begin() + aConstrPos;
498       myNeedToSolve = true;
499     } else {
500       myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>();
501
502       // To avoid SolveSpace problems:
503       // * if the circle is rigid, we will fix its center and radius;
504       // * if the arc is rigid, we will fix its start and end points and radius.
505       double aRadius = 0.0;
506       bool isArc = false;
507       bool isCircle = false;
508       if (aFeature) {
509         if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
510           std::shared_ptr<GeomDataAPI_Point2D> aCenter =
511               std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
512               aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
513           std::shared_ptr<GeomDataAPI_Point2D> aStart =
514               std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
515               aFeature->data()->attribute(SketchPlugin_Arc::START_ID()));
516           aRadius = aStart->pnt()->distance(aCenter->pnt());
517           isArc = true;
518         } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
519           aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
520               aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
521           isCircle = true;
522         }
523       }
524
525       // Get list of already fixed points
526       std::set<Slvs_hEntity> anAlreadyFixed;
527       std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
528       for (; aCIter != myConstraints.end(); aCIter++)
529         if (aCIter->type == SLVS_C_WHERE_DRAGGED)
530           anAlreadyFixed.insert(aCIter->ptA);
531
532       // Create constraints to fix the parameters of the entity
533       int aEntPos = Search(aConstrEnt, myEntities);
534       Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point;
535       if (isArc) aPointsPtr++; // avoid to fix center of arc
536       while (*aPointsPtr != 0) {
537         // Avoid to create additional "Rigid" constraints for coincident points
538         bool isCoincAlreadyFixed = false;
539         if (!anAlreadyFixed.empty()) {
540           if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end())
541             isCoincAlreadyFixed = true;
542
543           std::vector<std::set<Slvs_hEntity> >::const_iterator aCoincIter =
544               myCoincidentPoints.begin();
545           for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) {
546             if (aCoincIter->find(*aPointsPtr) == aCoincIter->end())
547               continue;
548             std::set<Slvs_hEntity>::const_iterator anIter = anAlreadyFixed.begin();
549             for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++)
550               if (aCoincIter->find(*anIter) != aCoincIter->end())
551                 isCoincAlreadyFixed = true;
552           }
553         }
554
555         if (!isCoincAlreadyFixed) {
556           Slvs_Constraint aConstraint = Slvs_MakeConstraint(
557               ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
558               *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
559           myConstraints.push_back(aConstraint);
560           myConstraintMap[theConstraint].push_back(aConstraint.h);
561         }
562         aPointsPtr++;
563       }
564
565       if (isArc || isCircle) { // add radius constraint
566         Slvs_Constraint aConstraint = Slvs_MakeConstraint(
567             ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius,
568             SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN);
569         myConstraints.push_back(aConstraint);
570         myConstraintMap[theConstraint].push_back(aConstraint.h);
571       }
572
573       // The object is already rigid, so there is no constraints added
574       if (myConstraintMap[theConstraint].empty()) {
575         myConstraintMap.erase(theConstraint);
576         myNeedToSolve = false;
577       }
578       else
579         myNeedToSolve = true;
580     }
581   }
582   return true;
583 }
584
585 // ============================================================================
586 //  Function: changeEntity
587 //  Class:    SketchSolver_ConstraintGroup
588 //  Purpose:  create/update the element affected by any constraint
589 // ============================================================================
590 Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
591     std::shared_ptr<ModelAPI_Attribute> theEntity)
592 {
593   // If the entity is already in the group, try to find it
594   std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
595       myEntityAttrMap.find(theEntity);
596   int aEntPos;
597   std::vector<Slvs_Param>::const_iterator aParamIter;  // looks at first parameter of already existent entity or at the end of vector otherwise
598   if (aEntIter == myEntityAttrMap.end())  // no such entity => should be created
599     aParamIter = myParams.end();
600   else {  // the entity already exists
601     aEntPos = Search(aEntIter->second, myEntities);
602     int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
603     aParamIter = myParams.begin() + aParamPos;
604   }
605   const bool isEntExists = (aEntIter != myEntityAttrMap.end());  // defines that the entity already exists
606   const bool isNeedToSolve = myNeedToSolve;
607   myNeedToSolve = false;
608
609   if (isEntExists) {
610     // Verify that the entity is not used by "Rigid" constraint.
611     // If it is used, the object should not move.
612     std::vector<std::set<Slvs_hEntity> >::iterator aCoincIter = myCoincidentPoints.begin();
613     for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
614       if (aCoincIter->find(aEntIter->second) != aCoincIter->end())
615         break;
616     std::set<Slvs_hEntity> aCoincident;
617     if (aCoincIter != myCoincidentPoints.end()) {
618       aCoincident = *aCoincIter;
619       aCoincident.erase(aEntIter->second);
620
621       std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
622       for (; aConstrIter != myConstraints.end(); aConstrIter++)
623         if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
624             aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
625           myNeedToSolve = true;
626           return aEntIter->second;
627         }
628     }
629   }
630
631   // Look over supported types of entities
632   Slvs_Entity aNewEntity;
633   aNewEntity.h = SLVS_E_UNKNOWN;
634
635   // Point in 3D
636   std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
637       theEntity);
638   if (aPoint) {
639     Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
640     Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
641     Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
642     if (!isEntExists) // New entity
643       aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
644   } else {
645     // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
646     if (myWorkplane.h == SLVS_E_UNKNOWN)
647       return SLVS_E_UNKNOWN;
648
649     // Point in 2D
650     std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
651         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
652     if (aPoint2D) {
653       Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
654       Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
655       if (!isEntExists) // New entity
656         aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
657     } else {
658       // Scalar value (used for the distance entities)
659       AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
660       if (aScalar) {
661         Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
662         if (!isEntExists) // New entity
663           aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
664       }
665     }
666   }
667   /// \todo Other types of entities
668
669   Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type
670
671   if (isEntExists) {
672     myNeedToSolve = myNeedToSolve || isNeedToSolve;
673     aResult = aEntIter->second;
674   } else if (aNewEntity.h != SLVS_E_UNKNOWN) {
675     myEntities.push_back(aNewEntity);
676     myEntOfConstr.push_back(false);
677     myEntityAttrMap[theEntity] = aNewEntity.h;
678     aResult = aNewEntity.h;
679   }
680
681   // If the attribute was changed by the user, we need to fix it before solving
682   if (myNeedToSolve && theEntity->isImmutable())
683     addTemporaryConstraintWhereDragged(theEntity, false);
684
685   return aResult;
686 }
687
688 // ============================================================================
689 //  Function: changeEntity
690 //  Class:    SketchSolver_ConstraintGroup
691 //  Purpose:  create/update the element defined by the feature affected by any constraint
692 // ============================================================================
693 Slvs_hEntity SketchSolver_ConstraintGroup::changeEntityFeature(FeaturePtr theEntity)
694 {
695   if (!theEntity->data()->isValid())
696     return SLVS_E_UNKNOWN;
697   // If the entity is already in the group, try to find it
698   std::map<FeaturePtr, Slvs_hEntity>::const_iterator aEntIter = myEntityFeatMap.find(theEntity);
699   // defines that the entity already exists
700   const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
701   
702   Slvs_Entity aNewEntity;
703   aNewEntity.h = SLVS_E_UNKNOWN;
704
705   // SketchPlugin features
706   std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
707       SketchPlugin_Feature>(theEntity);
708   if (aFeature) {  // Verify the feature by its kind
709     const std::string& aFeatureKind = aFeature->getKind();
710     AttributePtr anAttribute;
711
712     // Line
713     if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
714       anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
715       if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
716       Slvs_hEntity aStart = changeEntity(anAttribute);
717
718       anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
719       if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
720       Slvs_hEntity aEnd = changeEntity(anAttribute);
721
722       if (!isEntExists) // New entity
723         aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
724     }
725     // Circle
726     else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
727       anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
728       if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
729       Slvs_hEntity aCenter = changeEntity(anAttribute);
730
731       anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
732       if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
733       Slvs_hEntity aRadius = changeEntity(anAttribute);
734
735       if (!isEntExists) // New entity
736         aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter,
737                                      myWorkplane.normal, aRadius);
738     }
739     // Arc
740     else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
741       anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
742       if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
743       Slvs_hEntity aCenter = changeEntity(anAttribute);
744
745       anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
746       if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
747       Slvs_hEntity aStart = changeEntity(anAttribute);
748
749       anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
750       if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
751       Slvs_hEntity aEnd = changeEntity(anAttribute);
752
753       if (!isEntExists)
754         aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h,
755                                           myWorkplane.normal, aCenter, aStart, aEnd);
756     }
757     // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
758     else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) {
759       anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
760       if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
761       Slvs_hEntity aPoint = changeEntity(anAttribute);
762
763       if (isEntExists)
764         return aEntIter->second;
765
766       // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
767       myEntityFeatMap[theEntity] = aPoint;
768       myNeedToSolve = true;
769       return aPoint;
770     }
771   }
772   /// \todo Other types of features
773
774   if (isEntExists)
775     return aEntIter->second;
776
777   if (aNewEntity.h != SLVS_E_UNKNOWN) {
778     myEntities.push_back(aNewEntity);
779     myEntOfConstr.push_back(false);
780     myEntityFeatMap[theEntity] = aNewEntity.h;
781     myNeedToSolve = true;
782     return aNewEntity.h;
783   }
784
785   // Unsupported or wrong entity type
786   return SLVS_E_UNKNOWN;
787 }
788
789 // ============================================================================
790 //  Function: changeNormal
791 //  Class:    SketchSolver_ConstraintGroup
792 //  Purpose:  create/update the normal of workplane
793 // ============================================================================
794 Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal(
795     std::shared_ptr<ModelAPI_Attribute> theDirX, std::shared_ptr<ModelAPI_Attribute> theDirY,
796     std::shared_ptr<ModelAPI_Attribute> theNorm)
797 {
798   std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
799   std::shared_ptr<GeomDataAPI_Dir> aDirY = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirY);
800   if (!aDirX || !aDirY || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance)
801       || (fabs(aDirY->x()) + fabs(aDirY->y()) + fabs(aDirY->z()) < tolerance))
802     return SLVS_E_UNKNOWN;
803
804   // quaternion parameters of normal vector
805   double qw, qx, qy, qz;
806   Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
807                       &qx, &qy, &qz);
808   double aNormCoord[4] = { qw, qx, qy, qz };
809
810   // Try to find existent normal
811   std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
812       myEntityAttrMap.find(theNorm);
813   std::vector<Slvs_Param>::const_iterator aParamIter;  // looks to the first parameter of already existent entity or to the end of vector otherwise
814   if (aEntIter == myEntityAttrMap.end())  // no such entity => should be created
815     aParamIter = myParams.end();
816   else {  // the entity already exists, update it
817     int aEntPos = Search(aEntIter->second, myEntities);
818     int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
819     aParamIter = myParams.begin() + aParamPos;
820   }
821
822   // Change parameters of the normal
823   Slvs_hParam aNormParams[4];
824   for (int i = 0; i < 4; i++)
825     aNormParams[i] = changeParameter(aNormCoord[i], aParamIter);
826
827   if (aEntIter != myEntityAttrMap.end())  // the entity already exists
828     return aEntIter->second;
829
830   // Create a normal
831   Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, aNormParams[0], aNormParams[1],
832                                           aNormParams[2], aNormParams[3]);
833   myEntities.push_back(aNormal);
834   myEntOfConstr.push_back(false);
835   myEntityAttrMap[theNorm] = aNormal.h;
836   return aNormal.h;
837 }
838
839 // ============================================================================
840 //  Function: addWorkplane
841 //  Class:    SketchSolver_ConstraintGroup
842 //  Purpose:  create workplane for the group
843 // ============================================================================
844 bool SketchSolver_ConstraintGroup::addWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch)
845 {
846   if (myWorkplane.h || theSketch->getKind().compare(SketchPlugin_Sketch::ID()) != 0)
847     return false;  // the workplane already exists or the function parameter is not Sketch
848
849   mySketch = theSketch;
850   updateWorkplane();
851   return true;
852 }
853
854 // ============================================================================
855 //  Function: updateWorkplane
856 //  Class:    SketchSolver_ConstraintGroup
857 //  Purpose:  update parameters of workplane
858 // ============================================================================
859 bool SketchSolver_ConstraintGroup::updateWorkplane()
860 {
861   if (!mySketch->data())
862     return false; // case sketch is deleted
863   // Get parameters of workplane
864   std::shared_ptr<ModelAPI_Attribute> aDirX = mySketch->data()->attribute(
865       SketchPlugin_Sketch::DIRX_ID());
866   std::shared_ptr<ModelAPI_Attribute> aDirY = mySketch->data()->attribute(
867       SketchPlugin_Sketch::DIRY_ID());
868   std::shared_ptr<ModelAPI_Attribute> aNorm = mySketch->data()->attribute(
869       SketchPlugin_Sketch::NORM_ID());
870   std::shared_ptr<ModelAPI_Attribute> anOrigin = mySketch->data()->attribute(
871       SketchPlugin_Sketch::ORIGIN_ID());
872   // Transform them into SolveSpace format
873   Slvs_hEntity aNormalWP = changeNormal(aDirX, aDirY, aNorm);
874   if (!aNormalWP)
875     return false;
876   Slvs_hEntity anOriginWP = changeEntity(anOrigin);
877   if (!anOriginWP)
878     return false;
879
880   if (!myWorkplane.h) {
881     // Create workplane
882     myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
883     // Workplane should be added to the list of entities
884     myEntities.push_back(myWorkplane);
885     myEntOfConstr.push_back(false);
886   }
887   return true;
888 }
889
890 // ============================================================================
891 //  Function: changeParameter
892 //  Class:    SketchSolver_ConstraintGroup
893 //  Purpose:  create/update value of parameter
894 // ============================================================================
895 Slvs_hParam SketchSolver_ConstraintGroup::changeParameter(
896     const double& theParam, std::vector<Slvs_Param>::const_iterator& thePrmIter)
897 {
898   if (thePrmIter != myParams.end()) {  // Parameter should be updated
899     int aParamPos = thePrmIter - myParams.begin();
900     if (fabs(thePrmIter->val - theParam) > tolerance) {
901       myNeedToSolve = true;  // parameter is changed, need to resolve constraints
902       myParams[aParamPos].val = theParam;
903     }
904     thePrmIter++;
905     return myParams[aParamPos].h;
906   }
907
908   // Newly created parameter
909   Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
910   myParams.push_back(aParam);
911   myNeedToSolve = true;
912   // The list of parameters is changed, move iterator to the end of the list to avoid problems
913   thePrmIter = myParams.end();
914   return aParam.h;
915 }
916
917 // ============================================================================
918 //  Function: resolveConstraints
919 //  Class:    SketchSolver_ConstraintGroup
920 //  Purpose:  solve the set of constraints for the current group
921 // ============================================================================
922 bool SketchSolver_ConstraintGroup::resolveConstraints()
923 {
924   if (!myNeedToSolve)
925     return false;
926
927   myConstrSolver.setGroupID(myID);
928   myConstrSolver.setParameters(myParams);
929   myConstrSolver.setEntities(myEntities);
930   myConstrSolver.setConstraints(myConstraints);
931   myConstrSolver.setDraggedParameters(myTempPointWhereDragged);
932
933   int aResult = myConstrSolver.solve();
934   if (aResult == SLVS_RESULT_OKAY) {  // solution succeeded, store results into correspondent attributes
935                                       // Obtain result into the same list of parameters
936     if (!myConstrSolver.getResult(myParams))
937       return true;
938
939     // We should go through the attributes map, because only attributes have valued parameters
940     std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntIter =
941         myEntityAttrMap.begin();
942     for (; anEntIter != myEntityAttrMap.end(); anEntIter++) {
943       if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
944         anEntIter->first->owner()->data()->blockSendAttributeUpdated(true);
945       if (updateAttribute(anEntIter->first, anEntIter->second))
946         updateRelatedConstraints(anEntIter->first);
947     }
948     // unblock all features then
949     for (anEntIter = myEntityAttrMap.begin(); anEntIter != myEntityAttrMap.end(); anEntIter++) {
950       if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
951         anEntIter->first->owner()->data()->blockSendAttributeUpdated(false);
952     }
953   } else if (!myConstraints.empty())
954     Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
955
956   removeTemporaryConstraints();
957   myNeedToSolve = false;
958   return true;
959 }
960
961 // ============================================================================
962 //  Function: mergeGroups
963 //  Class:    SketchSolver_ConstraintGroup
964 //  Purpose:  append specified group to the current group
965 // ============================================================================
966 void SketchSolver_ConstraintGroup::mergeGroups(const SketchSolver_ConstraintGroup& theGroup)
967 {
968   // If specified group is empty, no need to merge
969   if (theGroup.myConstraintMap.empty())
970     return;
971
972   // Map between old and new indexes of SolveSpace constraints
973   std::map<Slvs_hConstraint, Slvs_hConstraint> aConstrMap;
974
975   // Add all constraints from theGroup to the current group
976   ConstraintMap::const_iterator aConstrIter = theGroup.myConstraintMap.begin();
977   for (; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++)
978     if (changeConstraint(aConstrIter->first))
979       aConstrMap[aConstrIter->second.back()] = myConstrMaxID;  // the constraint was added => store its ID
980
981   // Add temporary constraints from theGroup
982   std::list<Slvs_hConstraint>::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin();
983   for (; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++) {
984     std::map<Slvs_hConstraint, Slvs_hConstraint>::iterator aFind = aConstrMap.find(
985         *aTempConstrIter);
986     if (aFind != aConstrMap.end())
987       myTempConstraints.push_back(aFind->second);
988   }
989
990   if (myTempPointWhereDragged.empty())
991     myTempPointWhereDragged = theGroup.myTempPointWhereDragged;
992   else if (!theGroup.myTempPointWhereDragged.empty()) {  // Need to create additional transient constraint
993     std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aFeatureIter =
994         theGroup.myEntityAttrMap.begin();
995     for (; aFeatureIter != theGroup.myEntityAttrMap.end(); aFeatureIter++)
996       if (aFeatureIter->second == myTempPointWDrgdID) {
997         addTemporaryConstraintWhereDragged(aFeatureIter->first);
998         break;
999       }
1000   }
1001
1002   myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve;
1003 }
1004
1005 // ============================================================================
1006 //  Function: splitGroup
1007 //  Class:    SketchSolver_ConstraintGroup
1008 //  Purpose:  divide the group into several subgroups
1009 // ============================================================================
1010 void SketchSolver_ConstraintGroup::splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts)
1011 {
1012   // Divide constraints and entities into several groups
1013   std::vector<std::set<Slvs_hEntity> > aGroupsEntities;
1014   std::vector<std::set<Slvs_hConstraint> > aGroupsConstr;
1015   int aMaxNbEntities = 0;  // index of the group with maximal nuber of elements (this group will be left in the current)
1016   std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1017   for (; aConstrIter != myConstraints.end(); aConstrIter++) {
1018     Slvs_hEntity aConstrEnt[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA,
1019         aConstrIter->entityB };
1020     std::vector<int> anIndexes;
1021     // Go through the groupped entities and find even one of entities of current constraint
1022     std::vector<std::set<Slvs_hEntity> >::iterator aGrEntIter;
1023     for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++) {
1024       bool isFound = false;
1025       for (int i = 0; i < 4 && !isFound; i++)
1026         if (aConstrEnt[i] != 0) {
1027           isFound = (aGrEntIter->find(aConstrEnt[i]) != aGrEntIter->end());
1028           // Also we need to check sub-entities
1029           int aEntPos = Search(aConstrEnt[i], myEntities);
1030           if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
1031             Slvs_hEntity* aSub = myEntities[aEntPos].point;
1032             for (int j = 0; *aSub != 0 && j < 4 && !isFound; aSub++, j++)
1033               isFound = (aGrEntIter->find(*aSub) != aGrEntIter->end());
1034           }
1035         }
1036       if (isFound)
1037         anIndexes.push_back(aGrEntIter - aGroupsEntities.begin());
1038     }
1039     // Add new group if no one is found
1040     if (anIndexes.empty()) {
1041       std::set<Slvs_hEntity> aNewGrEnt;
1042       for (int i = 0; i < 4; i++)
1043         if (aConstrEnt[i] != 0) {
1044           aNewGrEnt.insert(aConstrEnt[i]);
1045           int aEntPos = Search(aConstrEnt[i], myEntities);
1046           if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
1047             Slvs_hEntity* aSub = myEntities[aEntPos].point;
1048             for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
1049               aNewGrEnt.insert(*aSub);
1050           }
1051         }
1052       std::set<Slvs_hConstraint> aNewGrConstr;
1053       aNewGrConstr.insert(aConstrIter->h);
1054
1055       aGroupsEntities.push_back(aNewGrEnt);
1056       aGroupsConstr.push_back(aNewGrConstr);
1057       if (aNewGrEnt.size() > aGroupsEntities[aMaxNbEntities].size())
1058         aMaxNbEntities = aGroupsEntities.size() - 1;
1059     } else {  // Add entities indexes into the found group
1060       aGrEntIter = aGroupsEntities.begin() + anIndexes.front();
1061       for (int i = 0; i < 4; i++)
1062         if (aConstrEnt[i] != 0) {
1063           aGrEntIter->insert(aConstrEnt[i]);
1064           int aEntPos = Search(aConstrEnt[i], myEntities);
1065           if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
1066             Slvs_hEntity* aSub = myEntities[aEntPos].point;
1067             for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
1068               aGrEntIter->insert(*aSub);
1069           }
1070         }
1071       aGroupsConstr[anIndexes.front()].insert(aConstrIter->h);
1072       if (aGrEntIter->size() > aGroupsEntities[aMaxNbEntities].size())
1073         aMaxNbEntities = aGrEntIter - aGroupsEntities.begin();
1074       if (anIndexes.size() > 1) {  // There are found several connected groups, merge them
1075         std::vector<std::set<Slvs_hEntity> >::iterator aFirstGroup = aGroupsEntities.begin()
1076             + anIndexes.front();
1077         std::vector<std::set<Slvs_hConstraint> >::iterator aFirstConstr = aGroupsConstr.begin()
1078             + anIndexes.front();
1079         std::vector<int>::iterator anInd = anIndexes.begin();
1080         for (++anInd; anInd != anIndexes.end(); anInd++) {
1081           aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end());
1082           aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end());
1083         }
1084         if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size())
1085           aMaxNbEntities = anIndexes.front();
1086         // Remove merged groups
1087         for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--) {
1088           aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd));
1089           aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd));
1090         }
1091       }
1092     }
1093   }
1094
1095   if (aGroupsEntities.size() <= 1)
1096     return;
1097
1098   // Remove the group with maximum elements as it will be left in the current group
1099   aGroupsEntities.erase(aGroupsEntities.begin() + aMaxNbEntities);
1100   aGroupsConstr.erase(aGroupsConstr.begin() + aMaxNbEntities);
1101
1102   // Add new groups of constraints and divide current group
1103   std::vector<SketchSolver_ConstraintGroup*> aNewGroups;
1104   for (int i = aGroupsEntities.size(); i > 0; i--) {
1105     SketchSolver_ConstraintGroup* aG = new SketchSolver_ConstraintGroup(mySketch);
1106     aNewGroups.push_back(aG);
1107   }
1108   ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.begin();
1109   int aConstrMapPos = 0;  // position of iterator in the map (used to restore iterator after removing constraint)
1110   while (aConstrMapIter != myConstraintMap.end()) {
1111     std::vector<std::set<Slvs_hConstraint> >::const_iterator aGIter = aGroupsConstr.begin();
1112     std::vector<SketchSolver_ConstraintGroup*>::iterator aGroup = aNewGroups.begin();
1113     for (; aGIter != aGroupsConstr.end(); aGIter++, aGroup++)
1114       if (aGIter->find(aConstrMapIter->second.front()) != aGIter->end()) {
1115         (*aGroup)->changeConstraint(aConstrMapIter->first);
1116         removeConstraint(aConstrMapIter->first);
1117         // restore iterator
1118         aConstrMapIter = myConstraintMap.begin();
1119         for (int i = 0; i < aConstrMapPos; i++)
1120           aConstrMapIter++;
1121         break;
1122       }
1123     if (aGIter == aGroupsConstr.end()) {
1124       aConstrMapIter++;
1125       aConstrMapPos++;
1126     }
1127   }
1128
1129   theCuts.insert(theCuts.end(), aNewGroups.begin(), aNewGroups.end());
1130 }
1131
1132 // ============================================================================
1133 //  Function: updateGroup
1134 //  Class:    SketchSolver_ConstraintGroup
1135 //  Purpose:  search removed entities and constraints
1136 // ============================================================================
1137 bool SketchSolver_ConstraintGroup::updateGroup()
1138 {
1139   ConstraintMap::reverse_iterator aConstrIter = myConstraintMap.rbegin();
1140   bool isAllValid = true;
1141   bool isCCRemoved = false;  // indicates that at least one of coincidence constraints was removed
1142   int aConstrIndex = 0;
1143   while (/*isAllValid && */aConstrIter != myConstraintMap.rend()) {
1144     if (!aConstrIter->first->data() || !aConstrIter->first->data()->isValid()) {
1145       if (aConstrIter->first->getKind().compare(SketchPlugin_ConstraintCoincidence::ID()) == 0)
1146         isCCRemoved = true;
1147       removeConstraint(aConstrIter->first);
1148       isAllValid = false;
1149       // Get back the correct position of iterator after the "remove" operation
1150       aConstrIter = myConstraintMap.rbegin();
1151       for (int i = 0; i < aConstrIndex && aConstrIter != myConstraintMap.rend(); i++)
1152         aConstrIter++;
1153     } else {
1154       aConstrIter++;
1155       aConstrIndex++;
1156     }
1157   }
1158
1159   // Check if some entities are invalid too
1160   std::set<Slvs_hEntity> anEntToRemove;
1161   std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
1162       anAttrIter = myEntityAttrMap.begin();
1163   while (anAttrIter != myEntityAttrMap.end()) {
1164     if (!anAttrIter->first->owner() || !anAttrIter->first->owner()->data() ||
1165         !anAttrIter->first->owner()->data()->isValid()) {
1166       anEntToRemove.insert(anAttrIter->second);
1167       std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
1168           aRemovedIter = anAttrIter;
1169       anAttrIter++;
1170       myEntityAttrMap.erase(aRemovedIter);
1171     } else
1172       anAttrIter++;
1173   }
1174   std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myEntityFeatMap.begin();
1175   while (aFeatIter != myEntityFeatMap.end()) {
1176     if (!aFeatIter->first || !aFeatIter->first->data() ||
1177         !aFeatIter->first->data()->isValid()) {
1178       anEntToRemove.insert(aFeatIter->second);
1179       std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = aFeatIter;
1180       aFeatIter++;
1181       myEntityFeatMap.erase(aRemovedIter);
1182     } else
1183       aFeatIter++;
1184   }
1185   removeEntitiesById(anEntToRemove);
1186
1187   // Probably, need to update coincidence constraints
1188   if (isCCRemoved && !myExtraCoincidence.empty()) {
1189     // Make a copy, because the new list of unused constrtaints will be generated
1190     std::set<std::shared_ptr<SketchPlugin_Constraint> > anExtraCopy = myExtraCoincidence;
1191     myExtraCoincidence.clear();
1192
1193     std::set<std::shared_ptr<SketchPlugin_Constraint> >::iterator aCIter = anExtraCopy.begin();
1194     for (; aCIter != anExtraCopy.end(); aCIter++)
1195       if ((*aCIter)->data() && (*aCIter)->data()->isValid())
1196         changeConstraint(*aCIter);
1197   }
1198
1199   return !isAllValid;
1200 }
1201
1202 // ============================================================================
1203 //  Function: updateAttribute
1204 //  Class:    SketchSolver_ConstraintGroup
1205 //  Purpose:  update features of sketch after resolving constraints
1206 // ============================================================================
1207 bool SketchSolver_ConstraintGroup::updateAttribute(
1208     std::shared_ptr<ModelAPI_Attribute> theAttribute, const Slvs_hEntity& theEntityID)
1209 {
1210   // Search the position of the first parameter of the entity
1211   int anEntPos = Search(theEntityID, myEntities);
1212   int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
1213
1214   // Look over supported types of entities
1215
1216   // Point in 3D
1217   std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1218       theAttribute);
1219   if (aPoint) {
1220     if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance
1221         || fabs(aPoint->y() - myParams[aFirstParamPos + 1].val) > tolerance
1222         || fabs(aPoint->z() - myParams[aFirstParamPos + 2].val) > tolerance) {
1223       aPoint->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val,
1224                        myParams[aFirstParamPos + 2].val);
1225       return true;
1226     }
1227     return false;
1228   }
1229
1230   // Point in 2D
1231   std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
1232       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
1233   if (aPoint2D) {
1234     if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance
1235         || fabs(aPoint2D->y() - myParams[aFirstParamPos + 1].val) > tolerance) {
1236       aPoint2D->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val);
1237       return true;
1238     }
1239     return false;
1240   }
1241
1242   // Scalar value
1243   AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
1244   if (aScalar) {
1245     if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance) {
1246       aScalar->setValue(myParams[aFirstParamPos].val);
1247       return true;
1248     }
1249     return false;
1250   }
1251
1252   /// \todo Support other types of entities
1253   return false;
1254 }
1255
1256 // ============================================================================
1257 //  Function: updateEntityIfPossible
1258 //  Class:    SketchSolver_ConstraintGroup
1259 //  Purpose:  search the entity in this group and update it
1260 // ============================================================================
1261 void SketchSolver_ConstraintGroup::updateEntityIfPossible(
1262     std::shared_ptr<ModelAPI_Attribute> theEntity)
1263 {
1264   if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) {
1265     // If the attribute is a point and it is changed (the group needs to rebuild),
1266     // probably user has dragged this point into this position,
1267     // so it is necessary to add constraint which will guarantee the point will not change
1268
1269     // Store myNeedToSolve flag to verify the entity is really changed
1270     bool aNeedToSolveCopy = myNeedToSolve;
1271     myNeedToSolve = false;
1272
1273     changeEntity(theEntity);
1274
1275     if (myNeedToSolve)  // the entity is changed
1276     {
1277       // Verify the entity is a point and add temporary constraint of permanency
1278       std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1279           theEntity);
1280       std::shared_ptr<GeomDataAPI_Point2D> aPoint2D = std::dynamic_pointer_cast<
1281           GeomDataAPI_Point2D>(theEntity);
1282       if (aPoint || aPoint2D)
1283         addTemporaryConstraintWhereDragged(theEntity);
1284     }
1285
1286     // Restore flag of changes
1287     myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
1288
1289     if (myNeedToSolve)
1290       updateRelatedConstraints(theEntity);
1291   }
1292 }
1293
1294 // ============================================================================
1295 //  Function: addTemporaryConstraintWhereDragged
1296 //  Class:    SketchSolver_ConstraintGroup
1297 //  Purpose:  add transient constraint SLVS_C_WHERE_DRAGGED for the entity, 
1298 //            which was moved by user
1299 // ============================================================================
1300 void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged(
1301     std::shared_ptr<ModelAPI_Attribute> theEntity,
1302     bool theAllowToFit)
1303 {
1304   // Find identifier of the entity
1305   std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
1306       myEntityAttrMap.find(theEntity);
1307   if (anEntIter == myEntityAttrMap.end())
1308     return;
1309
1310   // Get identifiers of all dragged points
1311   std::set<Slvs_hEntity> aDraggedPntID;
1312   aDraggedPntID.insert(myTempPointWDrgdID);
1313   std::list<Slvs_hConstraint>::const_iterator aTmpCoIter = myTempConstraints.begin();
1314   for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) {
1315     unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
1316     if (aConstrPos < myConstraints.size())
1317       aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
1318   }
1319   std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1320   for (; aConstrIter != myConstraints.end(); aConstrIter++)
1321     if (aConstrIter->type == SLVS_C_WHERE_DRAGGED)
1322       aDraggedPntID.insert(aConstrIter->ptA);
1323   // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
1324   std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1325   for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) {
1326     if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
1327       continue;  // the entity was not found in current set
1328
1329     // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
1330     std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
1331     for (; aDrgIter != aDraggedPntID.end(); aDrgIter++)
1332       if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
1333         return;  // the SLVS_C_WHERE_DRAGGED constraint already exists
1334   }
1335   if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end())
1336     return;
1337
1338   // If this is a first dragged point, its parameters should be placed 
1339   // into Slvs_System::dragged field to avoid system inconsistense
1340   if (myTempPointWhereDragged.empty() && theAllowToFit) {
1341     int anEntPos = Search(anEntIter->second, myEntities);
1342     Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
1343     for (int i = 0; i < 4; i++, aDraggedParam++)
1344       if (*aDraggedParam != 0)
1345         myTempPointWhereDragged.push_back(*aDraggedParam);
1346     myTempPointWDrgdID = myEntities[anEntPos].h;
1347     return;
1348   }
1349
1350   // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
1351   Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
1352                                                   myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
1353   myConstraints.push_back(aWDConstr);
1354   myTempConstraints.push_back(aWDConstr.h);
1355 }
1356
1357 // ============================================================================
1358 //  Function: removeTemporaryConstraints
1359 //  Class:    SketchSolver_ConstraintGroup
1360 //  Purpose:  remove all transient SLVS_C_WHERE_DRAGGED constraints after
1361 //            resolving the set of constraints
1362 // ============================================================================
1363 void SketchSolver_ConstraintGroup::removeTemporaryConstraints(
1364     const std::set<Slvs_hConstraint>& theRemoved)
1365 {
1366   std::list<Slvs_hConstraint>::reverse_iterator aTmpConstrIter;
1367   for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend();
1368       aTmpConstrIter++) {
1369     if (!theRemoved.empty() && theRemoved.find(*aTmpConstrIter) == theRemoved.end())
1370       continue;
1371     unsigned int aConstrPos = Search(*aTmpConstrIter, myConstraints);
1372     if (aConstrPos >= myConstraints.size())
1373       continue;
1374     myConstraints.erase(myConstraints.begin() + aConstrPos);
1375
1376     // If the removing constraint has higher index, decrease the indexer
1377     if (*aTmpConstrIter == myConstrMaxID)
1378       myConstrMaxID--;
1379   }
1380   myTempConstraints.clear();
1381
1382   // Clear basic dragged point
1383   myTempPointWhereDragged.clear();
1384   myTempPointWDrgdID = SLVS_E_UNKNOWN;
1385 }
1386
1387 // ============================================================================
1388 //  Function: removeConstraint
1389 //  Class:    SketchSolver_ConstraintGroup
1390 //  Purpose:  remove constraint and all unused entities
1391 // ============================================================================
1392 void SketchSolver_ConstraintGroup::removeConstraint(
1393     std::shared_ptr<SketchPlugin_Constraint> theConstraint)
1394 {
1395   ConstraintMap::iterator anIterToRemove = myConstraintMap.find(theConstraint);
1396   if (anIterToRemove == myConstraintMap.end())
1397     return;
1398
1399   std::vector<Slvs_hConstraint> aCnstrToRemove = anIterToRemove->second;
1400   // Remove constraint from the map
1401   myConstraintMap.erase(anIterToRemove);
1402
1403   std::set<Slvs_hEntity> anEntToRemove;
1404   
1405   // Find unused entities
1406   std::vector<Slvs_hConstraint>::iterator aCnstrToRemoveIter = aCnstrToRemove.begin();
1407   for (; aCnstrToRemoveIter != aCnstrToRemove.end(); aCnstrToRemoveIter++) {
1408     int aConstrPos = Search(*aCnstrToRemoveIter, myConstraints);
1409     Slvs_hEntity aCnstEnt[] = { myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB,
1410         myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB };
1411     for (int i = 0; i < 4; i++)
1412       if (aCnstEnt[i] != 0)
1413         anEntToRemove.insert(aCnstEnt[i]);
1414     myConstraints.erase(myConstraints.begin() + aConstrPos);
1415     if (*aCnstrToRemoveIter == myConstrMaxID)
1416       myConstrMaxID--;
1417   }
1418
1419   // Find all entities which are based on these unused
1420   std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
1421   for ( ; anEntIter != myEntities.end(); anEntIter++)
1422     if (anEntIter->type == SLVS_E_LINE_SEGMENT || anEntIter->type == SLVS_E_CIRCLE ||
1423         anEntIter->type == SLVS_E_ARC_OF_CIRCLE) {
1424       for (int i = 0; i < 4; i++)
1425         if (anEntToRemove.find(anEntIter->point[i]) != anEntToRemove.end()) {
1426           anEntToRemove.insert(anEntIter->h);
1427           for (int j = 0; j < 4; j++)
1428             if (anEntIter->param[j] != 0)
1429               anEntToRemove.insert(anEntIter->point[j]);
1430           break;
1431         }
1432     }
1433
1434   std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1435   for (; aConstrIter != myConstraints.end(); aConstrIter++) {
1436     Slvs_hEntity aEnts[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA, aConstrIter
1437         ->entityB };
1438     for (int i = 0; i < 4; i++)
1439       if (aEnts[i] != 0 && anEntToRemove.find(aEnts[i]) != anEntToRemove.end())
1440         anEntToRemove.erase(aEnts[i]);
1441   }
1442
1443   if (anEntToRemove.empty())
1444     return;
1445
1446   // Remove unused entities
1447   std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntAttrIter =
1448       myEntityAttrMap.begin();
1449   while (anEntAttrIter != myEntityAttrMap.end()) {
1450     if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end()) {
1451       std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator aRemovedIter =
1452           anEntAttrIter;
1453       anEntAttrIter++;
1454       myEntityAttrMap.erase(aRemovedIter);
1455     } else
1456       anEntAttrIter++;
1457   }
1458   std::map<FeaturePtr, Slvs_hEntity>::iterator anEntFeatIter = myEntityFeatMap.begin();
1459   while (anEntFeatIter != myEntityFeatMap.end()) {
1460     if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end()) {
1461       std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = anEntFeatIter;
1462       anEntFeatIter++;
1463       myEntityFeatMap.erase(aRemovedIter);
1464     } else
1465       anEntFeatIter++;
1466   }
1467
1468   removeEntitiesById(anEntToRemove);
1469
1470   if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty())
1471     myCoincidentPoints.clear();
1472 }
1473
1474 // ============================================================================
1475 //  Function: removeEntitiesById
1476 //  Class:    SketchSolver_ConstraintGroup
1477 //  Purpose:  Removes specified entities and their parameters
1478 // ============================================================================
1479 void SketchSolver_ConstraintGroup::removeEntitiesById(const std::set<Slvs_hEntity>& theEntities)
1480 {
1481   std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = theEntities.rbegin();
1482   for (; aRemIter != theEntities.rend(); aRemIter++) {
1483     unsigned int anEntPos = Search(*aRemIter, myEntities);
1484     if (anEntPos >= myEntities.size())
1485       continue;
1486     if (myEntities[anEntPos].param[0] != 0) {
1487       unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
1488       if (aParamPos >= myParams.size())
1489         continue;
1490       int aNbParams = 0;
1491       while (myEntities[anEntPos].param[aNbParams] != 0)
1492         aNbParams++;
1493       if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID)
1494         myParamMaxID -= aNbParams;
1495       myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
1496       if (*aRemIter == myEntityMaxID)
1497         myEntityMaxID--;
1498     }
1499     myEntities.erase(myEntities.begin() + anEntPos);
1500     myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos);
1501
1502     // Remove entity's ID from the lists of conincident points
1503     std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1504     for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
1505       aCoPtIter->erase(*aRemIter);
1506   }
1507 }
1508
1509 // ============================================================================
1510 //  Function: addCoincidentPoints
1511 //  Class:    SketchSolver_ConstraintGroup
1512 //  Purpose:  add coincident point the appropriate list of such points
1513 // ============================================================================
1514 bool SketchSolver_ConstraintGroup::addCoincidentPoints(const Slvs_hEntity& thePoint1,
1515                                                        const Slvs_hEntity& thePoint2)
1516 {
1517   std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1518   std::vector<std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
1519   while (aCoPtIter != myCoincidentPoints.end()) {
1520     bool isFound[2] = {  // indicate which point ID was already in coincidence constraint
1521         aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2)
1522             != aCoPtIter->end(), };
1523     if (isFound[0] && isFound[1])  // points are already connected by coincidence constraints => no need additional one
1524       return false;
1525     if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) {
1526       if (aFirstFound != myCoincidentPoints.end()) {  // there are two groups of coincident points connected by created constraint => merge them
1527         int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
1528         int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
1529         aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
1530         myCoincidentPoints.erase(aCoPtIter);
1531         aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
1532         aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
1533         continue;
1534       } else {
1535         aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
1536         aFirstFound = aCoPtIter;
1537       }
1538     }
1539     aCoPtIter++;
1540   }
1541   // No points were found, need to create new set
1542   if (aFirstFound == myCoincidentPoints.end()) {
1543     std::set<Slvs_hEntity> aNewSet;
1544     aNewSet.insert(thePoint1);
1545     aNewSet.insert(thePoint2);
1546     myCoincidentPoints.push_back(aNewSet);
1547   }
1548
1549   return true;
1550 }
1551
1552 // ============================================================================
1553 //  Function: updateRelatedConstraints
1554 //  Class:    SketchSolver_ConstraintGroup
1555 //  Purpose:  emit the signal to update constraints
1556 // ============================================================================
1557 void SketchSolver_ConstraintGroup::updateRelatedConstraints(
1558     std::shared_ptr<ModelAPI_Attribute> theEntity) const
1559 {
1560   ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
1561   for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
1562     std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
1563         ->attributes(std::string());
1564
1565     std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
1566     for (; anAttrIter != anAttributes.end(); anAttrIter++) {
1567       bool isUpd = (*anAttrIter == theEntity);
1568       std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
1569           ModelAPI_AttributeRefAttr>(*anAttrIter);
1570       if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
1571         isUpd = true;
1572
1573       if (isUpd) {
1574         static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1575         ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
1576         break;
1577       }
1578     }
1579   }
1580 }
1581
1582 void SketchSolver_ConstraintGroup::updateRelatedConstraintsFeature(
1583     std::shared_ptr<ModelAPI_Feature> theFeature) const
1584 {
1585   ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
1586   for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
1587     std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
1588         ->attributes(std::string());
1589
1590     std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
1591     for (; anAttrIter != anAttributes.end(); anAttrIter++) {
1592       std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
1593           ModelAPI_AttributeRefAttr>(*anAttrIter);
1594       if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature) {
1595         static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1596         ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
1597         break;
1598       }
1599     }
1600   }
1601 }
1602
1603 // ========================================================
1604 // =========      Auxiliary functions       ===============
1605 // ========================================================
1606
1607 template<typename T>
1608 int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
1609 {
1610   int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
1611   int aVecSize = theEntities.size();
1612   while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
1613     aResIndex--;
1614   while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
1615     aResIndex++;
1616   if (aResIndex == -1)
1617     aResIndex = aVecSize;
1618   return aResIndex;
1619 }