Salome HOME
0a250d8c2d8dfea3340b93b3b473b37432526327
[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       myFeatureStorage->blockEvents(true);
1401       ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
1402       for (; aConstrIter != myConstraints.end(); aConstrIter++)
1403         aConstrIter->second->refresh();
1404       myFeatureStorage->blockEvents(false);
1405     } else if (!myConstraints.empty())
1406       Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
1407
1408     aResolved = true;
1409   }
1410   removeTemporaryConstraints();
1411   myStorage->setNeedToResolve(false);
1412   return aResolved;
1413 }
1414
1415 // ============================================================================
1416 //  Function: mergeGroups
1417 //  Class:    SketchSolver_Group
1418 //  Purpose:  append specified group to the current group
1419 // ============================================================================
1420 void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
1421 {
1422   // If specified group is empty, no need to merge
1423   if (theGroup.isEmpty())
1424     return;
1425   if (!myFeatureStorage)
1426     myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
1427
1428   ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
1429   for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++)
1430     changeConstraint(aConstrIter->first);
1431 }
1432
1433 // ============================================================================
1434 //  Function: splitGroup
1435 //  Class:    SketchSolver_Group
1436 //  Purpose:  divide the group into several subgroups
1437 // ============================================================================
1438 void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
1439 {
1440   // Obtain constraints, which should be separated
1441   FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage);
1442   std::vector<ConstraintPtr> anUnusedConstraints;
1443   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
1444   for ( ; aCIter != myConstraints.end(); aCIter++) {
1445     std::list<ConstraintPtr> aBaseConstraints = aCIter->second->constraints();
1446     std::list<ConstraintPtr>::iterator anIter = aBaseConstraints.begin();
1447     for (; anIter != aBaseConstraints.end(); anIter++)
1448       if (aNewFeatStorage->isInteract(*anIter)) {
1449         aNewFeatStorage->changeConstraint(*anIter);
1450       } else
1451         anUnusedConstraints.push_back(*anIter);
1452   }
1453
1454   std::vector<SketchSolver_Group*>::iterator aCutsIter;
1455   std::vector<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
1456   for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) {
1457     // Remove unused constraints
1458     removeConstraint(*aUnuseIt);
1459     // Try to append constraint to already existent group
1460     for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); aCutsIter++)
1461       if ((*aCutsIter)->isInteract(*aUnuseIt)) {
1462         (*aCutsIter)->changeConstraint(*aUnuseIt);
1463         break;
1464       }
1465     if (aCutsIter == theCuts.end()) {
1466       // Add new group
1467       SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch);
1468       aGroup->changeConstraint(*aUnuseIt);
1469       theCuts.push_back(aGroup);
1470     }
1471   }
1472 }
1473
1474 // ============================================================================
1475 //  Function: isConsistent
1476 //  Class:    SketchSolver_Group
1477 //  Purpose:  search removed entities and constraints
1478 // ============================================================================
1479 bool SketchSolver_Group::isConsistent()
1480 {
1481   if (!myFeatureStorage) // no one constraint is initialized yet
1482     return true;
1483
1484   bool aResult = myFeatureStorage->isConsistent();
1485   if (!aResult) {
1486     // remove invalid entities
1487     ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
1488     while (aCIter != myConstraints.end()) {
1489       std::list<ConstraintPtr> aConstraints = aCIter->second->constraints();
1490       std::list<ConstraintPtr>::iterator anIt = aConstraints.begin();
1491       for (; anIt != aConstraints.end(); anIt++)
1492         if (!(*anIt)->data() || !(*anIt)->data()->isValid())
1493           if (aCIter->second->remove(*anIt)) {
1494             // the constraint is fully removed, detach it from the list
1495             ConstraintConstraintMap::iterator aTmpIt = aCIter++;
1496             myFeatureStorage->removeConstraint(aTmpIt->first);
1497             myConstraints.erase(aTmpIt);
1498             break;
1499           }
1500       if (anIt == aConstraints.end())
1501         aCIter++;
1502     }
1503   }
1504   return aResult;
1505 }
1506
1507 ////// ============================================================================
1508 //////  Function: updateAttribute
1509 //////  Class:    SketchSolver_Group
1510 //////  Purpose:  update features of sketch after resolving constraints
1511 ////// ============================================================================
1512 ////bool SketchSolver_Group::updateAttribute(
1513 ////    std::shared_ptr<ModelAPI_Attribute> theAttribute, const Slvs_hEntity& theEntityID)
1514 ////{
1515 ////  // Search the position of the first parameter of the entity
1516 ////  int anEntPos = Search(theEntityID, myEntities);
1517 ////  int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
1518 ////
1519 ////  // Look over supported types of entities
1520 ////
1521 ////  // Point in 3D
1522 ////  std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1523 ////      theAttribute);
1524 ////  if (aPoint) {
1525 ////    if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance
1526 ////        || fabs(aPoint->y() - myParams[aFirstParamPos + 1].val) > tolerance
1527 ////        || fabs(aPoint->z() - myParams[aFirstParamPos + 2].val) > tolerance) {
1528 ////      aPoint->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val,
1529 ////                       myParams[aFirstParamPos + 2].val);
1530 ////      return true;
1531 ////    }
1532 ////    return false;
1533 ////  }
1534 ////
1535 ////  // Point in 2D
1536 ////  std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
1537 ////      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
1538 ////  if (aPoint2D) {
1539 ////    if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance
1540 ////        || fabs(aPoint2D->y() - myParams[aFirstParamPos + 1].val) > tolerance) {
1541 ////      aPoint2D->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val);
1542 ////      return true;
1543 ////    }
1544 ////    return false;
1545 ////  }
1546 ////
1547 ////  // Scalar value
1548 ////  AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
1549 ////  if (aScalar) {
1550 ////    if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance) {
1551 ////      aScalar->setValue(myParams[aFirstParamPos].val);
1552 ////      return true;
1553 ////    }
1554 ////    return false;
1555 ////  }
1556 ////
1557 ////  /// \todo Support other types of entities
1558 ////  return false;
1559 ////}
1560 ////
1561 ////// ============================================================================
1562 //////  Function: updateEntityIfPossible
1563 //////  Class:    SketchSolver_Group
1564 //////  Purpose:  search the entity in this group and update it
1565 ////// ============================================================================
1566 ////void SketchSolver_Group::updateEntityIfPossible(
1567 ////    std::shared_ptr<ModelAPI_Attribute> theEntity)
1568 ////{
1569 ////  if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) {
1570 ////    // If the attribute is a point and it is changed (the group needs to rebuild),
1571 ////    // probably user has dragged this point into this position,
1572 ////    // so it is necessary to add constraint which will guarantee the point will not change
1573 ////
1574 ////    // Store myNeedToSolve flag to verify the entity is really changed
1575 ////    bool aNeedToSolveCopy = myNeedToSolve;
1576 ////    myNeedToSolve = false;
1577 ////
1578 ////    changeEntity(theEntity);
1579 ////
1580 ////    if (myNeedToSolve)  // the entity is changed
1581 ////    {
1582 ////      // Verify the entity is a point and add temporary constraint of permanency
1583 ////      std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1584 ////          theEntity);
1585 ////      std::shared_ptr<GeomDataAPI_Point2D> aPoint2D = std::dynamic_pointer_cast<
1586 ////          GeomDataAPI_Point2D>(theEntity);
1587 ////      if (aPoint || aPoint2D)
1588 ////        addTemporaryConstraintWhereDragged(theEntity);
1589 ////    }
1590 ////
1591 ////    // Restore flag of changes
1592 ////    myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
1593 ////
1594 ////    if (myNeedToSolve)
1595 ////      updateRelatedConstraints(theEntity);
1596 ////  }
1597 ////}
1598 ////
1599 ////// ============================================================================
1600 //////  Function: addTemporaryConstraintWhereDragged
1601 //////  Class:    SketchSolver_Group
1602 //////  Purpose:  add transient constraint SLVS_C_WHERE_DRAGGED for the entity, 
1603 //////            which was moved by user
1604 ////// ============================================================================
1605 ////void SketchSolver_Group::addTemporaryConstraintWhereDragged(
1606 ////    std::shared_ptr<ModelAPI_Attribute> theEntity,
1607 ////    bool theAllowToFit)
1608 ////{
1609 ////  // Find identifier of the entity
1610 ////  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
1611 ////      myEntityAttrMap.find(theEntity);
1612 ////  if (anEntIter == myEntityAttrMap.end())
1613 ////    return;
1614 ////
1615 ////  // Get identifiers of all dragged points
1616 ////  std::set<Slvs_hEntity> aDraggedPntID;
1617 ////  aDraggedPntID.insert(myTempPointWDrgdID);
1618 ////  std::list<Slvs_hConstraint>::const_iterator aTmpCoIter = myTempConstraints.begin();
1619 ////  for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) {
1620 ////    unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
1621 ////    if (aConstrPos < myConstraints.size())
1622 ////      aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
1623 ////  }
1624 ////  std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1625 ////  for (; aConstrIter != myConstraints.end(); aConstrIter++)
1626 ////    if (aConstrIter->type == SLVS_C_WHERE_DRAGGED)
1627 ////      aDraggedPntID.insert(aConstrIter->ptA);
1628 ////  // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
1629 ////  std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1630 ////  for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) {
1631 ////    if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
1632 ////      continue;  // the entity was not found in current set
1633 ////
1634 ////    // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
1635 ////    std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
1636 ////    for (; aDrgIter != aDraggedPntID.end(); aDrgIter++)
1637 ////      if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
1638 ////        return;  // the SLVS_C_WHERE_DRAGGED constraint already exists
1639 ////  }
1640 ////  if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end())
1641 ////    return;
1642 ////
1643 ////  // If this is a first dragged point, its parameters should be placed 
1644 ////  // into Slvs_System::dragged field to avoid system inconsistense
1645 ////  if (myTempPointWhereDragged.empty() && theAllowToFit) {
1646 ////    int anEntPos = Search(anEntIter->second, myEntities);
1647 ////    Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
1648 ////    for (int i = 0; i < 4; i++, aDraggedParam++)
1649 ////      if (*aDraggedParam != 0)
1650 ////        myTempPointWhereDragged.push_back(*aDraggedParam);
1651 ////    myTempPointWDrgdID = myEntities[anEntPos].h;
1652 ////    return;
1653 ////  }
1654 ////
1655 ////  // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
1656 ////  Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
1657 ////                                                  myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
1658 ////  myConstraints.push_back(aWDConstr);
1659 ////  myTempConstraints.push_back(aWDConstr.h);
1660 ////}
1661
1662 // ============================================================================
1663 //  Function: removeTemporaryConstraints
1664 //  Class:    SketchSolver_Group
1665 //  Purpose:  remove all transient SLVS_C_WHERE_DRAGGED constraints after
1666 //            resolving the set of constraints
1667 // ============================================================================
1668 void SketchSolver_Group::removeTemporaryConstraints()
1669 {
1670   myTempConstraints.clear();
1671   // Clean lists of removed entities in the storage
1672   std::set<Slvs_hParam> aRemPar;
1673   std::set<Slvs_hEntity> aRemEnt;
1674   std::set<Slvs_hConstraint> aRemCon;
1675   myStorage->getRemoved(aRemPar, aRemEnt, aRemCon);
1676 }
1677
1678 // ============================================================================
1679 //  Function: removeConstraint
1680 //  Class:    SketchSolver_Group
1681 //  Purpose:  remove constraint and all unused entities
1682 // ============================================================================
1683 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
1684 {
1685   myFeatureStorage->removeConstraint(theConstraint);
1686   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
1687   for (; aCIter != myConstraints.end(); aCIter++)
1688     if (aCIter->second->hasConstraint(theConstraint)) {
1689       if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed
1690         aCIter = myConstraints.end();
1691       break;
1692     }
1693   if (aCIter != myConstraints.end())
1694     myConstraints.erase(aCIter);
1695 }
1696
1697 ////// ============================================================================
1698 //////  Function: removeEntitiesById
1699 //////  Class:    SketchSolver_Group
1700 //////  Purpose:  Removes specified entities and their parameters
1701 ////// ============================================================================
1702 ////void SketchSolver_Group::removeEntitiesById(const std::set<Slvs_hEntity>& theEntities)
1703 ////{
1704 ////  std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = theEntities.rbegin();
1705 ////  for (; aRemIter != theEntities.rend(); aRemIter++) {
1706 ////    unsigned int anEntPos = Search(*aRemIter, myEntities);
1707 ////    if (anEntPos >= myEntities.size())
1708 ////      continue;
1709 ////    if (myEntities[anEntPos].param[0] != 0) {
1710 ////      unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
1711 ////      if (aParamPos >= myParams.size())
1712 ////        continue;
1713 ////      int aNbParams = 0;
1714 ////      while (myEntities[anEntPos].param[aNbParams] != 0)
1715 ////        aNbParams++;
1716 ////      if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID)
1717 ////        myParamMaxID -= aNbParams;
1718 ////      myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
1719 ////      if (*aRemIter == myEntityMaxID)
1720 ////        myEntityMaxID--;
1721 ////    }
1722 ////    myEntities.erase(myEntities.begin() + anEntPos);
1723 ////    myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos);
1724 ////
1725 ////    // Remove entity's ID from the lists of conincident points
1726 ////    std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1727 ////    for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
1728 ////      aCoPtIter->erase(*aRemIter);
1729 ////  }
1730 ////}
1731 ////
1732 ////// ============================================================================
1733 //////  Function: addCoincidentPoints
1734 //////  Class:    SketchSolver_Group
1735 //////  Purpose:  add coincident point the appropriate list of such points
1736 ////// ============================================================================
1737 ////bool SketchSolver_Group::addCoincidentPoints(const Slvs_hEntity& thePoint1,
1738 ////                                                       const Slvs_hEntity& thePoint2)
1739 ////{
1740 ////  std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1741 ////  std::vector<std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
1742 ////  while (aCoPtIter != myCoincidentPoints.end()) {
1743 ////    bool isFound[2] = {  // indicate which point ID was already in coincidence constraint
1744 ////        aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2)
1745 ////            != aCoPtIter->end(), };
1746 ////    if (isFound[0] && isFound[1])  // points are already connected by coincidence constraints => no need additional one
1747 ////      return false;
1748 ////    if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) {
1749 ////      if (aFirstFound != myCoincidentPoints.end()) {  // there are two groups of coincident points connected by created constraint => merge them
1750 ////        int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
1751 ////        int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
1752 ////        aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
1753 ////        myCoincidentPoints.erase(aCoPtIter);
1754 ////        aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
1755 ////        aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
1756 ////        continue;
1757 ////      } else {
1758 ////        aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
1759 ////        aFirstFound = aCoPtIter;
1760 ////      }
1761 ////    }
1762 ////    aCoPtIter++;
1763 ////  }
1764 ////  // No points were found, need to create new set
1765 ////  if (aFirstFound == myCoincidentPoints.end()) {
1766 ////    std::set<Slvs_hEntity> aNewSet;
1767 ////    aNewSet.insert(thePoint1);
1768 ////    aNewSet.insert(thePoint2);
1769 ////    myCoincidentPoints.push_back(aNewSet);
1770 ////  }
1771 ////
1772 ////  return true;
1773 ////}
1774 ////
1775 ////// ============================================================================
1776 //////  Function: updateRelatedConstraints
1777 //////  Class:    SketchSolver_Group
1778 //////  Purpose:  emit the signal to update constraints
1779 ////// ============================================================================
1780 ////void SketchSolver_Group::updateRelatedConstraints(
1781 ////    std::shared_ptr<ModelAPI_Attribute> theEntity) const
1782 ////{
1783 ////  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
1784 ////  for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
1785 ////    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
1786 ////        ->attributes(std::string());
1787 ////
1788 ////    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
1789 ////    for (; anAttrIter != anAttributes.end(); anAttrIter++) {
1790 ////      bool isUpd = (*anAttrIter == theEntity);
1791 ////      std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
1792 ////          ModelAPI_AttributeRefAttr>(*anAttrIter);
1793 ////      if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
1794 ////        isUpd = true;
1795 ////
1796 ////      if (isUpd) {
1797 ////        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1798 ////        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
1799 ////        break;
1800 ////      }
1801 ////    }
1802 ////  }
1803 ////}
1804 ////
1805 ////void SketchSolver_Group::updateRelatedConstraintsFeature(
1806 ////    std::shared_ptr<ModelAPI_Feature> theFeature) const
1807 ////{
1808 ////  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
1809 ////  for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
1810 ////    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
1811 ////        ->attributes(std::string());
1812 ////
1813 ////    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
1814 ////    for (; anAttrIter != anAttributes.end(); anAttrIter++) {
1815 ////      std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
1816 ////          ModelAPI_AttributeRefAttr>(*anAttrIter);
1817 ////      if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature) {
1818 ////        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1819 ////        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
1820 ////        break;
1821 ////      }
1822 ////    }
1823 ////  }
1824 ////}
1825 ////
1826 ////// ============================================================================
1827 //////  Function: updateFilletConstraints
1828 //////  Class:    SketchSolver_Group
1829 //////  Purpose:  change fillet arc to be less than 180 degree
1830 ////// ============================================================================
1831 ////void SketchSolver_Group::updateFilletConstraints()
1832 ////{
1833 ////  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
1834 ////  for (; aConstrIter != myConstraintMap.end(); aConstrIter++)
1835 ////    if (aConstrIter->first->getKind() == SketchPlugin_ConstraintFillet::ID()) {
1836 ////      AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
1837 ////          aConstrIter->first->data()->attribute(SketchPlugin_ConstraintFillet::ENTITY_C()));
1838 ////      if (!aFilletRefList)
1839 ////        return;
1840 ////      ObjectPtr anArcObj = aFilletRefList->object(2);
1841 ////      std::shared_ptr<GeomDataAPI_Point2D> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1842 ////          anArcObj->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
1843 ////      std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1844 ////          anArcObj->data()->attribute(SketchPlugin_Arc::START_ID()));
1845 ////      std::shared_ptr<GeomDataAPI_Point2D> aEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1846 ////          anArcObj->data()->attribute(SketchPlugin_Arc::END_ID()));
1847 ////      double aCosA = aStart->x() - aCenter->x();
1848 ////      double aSinA = aStart->y() - aCenter->y();
1849 ////      double aCosB = aEnd->x() - aCenter->x();
1850 ////      double aSinB = aEnd->y() - aCenter->y();
1851 ////      if (aCosA * aSinB - aSinA * aCosB <= 0.0) {
1852 ////        anArcObj->data()->blockSendAttributeUpdated(true);
1853 ////        double x = aStart->x();
1854 ////        double y = aStart->y();
1855 ////        aStart->setValue(aEnd->x(), aEnd->y());
1856 ////        aEnd->setValue(x, y);
1857 ////        // Update constraint data
1858 ////        changeFilletConstraint(aConstrIter->first);
1859 ////        anArcObj->data()->blockSendAttributeUpdated(false);
1860 ////      }
1861 ////    }
1862 ////}
1863 ////
1864 ////// ============================================================================
1865 //////  Function: makeMirrorEntity
1866 //////  Class:    SketchSolver_Group
1867 //////  Purpose:  change entities parameters to make them symmetric relating to the mirror line
1868 ////// ============================================================================
1869 ////void SketchSolver_Group::makeMirrorEntity(const Slvs_hEntity& theBase,
1870 ////                                                    const Slvs_hEntity& theMirror,
1871 ////                                                    const Slvs_hEntity& theMirrorLine)
1872 ////{
1873 ////  Slvs_Entity aBase = myEntities[Search(theBase, myEntities)];
1874 ////  Slvs_Entity aMirror = myEntities[Search(theMirror, myEntities)];
1875 ////  int i = 0;
1876 ////  while (aBase.point[i] != 0 && aMirror.point[i] != 0) {
1877 ////    makeMirrorEntity(aBase.point[i], aMirror.point[i], theMirrorLine);
1878 ////    i++;
1879 ////  }
1880 ////  if (aBase.param[0] != 0 && aMirror.param[0] != 0) { // this is a point, copy it
1881 ////    Slvs_Entity aMirrorLine = myEntities[Search(theMirrorLine, myEntities)];
1882 ////    std::shared_ptr<GeomAPI_XY> aLinePoints[2];
1883 ////    for (i = 0; i < 2; i++) {
1884 ////      Slvs_Entity aPoint = myEntities[Search(aMirrorLine.point[i], myEntities)];
1885 ////      int aParamPos = Search(aPoint.param[0], myParams);
1886 ////      aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
1887 ////          new GeomAPI_XY(myParams[aParamPos].val, myParams[1+aParamPos].val));
1888 ////    }
1889 ////    int aBaseParamPos = Search(aBase.param[0], myParams);
1890 ////    int aMirrorParamPos = Search(aMirror.param[0], myParams);
1891 ////    std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(
1892 ////        new GeomAPI_XY(myParams[aBaseParamPos].val, myParams[1+aBaseParamPos].val));
1893 ////
1894 ////    // direction of a mirror line
1895 ////    std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
1896 ////        new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
1897 ////    // orthogonal direction
1898 ////    aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
1899 ////
1900 ////    std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
1901 ////        new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
1902 ////    double aDist = aVec->dot(aDir->xy());
1903 ////    std::shared_ptr<GeomAPI_XY> aMirrorPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
1904 ////
1905 ////    myParams[aMirrorParamPos].val = aMirrorPoint->x();
1906 ////    myParams[1+aMirrorParamPos].val = aMirrorPoint->y();
1907 ////  }
1908 ////}
1909 ////
1910 ////// ============================================================================
1911 //////  Function: calculateMiddlePoint
1912 //////  Class:    SketchSolver_Group
1913 //////  Purpose:  calculates middle point on line or arc
1914 ////// ============================================================================
1915 ////void SketchSolver_Group::calculateMiddlePoint(
1916 ////    const Slvs_hEntity& theEntity,
1917 ////    double& theX,
1918 ////    double& theY) const
1919 ////{
1920 ////  int anInd = Search(theEntity, myEntities);
1921 ////  if (myEntities[anInd].type == SLVS_E_LINE_SEGMENT) {
1922 ////    int aLineParams[2];
1923 ////    for (int i = 0; i < 2; i++) {
1924 ////      int aPtPos = Search(myEntities[anInd].point[i], myEntities);
1925 ////      aLineParams[i] = Search(myEntities[aPtPos].param[0], myParams);
1926 ////    }
1927 ////    theX = 0.5 * (myParams[aLineParams[0]].val + myParams[aLineParams[1]].val);
1928 ////    theY = 0.5 * (myParams[1 + aLineParams[0]].val + myParams[1 + aLineParams[1]].val);
1929 ////  } else if (myEntities[anInd].type == SLVS_E_ARC_OF_CIRCLE) {
1930 ////    double anArcPoint[3][2];
1931 ////    for (int i = 0; i < 3; i++) {
1932 ////      int aPtPos = Search(myEntities[anInd].point[i], myEntities);
1933 ////      int anArcParam = Search(myEntities[aPtPos].param[0], myParams);
1934 ////      anArcPoint[i][0] = myParams[anArcParam].val;
1935 ////      anArcPoint[i][1] = myParams[1 + anArcParam].val;
1936 ////    }
1937 ////    // project last point of arc on the arc
1938 ////    double x = anArcPoint[1][0] - anArcPoint[0][0];
1939 ////    double y = anArcPoint[1][1] - anArcPoint[0][1];
1940 ////    double aRad = sqrt(x*x + y*y);
1941 ////    x = anArcPoint[2][0] - anArcPoint[0][0];
1942 ////    y = anArcPoint[2][1] - anArcPoint[0][1];
1943 ////    double aNorm = sqrt(x*x + y*y);
1944 ////    if (aNorm >= tolerance) {
1945 ////      anArcPoint[2][0] = anArcPoint[0][0] + x * aRad / aNorm;
1946 ////      anArcPoint[2][1] = anArcPoint[0][1] + y * aRad / aNorm;
1947 ////    }
1948 ////
1949 ////    x = anArcPoint[1][0] + anArcPoint[2][0] - 2.0 * anArcPoint[0][0];
1950 ////    y = anArcPoint[1][1] + anArcPoint[2][1] - 2.0 * anArcPoint[0][1];
1951 ////    aNorm = sqrt(x*x + y*y);
1952 ////    if (aNorm >= tolerance) {
1953 ////      x *= aRad / aNorm;
1954 ////      y *= aRad / aNorm;
1955 ////    } else { // obtain orthogonal direction
1956 ////      x = 0.5 * (anArcPoint[2][1] - anArcPoint[1][1]);
1957 ////      y = -0.5 * (anArcPoint[2][0] - anArcPoint[1][0]);
1958 ////    }
1959 ////    theX = anArcPoint[0][0] + x;
1960 ////    theY = anArcPoint[0][1] + y;
1961 ////  }
1962 ////}
1963
1964
1965 // ========================================================
1966 // =========      Auxiliary functions       ===============
1967 // ========================================================
1968
1969 template<typename T>
1970 int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
1971 {
1972   int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
1973   int aVecSize = theEntities.size();
1974   while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
1975     aResIndex--;
1976   while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
1977     aResIndex++;
1978   if (aResIndex == -1)
1979     aResIndex = aVecSize;
1980   return aResIndex;
1981 }