]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SketchSolver_Group.cpp
Salome HOME
SketchSolver library refactoring
[modules/shaper.git] / src / SketchSolver / SketchSolver_Group.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    SketchSolver_Group.cpp
4 // Created: 27 May 2014
5 // Author:  Artem ZHIDKOV
6
7 #include "SketchSolver_Group.h"
8
9 #include <SketchSolver_Builder.h>
10 #include <SketchSolver_Constraint.h>
11 #include <SketchSolver_ConstraintCoincidence.h>
12 #include <SketchSolver_Error.h>
13
14 #include <Events_Error.h>
15 #include <Events_Loop.h>
16 #include <GeomAPI_XY.h>
17 #include <GeomAPI_Dir2d.h>
18 #include <GeomAPI_Pnt2d.h>
19 #include <GeomDataAPI_Dir.h>
20 #include <GeomDataAPI_Point.h>
21 #include <GeomDataAPI_Point2D.h>
22 #include <ModelAPI_AttributeDouble.h>
23 #include <ModelAPI_AttributeRefList.h>
24 #include <ModelAPI_Document.h>
25 #include <ModelAPI_Events.h>
26 #include <ModelAPI_ResultConstruction.h>
27
28 #include <SketchPlugin_Constraint.h>
29 #include <SketchPlugin_ConstraintFillet.h>
30 #include <SketchPlugin_ConstraintLength.h>
31 #include <SketchPlugin_ConstraintCoincidence.h>
32 #include <SketchPlugin_ConstraintMirror.h>
33 #include <SketchPlugin_ConstraintRigid.h>
34
35 #include <SketchPlugin_Arc.h>
36 #include <SketchPlugin_Circle.h>
37 #include <SketchPlugin_Line.h>
38 #include <SketchPlugin_Point.h>
39 #include <SketchPlugin_Sketch.h>
40
41 #include <math.h>
42 #include <assert.h>
43
44
45 /// \brief This class is used to give unique index to the groups
46 class GroupIndexer
47 {
48 public:
49   /// \brief Return vacant index
50   static Slvs_hGroup NEW_GROUP() { return ++myGroupIndex; }
51   /// \brief Removes the index
52   static void REMOVE_GROUP(const Slvs_hGroup& theIndex) {
53     if (myGroupIndex == theIndex)
54       myGroupIndex--;
55   }
56
57 private:
58   GroupIndexer() {};
59
60   static Slvs_hGroup myGroupIndex; ///< index of the group
61 };
62
63 Slvs_hGroup GroupIndexer::myGroupIndex = 0;
64
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_Group  ===============
76 // ========================================================
77
78 SketchSolver_Group::SketchSolver_Group(
79     std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
80     : myID(GroupIndexer::NEW_GROUP())
81 {
82   // Initialize workplane
83   myWorkplaneID = SLVS_E_UNKNOWN;
84 #ifndef NDEBUG
85   assert(addWorkplane(theWorkplane));
86 #else
87   addWorkplane(theWorkplane);
88 #endif
89 }
90
91 SketchSolver_Group::~SketchSolver_Group()
92 {
93   myConstraints.clear();
94   GroupIndexer::REMOVE_GROUP(myID);
95 }
96
97 // ============================================================================
98 //  Function: isBaseWorkplane
99 //  Class:    SketchSolver_Group
100 //  Purpose:  verify the group is based on the given workplane
101 // ============================================================================
102 bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const
103 {
104   return theWorkplane == mySketch;
105 }
106
107 // ============================================================================
108 //  Function: isInteract
109 //  Class:    SketchSolver_Group
110 //  Purpose:  verify are there any entities in the group used by given constraint
111 // ============================================================================
112 bool SketchSolver_Group::isInteract(
113     std::shared_ptr<SketchPlugin_Feature> theFeature) const
114 {
115   // Empty group interacts with everything
116   if (isEmpty()) return true;
117   ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
118   if (aConstraint)
119     return myFeatureStorage->isInteract(aConstraint);
120   return myFeatureStorage->isInteract(theFeature);
121 }
122
123 // ============================================================================
124 //  Function: getFeatureId
125 //  Class:    SketchSolver_Group
126 //  Purpose:  Find the identifier of the feature, if it already exists in the group
127 // ============================================================================
128 Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const
129 {
130   if (!myFeatureStorage)
131     return SLVS_E_UNKNOWN;
132   std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theFeature);
133   if (aConstraints.empty())
134     return SLVS_E_UNKNOWN;
135   ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstraints.begin());
136   if (aCIter == myConstraints.end())
137     return SLVS_E_UNKNOWN;
138   return aCIter->second->getId(theFeature);
139 }
140
141 // ============================================================================
142 //  Function: getAttributeId
143 //  Class:    SketchSolver_Group
144 //  Purpose:  Find the identifier of the attribute, if it already exists in the group
145 // ============================================================================
146 Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const
147 {
148   if (!myFeatureStorage)
149     return SLVS_E_UNKNOWN;
150   std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theAttribute);
151   if (aConstraints.empty())
152     return SLVS_E_UNKNOWN;
153   ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstraints.begin());
154   if (aCIter == myConstraints.end())
155     return SLVS_E_UNKNOWN;
156   return aCIter->second->getId(theAttribute);
157 }
158
159 // ============================================================================
160 //  Function: changeConstraint
161 //  Class:    SketchSolver_Group
162 //  Purpose:  create/update the constraint in the group
163 // ============================================================================
164 bool SketchSolver_Group::changeConstraint(
165     std::shared_ptr<SketchPlugin_Constraint> theConstraint)
166 {
167   // There is no workplane yet, something wrong
168   if (myWorkplaneID == SLVS_E_UNKNOWN)
169     return false;
170
171   if (!theConstraint)
172     return false;
173
174   if (myConstraints.find(theConstraint) == myConstraints.end()) {
175     // Add constraint to the current group
176     SolverConstraintPtr aConstraint =
177         SketchSolver_Builder::getInstance()->createConstraint(theConstraint);
178     if (!aConstraint)
179       return false;
180     aConstraint->setGroup(this);
181     aConstraint->setStorage(myStorage);
182     if (!aConstraint->error().empty()) {
183       if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
184         return false; // some attribute are not initialized yet, don't show message
185       Events_Error::send(aConstraint->error(), this);
186     }
187
188     // Additional verification of coincidence of several points
189     if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
190       ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
191       for (; aCIter != myConstraints.end(); aCIter++) {
192         std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoincidence =
193           std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aCIter->second);
194         if (!aCoincidence)
195           continue;
196         std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoinc2 =
197           std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aConstraint);
198         if (aCoincidence != aCoinc2 && aCoincidence->isCoincide(aCoinc2)) {
199           aCoincidence->attach(aCoinc2);
200           aConstraint = aCoincidence;
201         }
202       }
203     }
204     myConstraints[theConstraint] = aConstraint;
205   }
206   else
207     myConstraints[theConstraint]->update();
208
209   if (!myFeatureStorage)
210     myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
211   myFeatureStorage->changeConstraint(theConstraint);
212
213 ////  if (theConstraint) {
214 ////    if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID())
215 ////      return changeRigidConstraint(theConstraint);
216 ////    if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID())
217 ////      return changeMirrorConstraint(theConstraint);
218 ////    if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID())
219 ////      return changeFilletConstraint(theConstraint);
220 ////  }
221 ////
222 ////  // Search this constraint in the current group to update it
223 ////  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
224 ////  std::vector<Slvs_Constraint>::iterator aConstrIter;
225 ////  if (aConstrMapIter != myConstraintMap.end()) {
226 ////    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
227 ////    aConstrIter = myConstraints.begin() + aConstrPos;
228 ////  }
229 ////
230 ////  // Get constraint type and verify the constraint parameters are correct
231 ////  SketchSolver_Constraint aConstraint(theConstraint);
232 ////  int aConstrType = aConstraint.getType();
233 ////  if (aConstrType == SLVS_C_UNKNOWN
234 ////      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
235 ////    return false;
236 ////  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
237 ////
238 ////  // Create constraint parameters
239 ////  double aDistance = 0.0;  // scalar value of the constraint
240 ////  AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
241 ////      theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE()));
242 ////  if (aDistAttr) {
243 ////    aDistance = aDistAttr->value();
244 ////    // Issue #196: checking the positivity of the distance constraint
245 ////    if (aDistance < tolerance &&
246 ////       (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE))
247 ////      return false;
248 ////    // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
249 ////    if (aConstrType == SLVS_C_DIAMETER)
250 ////      aDistance *= 2.0;
251 ////    if (aConstrMapIter != myConstraintMap.end()
252 ////        && fabs(aConstrIter->valA - aDistance) > tolerance) {
253 ////      myNeedToSolve = true;
254 ////      aConstrIter->valA = aDistance;
255 ////    }
256 ////  }
257 ////
258 ////  size_t aNbTmpConstraints = myTempConstraints.size();
259 ////  Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE];  // parameters of the constraint
260 ////  for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
261 ////    aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
262 ////    std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
263 ////        ModelAPI_AttributeRefAttr>(
264 ////        theConstraint->data()->attribute(aConstraintAttributes[indAttr]));
265 ////    if (!aConstrAttr)
266 ////      continue;
267 ////
268 ////    // Convert the object of the attribute to the feature
269 ////    FeaturePtr aFeature;
270 ////    if (aConstrAttr->isObject() && aConstrAttr->object()) {
271 ////      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
272 ////          aConstrAttr->object());
273 ////      if (!aRC)
274 ////        continue;
275 ////      std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
276 ////      aFeature = aDoc->feature(aRC);
277 ////    }
278 ////
279 ////    // For the length constraint the start and end points of the line should be added to the entities list instead of line
280 ////    if (aConstrType == SLVS_C_PT_PT_DISTANCE
281 ////        && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0) {
282 ////      Slvs_hEntity aLineEnt = changeEntityFeature(aFeature);
283 ////      int aEntPos = Search(aLineEnt, myEntities);
284 ////      aConstrEnt[indAttr++] = myEntities[aEntPos].point[0];
285 ////      aConstrEnt[indAttr++] = myEntities[aEntPos].point[1];
286 ////      while (indAttr < CONSTRAINT_ATTR_SIZE)
287 ////        aConstrEnt[indAttr++] = 0;
288 ////      break;  // there should be no other entities
289 ////    } else if (aConstrAttr->isObject())
290 ////      aConstrEnt[indAttr] = changeEntityFeature(aFeature);
291 ////    else
292 ////      aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
293 ////  }
294 ////
295 ////  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
296 ////    // Several points may be coincident, it is not necessary to store all constraints between them.
297 ////    // Try to find sequence of coincident points which connects the points of new constraint
298 ////    if (aConstrType == SLVS_C_POINTS_COINCIDENT) {
299 ////      if (aConstrEnt[0] == aConstrEnt[1])  // no need to add self coincidence
300 ////        return false;
301 ////      if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) {
302 ////        myExtraCoincidence.insert(theConstraint);  // the constraint is stored for further purposes
303 ////        return false;
304 ////      }
305 ////      if (aNbTmpConstraints < myTempConstraints.size()) {
306 ////        // There was added temporary constraint. Check that there is no coincident points which already rigid.
307 ////
308 ////        // Get list of already fixed points
309 ////        std::set<Slvs_hEntity> anAlreadyFixed;
310 ////        std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
311 ////        for (; aCIter != myConstraints.end(); aCIter++)
312 ////          if (aCIter->type == SLVS_C_WHERE_DRAGGED) {
313 ////            std::list<Slvs_hConstraint>::const_iterator aTmpIt = myTempConstraints.begin();
314 ////            for (; aTmpIt != myTempConstraints.end(); aTmpIt++)
315 ////              if (*aTmpIt == aCIter->h)
316 ////                break;
317 ////            if (aTmpIt == myTempConstraints.end())
318 ////              anAlreadyFixed.insert(aCIter->ptA);
319 ////          }
320 ////
321 ////        std::set<Slvs_hConstraint> aTmpConstrToDelete;
322 ////        std::list<Slvs_hConstraint>::reverse_iterator aTmpIter = myTempConstraints.rbegin();
323 ////        size_t aCurSize = myTempConstraints.size();
324 ////        for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend();
325 ////            aTmpIter++, aCurSize--) {
326 ////          int aConstrPos = Search(*aTmpIter, myConstraints);
327 ////          std::vector<std::set<Slvs_hEntity> >::const_iterator
328 ////            aCoincIter = myCoincidentPoints.begin();
329 ////          for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
330 ////            if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) {
331 ////              std::set<Slvs_hEntity>::const_iterator anIt;
332 ////              for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++)
333 ////                if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) {
334 ////                  aTmpConstrToDelete.insert(*aTmpIter);
335 ////                  break;
336 ////                }
337 ////              break;
338 ////            }
339 ////        }
340 ////        if (!aTmpConstrToDelete.empty())
341 ////          removeTemporaryConstraints(aTmpConstrToDelete);
342 ////      }
343 ////    }
344 ////    // For the tangency constraints it is necessary to identify which points of entities are coincident
345 ////    int aSlvsOtherFlag = 0;
346 ////    int aSlvsOther2Flag = 0;
347 ////    if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) {
348 ////      // Search entities used by constraint
349 ////      int anEnt1Pos = Search(aConstrEnt[2], myEntities);
350 ////      int anEnt2Pos = Search(aConstrEnt[3], myEntities);
351 ////      // Obtain start and end points of entities
352 ////      Slvs_hEntity aPointsToFind[4];
353 ////      aPointsToFind[0] = myEntities[anEnt1Pos].point[1];
354 ////      aPointsToFind[1]= myEntities[anEnt1Pos].point[2];
355 ////      bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT);
356 ////      aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1];
357 ////      aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2];
358 ////      // Search coincident points
359 ////      bool isPointFound[4];
360 ////      std::vector<std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
361 ////      for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) {
362 ////        for (int i = 0; i < 4; i++)
363 ////          isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end());
364 ////        if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) {
365 ////          // the arc is tangent by end point
366 ////          if (isPointFound[1]) aSlvsOtherFlag = 1;
367 ////          // the second item is an arc and it is tangent by end point too
368 ////          if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1;
369 ////          break;
370 ////        }
371 ////      }
372 ////      if (aCPIter == myCoincidentPoints.end()) {
373 ////        // There is no coincident points between tangential objects. Generate error message
374 ////        Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
375 ////        return false;
376 ////      }
377 ////    }
378 ////
379 ////    // Create SolveSpace constraint structure
380 ////    Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
381 ////                                                      myWorkplane.h, aDistance, aConstrEnt[0],
382 ////                                                      aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
383 ////    if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag;
384 ////    if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag;
385 ////    myConstraints.push_back(aSlvsConstr);
386 ////    myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aSlvsConstr.h);
387 ////    int aConstrPos = Search(aSlvsConstr.h, myConstraints);
388 ////    aConstrIter = myConstraints.begin() + aConstrPos;
389 ////    myNeedToSolve = true;
390 ////  } else { // Attributes of constraint may be changed => update constraint
391 ////    Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB,
392 ////                                   &aConstrIter->entityA, &aConstrIter->entityB,
393 ////                                   &aConstrIter->entityC, &aConstrIter->entityD};
394 ////    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
395 ////      if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr])
396 ////      {
397 ////        *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr];
398 ////        myNeedToSolve = true;
399 ////      }
400 ////    }
401 ////  }
402 ////
403 ////  // Update flags of entities to be used by constraints
404 ////  for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
405 ////    if (aConstrEnt[indAttr] != 0) {
406 ////      int aPos = Search(aConstrEnt[indAttr], myEntities);
407 ////      myEntOfConstr[aPos] = true;
408 ////      // Sub-entities should be used implcitly
409 ////      Slvs_hEntity* aEntPtr = myEntities[aPos].point;
410 ////      while (*aEntPtr != 0) {
411 ////        aPos = Search(*aEntPtr, myEntities);
412 ////        myEntOfConstr[aPos] = true;
413 ////        aEntPtr++;
414 ////      }
415 ////    }
416 ////
417 ////  checkConstraintConsistence(*aConstrIter);
418   return true;
419 }
420
421
422 bool SketchSolver_Group::updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
423 {
424   std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theFeature);
425   if (aConstraints.empty())
426     return false;
427   std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
428   for (; aCIter != aConstraints.end(); aCIter++) {
429     ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter);
430     aSolConIter->second->update();
431   }
432   return true;
433 }
434
435 void SketchSolver_Group::moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
436 {
437   updateFeature(theFeature);
438   // Temporary rigid constraint
439   SolverConstraintPtr aConstraint =
440       SketchSolver_Builder::getInstance()->createRigidConstraint(theFeature);
441   if (!aConstraint)
442     return;
443   aConstraint->setGroup(this);
444   aConstraint->setStorage(myStorage);
445   myTempConstraints.insert(aConstraint);
446 }
447
448 ////// ============================================================================
449 //////  Function: changeRigidConstraint
450 //////  Class:    SketchSolver_Group
451 //////  Purpose:  create/update the "Rigid" constraint in the group
452 ////// ============================================================================
453 ////bool SketchSolver_Group::changeRigidConstraint(
454 ////    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
455 ////{
456 ////  // Search this constraint in the current group to update it
457 ////  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
458 ////  std::vector<Slvs_Constraint>::iterator aConstrIter;
459 ////  if (aConstrMapIter != myConstraintMap.end()) {
460 ////    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
461 ////    aConstrIter = myConstraints.begin() + aConstrPos;
462 ////  }
463 ////
464 ////  // Get constraint type and verify the constraint parameters are correct
465 ////  SketchSolver_Constraint aConstraint(theConstraint);
466 ////  int aConstrType = aConstraint.getType();
467 ////  if (aConstrType == SLVS_C_UNKNOWN
468 ////      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
469 ////    return false;
470 ////  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
471 ////
472 ////  Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN;
473 ////  std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
474 ////      ModelAPI_AttributeRefAttr>(
475 ////      theConstraint->data()->attribute(aConstraintAttributes[0]));
476 ////  if (!aConstrAttr)
477 ////    return false;
478 ////
479 ////  // Convert the object of the attribute to the feature
480 ////  FeaturePtr aFeature;
481 ////  if (aConstrAttr->isObject() && aConstrAttr->object()) {
482 ////    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
483 ////        aConstrAttr->object());
484 ////    if (!aRC)
485 ////      return false;
486 ////    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
487 ////    aFeature = aDoc->feature(aRC);
488 ////  }
489 ////
490 ////  aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr());
491 ////
492 ////  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
493 ////    // Check the fixed entity is not a point.
494 ////    std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
495 ////        ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0]));
496 ////    std::shared_ptr<GeomDataAPI_Point> aPoint =
497 ////        std::dynamic_pointer_cast<GeomDataAPI_Point>(aConstrAttr->attr());
498 ////    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
499 ////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aConstrAttr->attr());
500 ////    if (aPoint || aPoint2D) {
501 ////      // Create SolveSpace constraint structure
502 ////      Slvs_Constraint aConstraint = Slvs_MakeConstraint(
503 ////          ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
504 ////          aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
505 ////      myConstraints.push_back(aConstraint);
506 ////      myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aConstraint.h);
507 ////      int aConstrPos = Search(aConstraint.h, myConstraints);
508 ////      aConstrIter = myConstraints.begin() + aConstrPos;
509 ////      myNeedToSolve = true;
510 ////    } else {
511 ////      myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
512 ////
513 ////      // To avoid SolveSpace problems:
514 ////      // * if the circle is rigid, we will fix its center and radius;
515 ////      // * if the arc is rigid, we will fix its start and end points and radius.
516 ////      double aRadius = 0.0;
517 ////      bool isArc = false;
518 ////      bool isCircle = false;
519 ////      if (aFeature) {
520 ////        if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
521 ////          std::shared_ptr<GeomDataAPI_Point2D> aCenter =
522 ////              std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
523 ////              aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
524 ////          std::shared_ptr<GeomDataAPI_Point2D> aStart =
525 ////              std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
526 ////              aFeature->data()->attribute(SketchPlugin_Arc::START_ID()));
527 ////          aRadius = aStart->pnt()->distance(aCenter->pnt());
528 ////          isArc = true;
529 ////        } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
530 ////          aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
531 ////              aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
532 ////          isCircle = true;
533 ////        }
534 ////      }
535 ////
536 ////      // Get list of already fixed points
537 ////      std::set<Slvs_hEntity> anAlreadyFixed;
538 ////      std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
539 ////      for (; aCIter != myConstraints.end(); aCIter++)
540 ////        if (aCIter->type == SLVS_C_WHERE_DRAGGED)
541 ////          anAlreadyFixed.insert(aCIter->ptA);
542 ////
543 ////      // Create constraints to fix the parameters of the entity
544 ////      int aEntPos = Search(aConstrEnt, myEntities);
545 ////      Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point;
546 ////      if (isArc) aPointsPtr++; // avoid to fix center of arc
547 ////      while (*aPointsPtr != 0) {
548 ////        // Avoid to create additional "Rigid" constraints for coincident points
549 ////        bool isCoincAlreadyFixed = false;
550 ////        if (!anAlreadyFixed.empty()) {
551 ////          if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end())
552 ////            isCoincAlreadyFixed = true;
553 ////
554 ////          std::vector<std::set<Slvs_hEntity> >::const_iterator aCoincIter =
555 ////              myCoincidentPoints.begin();
556 ////          for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) {
557 ////            if (aCoincIter->find(*aPointsPtr) == aCoincIter->end())
558 ////              continue;
559 ////            std::set<Slvs_hEntity>::const_iterator anIter = anAlreadyFixed.begin();
560 ////            for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++)
561 ////              if (aCoincIter->find(*anIter) != aCoincIter->end())
562 ////                isCoincAlreadyFixed = true;
563 ////          }
564 ////        }
565 ////
566 ////        if (!isCoincAlreadyFixed) {
567 ////          Slvs_Constraint aConstraint = Slvs_MakeConstraint(
568 ////              ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
569 ////              *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
570 ////          myConstraints.push_back(aConstraint);
571 ////          myConstraintMap[theConstraint].push_back(aConstraint.h);
572 ////        }
573 ////        aPointsPtr++;
574 ////      }
575 ////
576 ////      if (isArc || isCircle) { // add radius constraint
577 ////        Slvs_Constraint aConstraint = Slvs_MakeConstraint(
578 ////            ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius,
579 ////            SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN);
580 ////        myConstraints.push_back(aConstraint);
581 ////        myConstraintMap[theConstraint].push_back(aConstraint.h);
582 ////      }
583 ////
584 ////      // The object is already rigid, so there is no constraints added
585 ////      if (myConstraintMap[theConstraint].empty()) {
586 ////        myConstraintMap.erase(theConstraint);
587 ////        myNeedToSolve = false;
588 ////      }
589 ////      else
590 ////        myNeedToSolve = true;
591 ////    }
592 ////  }
593 ////  return true;
594 ////}
595 ////
596 ////// ============================================================================
597 //////  Function: changeMirrorConstraint
598 //////  Class:    SketchSolver_Group
599 //////  Purpose:  create/update the "Mirror" constraint in the group
600 ////// ============================================================================
601 ////bool SketchSolver_Group::changeMirrorConstraint(
602 ////    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
603 ////{
604 ////  DataPtr aConstrData = theConstraint->data();
605 ////
606 ////  // Search this constraint in the current group to update it
607 ////  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
608 ////  std::vector<Slvs_Constraint>::iterator aConstrIter;
609 ////  if (aConstrMapIter != myConstraintMap.end()) {
610 ////    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
611 ////    aConstrIter = myConstraints.begin() + aConstrPos;
612 ////  }
613 ////
614 ////  // Get constraint type and verify the constraint parameters are correct
615 ////  SketchSolver_Constraint aConstraint(theConstraint);
616 ////  int aConstrType = aConstraint.getType();
617 ////  if (aConstrType == SLVS_C_UNKNOWN
618 ////      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
619 ////    return false;
620 ////  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
621 ////
622 ////  Slvs_hEntity aMirrorLineEnt = SLVS_E_UNKNOWN;
623 ////  AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
624 ////      aConstrData->attribute(aConstraintAttributes[0]));
625 ////  if (!aConstrAttr)
626 ////    return false;
627 ////
628 ////  // Convert the object of the attribute to the feature
629 ////  FeaturePtr aMirrorLineFeat;
630 ////  if (aConstrAttr->isObject() && aConstrAttr->object()) {
631 ////    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
632 ////        aConstrAttr->object());
633 ////    if (!aRC)
634 ////      return false;
635 ////    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
636 ////    aMirrorLineFeat = aDoc->feature(aRC);
637 ////  }
638 ////  aMirrorLineEnt = aConstrAttr->isObject() ?
639 ////      changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr());
640 ////
641 ////  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
642 ////    // Append symmetric constraint for each point of mirroring features
643 ////    AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
644 ////        aConstrData->attribute(aConstraintAttributes[1]));
645 ////    AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
646 ////        aConstrData->attribute(aConstraintAttributes[2]));
647 ////    if (!aBaseRefList || !aMirroredRefList)
648 ////      return false;
649 ////
650 ////    std::list<ObjectPtr> aBaseList = aBaseRefList->list();
651 ////    std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
652 ////    if (aBaseList.size() != aMirroredList.size())
653 ////      return false;
654 ////
655 ////    myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
656 ////
657 ////    FeaturePtr aBaseFeature, aMirrorFeature;
658 ////    ResultConstructionPtr aRC;
659 ////    std::list<ObjectPtr>::iterator aBaseIter = aBaseList.begin();
660 ////    std::list<ObjectPtr>::iterator aMirIter = aMirroredList.begin();
661 ////    for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) {
662 ////      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
663 ////      aBaseFeature = aRC ? aRC->document()->feature(aRC) :
664 ////          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aBaseIter);
665 ////      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirIter);
666 ////      aMirrorFeature = aRC ? aRC->document()->feature(aRC) :
667 ////          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aMirIter);
668 ////
669 ////      if (!aBaseFeature || !aMirrorFeature || 
670 ////          aBaseFeature->getKind() != aMirrorFeature->getKind())
671 ////        return false;
672 ////      Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature);
673 ////      Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature);
674 ////      // Make aMirrorEnt parameters to be symmetric with aBaseEnt
675 ////      makeMirrorEntity(aBaseEnt, aMirrorEnt, aMirrorLineEnt);
676 ////
677 ////      if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) {
678 ////        Slvs_Constraint aConstraint = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
679 ////            myWorkplane.h, 0.0, aBaseEnt, aMirrorEnt, aMirrorLineEnt, SLVS_E_UNKNOWN);
680 ////        myConstraints.push_back(aConstraint);
681 ////        myConstraintMap[theConstraint].push_back(aConstraint.h);
682 ////      } else {
683 ////        int aBasePos = Search(aBaseEnt, myEntities);
684 ////        int aMirrorPos = Search(aMirrorEnt, myEntities);
685 ////        if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) {
686 ////          for (int ind = 0; ind < 2; ind++) {
687 ////            Slvs_Constraint aConstraint = Slvs_MakeConstraint(
688 ////                ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
689 ////                myEntities[aBasePos].point[ind], myEntities[aMirrorPos].point[ind],
690 ////                aMirrorLineEnt, SLVS_E_UNKNOWN);
691 ////            myConstraints.push_back(aConstraint);
692 ////            myConstraintMap[theConstraint].push_back(aConstraint.h);
693 ////          }
694 ////        } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
695 ////          Slvs_Constraint aConstraint = Slvs_MakeConstraint(
696 ////              ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
697 ////              myEntities[aBasePos].point[0], myEntities[aMirrorPos].point[0],
698 ////              aMirrorLineEnt, SLVS_E_UNKNOWN);
699 ////          myConstraints.push_back(aConstraint);
700 ////          myConstraintMap[theConstraint].push_back(aConstraint.h);
701 ////          // Additional constraint for equal radii
702 ////          Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
703 ////              ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0,
704 ////              SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt);
705 ////          myConstraints.push_back(anEqRadConstr);
706 ////          myConstraintMap[theConstraint].push_back(anEqRadConstr.h);
707 ////        } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
708 ////          // Workaround to avoid problems in SolveSpace.
709 ////          // The symmetry of two arcs will be done using symmetry of three points on these arcs:
710 ////          // start point, end point, and any other point on the arc
711 ////          Slvs_hEntity aBaseArcPoints[3] = {
712 ////              myEntities[aBasePos].point[1],
713 ////              myEntities[aBasePos].point[2],
714 ////              SLVS_E_UNKNOWN};
715 ////          Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
716 ////              myEntities[aMirrorPos].point[2],
717 ////              myEntities[aMirrorPos].point[1],
718 ////              SLVS_E_UNKNOWN};
719 ////          Slvs_hEntity aBothArcs[2] = {aBaseEnt, aMirrorEnt};
720 ////          Slvs_hEntity aBothMiddlePoints[2];
721 ////          for (int i = 0; i < 2; i++) {
722 ////            double x, y;
723 ////            calculateMiddlePoint(aBothArcs[i], x, y);
724 ////            std::vector<Slvs_Param>::iterator aParamIter = myParams.end();
725 ////            Slvs_hParam u = changeParameter(x, aParamIter);
726 ////            Slvs_hParam v = changeParameter(y, aParamIter);
727 ////            Slvs_Entity aPoint = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, u, v);
728 ////            myEntities.push_back(aPoint);
729 ////            aBothMiddlePoints[i] = aPoint.h;
730 ////            // additional constraint point-on-curve
731 ////            Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
732 ////                ++myConstrMaxID, myID, SLVS_C_PT_ON_CIRCLE, myWorkplane.h, 0.0,
733 ////                aPoint.h, SLVS_E_UNKNOWN, aBothArcs[i], SLVS_E_UNKNOWN);
734 ////            myConstraints.push_back(aPonCircConstr);
735 ////            myConstraintMap[theConstraint].push_back(aPonCircConstr.h);
736 ////          }
737 ////
738 ////          aBaseArcPoints[2] = aBothMiddlePoints[0];
739 ////          aMirrorArcPoints[2] = aBothMiddlePoints[1];
740 ////          for (int ind = 0; ind < 3; ind++) {
741 ////            Slvs_Constraint aConstraint = Slvs_MakeConstraint(
742 ////                ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
743 ////                aBaseArcPoints[ind], aMirrorArcPoints[ind], aMirrorLineEnt, SLVS_E_UNKNOWN);
744 ////            myConstraints.push_back(aConstraint);
745 ////            myConstraintMap[theConstraint].push_back(aConstraint.h);
746 ////          }
747 ////        }
748 ////      }
749 ////    }
750 ////
751 ////    // Set the mirror line unchanged during constraint recalculation
752 ////    int aMirrorLinePos = Search(aMirrorLineEnt, myEntities);
753 ////    Slvs_Constraint aRigidStart = Slvs_MakeConstraint(
754 ////        ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
755 ////        myEntities[aMirrorLinePos].point[0], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
756 ////    myConstraints.push_back(aRigidStart);
757 ////    myConstraintMap[theConstraint].push_back(aRigidStart.h);
758 ////    Slvs_Constraint aRigidEnd = Slvs_MakeConstraint(
759 ////        ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
760 ////        myEntities[aMirrorLinePos].point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
761 ////    myConstraints.push_back(aRigidEnd);
762 ////    myConstraintMap[theConstraint].push_back(aRigidEnd.h);
763 ////
764 ////    // Add temporary constraints for initial objects to be unchanged
765 ////    for (aBaseIter = aBaseList.begin(); aBaseIter != aBaseList.end(); aBaseIter++) {
766 ////      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
767 ////      aBaseFeature = aRC ? aRC->document()->feature(aRC) :
768 ////          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aBaseIter);
769 ////      if (!aBaseFeature) continue;
770 ////      std::list<AttributePtr> aPoints = aBaseFeature->data()->attributes(GeomDataAPI_Point2D::type());
771 ////      std::list<AttributePtr>::iterator anIt = aPoints.begin();
772 ////      for ( ; anIt != aPoints.end(); anIt++) {
773 ////        // Arcs are fixed by center and start points only (to avoid solving errors in SolveSpace)
774 ////        if (aBaseFeature->getKind() == SketchPlugin_Arc::ID() &&
775 ////            (*anIt)->id() == SketchPlugin_Arc::END_ID())
776 ////          continue;
777 ////        addTemporaryConstraintWhereDragged(*anIt);
778 ////      }
779 ////    }
780 ////  }
781 ////  return true;
782 ////}
783 ////
784 ////// ============================================================================
785 //////  Function: changeFilletConstraint
786 //////  Class:    SketchSolver_Group
787 //////  Purpose:  create/update the "Fillet" constraint in the group
788 ////// ============================================================================
789 ////bool SketchSolver_Group::changeFilletConstraint(
790 ////    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
791 ////{
792 ////  DataPtr aConstrData = theConstraint->data();
793 ////
794 ////  // Search this constraint in the current group to update it
795 ////  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
796 ////  std::vector<Slvs_Constraint>::iterator aConstrIter;
797 ////  if (aConstrMapIter != myConstraintMap.end()) {
798 ////    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
799 ////    aConstrIter = myConstraints.begin() + aConstrPos;
800 ////  }
801 ////
802 ////  // Get constraint type and verify the constraint parameters are correct
803 ////  SketchSolver_Constraint aConstraint(theConstraint);
804 ////  int aConstrType = aConstraint.getType();
805 ////  if (aConstrType == SLVS_C_UNKNOWN)
806 ////    return false;
807 ////  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
808 ////
809 ////  // Obtain hEntity for basic objects of fillet
810 ////  Slvs_hEntity aBaseObject[2];
811 ////  FeaturePtr aBaseFeature[2];
812 ////  for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
813 ////    AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
814 ////        aConstrData->attribute(aConstraintAttributes[indAttr]));
815 ////    if (!aConstrAttr)
816 ////      return false;
817 ////    if (aConstrAttr->isObject() && aConstrAttr->object()) {
818 ////      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
819 ////          aConstrAttr->object());
820 ////      if (!aRC)
821 ////        return false;
822 ////      std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
823 ////      aBaseFeature[indAttr] = aDoc->feature(aRC);
824 ////    }
825 ////    aBaseObject[indAttr] = aConstrAttr->isObject() ?
826 ////        changeEntityFeature(aBaseFeature[indAttr]) : changeEntity(aConstrAttr->attr());
827 ////  }
828 ////  // Check the base entities have a coincident point
829 ////  int aBaseObjInd[2] = {
830 ////      Search(aBaseObject[0], myEntities),
831 ////      Search(aBaseObject[1], myEntities)
832 ////    };
833 ////  int aShift[2] = { // shift for calculating correct start and end points for different types of objects
834 ////      myEntities[aBaseObjInd[0]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
835 ////      myEntities[aBaseObjInd[1]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
836 ////    };
837 ////  Slvs_hEntity aFirstObjPoints[2] = { // indices of start and end point of first object
838 ////      myEntities[aBaseObjInd[0]].point[aShift[0]],
839 ////      myEntities[aBaseObjInd[0]].point[1+aShift[0]]
840 ////    };
841 ////  Slvs_hEntity aSecondObjPoints[2] = { // indices of start and end point of second object
842 ////      myEntities[aBaseObjInd[1]].point[aShift[1]],
843 ////      myEntities[aBaseObjInd[1]].point[1+aShift[1]]
844 ////    };
845 ////  bool isCoincidentFound = false;
846 ////  int aBaseCoincInd[2] = {0, 0}; // indices in aFirstObjPoint and aSecondObjPoint identifying coincident points
847 ////  std::vector<std::set<Slvs_hEntity> >::iterator aCPIter = myCoincidentPoints.begin();
848 ////  for ( ; aCPIter != myCoincidentPoints.end() && !isCoincidentFound; aCPIter++)
849 ////    for (int ind1 = 0; ind1 < 2 && !isCoincidentFound; ind1++)
850 ////      for (int ind2 = 0; ind2 < 2 && !isCoincidentFound; ind2++)
851 ////        if (aCPIter->find(aFirstObjPoints[ind1]) != aCPIter->end() &&
852 ////            aCPIter->find(aSecondObjPoints[ind2]) != aCPIter->end()) {
853 ////          aBaseCoincInd[0] = ind1;
854 ////          aBaseCoincInd[1] = ind2;
855 ////          isCoincidentFound = true;
856 ////        }
857 ////  if (!isCoincidentFound) {
858 ////    // There is no coincident points between objects. Generate error message
859 ////    Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
860 ////    return false;
861 ////  }
862 ////
863 ////  // Create fillet entities
864 ////  // - first object is placed on the first base 
865 ////  // - second object is on the second base 
866 ////  // - third object is a filleting arc
867 ////  static const int aNbFilletEnt = 3;
868 ////  Slvs_hEntity aFilletEnt[aNbFilletEnt];
869 ////  int aFilletObjInd[aNbFilletEnt];
870 ////  AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
871 ////      aConstrData->attribute(aConstraintAttributes[2]));
872 ////  if (!aFilletRefList)
873 ////    return false;
874 ////  std::list<ObjectPtr> aFilletList = aFilletRefList->list();
875 ////  if (aFilletList.size() < aNbFilletEnt)
876 ////    return false;
877 ////  FeaturePtr aFilletFeature;
878 ////  ResultConstructionPtr aRC;
879 ////  std::list<ObjectPtr>::iterator aFilIter = aFilletList.begin();
880 ////  for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) {
881 ////    aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aFilIter);
882 ////    aFilletFeature = aRC ? aRC->document()->feature(aRC) :
883 ////        std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFilIter);
884 ////    if (!aFilletFeature)
885 ////      return false;
886 ////    aFilletEnt[indEnt] = changeEntityFeature(aFilletFeature);
887 ////    aFilletObjInd[indEnt] = Search(aFilletEnt[indEnt], myEntities);
888 ////  }
889 ////  // At first time, for correct result, move floating points of fillet on the middle points of base objects
890 ////  if (myConstraintMap.find(theConstraint) == myConstraintMap.end()) {
891 ////    double anArcPoints[6];
892 ////    for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
893 ////      int anIndShift = myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
894 ////      int aPointsPos[2] = {
895 ////          Search(myEntities[aFilletObjInd[indEnt]].point[anIndShift], myEntities),
896 ////          Search(myEntities[aFilletObjInd[indEnt]].point[1+anIndShift], myEntities)
897 ////        };
898 ////      int aParamPos[2] = {
899 ////          Search(myEntities[aPointsPos[0]].param[0], myParams),
900 ////          Search(myEntities[aPointsPos[1]].param[0], myParams)
901 ////        };
902 ////      int anIndex = aParamPos[aBaseCoincInd[indEnt]];
903 ////      if (anIndShift == 0) {
904 ////        myParams[anIndex].val =
905 ////            0.5 * (myParams[aParamPos[0]].val + myParams[aParamPos[1]].val);
906 ////        myParams[1 + anIndex].val =
907 ////            0.5 * (myParams[1 + aParamPos[0]].val + myParams[1 + aParamPos[1]].val);
908 ////      } else { // place the changed point on the arc
909 ////        double x = 0, y = 0;
910 ////        calculateMiddlePoint(aFilletEnt[indEnt], x, y);
911 ////        myParams[anIndex].val = x;
912 ////        myParams[1 + anIndex].val = y;
913 ////      }
914 ////      anArcPoints[indEnt*2+2] = myParams[anIndex].val;
915 ////      anArcPoints[indEnt*2+3] = myParams[1 + anIndex].val;
916 ////    }
917 ////    anArcPoints[0] = 0.5 * (anArcPoints[2] + anArcPoints[4]);
918 ////    anArcPoints[1] = 0.5 * (anArcPoints[3] + anArcPoints[5]);
919 ////    for (int indArcPt = 0; indArcPt < 3; indArcPt++) {
920 ////      int aPtPos = Search(myEntities[aFilletObjInd[2]].point[indArcPt], myEntities);
921 ////      int aParamPos = Search(myEntities[aPtPos].param[0], myParams);
922 ////      myParams[aParamPos].val = anArcPoints[indArcPt * 2];
923 ////      myParams[aParamPos + 1].val = anArcPoints[indArcPt * 2 + 1];
924 ////    }
925 ////  }
926 ////
927 ////  // Check the fillet arc which point to be connected to
928 ////  bool isArcInversed = false; // indicates that start and end points of arc should be connected to second and first object respectively
929 ////  Slvs_hEntity hEnt = myEntities[aFilletObjInd[2]].point[1];
930 ////  int aPos = Search(hEnt, myEntities);
931 ////  Slvs_hParam anArcStartPoint = myEntities[aPos].param[0];
932 ////  aPos = Search(anArcStartPoint, myParams);
933 ////  double anArcPtCoord[2] = {myParams[aPos].val, myParams[aPos+1].val};
934 ////  double aSqDistances[2];
935 ////  int aPtInd;
936 ////  for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
937 ////    aPtInd = aBaseCoincInd[indEnt]+aShift[indEnt];
938 ////    hEnt = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
939 ////    aPos = Search(hEnt, myEntities);
940 ////    Slvs_hParam anObjectPoint = myEntities[aPos].param[0];
941 ////    aPos = Search(anObjectPoint, myParams);
942 ////    double aPtCoord[2] = {myParams[aPos].val, myParams[aPos+1].val};
943 ////    aSqDistances[indEnt] = 
944 ////        (anArcPtCoord[0] - aPtCoord[0]) * (anArcPtCoord[0] - aPtCoord[0]) +
945 ////        (anArcPtCoord[1] - aPtCoord[1]) * (anArcPtCoord[1] - aPtCoord[1]);
946 ////  }
947 ////  if (aSqDistances[1] < aSqDistances[0])
948 ////    isArcInversed = true;
949 ////
950 ////  // Create list of constraints to generate fillet
951 ////  std::vector<Slvs_hConstraint> aConstrList;
952 ////  bool isExists = myConstraintMap.find(theConstraint) != myConstraintMap.end(); // constraint already exists
953 ////  std::vector<Slvs_hConstraint>::iterator aCMapIter =
954 ////    isExists ? myConstraintMap[theConstraint].begin() : aConstrList.begin();
955 ////  int aCurConstrPos = isExists ? Search(*aCMapIter, myConstraints) : 0;
956 ////  for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
957 ////    // one point of fillet object should be coincident with the point on base, non-coincident with another base object
958 ////    aPtInd = 1-aBaseCoincInd[indEnt]+aShift[indEnt]; // (1-aBaseCoincInd[indEnt]) = index of non-coincident point, aShift is used to process all types of shapes
959 ////    Slvs_hEntity aPtBase = myEntities[aBaseObjInd[indEnt]].point[aPtInd];
960 ////    Slvs_hEntity aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
961 ////    if (isExists) {
962 ////      myConstraints[aCurConstrPos].ptA = aPtBase;
963 ////      myConstraints[aCurConstrPos].ptB = aPtFillet;
964 ////      aCMapIter++;
965 ////      aCurConstrPos = Search(*aCMapIter, myConstraints);
966 ////    } else {
967 ////      Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
968 ////          ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
969 ////          0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
970 ////      myConstraints.push_back(aCoincConstr);
971 ////      aConstrList.push_back(aCoincConstr.h);
972 ////    }
973 ////
974 ////    // another point of fillet object should be placed on the base object
975 ////    Slvs_Constraint aPonCurveConstr;
976 ////    int aTangentType;
977 ////    if (myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE) {
978 ////      // centers of arcs should be coincident
979 ////      aPtBase = myEntities[aBaseObjInd[indEnt]].point[0];
980 ////      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[0];
981 ////      if (isExists) {
982 ////        myConstraints[aCurConstrPos].ptA = aPtBase;
983 ////        myConstraints[aCurConstrPos].ptB = aPtFillet;
984 ////        aCMapIter++;
985 ////        aCurConstrPos = Search(*aCMapIter, myConstraints);
986 ////      } else {
987 ////        aPonCurveConstr = Slvs_MakeConstraint(
988 ////            ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
989 ////            0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
990 ////      }
991 ////      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[1+aBaseCoincInd[indEnt]]; // !!! will be used below
992 ////      aTangentType = SLVS_C_CURVE_CURVE_TANGENT;
993 ////    } else {
994 ////      aPtInd = aBaseCoincInd[indEnt];
995 ////      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
996 ////      if (isExists) {
997 ////        myConstraints[aCurConstrPos].ptA = aPtFillet;
998 ////        aCMapIter++;
999 ////        aCurConstrPos = Search(*aCMapIter, myConstraints);
1000 ////      } else {
1001 ////        aPonCurveConstr = Slvs_MakeConstraint(
1002 ////            ++myConstrMaxID, myID, SLVS_C_PT_ON_LINE, myWorkplane.h,
1003 ////            0, aPtFillet, SLVS_E_UNKNOWN, aBaseObject[indEnt], SLVS_E_UNKNOWN);
1004 ////      }
1005 ////      aTangentType = SLVS_C_ARC_LINE_TANGENT;
1006 ////    }
1007 ////    if (!isExists) {
1008 ////      myConstraints.push_back(aPonCurveConstr);
1009 ////      aConstrList.push_back(aPonCurveConstr.h);
1010 ////    }
1011 ////
1012 ////    // Bound point of fillet arc should be tangently coincident with a bound point of fillet object
1013 ////    aPtInd = 1 + (isArcInversed ? 1-indEnt : indEnt);
1014 ////    Slvs_hEntity aPtArc = myEntities[aFilletObjInd[2]].point[aPtInd];
1015 ////    if (isExists) {
1016 ////      myConstraints[aCurConstrPos].ptA = aPtArc;
1017 ////      myConstraints[aCurConstrPos].ptB = aPtFillet;
1018 ////      aCMapIter++;
1019 ////      aCurConstrPos = Search(*aCMapIter, myConstraints);
1020 ////      myConstraints[aCurConstrPos].entityA = aFilletEnt[2];
1021 ////      myConstraints[aCurConstrPos].entityB = aFilletEnt[indEnt];
1022 ////      myConstraints[aCurConstrPos].other = (isArcInversed ? 1-indEnt : indEnt);
1023 ////      aCMapIter++;
1024 ////      aCurConstrPos = Search(*aCMapIter, myConstraints);
1025 ////    } else {
1026 ////      Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
1027 ////          ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
1028 ////          0, aPtArc, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
1029 ////      myConstraints.push_back(aCoincConstr);
1030 ////      aConstrList.push_back(aCoincConstr.h);
1031 ////      Slvs_Constraint aTangency = Slvs_MakeConstraint(
1032 ////          ++myConstrMaxID, myID, aTangentType, myWorkplane.h,
1033 ////          0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aFilletEnt[2], aFilletEnt[indEnt]);
1034 ////      aTangency.other = (isArcInversed ? 1-indEnt : indEnt);
1035 ////      aTangency.other2 = aTangentType == SLVS_C_CURVE_CURVE_TANGENT ? aBaseCoincInd[indEnt] : 0;
1036 ////      myConstraints.push_back(aTangency);
1037 ////      aConstrList.push_back(aTangency.h);
1038 ////    }
1039 ////  }
1040 ////
1041 ////  // Additional constraint for fillet diameter
1042 ////  double aRadius = 0.0;  // scalar value of the constraint
1043 ////  AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
1044 ////      aConstrData->attribute(SketchPlugin_Constraint::VALUE()));
1045 ////  aRadius = aDistAttr->value();
1046 ////  if (isExists) {
1047 ////    myConstraints[aCurConstrPos].entityA = aFilletEnt[2];
1048 ////    myConstraints[aCurConstrPos].valA = aRadius * 2.0;
1049 ////    aCMapIter++;
1050 ////  } else {
1051 ////    Slvs_Constraint aDiamConstr = Slvs_MakeConstraint(
1052 ////        ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, aRadius * 2.0,
1053 ////        SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aFilletEnt[2], SLVS_E_UNKNOWN);
1054 ////    myConstraints.push_back(aDiamConstr);
1055 ////    aConstrList.push_back(aDiamConstr.h);
1056 ////
1057 ////    myConstraintMap[theConstraint] = aConstrList;
1058 ////  }
1059 ////
1060 ////  // Additional temporary constraints for base objects to be fixed
1061 ////  for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
1062 ////    if (!aBaseFeature[indAttr]) {
1063 ////      AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1064 ////          aConstrData->attribute(aConstraintAttributes[indAttr]));
1065 ////      addTemporaryConstraintWhereDragged(aConstrAttr->attr());
1066 ////      continue;
1067 ////    }
1068 ////    std::list<AttributePtr> anAttributes =
1069 ////        aBaseFeature[indAttr]->data()->attributes(GeomDataAPI_Point2D::type());
1070 ////    std::list<AttributePtr>::iterator anIt = anAttributes.begin();
1071 ////    for ( ; anIt != anAttributes.end(); anIt++) {
1072 ////      // Arc should be fixed by center and start points only (to avoid "conflicting constraints" message)
1073 ////      if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Arc::ID() &&
1074 ////          (*anIt)->id() == SketchPlugin_Arc::END_ID())
1075 ////        continue;
1076 ////      addTemporaryConstraintWhereDragged(*anIt);
1077 ////    }
1078 ////  }
1079 ////  return true;
1080 ////}
1081 ////
1082 ////// ============================================================================
1083 //////  Function: changeEntity
1084 //////  Class:    SketchSolver_Group
1085 //////  Purpose:  create/update the element affected by any constraint
1086 ////// ============================================================================
1087 ////Slvs_hEntity SketchSolver_Group::changeEntity(
1088 ////    std::shared_ptr<ModelAPI_Attribute> theEntity)
1089 ////{
1090 ////  // If the entity is already in the group, try to find it
1091 ////  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
1092 ////      myEntityAttrMap.find(theEntity);
1093 ////  int aEntPos;
1094 ////  std::vector<Slvs_Param>::const_iterator aParamIter;  // looks at first parameter of already existent entity or at the end of vector otherwise
1095 ////  if (aEntIter == myEntityAttrMap.end())  // no such entity => should be created
1096 ////    aParamIter = myParams.end();
1097 ////  else {  // the entity already exists
1098 ////    aEntPos = Search(aEntIter->second, myEntities);
1099 ////    int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
1100 ////    aParamIter = myParams.begin() + aParamPos;
1101 ////  }
1102 ////  const bool isEntExists = (aEntIter != myEntityAttrMap.end());  // defines that the entity already exists
1103 ////  const bool isNeedToSolve = myNeedToSolve;
1104 ////  myNeedToSolve = false;
1105 ////
1106 ////  if (isEntExists) {
1107 ////    // Verify that the entity is not used by "Rigid" constraint.
1108 ////    // If it is used, the object should not move.
1109 ////    std::vector<std::set<Slvs_hEntity> >::iterator aCoincIter = myCoincidentPoints.begin();
1110 ////    for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
1111 ////      if (aCoincIter->find(aEntIter->second) != aCoincIter->end())
1112 ////        break;
1113 ////    std::set<Slvs_hEntity> aCoincident;
1114 ////    if (aCoincIter != myCoincidentPoints.end()) {
1115 ////      aCoincident = *aCoincIter;
1116 ////      aCoincident.erase(aEntIter->second);
1117 ////
1118 ////      std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1119 ////      for (; aConstrIter != myConstraints.end(); aConstrIter++)
1120 ////        if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
1121 ////            aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
1122 ////          myNeedToSolve = true;
1123 ////          return aEntIter->second;
1124 ////        }
1125 ////    }
1126 ////  }
1127 ////
1128 ////  // Look over supported types of entities
1129 ////  Slvs_Entity aNewEntity;
1130 ////  aNewEntity.h = SLVS_E_UNKNOWN;
1131 ////
1132 ////  // Point in 3D
1133 ////  std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1134 ////      theEntity);
1135 ////  if (aPoint) {
1136 ////    Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
1137 ////    Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
1138 ////    Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
1139 ////    if (!isEntExists) // New entity
1140 ////      aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
1141 ////  } else {
1142 ////    // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
1143 ////    if (myWorkplane.h == SLVS_E_UNKNOWN)
1144 ////      return SLVS_E_UNKNOWN;
1145 ////
1146 ////    // Point in 2D
1147 ////    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
1148 ////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
1149 ////    if (aPoint2D) {
1150 ////      Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
1151 ////      Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
1152 ////      if (!isEntExists) // New entity
1153 ////        aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
1154 ////    } else {
1155 ////      // Scalar value (used for the distance entities)
1156 ////      AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
1157 ////      if (aScalar) {
1158 ////        Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
1159 ////        if (!isEntExists) // New entity
1160 ////          aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
1161 ////      }
1162 ////    }
1163 ////  }
1164 ////  /// \todo Other types of entities
1165 ////
1166 ////  Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type
1167 ////
1168 ////  if (isEntExists) {
1169 ////    myNeedToSolve = myNeedToSolve || isNeedToSolve;
1170 ////    aResult = aEntIter->second;
1171 ////  } else if (aNewEntity.h != SLVS_E_UNKNOWN) {
1172 ////    myEntities.push_back(aNewEntity);
1173 ////    myEntOfConstr.push_back(false);
1174 ////    myEntityAttrMap[theEntity] = aNewEntity.h;
1175 ////    aResult = aNewEntity.h;
1176 ////  }
1177 ////
1178 ////  // If the attribute was changed by the user, we need to fix it before solving
1179 ////  if (myNeedToSolve && theEntity->isImmutable())
1180 ////    addTemporaryConstraintWhereDragged(theEntity, false);
1181 ////
1182 ////  return aResult;
1183 ////}
1184 ////
1185 ////// ============================================================================
1186 //////  Function: changeEntity
1187 //////  Class:    SketchSolver_Group
1188 //////  Purpose:  create/update the element defined by the feature affected by any constraint
1189 ////// ============================================================================
1190 ////Slvs_hEntity SketchSolver_Group::changeEntityFeature(FeaturePtr theEntity)
1191 ////{
1192 ////  if (!theEntity->data()->isValid())
1193 ////    return SLVS_E_UNKNOWN;
1194 ////  // If the entity is already in the group, try to find it
1195 ////  std::map<FeaturePtr, Slvs_hEntity>::const_iterator aEntIter = myEntityFeatMap.find(theEntity);
1196 ////  // defines that the entity already exists
1197 ////  const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
1198 ////  
1199 ////  Slvs_Entity aNewEntity;
1200 ////  aNewEntity.h = SLVS_E_UNKNOWN;
1201 ////
1202 ////  // SketchPlugin features
1203 ////  std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
1204 ////      SketchPlugin_Feature>(theEntity);
1205 ////  if (aFeature) {  // Verify the feature by its kind
1206 ////    const std::string& aFeatureKind = aFeature->getKind();
1207 ////    AttributePtr anAttribute;
1208 ////
1209 ////    // Line
1210 ////    if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
1211 ////      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
1212 ////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1213 ////      Slvs_hEntity aStart = changeEntity(anAttribute);
1214 ////
1215 ////      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
1216 ////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1217 ////      Slvs_hEntity aEnd = changeEntity(anAttribute);
1218 ////
1219 ////      if (!isEntExists) // New entity
1220 ////        aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
1221 ////    }
1222 ////    // Circle
1223 ////    else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
1224 ////      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
1225 ////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1226 ////      Slvs_hEntity aCenter = changeEntity(anAttribute);
1227 ////
1228 ////      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
1229 ////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1230 ////      Slvs_hEntity aRadius = changeEntity(anAttribute);
1231 ////
1232 ////      if (!isEntExists) // New entity
1233 ////        aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter,
1234 ////                                     myWorkplane.normal, aRadius);
1235 ////    }
1236 ////    // Arc
1237 ////    else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
1238 ////      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
1239 ////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1240 ////      Slvs_hEntity aCenter = changeEntity(anAttribute);
1241 ////
1242 ////      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
1243 ////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1244 ////      Slvs_hEntity aStart = changeEntity(anAttribute);
1245 ////
1246 ////      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
1247 ////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1248 ////      Slvs_hEntity aEnd = changeEntity(anAttribute);
1249 ////
1250 ////      if (!isEntExists)
1251 ////        aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h,
1252 ////                                          myWorkplane.normal, aCenter, aStart, aEnd);
1253 ////    }
1254 ////    // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
1255 ////    else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) {
1256 ////      anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
1257 ////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1258 ////      Slvs_hEntity aPoint = changeEntity(anAttribute);
1259 ////
1260 ////      if (isEntExists)
1261 ////        return aEntIter->second;
1262 ////
1263 ////      // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
1264 ////      myEntityFeatMap[theEntity] = aPoint;
1265 ////      myNeedToSolve = true;
1266 ////      return aPoint;
1267 ////    }
1268 ////  }
1269 ////  /// \todo Other types of features
1270 ////
1271 ////  if (isEntExists)
1272 ////    return aEntIter->second;
1273 ////
1274 ////  if (aNewEntity.h != SLVS_E_UNKNOWN) {
1275 ////    myEntities.push_back(aNewEntity);
1276 ////    myEntOfConstr.push_back(false);
1277 ////    myEntityFeatMap[theEntity] = aNewEntity.h;
1278 ////    myNeedToSolve = true;
1279 ////    return aNewEntity.h;
1280 ////  }
1281 ////
1282 ////  // Unsupported or wrong entity type
1283 ////  return SLVS_E_UNKNOWN;
1284 ////}
1285
1286 // ============================================================================
1287 //  Function: addWorkplane
1288 //  Class:    SketchSolver_Group
1289 //  Purpose:  create workplane for the group
1290 // ============================================================================
1291 bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch)
1292 {
1293   if (myWorkplaneID != SLVS_E_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID())
1294     return false;  // the workplane already exists or the function parameter is not Sketch
1295
1296   mySketch = theSketch;
1297   updateWorkplane();
1298   return true;
1299 }
1300
1301 // ============================================================================
1302 //  Function: updateWorkplane
1303 //  Class:    SketchSolver_Group
1304 //  Purpose:  update parameters of workplane
1305 // ============================================================================
1306 bool SketchSolver_Group::updateWorkplane()
1307 {
1308   if (!myStorage) // Create storage if not exists
1309     myStorage = StoragePtr(new SketchSolver_Storage);
1310   SketchSolver_Builder* aBuilder = SketchSolver_Builder::getInstance();
1311
1312   std::vector<Slvs_Entity> anEntities;
1313   std::vector<Slvs_Param> aParams;
1314   if (!aBuilder->createWorkplane(mySketch, anEntities, aParams))
1315     return false;
1316
1317   if (myWorkplaneID == SLVS_E_UNKNOWN) {
1318     myWorkplaneID = anEntities.back().h;
1319     // Add new workplane elements
1320     std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
1321     for (; aParIter != aParams.end(); aParIter++) {
1322       aParIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
1323       aParIter->group = myID;
1324       aParIter->h = myStorage->addParameter(*aParIter);
1325     }
1326     std::vector<Slvs_Entity>::iterator anEntIter = anEntities.begin();
1327     for (; anEntIter != anEntities.end(); anEntIter++) {
1328       anEntIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
1329       anEntIter->group = myID;
1330       anEntIter->wrkpl = myWorkplaneID;
1331       for (int i = 0; i < 4; i++)
1332         if (anEntIter->param[i] != SLVS_E_UNKNOWN)
1333           anEntIter->param[i] = aParams[anEntIter->param[i]-1].h;
1334       for (int i = 0; i < 4; i++)
1335         if (anEntIter->point[i] != SLVS_E_UNKNOWN)
1336           anEntIter->point[i] = anEntities[anEntIter->point[i]-1].h;
1337       anEntIter->h = myStorage->addEntity(*anEntIter);
1338     }
1339   } else {
1340     // Update existent workplane
1341     const Slvs_Entity& aWP = myStorage->getEntity(myWorkplaneID);
1342     const Slvs_Entity& anOrigin = myStorage->getEntity(aWP.point[0]);
1343     const Slvs_Entity& aNormal = myStorage->getEntity(aWP.normal);
1344     // Get parameters and update them
1345     Slvs_hParam aWPParams[7] = {
1346         anOrigin.param[0], anOrigin.param[1], anOrigin.param[2],
1347         aNormal.param[0], aNormal.param[1], aNormal.param[2], aNormal.param[3]
1348       };
1349     std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
1350     for (int i = 0; aParIter != aParams.end(); aParIter++, i++) {
1351       Slvs_Param aParam = myStorage->getParameter(aWPParams[i]);
1352       aParam.val = aParIter->val;
1353       myStorage->updateParameter(aParam);
1354     }
1355   }
1356   return myWorkplaneID > 0;
1357 }
1358
1359 ////// ============================================================================
1360 //////  Function: changeParameter
1361 //////  Class:    SketchSolver_Group
1362 //////  Purpose:  create/update value of parameter
1363 ////// ============================================================================
1364 ////Slvs_hParam SketchSolver_Group::changeParameter(
1365 ////    const double& theParam, std::vector<Slvs_Param>::const_iterator& thePrmIter)
1366 ////{
1367 ////  if (thePrmIter != myParams.end()) {  // Parameter should be updated
1368 ////    int aParamPos = thePrmIter - myParams.begin();
1369 ////    if (fabs(thePrmIter->val - theParam) > tolerance) {
1370 ////      myNeedToSolve = true;  // parameter is changed, need to resolve constraints
1371 ////      myParams[aParamPos].val = theParam;
1372 ////    }
1373 ////    thePrmIter++;
1374 ////    return myParams[aParamPos].h;
1375 ////  }
1376 ////
1377 ////  // Newly created parameter
1378 ////  Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
1379 ////  myParams.push_back(aParam);
1380 ////  myNeedToSolve = true;
1381 ////  // The list of parameters is changed, move iterator to the end of the list to avoid problems
1382 ////  thePrmIter = myParams.end();
1383 ////  return aParam.h;
1384 ////}
1385
1386 // ============================================================================
1387 //  Function: resolveConstraints
1388 //  Class:    SketchSolver_Group
1389 //  Purpose:  solve the set of constraints for the current group
1390 // ============================================================================
1391 bool SketchSolver_Group::resolveConstraints()
1392 {
1393   bool aResolved = false;
1394   if (myStorage->isNeedToResolve() && !isEmpty()) {
1395     myConstrSolver.setGroupID(myID);
1396     myStorage->initializeSolver(myConstrSolver);
1397
1398     int aResult = myConstrSolver.solve();
1399     if (aResult == SLVS_RESULT_OKAY) {  // solution succeeded, store results into correspondent attributes
1400       ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
1401       for (; aConstrIter != myConstraints.end(); aConstrIter++)
1402         aConstrIter->second->refresh();
1403     } else if (!myConstraints.empty())
1404       Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
1405
1406     myStorage->setNeedToResolve(false);
1407     aResolved = true;
1408   }
1409   removeTemporaryConstraints();
1410   return aResolved;
1411 }
1412
1413 // ============================================================================
1414 //  Function: mergeGroups
1415 //  Class:    SketchSolver_Group
1416 //  Purpose:  append specified group to the current group
1417 // ============================================================================
1418 void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
1419 {
1420   // If specified group is empty, no need to merge
1421   if (theGroup.isEmpty())
1422     return;
1423   if (!myFeatureStorage)
1424     myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
1425
1426   ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
1427   for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++)
1428     changeConstraint(aConstrIter->first);
1429 }
1430
1431 // ============================================================================
1432 //  Function: splitGroup
1433 //  Class:    SketchSolver_Group
1434 //  Purpose:  divide the group into several subgroups
1435 // ============================================================================
1436 void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
1437 {
1438   // Obtain constraints, which should be separated
1439   FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage);
1440   std::vector<ConstraintPtr> anUnusedConstraints;
1441   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
1442   for ( ; aCIter != myConstraints.end(); aCIter++) {
1443     std::list<ConstraintPtr> aBaseConstraints = aCIter->second->constraints();
1444     std::list<ConstraintPtr>::iterator anIter = aBaseConstraints.begin();
1445     for (; anIter != aBaseConstraints.end(); anIter++)
1446       if (aNewFeatStorage->isInteract(*anIter)) {
1447         aNewFeatStorage->changeConstraint(*anIter);
1448       } else
1449         anUnusedConstraints.push_back(*anIter);
1450   }
1451
1452   std::vector<SketchSolver_Group*>::iterator aCutsIter;
1453   std::vector<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
1454   for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) {
1455     // Remove unused constraints
1456     removeConstraint(*aUnuseIt);
1457     // Try to append constraint to already existent group
1458     for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); aCutsIter++)
1459       if ((*aCutsIter)->isInteract(*aUnuseIt)) {
1460         (*aCutsIter)->changeConstraint(*aUnuseIt);
1461         break;
1462       }
1463     if (aCutsIter == theCuts.end()) {
1464       // Add new group
1465       SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch);
1466       aGroup->changeConstraint(*aUnuseIt);
1467       theCuts.push_back(aGroup);
1468     }
1469   }
1470 }
1471
1472 // ============================================================================
1473 //  Function: isConsistent
1474 //  Class:    SketchSolver_Group
1475 //  Purpose:  search removed entities and constraints
1476 // ============================================================================
1477 bool SketchSolver_Group::isConsistent()
1478 {
1479   if (!myFeatureStorage) // no one constraint is initialized yet
1480     return true;
1481
1482   bool aResult = myFeatureStorage->isConsistent();
1483   if (!aResult) {
1484     // remove invalid entities
1485     ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
1486     while (aCIter != myConstraints.end()) {
1487       std::list<ConstraintPtr> aConstraints = aCIter->second->constraints();
1488       std::list<ConstraintPtr>::iterator anIt = aConstraints.begin();
1489       for (; anIt != aConstraints.end(); anIt++)
1490         if (!(*anIt)->data() || !(*anIt)->data()->isValid())
1491           if (aCIter->second->remove(*anIt)) {
1492             // the constraint is fully removed, detach it from the list
1493             ConstraintConstraintMap::iterator aTmpIt = aCIter++;
1494             myFeatureStorage->removeConstraint(aTmpIt->first);
1495             myConstraints.erase(aTmpIt);
1496             break;
1497           }
1498       if (anIt == aConstraints.end())
1499         aCIter++;
1500     }
1501   }
1502   return aResult;
1503 }
1504
1505 ////// ============================================================================
1506 //////  Function: updateAttribute
1507 //////  Class:    SketchSolver_Group
1508 //////  Purpose:  update features of sketch after resolving constraints
1509 ////// ============================================================================
1510 ////bool SketchSolver_Group::updateAttribute(
1511 ////    std::shared_ptr<ModelAPI_Attribute> theAttribute, const Slvs_hEntity& theEntityID)
1512 ////{
1513 ////  // Search the position of the first parameter of the entity
1514 ////  int anEntPos = Search(theEntityID, myEntities);
1515 ////  int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
1516 ////
1517 ////  // Look over supported types of entities
1518 ////
1519 ////  // Point in 3D
1520 ////  std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1521 ////      theAttribute);
1522 ////  if (aPoint) {
1523 ////    if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance
1524 ////        || fabs(aPoint->y() - myParams[aFirstParamPos + 1].val) > tolerance
1525 ////        || fabs(aPoint->z() - myParams[aFirstParamPos + 2].val) > tolerance) {
1526 ////      aPoint->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val,
1527 ////                       myParams[aFirstParamPos + 2].val);
1528 ////      return true;
1529 ////    }
1530 ////    return false;
1531 ////  }
1532 ////
1533 ////  // Point in 2D
1534 ////  std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
1535 ////      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
1536 ////  if (aPoint2D) {
1537 ////    if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance
1538 ////        || fabs(aPoint2D->y() - myParams[aFirstParamPos + 1].val) > tolerance) {
1539 ////      aPoint2D->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val);
1540 ////      return true;
1541 ////    }
1542 ////    return false;
1543 ////  }
1544 ////
1545 ////  // Scalar value
1546 ////  AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
1547 ////  if (aScalar) {
1548 ////    if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance) {
1549 ////      aScalar->setValue(myParams[aFirstParamPos].val);
1550 ////      return true;
1551 ////    }
1552 ////    return false;
1553 ////  }
1554 ////
1555 ////  /// \todo Support other types of entities
1556 ////  return false;
1557 ////}
1558 ////
1559 ////// ============================================================================
1560 //////  Function: updateEntityIfPossible
1561 //////  Class:    SketchSolver_Group
1562 //////  Purpose:  search the entity in this group and update it
1563 ////// ============================================================================
1564 ////void SketchSolver_Group::updateEntityIfPossible(
1565 ////    std::shared_ptr<ModelAPI_Attribute> theEntity)
1566 ////{
1567 ////  if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) {
1568 ////    // If the attribute is a point and it is changed (the group needs to rebuild),
1569 ////    // probably user has dragged this point into this position,
1570 ////    // so it is necessary to add constraint which will guarantee the point will not change
1571 ////
1572 ////    // Store myNeedToSolve flag to verify the entity is really changed
1573 ////    bool aNeedToSolveCopy = myNeedToSolve;
1574 ////    myNeedToSolve = false;
1575 ////
1576 ////    changeEntity(theEntity);
1577 ////
1578 ////    if (myNeedToSolve)  // the entity is changed
1579 ////    {
1580 ////      // Verify the entity is a point and add temporary constraint of permanency
1581 ////      std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1582 ////          theEntity);
1583 ////      std::shared_ptr<GeomDataAPI_Point2D> aPoint2D = std::dynamic_pointer_cast<
1584 ////          GeomDataAPI_Point2D>(theEntity);
1585 ////      if (aPoint || aPoint2D)
1586 ////        addTemporaryConstraintWhereDragged(theEntity);
1587 ////    }
1588 ////
1589 ////    // Restore flag of changes
1590 ////    myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
1591 ////
1592 ////    if (myNeedToSolve)
1593 ////      updateRelatedConstraints(theEntity);
1594 ////  }
1595 ////}
1596 ////
1597 ////// ============================================================================
1598 //////  Function: addTemporaryConstraintWhereDragged
1599 //////  Class:    SketchSolver_Group
1600 //////  Purpose:  add transient constraint SLVS_C_WHERE_DRAGGED for the entity, 
1601 //////            which was moved by user
1602 ////// ============================================================================
1603 ////void SketchSolver_Group::addTemporaryConstraintWhereDragged(
1604 ////    std::shared_ptr<ModelAPI_Attribute> theEntity,
1605 ////    bool theAllowToFit)
1606 ////{
1607 ////  // Find identifier of the entity
1608 ////  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
1609 ////      myEntityAttrMap.find(theEntity);
1610 ////  if (anEntIter == myEntityAttrMap.end())
1611 ////    return;
1612 ////
1613 ////  // Get identifiers of all dragged points
1614 ////  std::set<Slvs_hEntity> aDraggedPntID;
1615 ////  aDraggedPntID.insert(myTempPointWDrgdID);
1616 ////  std::list<Slvs_hConstraint>::const_iterator aTmpCoIter = myTempConstraints.begin();
1617 ////  for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) {
1618 ////    unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
1619 ////    if (aConstrPos < myConstraints.size())
1620 ////      aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
1621 ////  }
1622 ////  std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1623 ////  for (; aConstrIter != myConstraints.end(); aConstrIter++)
1624 ////    if (aConstrIter->type == SLVS_C_WHERE_DRAGGED)
1625 ////      aDraggedPntID.insert(aConstrIter->ptA);
1626 ////  // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
1627 ////  std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1628 ////  for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) {
1629 ////    if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
1630 ////      continue;  // the entity was not found in current set
1631 ////
1632 ////    // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
1633 ////    std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
1634 ////    for (; aDrgIter != aDraggedPntID.end(); aDrgIter++)
1635 ////      if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
1636 ////        return;  // the SLVS_C_WHERE_DRAGGED constraint already exists
1637 ////  }
1638 ////  if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end())
1639 ////    return;
1640 ////
1641 ////  // If this is a first dragged point, its parameters should be placed 
1642 ////  // into Slvs_System::dragged field to avoid system inconsistense
1643 ////  if (myTempPointWhereDragged.empty() && theAllowToFit) {
1644 ////    int anEntPos = Search(anEntIter->second, myEntities);
1645 ////    Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
1646 ////    for (int i = 0; i < 4; i++, aDraggedParam++)
1647 ////      if (*aDraggedParam != 0)
1648 ////        myTempPointWhereDragged.push_back(*aDraggedParam);
1649 ////    myTempPointWDrgdID = myEntities[anEntPos].h;
1650 ////    return;
1651 ////  }
1652 ////
1653 ////  // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
1654 ////  Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
1655 ////                                                  myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
1656 ////  myConstraints.push_back(aWDConstr);
1657 ////  myTempConstraints.push_back(aWDConstr.h);
1658 ////}
1659
1660 // ============================================================================
1661 //  Function: removeTemporaryConstraints
1662 //  Class:    SketchSolver_Group
1663 //  Purpose:  remove all transient SLVS_C_WHERE_DRAGGED constraints after
1664 //            resolving the set of constraints
1665 // ============================================================================
1666 void SketchSolver_Group::removeTemporaryConstraints()
1667 {
1668   myTempConstraints.clear();
1669   // Clean lists of removed entities in the storage
1670   std::set<Slvs_hParam> aRemPar;
1671   std::set<Slvs_hEntity> aRemEnt;
1672   std::set<Slvs_hConstraint> aRemCon;
1673   myStorage->getRemoved(aRemPar, aRemEnt, aRemCon);
1674 }
1675
1676 // ============================================================================
1677 //  Function: removeConstraint
1678 //  Class:    SketchSolver_Group
1679 //  Purpose:  remove constraint and all unused entities
1680 // ============================================================================
1681 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
1682 {
1683   myFeatureStorage->removeConstraint(theConstraint);
1684   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
1685   for (; aCIter != myConstraints.end(); aCIter++)
1686     if (aCIter->second->hasConstraint(theConstraint)) {
1687       if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed
1688         aCIter = myConstraints.end();
1689       break;
1690     }
1691   if (aCIter != myConstraints.end())
1692     myConstraints.erase(aCIter);
1693 }
1694
1695 ////// ============================================================================
1696 //////  Function: removeEntitiesById
1697 //////  Class:    SketchSolver_Group
1698 //////  Purpose:  Removes specified entities and their parameters
1699 ////// ============================================================================
1700 ////void SketchSolver_Group::removeEntitiesById(const std::set<Slvs_hEntity>& theEntities)
1701 ////{
1702 ////  std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = theEntities.rbegin();
1703 ////  for (; aRemIter != theEntities.rend(); aRemIter++) {
1704 ////    unsigned int anEntPos = Search(*aRemIter, myEntities);
1705 ////    if (anEntPos >= myEntities.size())
1706 ////      continue;
1707 ////    if (myEntities[anEntPos].param[0] != 0) {
1708 ////      unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
1709 ////      if (aParamPos >= myParams.size())
1710 ////        continue;
1711 ////      int aNbParams = 0;
1712 ////      while (myEntities[anEntPos].param[aNbParams] != 0)
1713 ////        aNbParams++;
1714 ////      if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID)
1715 ////        myParamMaxID -= aNbParams;
1716 ////      myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
1717 ////      if (*aRemIter == myEntityMaxID)
1718 ////        myEntityMaxID--;
1719 ////    }
1720 ////    myEntities.erase(myEntities.begin() + anEntPos);
1721 ////    myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos);
1722 ////
1723 ////    // Remove entity's ID from the lists of conincident points
1724 ////    std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1725 ////    for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
1726 ////      aCoPtIter->erase(*aRemIter);
1727 ////  }
1728 ////}
1729 ////
1730 ////// ============================================================================
1731 //////  Function: addCoincidentPoints
1732 //////  Class:    SketchSolver_Group
1733 //////  Purpose:  add coincident point the appropriate list of such points
1734 ////// ============================================================================
1735 ////bool SketchSolver_Group::addCoincidentPoints(const Slvs_hEntity& thePoint1,
1736 ////                                                       const Slvs_hEntity& thePoint2)
1737 ////{
1738 ////  std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1739 ////  std::vector<std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
1740 ////  while (aCoPtIter != myCoincidentPoints.end()) {
1741 ////    bool isFound[2] = {  // indicate which point ID was already in coincidence constraint
1742 ////        aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2)
1743 ////            != aCoPtIter->end(), };
1744 ////    if (isFound[0] && isFound[1])  // points are already connected by coincidence constraints => no need additional one
1745 ////      return false;
1746 ////    if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) {
1747 ////      if (aFirstFound != myCoincidentPoints.end()) {  // there are two groups of coincident points connected by created constraint => merge them
1748 ////        int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
1749 ////        int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
1750 ////        aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
1751 ////        myCoincidentPoints.erase(aCoPtIter);
1752 ////        aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
1753 ////        aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
1754 ////        continue;
1755 ////      } else {
1756 ////        aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
1757 ////        aFirstFound = aCoPtIter;
1758 ////      }
1759 ////    }
1760 ////    aCoPtIter++;
1761 ////  }
1762 ////  // No points were found, need to create new set
1763 ////  if (aFirstFound == myCoincidentPoints.end()) {
1764 ////    std::set<Slvs_hEntity> aNewSet;
1765 ////    aNewSet.insert(thePoint1);
1766 ////    aNewSet.insert(thePoint2);
1767 ////    myCoincidentPoints.push_back(aNewSet);
1768 ////  }
1769 ////
1770 ////  return true;
1771 ////}
1772 ////
1773 ////// ============================================================================
1774 //////  Function: updateRelatedConstraints
1775 //////  Class:    SketchSolver_Group
1776 //////  Purpose:  emit the signal to update constraints
1777 ////// ============================================================================
1778 ////void SketchSolver_Group::updateRelatedConstraints(
1779 ////    std::shared_ptr<ModelAPI_Attribute> theEntity) const
1780 ////{
1781 ////  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
1782 ////  for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
1783 ////    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
1784 ////        ->attributes(std::string());
1785 ////
1786 ////    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
1787 ////    for (; anAttrIter != anAttributes.end(); anAttrIter++) {
1788 ////      bool isUpd = (*anAttrIter == theEntity);
1789 ////      std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
1790 ////          ModelAPI_AttributeRefAttr>(*anAttrIter);
1791 ////      if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
1792 ////        isUpd = true;
1793 ////
1794 ////      if (isUpd) {
1795 ////        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1796 ////        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
1797 ////        break;
1798 ////      }
1799 ////    }
1800 ////  }
1801 ////}
1802 ////
1803 ////void SketchSolver_Group::updateRelatedConstraintsFeature(
1804 ////    std::shared_ptr<ModelAPI_Feature> theFeature) const
1805 ////{
1806 ////  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
1807 ////  for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
1808 ////    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
1809 ////        ->attributes(std::string());
1810 ////
1811 ////    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
1812 ////    for (; anAttrIter != anAttributes.end(); anAttrIter++) {
1813 ////      std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
1814 ////          ModelAPI_AttributeRefAttr>(*anAttrIter);
1815 ////      if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature) {
1816 ////        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1817 ////        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
1818 ////        break;
1819 ////      }
1820 ////    }
1821 ////  }
1822 ////}
1823 ////
1824 ////// ============================================================================
1825 //////  Function: updateFilletConstraints
1826 //////  Class:    SketchSolver_Group
1827 //////  Purpose:  change fillet arc to be less than 180 degree
1828 ////// ============================================================================
1829 ////void SketchSolver_Group::updateFilletConstraints()
1830 ////{
1831 ////  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
1832 ////  for (; aConstrIter != myConstraintMap.end(); aConstrIter++)
1833 ////    if (aConstrIter->first->getKind() == SketchPlugin_ConstraintFillet::ID()) {
1834 ////      AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
1835 ////          aConstrIter->first->data()->attribute(SketchPlugin_ConstraintFillet::ENTITY_C()));
1836 ////      if (!aFilletRefList)
1837 ////        return;
1838 ////      ObjectPtr anArcObj = aFilletRefList->object(2);
1839 ////      std::shared_ptr<GeomDataAPI_Point2D> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1840 ////          anArcObj->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
1841 ////      std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1842 ////          anArcObj->data()->attribute(SketchPlugin_Arc::START_ID()));
1843 ////      std::shared_ptr<GeomDataAPI_Point2D> aEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1844 ////          anArcObj->data()->attribute(SketchPlugin_Arc::END_ID()));
1845 ////      double aCosA = aStart->x() - aCenter->x();
1846 ////      double aSinA = aStart->y() - aCenter->y();
1847 ////      double aCosB = aEnd->x() - aCenter->x();
1848 ////      double aSinB = aEnd->y() - aCenter->y();
1849 ////      if (aCosA * aSinB - aSinA * aCosB <= 0.0) {
1850 ////        anArcObj->data()->blockSendAttributeUpdated(true);
1851 ////        double x = aStart->x();
1852 ////        double y = aStart->y();
1853 ////        aStart->setValue(aEnd->x(), aEnd->y());
1854 ////        aEnd->setValue(x, y);
1855 ////        // Update constraint data
1856 ////        changeFilletConstraint(aConstrIter->first);
1857 ////        anArcObj->data()->blockSendAttributeUpdated(false);
1858 ////      }
1859 ////    }
1860 ////}
1861 ////
1862 ////// ============================================================================
1863 //////  Function: makeMirrorEntity
1864 //////  Class:    SketchSolver_Group
1865 //////  Purpose:  change entities parameters to make them symmetric relating to the mirror line
1866 ////// ============================================================================
1867 ////void SketchSolver_Group::makeMirrorEntity(const Slvs_hEntity& theBase,
1868 ////                                                    const Slvs_hEntity& theMirror,
1869 ////                                                    const Slvs_hEntity& theMirrorLine)
1870 ////{
1871 ////  Slvs_Entity aBase = myEntities[Search(theBase, myEntities)];
1872 ////  Slvs_Entity aMirror = myEntities[Search(theMirror, myEntities)];
1873 ////  int i = 0;
1874 ////  while (aBase.point[i] != 0 && aMirror.point[i] != 0) {
1875 ////    makeMirrorEntity(aBase.point[i], aMirror.point[i], theMirrorLine);
1876 ////    i++;
1877 ////  }
1878 ////  if (aBase.param[0] != 0 && aMirror.param[0] != 0) { // this is a point, copy it
1879 ////    Slvs_Entity aMirrorLine = myEntities[Search(theMirrorLine, myEntities)];
1880 ////    std::shared_ptr<GeomAPI_XY> aLinePoints[2];
1881 ////    for (i = 0; i < 2; i++) {
1882 ////      Slvs_Entity aPoint = myEntities[Search(aMirrorLine.point[i], myEntities)];
1883 ////      int aParamPos = Search(aPoint.param[0], myParams);
1884 ////      aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
1885 ////          new GeomAPI_XY(myParams[aParamPos].val, myParams[1+aParamPos].val));
1886 ////    }
1887 ////    int aBaseParamPos = Search(aBase.param[0], myParams);
1888 ////    int aMirrorParamPos = Search(aMirror.param[0], myParams);
1889 ////    std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(
1890 ////        new GeomAPI_XY(myParams[aBaseParamPos].val, myParams[1+aBaseParamPos].val));
1891 ////
1892 ////    // direction of a mirror line
1893 ////    std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
1894 ////        new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
1895 ////    // orthogonal direction
1896 ////    aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
1897 ////
1898 ////    std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
1899 ////        new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
1900 ////    double aDist = aVec->dot(aDir->xy());
1901 ////    std::shared_ptr<GeomAPI_XY> aMirrorPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
1902 ////
1903 ////    myParams[aMirrorParamPos].val = aMirrorPoint->x();
1904 ////    myParams[1+aMirrorParamPos].val = aMirrorPoint->y();
1905 ////  }
1906 ////}
1907 ////
1908 ////// ============================================================================
1909 //////  Function: calculateMiddlePoint
1910 //////  Class:    SketchSolver_Group
1911 //////  Purpose:  calculates middle point on line or arc
1912 ////// ============================================================================
1913 ////void SketchSolver_Group::calculateMiddlePoint(
1914 ////    const Slvs_hEntity& theEntity,
1915 ////    double& theX,
1916 ////    double& theY) const
1917 ////{
1918 ////  int anInd = Search(theEntity, myEntities);
1919 ////  if (myEntities[anInd].type == SLVS_E_LINE_SEGMENT) {
1920 ////    int aLineParams[2];
1921 ////    for (int i = 0; i < 2; i++) {
1922 ////      int aPtPos = Search(myEntities[anInd].point[i], myEntities);
1923 ////      aLineParams[i] = Search(myEntities[aPtPos].param[0], myParams);
1924 ////    }
1925 ////    theX = 0.5 * (myParams[aLineParams[0]].val + myParams[aLineParams[1]].val);
1926 ////    theY = 0.5 * (myParams[1 + aLineParams[0]].val + myParams[1 + aLineParams[1]].val);
1927 ////  } else if (myEntities[anInd].type == SLVS_E_ARC_OF_CIRCLE) {
1928 ////    double anArcPoint[3][2];
1929 ////    for (int i = 0; i < 3; i++) {
1930 ////      int aPtPos = Search(myEntities[anInd].point[i], myEntities);
1931 ////      int anArcParam = Search(myEntities[aPtPos].param[0], myParams);
1932 ////      anArcPoint[i][0] = myParams[anArcParam].val;
1933 ////      anArcPoint[i][1] = myParams[1 + anArcParam].val;
1934 ////    }
1935 ////    // project last point of arc on the arc
1936 ////    double x = anArcPoint[1][0] - anArcPoint[0][0];
1937 ////    double y = anArcPoint[1][1] - anArcPoint[0][1];
1938 ////    double aRad = sqrt(x*x + y*y);
1939 ////    x = anArcPoint[2][0] - anArcPoint[0][0];
1940 ////    y = anArcPoint[2][1] - anArcPoint[0][1];
1941 ////    double aNorm = sqrt(x*x + y*y);
1942 ////    if (aNorm >= tolerance) {
1943 ////      anArcPoint[2][0] = anArcPoint[0][0] + x * aRad / aNorm;
1944 ////      anArcPoint[2][1] = anArcPoint[0][1] + y * aRad / aNorm;
1945 ////    }
1946 ////
1947 ////    x = anArcPoint[1][0] + anArcPoint[2][0] - 2.0 * anArcPoint[0][0];
1948 ////    y = anArcPoint[1][1] + anArcPoint[2][1] - 2.0 * anArcPoint[0][1];
1949 ////    aNorm = sqrt(x*x + y*y);
1950 ////    if (aNorm >= tolerance) {
1951 ////      x *= aRad / aNorm;
1952 ////      y *= aRad / aNorm;
1953 ////    } else { // obtain orthogonal direction
1954 ////      x = 0.5 * (anArcPoint[2][1] - anArcPoint[1][1]);
1955 ////      y = -0.5 * (anArcPoint[2][0] - anArcPoint[1][0]);
1956 ////    }
1957 ////    theX = anArcPoint[0][0] + x;
1958 ////    theY = anArcPoint[0][1] + y;
1959 ////  }
1960 ////}
1961
1962
1963 // ========================================================
1964 // =========      Auxiliary functions       ===============
1965 // ========================================================
1966
1967 template<typename T>
1968 int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
1969 {
1970   int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
1971   int aVecSize = theEntities.size();
1972   while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
1973     aResIndex--;
1974   while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
1975     aResIndex++;
1976   if (aResIndex == -1)
1977     aResIndex = aVecSize;
1978   return aResIndex;
1979 }