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