]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.cpp
Salome HOME
Fix the problem with multi-coincidence of points (issue #1143)
[modules/shaper.git] / src / SketchSolver / SolveSpaceSolver / SolveSpaceSolver_Storage.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    SolveSpaceSolver_Storage.cpp
4 // Created: 18 Mar 2015
5 // Author:  Artem ZHIDKOV
6
7 #include <SolveSpaceSolver_Storage.h>
8 #include <SolveSpaceSolver_ConstraintWrapper.h>
9 #include <SolveSpaceSolver_EntityWrapper.h>
10 #include <SolveSpaceSolver_ParameterWrapper.h>
11 #include <SolveSpaceSolver_Builder.h>
12
13 #include <GeomAPI_Dir2d.h>
14 #include <GeomAPI_Pnt2d.h>
15 #include <GeomAPI_XY.h>
16 #include <math.h>
17 #include <assert.h>
18
19 #include <GeomDataAPI_Point.h>
20 #include <GeomDataAPI_Point2D.h>
21 #include <ModelAPI_AttributeDouble.h>
22
23 /** \brief Search the entity/parameter with specified ID in the list of elements
24  *  \param[in] theEntityID unique ID of the element
25  *  \param[in] theEntities list of elements
26  *  \return position of the found element or -1 if the element is not found
27  */
28 template<typename T>
29 static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
30
31 /// \brief Compare two parameters to be different
32 static bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2);
33 /// \brief Compare two entities to be different
34 static bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2);
35 /// \brief Compare two constraints to be different
36 static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2);
37
38
39 SolveSpaceSolver_Storage::SolveSpaceSolver_Storage(const GroupID& theGroup)
40   : SketchSolver_Storage(theGroup),
41     myWorkplaneID(SLVS_E_UNKNOWN),
42     myParamMaxID(SLVS_E_UNKNOWN),
43     myEntityMaxID(SLVS_E_UNKNOWN),
44     myConstrMaxID(SLVS_C_UNKNOWN),
45     myFixed(SLVS_E_UNKNOWN),
46     myDuplicatedConstraint(false)
47 {
48 }
49
50 bool SolveSpaceSolver_Storage::update(ConstraintWrapperPtr& theConstraint)
51 {
52   bool isUpdated = false;
53   std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
54       std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
55   Slvs_Constraint aSlvsConstr = getConstraint((Slvs_hConstraint)aConstraint->id());
56   if (aSlvsConstr.h == SLVS_C_UNKNOWN)
57     aSlvsConstr = aConstraint->constraint();
58
59   // update value of constraint if exist
60   if (fabs(aSlvsConstr.valA - theConstraint->value()) > tolerance) {
61     aSlvsConstr.valA = theConstraint->value();
62     isUpdated = true;
63   }
64
65   // update constrained entities
66   Slvs_hEntity* aPnts[2] = {&aSlvsConstr.ptA, &aSlvsConstr.ptB};
67   Slvs_hEntity* anEnts[4] = {&aSlvsConstr.entityA, &aSlvsConstr.entityB,
68                              &aSlvsConstr.entityC, &aSlvsConstr.entityD};
69   int aPtInd = 0;
70   int aEntInd = 0;
71
72   std::list<EntityWrapperPtr> anEntities = theConstraint->entities();
73   std::list<EntityWrapperPtr>::iterator anIt = anEntities.begin();
74   for (; anIt != anEntities.end(); ++anIt) {
75     isUpdated = update(*anIt) || isUpdated;
76     // do not update constrained entities for Multi constraints
77     if (aSlvsConstr.type == SLVS_C_MULTI_ROTATION || aSlvsConstr.type != SLVS_C_MULTI_TRANSLATION)
78       continue;
79
80     Slvs_hEntity anID = (Slvs_hEntity)(*anIt)->id();
81     if ((*anIt)->type() == ENTITY_POINT) {
82       if (*(aPnts[aPtInd]) != anID) {
83         *(aPnts[aPtInd]) = anID;
84         isUpdated = true;
85       }
86       ++aPtInd;
87     } else {
88       if (*(anEnts[aEntInd]) != anID) {
89         *(anEnts[aEntInd]) = anID;
90         isUpdated = true;
91       }
92       ++aEntInd;
93     }
94   }
95
96   // update constraint itself (do not update constraints Multi)
97   if (aSlvsConstr.type != SLVS_C_MULTI_ROTATION && aSlvsConstr.type != SLVS_C_MULTI_TRANSLATION) {
98     if (aSlvsConstr.wrkpl == SLVS_E_UNKNOWN && myWorkplaneID != SLVS_E_UNKNOWN)
99       aSlvsConstr.wrkpl = myWorkplaneID;
100     if (aSlvsConstr.group == SLVS_G_UNKNOWN)
101       aSlvsConstr.group = (Slvs_hGroup)myGroupID;
102     Slvs_hConstraint aConstrID = updateConstraint(aSlvsConstr);
103     if (aSlvsConstr.h == SLVS_C_UNKNOWN) {
104       aConstraint->changeConstraint() = getConstraint(aConstrID);
105       isUpdated = true;
106     }
107   }
108   return isUpdated;
109 }
110
111 bool SolveSpaceSolver_Storage::update(EntityWrapperPtr& theEntity)
112 {
113   bool isUpdated = false;
114   std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity = 
115       std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theEntity);
116   Slvs_Entity aSlvsEnt = getEntity((Slvs_hEntity)anEntity->id());
117   if (aSlvsEnt.h == SLVS_E_UNKNOWN)
118     aSlvsEnt = anEntity->entity();
119
120   std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
121   std::list<ParameterWrapperPtr>::iterator aPIt;
122   // if the entity is an attribute, need to update its coordinates
123   if (anEntity->baseAttribute()) {
124     BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
125     EntityWrapperPtr anUpdAttr = aBuilder->createAttribute(anEntity->baseAttribute(), GID_UNKNOWN);
126     if (anUpdAttr) {
127       std::list<ParameterWrapperPtr> anUpdParams = anUpdAttr->parameters();
128       std::list<ParameterWrapperPtr>::iterator anUpdIt = anUpdParams.begin();
129       for (aPIt = aParams.begin(); aPIt != aParams.end() && anUpdIt != anUpdParams.end();
130           ++aPIt, ++anUpdIt) {
131         (*aPIt)->update(*anUpdIt);
132       }
133     }
134   }
135
136   // update parameters
137   int anInd = 0;
138   for (aPIt = aParams.begin(); aPIt != aParams.end(); ++aPIt, ++anInd) {
139     assert(anInd < 4);
140     isUpdated = update(*aPIt) || isUpdated;
141     if (aSlvsEnt.param[anInd] != (Slvs_hEntity)(*aPIt)->id()) {
142       isUpdated = true;
143       aSlvsEnt.param[anInd] = (Slvs_hEntity)(*aPIt)->id();
144     }
145   }
146
147   // update sub-entities
148   std::list<EntityWrapperPtr> aSubEntities = theEntity->subEntities();
149   std::list<EntityWrapperPtr>::iterator aSIt = aSubEntities.begin();
150   for (anInd = 0; aSIt != aSubEntities.end(); ++aSIt, ++anInd) {
151     assert(anInd < 4);
152     isUpdated = update(*aSIt) || isUpdated;
153
154     Slvs_hEntity anID = Slvs_hEntity((*aSIt)->id());
155     if ((*aSIt)->type() == ENTITY_NORMAL)
156       aSlvsEnt.normal = anID;
157     else if ((*aSIt)->type() == ENTITY_SCALAR)
158       aSlvsEnt.distance = anID;
159     else if (aSlvsEnt.point[anInd] != anID) {
160       aSlvsEnt.point[anInd] = anID;
161       isUpdated = true;
162     }
163   }
164
165   // update entity itself
166   if (aSlvsEnt.wrkpl == SLVS_E_UNKNOWN && myWorkplaneID != SLVS_E_UNKNOWN)
167     aSlvsEnt.wrkpl = myWorkplaneID;
168   if (aSlvsEnt.group == SLVS_G_UNKNOWN)
169     aSlvsEnt.group = (Slvs_hGroup)myGroupID;
170   Slvs_hEntity anEntID = updateEntity(aSlvsEnt);
171   if (aSlvsEnt.h == SLVS_E_UNKNOWN) {
172     anEntity->changeEntity() = getEntity(anEntID);
173     isUpdated = true;
174
175     if (anEntity->type() == ENTITY_SKETCH)
176       storeWorkplane(anEntity);
177   }
178   return isUpdated;
179 }
180
181 bool SolveSpaceSolver_Storage::update(ParameterWrapperPtr& theParameter)
182 {
183   std::shared_ptr<SolveSpaceSolver_ParameterWrapper> aParameter = 
184       std::dynamic_pointer_cast<SolveSpaceSolver_ParameterWrapper>(theParameter);
185   const Slvs_Param& aParam = getParameter((Slvs_hParam)aParameter->id());
186   if (aParam.h != SLVS_E_UNKNOWN && fabs(aParam.val - aParameter->value()) < tolerance)
187     return false;
188   Slvs_Param aParamToUpd = aParameter->parameter();
189   if (aParamToUpd.group == SLVS_G_UNKNOWN)
190     aParamToUpd.group = aParameter->isParametric() ? (Slvs_hGroup)GID_OUTOFGROUP : (Slvs_hGroup)myGroupID;
191   Slvs_hParam anID = updateParameter(aParamToUpd);
192   if (aParam.h == SLVS_E_UNKNOWN) // new parameter
193     aParameter->changeParameter() = getParameter(anID);
194   return true;
195 }
196
197 void SolveSpaceSolver_Storage::storeWorkplane(EntityWrapperPtr theSketch)
198 {
199   myWorkplaneID = (Slvs_hEntity)theSketch->id();
200
201   // Update sub-entities of the sketch
202   std::list<EntityWrapperPtr> aSubEntities = theSketch->subEntities();
203   std::list<EntityWrapperPtr>::iterator aSIt = aSubEntities.begin();
204   for (; aSIt != aSubEntities.end(); ++aSIt) {
205     std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSub =
206         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*aSIt);
207     aSub->changeEntity().wrkpl = myWorkplaneID;
208   }
209
210   // Update all stored entities
211   std::vector<Slvs_Entity>::iterator anIt = myEntities.begin();
212   for (; anIt != myEntities.end(); ++anIt)
213     anIt->wrkpl = myWorkplaneID;
214 }
215
216 void SolveSpaceSolver_Storage::changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup)
217 {
218   std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
219   std::list<ParameterWrapperPtr>::iterator aPIt = aParams.begin();
220   for (; aPIt != aParams.end(); ++aPIt)
221     changeGroup(*aPIt, theGroup);
222
223   std::list<EntityWrapperPtr> aSubs = theEntity->subEntities();
224   std::list<EntityWrapperPtr>::iterator aSIt = aSubs.begin();
225   for (; aSIt != aSubs.end(); ++aSIt)
226     changeGroup(*aSIt, theGroup);
227
228   if (theEntity->group() != theGroup) {
229     theEntity->setGroup(theGroup);
230     int aPos = Search((Slvs_hEntity)theEntity->id(), myEntities);
231     if (aPos >= 0 && aPos < (int)myEntities.size()) {
232       myEntities[aPos].group = (Slvs_hGroup)theGroup;
233       setNeedToResolve(true);
234     }
235   }
236 }
237
238 void SolveSpaceSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup)
239 {
240   GroupID aGroup = theGroup;
241   if (theParam->isParametric())
242     aGroup = GID_OUTOFGROUP;
243   if (theParam->group() == aGroup)
244     return;
245
246   theParam->setGroup(aGroup);
247   int aPos = Search((Slvs_hParam)theParam->id(), myParameters);
248   if (aPos >= 0 && aPos < (int)myParameters.size()) {
249     myParameters[aPos].group = (Slvs_hGroup)aGroup;
250     setNeedToResolve(true);
251   }
252 }
253
254 void SolveSpaceSolver_Storage::addCoincidentPoints(
255     EntityWrapperPtr theMaster, EntityWrapperPtr theSlave)
256 {
257   if (theMaster->type() != ENTITY_POINT || theSlave->type() != ENTITY_POINT)
258     return;
259
260   // Search available coincidence
261   CoincidentPointsMap::iterator aMasterFound = myCoincidentPoints.find(theMaster);
262   CoincidentPointsMap::iterator aSlaveFound = myCoincidentPoints.find(theSlave);
263   if (aMasterFound == myCoincidentPoints.end() &&  aSlaveFound == myCoincidentPoints.end()) {
264     // try to find master and slave points in the lists of slaves of already existent coincidences
265     CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin();
266     for (; anIt != myCoincidentPoints.end(); ++anIt) {
267       if (anIt->second.find(theMaster) != anIt->second.end())
268         aMasterFound = anIt;
269       else if (anIt->second.find(theSlave) != anIt->second.end())
270         aSlaveFound = anIt;
271
272       if (aMasterFound != myCoincidentPoints.end() &&  aSlaveFound != myCoincidentPoints.end())
273         break;
274     }
275   }
276
277   if (aMasterFound == myCoincidentPoints.end()) {
278     // create new group
279     myCoincidentPoints[theMaster] = std::set<EntityWrapperPtr>();
280     aMasterFound = myCoincidentPoints.find(theMaster);
281   } else if (aMasterFound == aSlaveFound)
282     return; // already coincident
283
284   if (aSlaveFound != myCoincidentPoints.end()) {
285     // A slave has been found, we need to attach all points coincident with it to the new master
286     std::set<EntityWrapperPtr> aNewSlaves = aSlaveFound->second;
287     aNewSlaves.insert(aSlaveFound->first);
288     myCoincidentPoints.erase(aSlaveFound);
289
290     std::set<EntityWrapperPtr>::const_iterator aSlIt = aNewSlaves.begin();
291     for (; aSlIt != aNewSlaves.end(); ++aSlIt)
292       addCoincidentPoints(theMaster, *aSlIt);
293   } else {
294     // Update the slave if it was used in constraints and features
295     replaceInFeatures(theSlave, theMaster);
296     replaceInConstraints(theSlave, theMaster);
297
298     // Remove slave entity (if the IDs are equal no need to remove slave entity, just update it)
299     if (theMaster->id() != theSlave->id())
300       removeEntity((Slvs_hEntity)theSlave->id());
301
302     std::shared_ptr<SolveSpaceSolver_EntityWrapper> aPointMaster = 
303         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMaster);
304     std::shared_ptr<SolveSpaceSolver_EntityWrapper> aPointSlave = 
305         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSlave);
306     aPointSlave->changeEntity() = aPointMaster->entity();
307     aPointSlave->setParameters(aPointMaster->parameters());
308
309     aMasterFound->second.insert(theSlave);
310   }
311 }
312
313 void SolveSpaceSolver_Storage::replaceInFeatures(
314     EntityWrapperPtr theSource, EntityWrapperPtr theDest)
315 {
316   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator anIt = myFeatureMap.begin();
317   for (; anIt != myFeatureMap.end(); ++anIt) {
318     bool isUpdated = false;
319     std::list<EntityWrapperPtr> aSubs = anIt->second->subEntities();
320     std::list<EntityWrapperPtr>::iterator aSubIt = aSubs.begin();
321     for (; aSubIt != aSubs.end(); ++aSubIt)
322       if ((*aSubIt)->id() == theSource->id()) {
323         (*aSubIt)->update(theDest);
324         isUpdated = true;
325       }
326
327     if (!isUpdated)
328       continue;
329
330     std::shared_ptr<SolveSpaceSolver_EntityWrapper> aWrapper =
331         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(anIt->second);
332     // update SolveSpace entity
333     Slvs_Entity anEnt = aWrapper->entity();
334     for (int i = 0; i < 4; ++i)
335       if (anEnt.point[i] == (Slvs_hEntity)theSource->id())
336         anEnt.point[i] = (Slvs_hEntity)theDest->id();
337     anEnt.h = updateEntity(anEnt);
338     aWrapper->changeEntity() = anEnt;
339
340     // update sub-entities
341     aWrapper->setSubEntities(aSubs);
342   }
343 }
344
345 void SolveSpaceSolver_Storage::replaceInConstraints(
346     EntityWrapperPtr theSource, EntityWrapperPtr theDest)
347 {
348   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
349       anIt = myConstraintMap.begin();
350   std::list<ConstraintWrapperPtr>::const_iterator aCIt;
351   for (; anIt != myConstraintMap.end(); ++anIt)
352     for (aCIt = anIt->second.begin(); aCIt != anIt->second.end(); ++aCIt) {
353       // Do not process coincidence between points
354       // (these constraints are stored to keep the structure of constraints).
355       if ((*aCIt)->type() == CONSTRAINT_PT_PT_COINCIDENT)
356         continue;
357
358       bool isUpdated = false;
359       std::list<EntityWrapperPtr> aSubs = (*aCIt)->entities();
360       std::list<EntityWrapperPtr>::iterator aSubIt = aSubs.begin();
361       for (; aSubIt != aSubs.end(); ++aSubIt)
362         if ((*aSubIt)->id() == theSource->id()) {
363           (*aSubIt)->update(theDest);
364           isUpdated = true;
365         }
366
367       if (!isUpdated)
368         continue;
369
370       std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aWrapper =
371           std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(*aCIt);
372       // change constraint entities
373       Slvs_Constraint aConstr = aWrapper->constraint();
374       if (aConstr.ptA == (Slvs_hEntity)theSource->id())
375         aConstr.ptA = (Slvs_hEntity)theDest->id();
376       if (aConstr.ptB == (Slvs_hEntity)theSource->id())
377         aConstr.ptB = (Slvs_hEntity)theDest->id();
378
379       // check the constraint is duplicated
380       std::vector<Slvs_Constraint>::const_iterator aSlvsCIt = myConstraints.begin();
381       for (; aSlvsCIt != myConstraints.end(); ++aSlvsCIt)
382         if (aConstr.h != aSlvsCIt->h &&
383             aConstr.type == aSlvsCIt->type &&
384             aConstr.ptA == aSlvsCIt->ptA && aConstr.ptB == aSlvsCIt->ptB &&
385             aConstr.entityA == aSlvsCIt->entityA && aConstr.entityB == aSlvsCIt->entityB &&
386             aConstr.entityC == aSlvsCIt->entityC && aConstr.entityD == aSlvsCIt->entityD) {
387           removeConstraint(aConstr.h);
388           aConstr = *aSlvsCIt;
389           break;
390         }
391
392       if (aSlvsCIt != myConstraints.end()) {
393         // constraint is duplicated, search its wrapper to add the mapping
394         std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
395             anIt2 = myConstraintMap.begin();
396         std::list<ConstraintWrapperPtr>::const_iterator aCIt2;
397         for (; anIt2 != myConstraintMap.end(); ++anIt2)
398           for (aCIt2 = anIt2->second.begin(); aCIt2 != anIt2->second.end(); ++aCIt2)
399             if ((Slvs_hConstraint)(*aCIt2)->id() == aConstr.h) {
400               addSameConstraints(*aCIt2, aWrapper);
401               break;
402             }
403       } else 
404         aConstr.h = updateConstraint(aConstr);
405       aWrapper->changeConstraint() = aConstr;
406
407       // update sub-entities
408       aWrapper->setEntities(aSubs);
409     }
410 }
411
412 void SolveSpaceSolver_Storage::addSameConstraints(ConstraintWrapperPtr theConstraint1,
413                                                   ConstraintWrapperPtr theConstraint2)
414 {
415   SameConstraintMap::iterator anIt = myEqualConstraints.begin();
416   for (; anIt != myEqualConstraints.end(); ++anIt) {
417     if (anIt->find(theConstraint1) != anIt->end()) {
418       anIt->insert(theConstraint2);
419       return;
420     }
421     else if (anIt->find(theConstraint2) != anIt->end()) {
422       anIt->insert(theConstraint1);
423       return;
424     }
425   }
426   // group not found => create new one
427   std::set<ConstraintWrapperPtr> aNewGroup;
428   aNewGroup.insert(theConstraint1);
429   aNewGroup.insert(theConstraint2);
430   myEqualConstraints.push_back(aNewGroup);
431 }
432
433
434 EntityWrapperPtr SolveSpaceSolver_Storage::calculateMiddlePoint(
435     EntityWrapperPtr theBase, double theCoeff)
436 {
437   BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
438
439   std::shared_ptr<GeomAPI_XY> aMidPoint;
440   if (theBase->type() == ENTITY_LINE) {
441     std::shared_ptr<GeomAPI_Pnt2d> aPoints[2];
442     const std::list<EntityWrapperPtr>& aSubs = theBase->subEntities();
443     std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
444     for (int i = 0; i < 2; ++i, ++anIt)
445       aPoints[i] = aBuilder->point(*anIt);
446     aMidPoint = aPoints[0]->xy()->multiplied(1.0 - theCoeff)->added(
447         aPoints[1]->xy()->multiplied(theCoeff));
448   }
449   else if (theBase->type() == ENTITY_ARC) {
450     double theX, theY;
451     double anArcPoint[3][2];
452     const std::list<EntityWrapperPtr>& aSubs = theBase->subEntities();
453     std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
454     for (int i = 0; i < 3; ++i, ++anIt) {
455       std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(*anIt);
456       anArcPoint[i][0] = aPoint->x();
457       anArcPoint[i][1] = aPoint->y();
458     }
459     // project last point of arc on the arc
460     double x = anArcPoint[1][0] - anArcPoint[0][0];
461     double y = anArcPoint[1][1] - anArcPoint[0][1];
462     double aRad = sqrt(x*x + y*y);
463     x = anArcPoint[2][0] - anArcPoint[0][0];
464     y = anArcPoint[2][1] - anArcPoint[0][1];
465     double aNorm = sqrt(x*x + y*y);
466     if (aNorm >= tolerance) {
467       anArcPoint[2][0] = x * aRad / aNorm;
468       anArcPoint[2][1] = y * aRad / aNorm;
469     }
470     anArcPoint[1][0] -= anArcPoint[0][0];
471     anArcPoint[1][1] -= anArcPoint[0][1];
472     if (theCoeff < tolerance) {
473       theX = anArcPoint[0][0] + anArcPoint[1][0];
474       theY = anArcPoint[0][1] + anArcPoint[1][1];
475     } else if (1 - theCoeff < tolerance) {
476       theX = anArcPoint[0][0] + anArcPoint[2][0];
477       theY = anArcPoint[0][1] + anArcPoint[2][1];
478     } else {
479       std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1]));
480       std::shared_ptr<GeomAPI_Dir2d> aEndDir(new GeomAPI_Dir2d(anArcPoint[2][0], anArcPoint[2][1]));
481       double anAngle = aStartDir->angle(aEndDir);
482       if (anAngle < 0)
483         anAngle += 2.0 * PI;
484       anAngle *= theCoeff;
485       double aCos = cos(anAngle);
486       double aSin = sin(anAngle);
487       theX = anArcPoint[0][0] + anArcPoint[1][0] * aCos - anArcPoint[1][1] * aSin;
488       theY = anArcPoint[0][1] + anArcPoint[1][0] * aSin + anArcPoint[1][1] * aCos;
489     }
490     aMidPoint = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(theX, theY));
491   }
492
493   if (!aMidPoint)
494     return EntityWrapperPtr();
495
496   std::list<ParameterWrapperPtr> aParameters;
497   Slvs_Param aParam1 = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID, aMidPoint->x());
498   aParam1.h = addParameter(aParam1);
499   aParameters.push_back(ParameterWrapperPtr(new SolveSpaceSolver_ParameterWrapper(aParam1)));
500   Slvs_Param aParam2 = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID, aMidPoint->y());
501   aParam2.h = addParameter(aParam2);
502   aParameters.push_back(ParameterWrapperPtr(new SolveSpaceSolver_ParameterWrapper(aParam2)));
503   // Create entity (parameters are not filled)
504   Slvs_Entity anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID,
505       (Slvs_hEntity)myWorkplaneID, aParam1.h, aParam2.h);
506   anEntity.h = addEntity(anEntity);
507
508   EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(AttributePtr(), anEntity));
509   aResult->setParameters(aParameters);
510   return aResult;
511 }
512
513
514
515
516
517
518 Slvs_hParam SolveSpaceSolver_Storage::addParameter(const Slvs_Param& theParam)
519 {
520   if (theParam.h > 0 && theParam.h <= myParamMaxID) {
521     // parameter is already used, rewrite it
522     return updateParameter(theParam);
523   }
524
525   Slvs_Param aParam = theParam;
526   if (aParam.h > myParamMaxID)
527     myParamMaxID = aParam.h;
528   else
529     aParam.h = ++myParamMaxID;
530   myParameters.push_back(aParam);
531   myNeedToResolve = true;
532   return aParam.h;
533 }
534
535 Slvs_hParam SolveSpaceSolver_Storage::updateParameter(const Slvs_Param& theParam)
536 {
537   if (theParam.h > 0 && theParam.h <= myParamMaxID) {
538     // parameter already used, rewrite it
539     int aPos = Search(theParam.h, myParameters);
540     if (aPos >= 0 && aPos < (int)myParameters.size()) {
541       if (IsNotEqual(myParameters[aPos], theParam)) {
542         myUpdatedParameters.insert(theParam.h);
543         setNeedToResolve(true);
544       }
545       myParameters[aPos] = theParam;
546       return theParam.h;
547     }
548   }
549
550   // Parameter is not found, add new one
551   Slvs_Param aParam = theParam;
552   aParam.h = 0;
553   return addParameter(aParam);
554 }
555
556 bool SolveSpaceSolver_Storage::removeParameter(const Slvs_hParam& theParamID)
557 {
558   int aPos = Search(theParamID, myParameters);
559   if (aPos >= 0 && aPos < (int)myParameters.size()) {
560     // Firstly, search the parameter is not used elsewhere
561     std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
562     for (; anEntIter != myEntities.end(); anEntIter++) {
563       for (int i = 0; i < 4; i++)
564         if (anEntIter->param[i] == theParamID)
565           return false;
566     }
567     // Remove parameter
568     myParameters.erase(myParameters.begin() + aPos);
569     myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h;
570     myNeedToResolve = true;
571   }
572   return true;
573 }
574
575 const Slvs_Param& SolveSpaceSolver_Storage::getParameter(const Slvs_hParam& theParamID) const
576 {
577   int aPos = Search(theParamID, myParameters);
578   if (aPos >= 0 && aPos < (int)myParameters.size())
579     return myParameters[aPos];
580
581   // Parameter is not found, return empty object
582   static Slvs_Param aDummy;
583   aDummy.h = 0;
584   return aDummy;
585 }
586
587
588 Slvs_hEntity SolveSpaceSolver_Storage::addEntity(const Slvs_Entity& theEntity)
589 {
590   if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
591     // Entity is already used, rewrite it
592     return updateEntity(theEntity);
593   }
594
595   Slvs_Entity aEntity = theEntity;
596   if (aEntity.h > myEntityMaxID)
597     myEntityMaxID = aEntity.h;
598   else
599     aEntity.h = ++myEntityMaxID;
600   myEntities.push_back(aEntity);
601   myNeedToResolve = true;
602   return aEntity.h;
603 }
604
605 Slvs_hEntity SolveSpaceSolver_Storage::updateEntity(const Slvs_Entity& theEntity)
606 {
607   if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
608     // Entity already used, rewrite it
609     int aPos = Search(theEntity.h, myEntities);
610     if (aPos >= 0 && aPos < (int)myEntities.size()) {
611       myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity);
612       myEntities[aPos] = theEntity;
613       return theEntity.h;
614     }
615   }
616
617   // Entity is not found, add new one
618   Slvs_Entity aEntity = theEntity;
619   aEntity.h = 0;
620   return addEntity(aEntity);
621 }
622
623 bool SolveSpaceSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
624 {
625   bool aResult = true;
626   int aPos = Search(theEntityID, myEntities);
627   if (aPos >= 0 && aPos < (int)myEntities.size()) {
628     // Firstly, check the entity and its attributes is not used elsewhere
629     std::set<Slvs_hEntity> anEntAndSubs;
630     anEntAndSubs.insert(theEntityID);
631     for (int i = 0; i < 4; i++)
632       if (myEntities[aPos].point[i] != SLVS_E_UNKNOWN)
633         anEntAndSubs.insert(myEntities[aPos].point[i]);
634
635     std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
636     for (; anEntIter != myEntities.end(); anEntIter++) {
637       if (anEntAndSubs.find(anEntIter->h) != anEntAndSubs.end())
638         continue;
639       for (int i = 0; i < 4; i++)
640         if (anEntAndSubs.find(anEntIter->point[i]) != anEntAndSubs.end())
641           return false;
642       if (anEntAndSubs.find(anEntIter->distance) != anEntAndSubs.end())
643         return false;
644     }
645     std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
646     for (; aConstrIter != myConstraints.end(); aConstrIter++) {
647       Slvs_hEntity anEntIDs[6] = {aConstrIter->ptA, aConstrIter->ptB,
648           aConstrIter->entityA, aConstrIter->entityB,
649           aConstrIter->entityC, aConstrIter->entityD};
650       for (int i = 0; i < 6; i++)
651         if (anEntAndSubs.find(anEntIDs[i]) != anEntAndSubs.end())
652           return false;
653     }
654     // The entity is not used, remove it and its parameters
655     Slvs_Entity anEntity = myEntities[aPos];
656     myEntities.erase(myEntities.begin() + aPos);
657     myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
658     if (anEntity.distance != SLVS_E_UNKNOWN)
659       aResult = aResult && removeParameter(anEntity.distance);
660     for (int i = 0; i < 4; i++)
661       if (anEntity.param[i] != SLVS_E_UNKNOWN)
662         aResult = removeParameter(anEntity.param[i]) && aResult;
663     for (int i = 0; i < 4; i++)
664       if (anEntity.point[i] != SLVS_E_UNKNOWN)
665         aResult = removeEntity(anEntity.point[i]) && aResult;
666     myNeedToResolve = true;
667   }
668   return aResult;
669 }
670
671 void SolveSpaceSolver_Storage::removeUnusedEntities()
672 {
673   std::set<Slvs_hEntity> anUnusedEntities;
674   std::vector<Slvs_Entity>::const_iterator aEIt = myEntities.begin();
675   for (; aEIt != myEntities.end(); ++aEIt) {
676     if (aEIt->h == aEIt->wrkpl) {
677       // don't remove workplane
678       anUnusedEntities.erase(aEIt->point[0]);
679       anUnusedEntities.erase(aEIt->normal);
680       continue;
681     }
682     anUnusedEntities.insert(aEIt->h);
683   }
684
685   std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
686   for (; aCIt != myConstraints.end(); ++aCIt) {
687     Slvs_hEntity aSubs[6] = {
688         aCIt->entityA, aCIt->entityB,
689         aCIt->entityC, aCIt->entityD,
690         aCIt->ptA,     aCIt->ptB};
691     for (int i = 0; i < 6; i++) {
692       if (aSubs[i] != SLVS_E_UNKNOWN) {
693         anUnusedEntities.erase(aSubs[i]);
694         int aPos = Search(aSubs[i], myEntities);
695         if (aPos >= 0 && aPos < (int)myEntities.size()) {
696           for (int j = 0; j < 4; j++)
697             if (myEntities[aPos].point[j] != SLVS_E_UNKNOWN)
698               anUnusedEntities.erase(myEntities[aPos].point[j]);
699           if (myEntities[aPos].distance != SLVS_E_UNKNOWN)
700             anUnusedEntities.erase(myEntities[aPos].distance);
701         }
702       }
703     }
704   }
705
706   std::set<Slvs_hEntity>::const_iterator anEntIt = anUnusedEntities.begin();
707   while (anEntIt != anUnusedEntities.end()) {
708     int aPos = Search(*anEntIt, myEntities);
709     if (aPos < 0 && aPos >= (int)myEntities.size())
710       continue;
711     Slvs_Entity anEntity = myEntities[aPos];
712     // Remove entity if and only if all its parameters unused
713     bool isUsed = false;
714     if (anEntity.distance != SLVS_E_UNKNOWN && 
715       anUnusedEntities.find(anEntity.distance) == anUnusedEntities.end())
716       isUsed = true;
717     for (int i = 0; i < 4 && !isUsed; i++)
718       if (anEntity.point[i] != SLVS_E_UNKNOWN &&
719           anUnusedEntities.find(anEntity.point[i]) == anUnusedEntities.end())
720         isUsed = true;
721     if (isUsed) {
722       anUnusedEntities.erase(anEntity.distance);
723       for (int i = 0; i < 4; i++)
724         if (anEntity.point[i] != SLVS_E_UNKNOWN)
725           anUnusedEntities.erase(anEntity.point[i]);
726       std::set<Slvs_hEntity>::iterator aRemoveIt = anEntIt++;
727       anUnusedEntities.erase(aRemoveIt);
728       continue;
729     }
730     ++anEntIt;
731   }
732
733   for (anEntIt = anUnusedEntities.begin(); anEntIt != anUnusedEntities.end(); ++anEntIt) {
734     int aPos = Search(*anEntIt, myEntities);
735     if (aPos >= 0 && aPos < (int)myEntities.size()) {
736       // Remove entity and its parameters
737       Slvs_Entity anEntity = myEntities[aPos];
738       myEntities.erase(myEntities.begin() + aPos);
739       myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
740       if (anEntity.distance != SLVS_E_UNKNOWN)
741         removeParameter(anEntity.distance);
742       for (int i = 0; i < 4; i++)
743         if (anEntity.param[i] != SLVS_E_UNKNOWN)
744           removeParameter(anEntity.param[i]);
745       for (int i = 0; i < 4; i++)
746         if (anEntity.point[i] != SLVS_E_UNKNOWN)
747           removeEntity(anEntity.point[i]);
748     }
749   }
750
751   if (!anUnusedEntities.empty())
752     myNeedToResolve = true;
753 }
754
755 bool SolveSpaceSolver_Storage::isUsedByConstraints(const Slvs_hEntity& theEntityID) const
756 {
757   std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
758   for (; aCIt != myConstraints.end(); ++aCIt) {
759     Slvs_hEntity aSubs[6] = {
760         aCIt->entityA, aCIt->entityB,
761         aCIt->entityC, aCIt->entityD,
762         aCIt->ptA,     aCIt->ptB};
763     for (int i = 0; i < 6; i++)
764       if (aSubs[i] != SLVS_E_UNKNOWN && aSubs[i] == theEntityID)
765         return true;
766   }
767   return false;
768 }
769
770 const Slvs_Entity& SolveSpaceSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const
771 {
772   int aPos = Search(theEntityID, myEntities);
773   if (aPos >= 0 && aPos < (int)myEntities.size())
774     return myEntities[aPos];
775
776   // Entity is not found, return empty object
777   static Slvs_Entity aDummy;
778   aDummy.h = SLVS_E_UNKNOWN;
779   return aDummy;
780 }
781
782 Slvs_hEntity SolveSpaceSolver_Storage::copyEntity(const Slvs_hEntity& theCopied)
783 {
784   int aPos = Search(theCopied, myEntities);
785   if (aPos < 0 || aPos >= (int)myEntities.size())
786     return SLVS_E_UNKNOWN;
787
788   Slvs_Entity aCopy = myEntities[aPos];
789   aCopy.h = SLVS_E_UNKNOWN;
790   int i = 0;
791   while (aCopy.point[i] != SLVS_E_UNKNOWN) {
792     aCopy.point[i] = copyEntity(aCopy.point[i]);
793     i++;
794   }
795   if (aCopy.param[0] != SLVS_E_UNKNOWN) {
796     aPos = Search(aCopy.param[0], myParameters);
797     i = 0;
798     while (aCopy.param[i] != SLVS_E_UNKNOWN) {
799       Slvs_Param aNewParam = myParameters[aPos];
800       aNewParam.h = SLVS_E_UNKNOWN;
801       aCopy.param[i] = addParameter(aNewParam);
802       i++;
803       aPos++;
804     }
805   }
806   return addEntity(aCopy);
807 }
808
809 void SolveSpaceSolver_Storage::copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo)
810 {
811   int aPosFrom = Search(theFrom, myEntities);
812   int aPosTo = Search(theTo, myEntities);
813   if (aPosFrom < 0 || aPosFrom >= (int)myEntities.size() || 
814       aPosTo < 0 || aPosTo >= (int)myEntities.size())
815     return;
816
817   Slvs_Entity aEntFrom = myEntities[aPosFrom];
818   Slvs_Entity aEntTo = myEntities[aPosTo];
819   int i = 0;
820   while (aEntFrom.point[i] != SLVS_E_UNKNOWN) {
821     copyEntity(aEntFrom.point[i], aEntTo.point[i]);
822     i++;
823   }
824   if (aEntFrom.param[0] != SLVS_E_UNKNOWN) {
825     aPosFrom = Search(aEntFrom.param[0], myParameters);
826     aPosTo = Search(aEntTo.param[0], myParameters);
827     i = 0;
828     while (aEntFrom.param[i] != SLVS_E_UNKNOWN) {
829       myParameters[aPosTo++].val = myParameters[aPosFrom++].val;
830       i++;
831     }
832   }
833 }
834
835
836 bool SolveSpaceSolver_Storage::isPointFixed(
837     const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate) const
838 {
839   // Search the set of coincident points
840   std::set<Slvs_hEntity> aCoincident;
841   aCoincident.insert(thePointID);
842
843   // Check whether one of coincident points is out-of-group
844   std::set<Slvs_hEntity>::const_iterator aCoincIt = aCoincident.begin();
845   for (; aCoincIt != aCoincident.end(); ++aCoincIt) {
846     Slvs_Entity aPoint = getEntity(*aCoincIt);
847     if (aPoint.group == SLVS_G_OUTOFGROUP)
848       return true;
849   }
850
851   // Search the Rigid constraint
852   theFixed = SLVS_C_UNKNOWN;
853   std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
854   for (; aConstrIter != myConstraints.end(); aConstrIter++)
855     if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
856         aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
857       theFixed = aConstrIter->h;
858       if (aConstrIter->ptA == thePointID)
859         return true;
860     }
861   if (theFixed != SLVS_C_UNKNOWN)
862     return true;
863
864   if (theAccurate) {
865     // Try to find the fixed entity which uses such point or its coincidence
866     std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
867     for (; anEntIter != myEntities.end(); anEntIter++) {
868       for (int i = 0; i < 4; i++) {
869         Slvs_hEntity aPt = anEntIter->point[i];
870         if (aPt != SLVS_E_UNKNOWN &&
871             (aPt == thePointID || aCoincident.find(aPt) != aCoincident.end())) {
872           if (isEntityFixed(anEntIter->h, true))
873             return true;
874         }
875       }
876     }
877   }
878   return SLVS_E_UNKNOWN;
879 }
880
881 bool SolveSpaceSolver_Storage::isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate) const
882 {
883   int aPos = Search(theEntityID, myEntities);
884   if (aPos < 0 || aPos >= (int)myEntities.size())
885     return false;
886
887   // Firstly, find how many points are under Rigid constraint
888   int aNbFixed = 0;
889   for (int i = 0; i < 4; i++) {
890     Slvs_hEntity aPoint = myEntities[aPos].point[i];
891     if (aPoint == SLVS_E_UNKNOWN)
892       continue;
893
894     std::set<Slvs_hEntity> aCoincident;
895     aCoincident.insert(aPoint);
896
897     // Search the Rigid constraint
898     std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
899     for (; aConstrIter != myConstraints.end(); aConstrIter++)
900       if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
901           aCoincident.find(aConstrIter->ptA) != aCoincident.end())
902         aNbFixed++;
903   }
904
905   std::list<Slvs_Constraint> aList;
906   std::list<Slvs_Constraint>::iterator anIt;
907   Slvs_hConstraint aTempID; // used in isPointFixed() method
908
909   if (myEntities[aPos].type == SLVS_E_LINE_SEGMENT) {
910     if (aNbFixed == 2)
911       return true;
912     else if (aNbFixed == 0 || !theAccurate)
913       return false;
914     // Additional check (the line may be fixed if it is used by different constraints):
915     // 1. The line is used in Equal constraint, another entity is fixed and there is a fixed point on line
916     aList = getConstraintsByType(SLVS_C_PT_ON_LINE);
917     for (anIt = aList.begin(); anIt != aList.end(); anIt++)
918       if (anIt->entityA == theEntityID && isPointFixed(anIt->ptA, aTempID))
919         break;
920     if (anIt != aList.end()) {
921       aList = getConstraintsByType(SLVS_C_EQUAL_LENGTH_LINES);
922       aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
923       for (anIt = aList.begin(); anIt != aList.end(); anIt++)
924         if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
925           Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
926           if (isEntityFixed(anOther, false))
927             return true;
928         }
929     }
930     // 2. The line is used in Parallel/Perpendicular/Vertical/Horizontal and Length constraints
931     aList = getConstraintsByType(SLVS_C_PARALLEL);
932     aList.splice(aList.end(), getConstraintsByType(SLVS_C_PERPENDICULAR));
933     aList.splice(aList.end(), getConstraintsByType(SLVS_C_VERTICAL));
934     aList.splice(aList.end(), getConstraintsByType(SLVS_C_HORIZONTAL));
935     for (anIt = aList.begin(); anIt != aList.end(); anIt++)
936       if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
937         Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
938         if (isEntityFixed(anOther, false))
939           break;
940       }
941     if (anIt != aList.end()) {
942       aList = getConstraintsByType(SLVS_C_PT_PT_DISTANCE);
943       for (anIt = aList.begin(); anIt != aList.end(); anIt++)
944         if ((anIt->ptA == myEntities[aPos].point[0] && anIt->ptB == myEntities[aPos].point[1]) ||
945             (anIt->ptA == myEntities[aPos].point[1] && anIt->ptB == myEntities[aPos].point[0]))
946           return true;
947     }
948     // 3. Another verifiers ...
949   } else if (myEntities[aPos].type == SLVS_E_CIRCLE) {
950     if (aNbFixed == 0)
951       return false;
952     // Search for Diameter constraint
953     aList = getConstraintsByType(SLVS_C_DIAMETER);
954     for (anIt = aList.begin(); anIt != aList.end(); anIt++)
955       if (anIt->entityA == theEntityID)
956         return true;
957     if (!theAccurate)
958       return false;
959     // Additional check (the circle may be fixed if it is used by different constraints):
960     // 1. The circle is used in Equal constraint and another entity is fixed
961     aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
962     for (anIt = aList.begin(); anIt != aList.end(); anIt++)
963       if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
964         Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
965         if (isEntityFixed(anOther, false))
966           return true;
967       }
968     // 2. Another verifiers ...
969   } else if (myEntities[aPos].type == SLVS_E_ARC_OF_CIRCLE) {
970     if (aNbFixed > 2)
971       return true;
972     else if (aNbFixed <= 1)
973       return false;
974     // Search for Diameter constraint
975     aList = getConstraintsByType(SLVS_C_DIAMETER);
976     for (anIt = aList.begin(); anIt != aList.end(); anIt++)
977       if (anIt->entityA == theEntityID)
978         return true;
979     if (!theAccurate)
980       return false;
981     // Additional check (the arc may be fixed if it is used by different constraints):
982     // 1. The arc is used in Equal constraint and another entity is fixed
983     aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
984     aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
985     for (anIt = aList.begin(); anIt != aList.end(); anIt++)
986       if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
987         Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
988         if (isEntityFixed(anOther, false))
989           return true;
990       }
991     // 2. Another verifiers ...
992   }
993   return false;
994 }
995
996
997 Slvs_hConstraint SolveSpaceSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
998 {
999   if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
1000     // Constraint is already used, rewrite it
1001     return updateConstraint(theConstraint);
1002   }
1003
1004   Slvs_Constraint aConstraint = theConstraint;
1005
1006   // Find a constraint with same type uses same arguments to show user overconstraint situation
1007   std::vector<Slvs_Constraint>::iterator aCIt = myConstraints.begin();
1008   for (; aCIt != myConstraints.end(); aCIt++) {
1009     if (aConstraint.type != aCIt->type)
1010       continue;
1011     if (aConstraint.ptA == aCIt->ptA && aConstraint.ptB == aCIt->ptB &&
1012         aConstraint.entityA == aCIt->entityA && aConstraint.entityB == aCIt->entityB &&
1013         aConstraint.entityC == aCIt->entityC && aConstraint.entityD == aCIt->entityD)
1014       myDuplicatedConstraint = true;
1015   }
1016
1017   if (aConstraint.h > myConstrMaxID)
1018     myConstrMaxID = aConstraint.h;
1019   else
1020     aConstraint.h = ++myConstrMaxID;
1021   myConstraints.push_back(aConstraint);
1022   myNeedToResolve = true;
1023   return aConstraint.h;
1024 }
1025
1026 Slvs_hConstraint SolveSpaceSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint)
1027 {
1028   if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
1029     // Constraint already used, rewrite it
1030     int aPos = Search(theConstraint.h, myConstraints);
1031     if (aPos >= 0 && aPos < (int)myConstraints.size()) {
1032       myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint);
1033       myConstraints[aPos] = theConstraint;
1034       return theConstraint.h;
1035     }
1036   }
1037
1038   // Constraint is not found, add new one
1039   Slvs_Constraint aConstraint = theConstraint;
1040   aConstraint.h = 0;
1041   return addConstraint(aConstraint);
1042 }
1043
1044 bool SolveSpaceSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID)
1045 {
1046   bool aResult = true;
1047   int aPos = Search(theConstraintID, myConstraints);
1048   if (aPos >= 0 && aPos < (int)myConstraints.size()) {
1049     Slvs_Constraint aConstraint = myConstraints[aPos];
1050     myConstraints.erase(myConstraints.begin() + aPos);
1051     myConstrMaxID = myConstraints.empty() ? SLVS_E_UNKNOWN : myConstraints.back().h;
1052     myNeedToResolve = true;
1053
1054     // Remove all entities
1055     Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB,
1056         aConstraint.entityA, aConstraint.entityB,
1057         aConstraint.entityC, aConstraint.entityD};
1058     for (int i = 0; i < 6; i++)
1059       if (anEntities[i] != SLVS_E_UNKNOWN)
1060         aResult = removeEntity(anEntities[i]) && aResult;
1061     // remove temporary fixed point, if available
1062     if (myFixed == theConstraintID)
1063       myFixed = SLVS_E_UNKNOWN;
1064     if (myDuplicatedConstraint) {
1065       // Check the duplicated constraints are still available
1066       myDuplicatedConstraint = false;
1067       std::vector<Slvs_Constraint>::const_iterator anIt1 = myConstraints.begin();
1068       std::vector<Slvs_Constraint>::const_iterator anIt2 = myConstraints.begin();
1069       for (; anIt1 != myConstraints.end() && !myDuplicatedConstraint; anIt1++)
1070         for (anIt2 = anIt1+1; anIt2 != myConstraints.end() && !myDuplicatedConstraint; anIt2++) {
1071           if (anIt1->type != anIt2->type)
1072             continue;
1073           if (anIt1->ptA == anIt2->ptA && anIt1->ptB == anIt2->ptB &&
1074               anIt1->entityA == anIt2->entityA && anIt1->entityB == anIt2->entityB &&
1075               anIt1->entityC == anIt2->entityC && anIt1->entityD == anIt2->entityD)
1076             myDuplicatedConstraint = true;
1077         }
1078     }
1079   }
1080   return aResult;
1081 }
1082
1083 const Slvs_Constraint& SolveSpaceSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const
1084 {
1085   int aPos = Search(theConstraintID, myConstraints);
1086   if (aPos >= 0 && aPos < (int)myConstraints.size())
1087     return myConstraints[aPos];
1088
1089   // Constraint is not found, return empty object
1090   static Slvs_Constraint aDummy;
1091   aDummy.h = 0;
1092   return aDummy;
1093 }
1094
1095 std::list<Slvs_Constraint> SolveSpaceSolver_Storage::getConstraintsByType(int theConstraintType) const
1096 {
1097   std::list<Slvs_Constraint> aResult;
1098   std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
1099   for (; aCIter != myConstraints.end(); aCIter++)
1100     if (aCIter->type == theConstraintType)
1101       aResult.push_back(*aCIter);
1102   return aResult;
1103 }
1104
1105
1106 void SolveSpaceSolver_Storage::addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID)
1107 {
1108   if (myFixed != SLVS_E_UNKNOWN)
1109     return; // the point is already fixed
1110   int aPos = Search(theConstraintID, myConstraints);
1111   if (aPos >= 0 && aPos < (int)myConstraints.size())
1112     myFixed = theConstraintID;
1113 }
1114
1115 void SolveSpaceSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
1116 {
1117   myTemporaryConstraints.insert(theConstraintID);
1118 }
1119
1120 void SolveSpaceSolver_Storage::removeAllTemporary()
1121 {
1122   myTemporaryConstraints.clear();
1123 }
1124
1125 size_t SolveSpaceSolver_Storage::removeTemporary(size_t theNbConstraints)
1126 {
1127   if (myTemporaryConstraints.empty())
1128     return 0;
1129   // Search the point-on-line or a non-rigid constraint
1130   std::set<Slvs_hConstraint>::iterator aCIt = myTemporaryConstraints.begin();
1131   for (; aCIt != myTemporaryConstraints.end(); aCIt++) {
1132     int aPos = Search(*aCIt, myConstraints);
1133     if (aPos >= (int)myConstraints.size() || myConstraints[aPos].type != SLVS_C_WHERE_DRAGGED)
1134       break;
1135     std::vector<Slvs_Constraint>::iterator anIt = myConstraints.begin();
1136     for (; anIt != myConstraints.end(); anIt++)
1137       if (anIt->type == SLVS_C_PT_ON_LINE && anIt->ptA == myConstraints[aPos].ptA)
1138         break;
1139     if (anIt != myConstraints.end())
1140       break;
1141   }
1142   if (aCIt == myTemporaryConstraints.end())
1143     aCIt = myTemporaryConstraints.begin();
1144   bool aNewFixed = false;
1145
1146   size_t aNbRemain = theNbConstraints;
1147   while (aNbRemain > 0 && aCIt != myTemporaryConstraints.end()) {
1148     aNewFixed = aNewFixed || (*aCIt == myFixed);
1149     --aNbRemain;
1150
1151     std::set<Slvs_hConstraint>::iterator aRemoveIt = aCIt++;
1152     removeConstraint(*aRemoveIt);
1153     myTemporaryConstraints.erase(aRemoveIt);
1154     if (aCIt == myTemporaryConstraints.end())
1155       aCIt = myTemporaryConstraints.begin();
1156   }
1157
1158   if (aNewFixed) {
1159     for (aCIt = myTemporaryConstraints.begin(); aCIt != myTemporaryConstraints.end(); aCIt++) {
1160       int aPos = Search(*aCIt, myConstraints);
1161       if (myConstraints[aPos].type == SLVS_C_WHERE_DRAGGED) {
1162         myFixed = *aCIt;
1163         break;
1164       }
1165     }
1166   }
1167   return myTemporaryConstraints.size();
1168 }
1169
1170 bool SolveSpaceSolver_Storage::isTemporary(const Slvs_hConstraint& theConstraintID) const
1171 {
1172   return myTemporaryConstraints.find(theConstraintID) != myTemporaryConstraints.end();
1173 }
1174
1175
1176
1177 void SolveSpaceSolver_Storage::initializeSolver(SolverPtr theSolver)
1178 {
1179   std::shared_ptr<SolveSpaceSolver_Solver> aSolver =
1180       std::dynamic_pointer_cast<SolveSpaceSolver_Solver>(theSolver);
1181   if (!aSolver)
1182     return;
1183
1184   if (myConstraints.empty()) {
1185     // Adjust all arc to place their points correctly
1186     std::vector<Slvs_Entity>::const_iterator anEntIt = myEntities.begin();
1187     for (; anEntIt != myEntities.end(); ++anEntIt)
1188       if (anEntIt->type == SLVS_E_ARC_OF_CIRCLE)
1189         adjustArc(*anEntIt);
1190   }
1191
1192   aSolver->setParameters(myParameters.data(), (int)myParameters.size());
1193   aSolver->setEntities(myEntities.data(), (int)myEntities.size());
1194
1195   // Copy constraints excluding the fixed one
1196   std::vector<Slvs_Constraint> aConstraints = myConstraints;
1197   if (myFixed != SLVS_E_UNKNOWN) {
1198     Slvs_hEntity aFixedPoint = SLVS_E_UNKNOWN;
1199     std::vector<Slvs_Constraint>::iterator anIt = aConstraints.begin();
1200     for (; anIt != aConstraints.end(); anIt++)
1201       if (anIt->h == myFixed) {
1202         aFixedPoint = anIt->ptA;
1203         aConstraints.erase(anIt);
1204         break;
1205       }
1206     // set dragged parameters
1207     int aPos = Search(aFixedPoint, myEntities);
1208     aSolver->setDraggedParameters(myEntities[aPos].param);
1209   }
1210   aSolver->setConstraints(aConstraints.data(), (int)aConstraints.size());
1211 }
1212
1213
1214 bool SolveSpaceSolver_Storage::isEqual(
1215     const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const
1216 {
1217   // Precise checking of coincidence: verify that points have equal coordinates
1218   int aEnt1Pos = Search(thePoint1, myEntities);
1219   int aEnt2Pos = Search(thePoint2, myEntities);
1220   if (aEnt1Pos >= 0 && aEnt1Pos < (int)myEntities.size() &&
1221       aEnt2Pos >= 0 && aEnt2Pos < (int)myEntities.size()) {
1222     double aDist[2];
1223     int aParamPos;
1224     for (int i = 0; i < 2; i++) {
1225       aParamPos = Search(myEntities[aEnt1Pos].param[i], myParameters);
1226       aDist[i] = myParameters[aParamPos].val;
1227       aParamPos = Search(myEntities[aEnt2Pos].param[i], myParameters);
1228       aDist[i] -= myParameters[aParamPos].val;
1229     }
1230     if (aDist[0] * aDist[0] + aDist[1] * aDist[1] < tolerance * tolerance)
1231       return true;
1232   }
1233   return false;
1234 }
1235
1236
1237 std::vector<Slvs_hConstraint> SolveSpaceSolver_Storage::fixEntity(const Slvs_hEntity& theEntity)
1238 {
1239   std::vector<Slvs_hConstraint> aNewConstraints;
1240
1241   int aPos = Search(theEntity, myEntities);
1242   if (aPos >= 0 && aPos < (int)myEntities.size()) {
1243     switch (myEntities[aPos].type) {
1244     case SLVS_E_POINT_IN_2D:
1245     case SLVS_E_POINT_IN_3D:
1246       fixPoint(myEntities[aPos], aNewConstraints);
1247       break;
1248     case SLVS_E_LINE_SEGMENT:
1249       fixLine(myEntities[aPos], aNewConstraints);
1250       break;
1251     case SLVS_E_CIRCLE:
1252       fixCircle(myEntities[aPos], aNewConstraints);
1253       break;
1254     case SLVS_E_ARC_OF_CIRCLE:
1255       fixArc(myEntities[aPos], aNewConstraints);
1256       break;
1257     default:
1258       break;
1259     }
1260   }
1261
1262   return aNewConstraints;
1263 }
1264
1265 void SolveSpaceSolver_Storage::fixPoint(const Slvs_Entity& thePoint,
1266     std::vector<Slvs_hConstraint>& theCreated)
1267 {
1268   Slvs_Constraint aConstraint;
1269   Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN;
1270   bool isFixed = isPointFixed(thePoint.h, aConstrID, true);
1271   bool isForceUpdate = (isFixed && isTemporary(aConstrID));
1272   if (!isForceUpdate) { // create new constraint
1273     if (isFixed) return;
1274     aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, thePoint.group, SLVS_C_WHERE_DRAGGED, thePoint.wrkpl,
1275         0.0, thePoint.h, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
1276     aConstraint.h = addConstraint(aConstraint);
1277     theCreated.push_back(aConstraint.h);
1278   } else { // update already existent constraint
1279     if (!isFixed || aConstrID == SLVS_E_UNKNOWN)
1280       return;
1281     int aPos = Search(aConstrID, myConstraints);
1282     if (aPos >= 0 && aPos < (int)myConstraints.size())
1283       myConstraints[aPos].ptA = thePoint.h;
1284   }
1285 }
1286
1287 void SolveSpaceSolver_Storage::fixLine(const Slvs_Entity& theLine,
1288     std::vector<Slvs_hConstraint>& theCreated)
1289 {
1290   Slvs_Entity aPoint[2] = {
1291       getEntity(theLine.point[0]),
1292       getEntity(theLine.point[1])
1293   };
1294
1295   Slvs_Constraint anEqual;
1296   if (isAxisParallel(theLine.h)) {
1297     // Fix one point and a line length
1298     Slvs_hConstraint aFixed;
1299     if (!isPointFixed(theLine.point[0], aFixed, true) &&
1300         !isPointFixed(theLine.point[1], aFixed, true))
1301       fixPoint(aPoint[0], theCreated);
1302     if (!isUsedInEqual(theLine.h, anEqual)) {
1303       // Check the distance is not set yet
1304       std::vector<Slvs_Constraint>::const_iterator aDistIt = myConstraints.begin();
1305       for (; aDistIt != myConstraints.end(); ++aDistIt)
1306         if ((aDistIt->type == SLVS_C_PT_PT_DISTANCE) &&
1307            ((aDistIt->ptA == theLine.point[0] && aDistIt->ptB == theLine.point[1]) ||
1308             (aDistIt->ptA == theLine.point[1] && aDistIt->ptB == theLine.point[0])))
1309           return;
1310       // Calculate distance between points on the line
1311       double aCoords[4];
1312       for (int i = 0; i < 2; i++)
1313         for (int j = 0; j < 2; j++) {
1314           Slvs_Param aParam = getParameter(aPoint[i].param[j]);
1315           aCoords[2*i+j] = aParam.val;
1316         }
1317
1318       double aLength = sqrt((aCoords[2] - aCoords[0]) * (aCoords[2] - aCoords[0]) + 
1319                             (aCoords[3] - aCoords[1]) * (aCoords[3] - aCoords[1]));
1320       // fix line length
1321       Slvs_Constraint aDistance = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group,
1322           SLVS_C_PT_PT_DISTANCE, theLine.wrkpl, aLength,
1323           theLine.point[0], theLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
1324       aDistance.h = addConstraint(aDistance);
1325       theCreated.push_back(aDistance.h);
1326     }
1327     return;
1328   }
1329   else if (isUsedInEqual(theLine.h, anEqual)) {
1330     // Check another entity of Equal is already fixed
1331     Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA;
1332     if (isEntityFixed(anOtherEntID, true)) {
1333       // Fix start point of the line (if end point is not fixed yet) ...
1334       Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN;
1335       bool isFixed = isPointFixed(theLine.point[1], anEndFixedID, true);
1336       if (isFixed == SLVS_E_UNKNOWN)
1337         fixPoint(aPoint[0], theCreated);
1338       // ...  and create fixed point lying on this line
1339       Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0];
1340       // Firstly, search already fixed point on line
1341       bool isPonLineFixed = false;
1342       Slvs_hEntity aFixedPoint;
1343       std::vector<Slvs_Constraint>::const_iterator aPLIter = myConstraints.begin();
1344       for (; aPLIter != myConstraints.end() && !isPonLineFixed; ++aPLIter)
1345         if (aPLIter->type == SLVS_C_PT_ON_LINE && aPLIter->entityA == theLine.h) {
1346           isPonLineFixed = isPointFixed(aPLIter->ptA, anEndFixedID);
1347           aFixedPoint = aPLIter->ptA;
1348         }
1349
1350       if (isPonLineFixed) { // update existent constraint
1351         copyEntity(aPointToCopy, aFixedPoint);
1352       } else { // create new constraint
1353         Slvs_hEntity aCopied = copyEntity(aPointToCopy);
1354         Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group, SLVS_C_PT_ON_LINE,
1355             theLine.wrkpl, 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN);
1356         aPonLine.h = addConstraint(aPonLine);
1357         theCreated.push_back(aPonLine.h);
1358         fixPoint(getEntity(aCopied), theCreated);
1359       }
1360       return;
1361     }
1362   }
1363
1364   // Fix both points
1365   for (int i = 0; i < 2; i++)
1366     fixPoint(aPoint[i], theCreated);
1367 }
1368
1369 void SolveSpaceSolver_Storage::fixCircle(const Slvs_Entity& theCircle,
1370     std::vector<Slvs_hConstraint>& theCreated)
1371 {
1372   bool isFixRadius = true;
1373   // Verify the arc is under Equal constraint
1374   Slvs_Constraint anEqual;
1375   if (isUsedInEqual(theCircle.h, anEqual)) {
1376     // Check another entity of Equal is already fixed
1377     Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA;
1378     if (isEntityFixed(anOtherEntID, true))
1379       isFixRadius = false;
1380   }
1381
1382   fixPoint(getEntity(theCircle.point[0]), theCreated);
1383
1384   if (isFixRadius) {
1385     // Search the radius is already fixed
1386     std::vector<Slvs_Constraint>::const_iterator aDiamIter = myConstraints.begin();
1387     for (; aDiamIter != myConstraints.end(); ++aDiamIter)
1388       if (aDiamIter->type == SLVS_C_DIAMETER && aDiamIter->entityA == theCircle.h)
1389         return;
1390
1391     // Fix radius of a circle
1392     const Slvs_Entity& aRadEnt = getEntity(theCircle.distance);
1393     double aRadius = getParameter(aRadEnt.param[0]).val;
1394     Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theCircle.group, SLVS_C_DIAMETER,
1395         theCircle.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theCircle.h, SLVS_E_UNKNOWN);
1396     aFixedR.h = addConstraint(aFixedR);
1397     theCreated.push_back(aFixedR.h);
1398   }
1399 }
1400
1401 void SolveSpaceSolver_Storage::fixArc(const Slvs_Entity& theArc,
1402     std::vector<Slvs_hConstraint>& theCreated)
1403 {
1404   Slvs_Entity aPoint[3] = {
1405       getEntity(theArc.point[0]),
1406       getEntity(theArc.point[1]),
1407       getEntity(theArc.point[2])
1408   };
1409
1410   bool isFixRadius = true;
1411   std::list<Slvs_Entity> aPointsToFix;
1412   aPointsToFix.push_back(aPoint[1]);
1413   aPointsToFix.push_back(aPoint[2]);
1414
1415   // Verify the arc is under Equal constraint
1416   Slvs_Constraint anEqual;
1417   if (isUsedInEqual(theArc.h, anEqual)) {
1418     // Check another entity of Equal is already fixed
1419     Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA;
1420     if (isEntityFixed(anOtherEntID, true)) {
1421       isFixRadius = false;
1422       Slvs_Entity anOtherEntity = getEntity(anOtherEntID);
1423       if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) {
1424         aPointsToFix.pop_back();
1425         aPointsToFix.push_back(aPoint[0]);
1426       }
1427     }
1428   }
1429
1430   Slvs_hConstraint aConstrID;
1431   int aNbPointsToFix = 2; // number of fixed points for the arc
1432   if (isPointFixed(theArc.point[0], aConstrID, true))
1433     aNbPointsToFix--;
1434
1435   double anArcPoints[3][2];
1436   for (int i = 0; i < 3; i++) {
1437     const Slvs_Entity& aPointOnArc = getEntity(theArc.point[i]);
1438     for (int j = 0; j < 2; j++)
1439       anArcPoints[i][j] = getParameter(aPointOnArc.param[j]).val;
1440   }
1441
1442   // Radius of the arc
1443   std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(anArcPoints[0][0], anArcPoints[0][1]));
1444   std::shared_ptr<GeomAPI_Pnt2d> aStart(new GeomAPI_Pnt2d(anArcPoints[1][0], anArcPoints[1][1]));
1445   double aRadius = aCenter->distance(aStart);
1446
1447   // Update end point of the arc to be on a curve
1448   std::shared_ptr<GeomAPI_Pnt2d> anEnd(new GeomAPI_Pnt2d(anArcPoints[2][0], anArcPoints[2][1]));
1449   double aDistance = anEnd->distance(aCenter);
1450   std::shared_ptr<GeomAPI_XY> aDir = anEnd->xy()->decreased(aCenter->xy());
1451   if (aDistance < tolerance)
1452     aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0);
1453   else
1454     aDir = aDir->multiplied(aRadius / aDistance);
1455   double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()};
1456   const Slvs_Entity& aEndPoint = getEntity(theArc.point[2]);
1457   for (int i = 0; i < 2; i++) {
1458     Slvs_Param aParam = getParameter(aEndPoint.param[i]);
1459     aParam.val = xy[i];
1460     updateParameter(aParam);
1461   }
1462
1463   std::list<Slvs_Entity>::iterator aPtIt = aPointsToFix.begin();
1464   for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--)
1465     fixPoint(*aPtIt, theCreated);
1466
1467   if (isFixRadius) {
1468     // Fix radius of the arc
1469     bool isExists = false;
1470     std::vector<Slvs_Constraint>::iterator anIt = myConstraints.begin();
1471     for (; anIt != myConstraints.end() && !isExists; ++anIt)
1472       if (anIt->type == SLVS_C_DIAMETER && anIt->entityA == theArc.h)
1473         isExists = true;
1474     if (!isExists) {
1475       Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theArc.group, SLVS_C_DIAMETER,
1476           theArc.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theArc.h, SLVS_E_UNKNOWN);
1477       aFixedR.h = addConstraint(aFixedR);
1478       theCreated.push_back(aFixedR.h);
1479     }
1480   }
1481 }
1482
1483
1484 bool SolveSpaceSolver_Storage::isAxisParallel(const Slvs_hEntity& theEntity) const
1485 {
1486   std::vector<Slvs_Constraint>::const_iterator anIter = myConstraints.begin();
1487   for (; anIter != myConstraints.end(); anIter++)
1488     if ((anIter->type == SLVS_C_HORIZONTAL || anIter->type == SLVS_C_VERTICAL) && 
1489         anIter->entityA == theEntity)
1490       return true;
1491   return false;
1492 }
1493
1494 bool SolveSpaceSolver_Storage::isUsedInEqual(
1495     const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const
1496 {
1497   // Check the entity is used in Equal constraint
1498   std::vector<Slvs_Constraint>::const_iterator anEqIter = myConstraints.begin();
1499   for (; anEqIter != myConstraints.end(); anEqIter++)
1500     if ((anEqIter->type == SLVS_C_EQUAL_LENGTH_LINES ||
1501          anEqIter->type == SLVS_C_EQUAL_LINE_ARC_LEN ||
1502          anEqIter->type == SLVS_C_EQUAL_RADIUS) &&
1503        (anEqIter->entityA == theEntity || anEqIter->entityB == theEntity)) {
1504       theEqual = *anEqIter;
1505       return true;
1506     }
1507   return false;
1508 }
1509
1510 void SolveSpaceSolver_Storage::setTemporary(ConstraintPtr theConstraint)
1511 {
1512   // TODO
1513 }
1514
1515 bool SolveSpaceSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
1516 {
1517   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::iterator
1518       aFound = myConstraintMap.find(theConstraint);
1519   if (aFound == myConstraintMap.end())
1520     return true; // no constraint, already deleted
1521
1522   // Remove constraint
1523   std::list<ConstraintWrapperPtr> aConstrList = aFound->second;
1524   myConstraintMap.erase(aFound);
1525   // Remove SolveSpace constraints
1526   bool isFullyRemoved = true;
1527   std::list<ConstraintWrapperPtr>::iterator anIt = aConstrList.begin();
1528   while (anIt != aConstrList.end()) {
1529     if (remove(*anIt)) {
1530       std::list<ConstraintWrapperPtr>::iterator aRemoveIt = anIt++;
1531       aConstrList.erase(aRemoveIt);
1532     } else {
1533       isFullyRemoved = false;
1534       ++anIt;
1535     }
1536   }
1537   if (!isFullyRemoved)
1538     myConstraintMap[theConstraint] = aConstrList;
1539   return isFullyRemoved;
1540 }
1541
1542 template <class ENT_TYPE>
1543 static bool isUsed(ConstraintWrapperPtr theConstraint, ENT_TYPE theEntity)
1544 {
1545   std::list<EntityWrapperPtr>::const_iterator anEntIt = theConstraint->entities().begin();
1546   for (; anEntIt != theConstraint->entities().end(); ++anEntIt)
1547     if (std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anEntIt)->isBase(theEntity))
1548       return true;
1549   return false;
1550 }
1551
1552 static bool isUsed(EntityWrapperPtr theFeature, AttributePtr theSubEntity)
1553 {
1554   std::list<EntityWrapperPtr>::const_iterator aSubIt = theFeature->subEntities().begin();
1555   for (; aSubIt != theFeature->subEntities().end(); ++aSubIt)
1556     if (std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*aSubIt)->isBase(theSubEntity))
1557       return true;
1558   return false;
1559 }
1560
1561 bool SolveSpaceSolver_Storage::isUsed(FeaturePtr theFeature) const
1562 {
1563   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
1564       aCIt = myConstraintMap.begin();
1565   std::list<ConstraintWrapperPtr>::const_iterator aCWIt;
1566   for (; aCIt != myConstraintMap.end(); ++aCIt)
1567     for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt)
1568       if (::isUsed(*aCWIt, theFeature))
1569         return true;
1570   // check attributes
1571   std::list<AttributePtr> anAttrList = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
1572   std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
1573   for (; anIt != anAttrList.end(); ++anIt)
1574     if (isUsed(*anIt))
1575       return true;
1576   return false;
1577 }
1578
1579 bool SolveSpaceSolver_Storage::isUsed(AttributePtr theAttribute) const
1580 {
1581   AttributePtr anAttribute = theAttribute;
1582   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
1583   if (aRefAttr) {
1584     if (aRefAttr->isObject())
1585       return isUsed(ModelAPI_Feature::feature(aRefAttr->object()));
1586     else
1587       anAttribute = aRefAttr->attr();
1588   }
1589
1590   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
1591       aCIt = myConstraintMap.begin();
1592   std::list<ConstraintWrapperPtr>::const_iterator aCWIt;
1593   for (; aCIt != myConstraintMap.end(); ++aCIt)
1594     for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt)
1595       if (::isUsed(*aCWIt, anAttribute))
1596         return true;
1597   return false;
1598 }
1599
1600
1601 bool SolveSpaceSolver_Storage::removeEntity(FeaturePtr theFeature)
1602 {
1603   std::map<FeaturePtr, EntityWrapperPtr>::iterator aFound = myFeatureMap.find(theFeature);
1604   if (aFound == myFeatureMap.end())
1605     return false; // feature not found, nothing to delete
1606
1607   // Check the feature is not used by constraints
1608   if (isUsed(theFeature))
1609     return false; // the feature is used, don't remove it
1610
1611   // Remove feature
1612   EntityWrapperPtr anEntity = aFound->second;
1613   myFeatureMap.erase(aFound);
1614   if (remove(anEntity))
1615     return true;
1616   // feature is not removed, revert operation
1617   myFeatureMap[theFeature] = anEntity;
1618   return false;
1619 }
1620
1621 bool SolveSpaceSolver_Storage::removeEntity(AttributePtr theAttribute)
1622 {
1623   std::map<AttributePtr, EntityWrapperPtr>::iterator aFound = myAttributeMap.find(theAttribute);
1624   if (aFound == myAttributeMap.end())
1625     return false; // attribute not found, nothing to delete
1626
1627   // Check the attribute is not used by constraints
1628   if (isUsed(theAttribute))
1629     return false; // the attribute is used, don't remove it
1630   // Check the attribute is not used by other features
1631   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
1632   for (; aFIt != myFeatureMap.end(); ++aFIt)
1633     if (::isUsed(aFIt->second, theAttribute)) // the attribute is used, don't remove it
1634       return false;
1635
1636   // Remove attribute
1637   EntityWrapperPtr anEntity = aFound->second;
1638   myAttributeMap.erase(aFound);
1639   if (remove(anEntity))
1640     return true;
1641   // attribute is not removed, revert operation
1642   myAttributeMap[theAttribute] = anEntity;
1643   return false;
1644 }
1645
1646
1647 bool SolveSpaceSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
1648 {
1649   std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
1650       std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
1651
1652   // verify whether the constraint has duplicated
1653   SameConstraintMap::iterator anEqIt = myEqualConstraints.begin();
1654   for (; anEqIt != myEqualConstraints.end(); ++anEqIt)
1655     if (anEqIt->find(aConstraint) != anEqIt->end()) {
1656       anEqIt->erase(aConstraint);
1657       break;
1658     }
1659   if (anEqIt != myEqualConstraints.end())
1660     return true;
1661
1662   bool isFullyRemoved = removeConstraint((Slvs_hConstraint)aConstraint->id());
1663
1664   std::list<EntityWrapperPtr>::const_iterator anIt = aConstraint->entities().begin();
1665   for (; anIt != aConstraint->entities().end(); ++anIt) {
1666     std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity = 
1667         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
1668     FeaturePtr aBaseFeature = anEntity->baseFeature();
1669     if (aBaseFeature)
1670       isFullyRemoved = removeEntity(aBaseFeature) && isFullyRemoved;
1671     else
1672       isFullyRemoved = removeEntity(anEntity->baseAttribute()) && isFullyRemoved;
1673   }
1674
1675   return isFullyRemoved;
1676 }
1677
1678 bool SolveSpaceSolver_Storage::remove(EntityWrapperPtr theEntity)
1679 {
1680   std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity = 
1681         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theEntity);
1682   bool isFullyRemoved = removeEntity((Slvs_hEntity)anEntity->id());
1683
1684   std::list<EntityWrapperPtr>::const_iterator anEntIt = anEntity->subEntities().begin();
1685   for (; anEntIt != anEntity->subEntities().end(); ++anEntIt) {
1686     std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSubEntity = 
1687         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anEntIt);
1688     FeaturePtr aBaseFeature = aSubEntity->baseFeature();
1689     if (aBaseFeature)
1690       isFullyRemoved = removeEntity(aBaseFeature) && isFullyRemoved;
1691     else
1692       isFullyRemoved = removeEntity(aSubEntity->baseAttribute()) && isFullyRemoved;
1693   }
1694
1695   std::list<ParameterWrapperPtr>::const_iterator aParIt = anEntity->parameters().begin();
1696   for (; aParIt != anEntity->parameters().end(); ++aParIt)
1697     isFullyRemoved = remove(*aParIt) && isFullyRemoved;
1698   return isFullyRemoved;
1699 }
1700
1701 bool SolveSpaceSolver_Storage::remove(ParameterWrapperPtr theParameter)
1702 {
1703   return removeParameter((Slvs_hParam)theParameter->id());
1704 }
1705
1706
1707 void SolveSpaceSolver_Storage::refresh(bool theFixedOnly) const
1708 {
1709   blockEvents(true);
1710
1711   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
1712   std::list<ParameterWrapperPtr> aParams;
1713   std::list<ParameterWrapperPtr>::const_iterator aParIt;
1714   for (; anIt != myAttributeMap.end(); ++anIt) {
1715     // the external feature always should keep the up to date values, so, 
1716     // refresh from the solver is never needed
1717     if (anIt->first.get()) {
1718       std::shared_ptr<SketchPlugin_Feature> aSketchFeature = 
1719         std::dynamic_pointer_cast<SketchPlugin_Feature>(anIt->first->owner());
1720       if (aSketchFeature.get() && aSketchFeature->isExternal())
1721         continue;
1722     }
1723
1724     // update parameter wrappers and obtain values of attributes
1725     aParams = anIt->second->parameters();
1726     double aCoords[3];
1727     bool isUpd[3] = {false};
1728     int i = 0;
1729     for (aParIt = aParams.begin(); i < 3 && aParIt != aParams.end(); ++aParIt, ++i) {
1730       std::shared_ptr<SolveSpaceSolver_ParameterWrapper> aWrapper = 
1731           std::dynamic_pointer_cast<SolveSpaceSolver_ParameterWrapper>(*aParIt);
1732       if (!theFixedOnly || aWrapper->group() == GID_OUTOFGROUP || aWrapper->isParametric()) {
1733         aWrapper->changeParameter().val = getParameter((Slvs_hParam)aWrapper->id()).val;
1734         aCoords[i] = aWrapper->value();
1735         isUpd[i] = true;
1736       }
1737     }
1738     if (!isUpd[0] && !isUpd[1] && !isUpd[2])
1739       continue; // nothing is updated
1740
1741     std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
1742         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
1743     if (aPoint2D) {
1744       if ((isUpd[0] && fabs(aPoint2D->x() - aCoords[0]) > tolerance) ||
1745           (isUpd[1] && fabs(aPoint2D->y() - aCoords[1]) > tolerance)) {
1746         if (!isUpd[0]) aCoords[0] = aPoint2D->x();
1747         if (!isUpd[1]) aCoords[1] = aPoint2D->y();
1748         aPoint2D->setValue(aCoords[0], aCoords[1]);
1749         // Find points coincident with this one (probably not in GID_OUTOFGROUP)
1750         std::map<AttributePtr, EntityWrapperPtr>::const_iterator aLocIt =
1751             theFixedOnly ? myAttributeMap.begin() : anIt;
1752         for (++aLocIt; aLocIt != myAttributeMap.end(); ++aLocIt)
1753           if (anIt->second->id() == aLocIt->second->id()) {
1754             aPoint2D = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aLocIt->first);
1755             aPoint2D->setValue(aCoords[0], aCoords[1]);
1756           }
1757       }
1758       continue;
1759     }
1760     AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
1761     if (aScalar) {
1762       if (isUpd[0] && fabs(aScalar->value() - aCoords[0]) > tolerance)
1763         aScalar->setValue(aCoords[0]);
1764       continue;
1765     }
1766     std::shared_ptr<GeomDataAPI_Point> aPoint =
1767         std::dynamic_pointer_cast<GeomDataAPI_Point>(anIt->first);
1768     if (aPoint) {
1769       if ((isUpd[0] && fabs(aPoint->x() - aCoords[0]) > tolerance) ||
1770           (isUpd[1] && fabs(aPoint->y() - aCoords[1]) > tolerance) ||
1771           (isUpd[2] && fabs(aPoint->z() - aCoords[2]) > tolerance))
1772         if (!isUpd[0]) aCoords[0] = aPoint->x();
1773         if (!isUpd[1]) aCoords[1] = aPoint->y();
1774         if (!isUpd[2]) aCoords[2] = aPoint->z();
1775         aPoint->setValue(aCoords[0], aCoords[1], aCoords[2]);
1776       continue;
1777     }
1778   }
1779
1780   blockEvents(false);
1781 }
1782
1783 void SolveSpaceSolver_Storage::verifyFixed()
1784 {
1785   std::map<AttributePtr, EntityWrapperPtr>::iterator anAttrIt = myAttributeMap.begin();
1786   for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
1787     const std::list<ParameterWrapperPtr>& aParameters = anAttrIt->second->parameters();
1788     std::list<ParameterWrapperPtr>::const_iterator aParIt = aParameters.begin();
1789     for (; aParIt != aParameters.end(); ++aParIt)
1790       if ((*aParIt)->group() == GID_OUTOFGROUP) {
1791         Slvs_Param aParam = getParameter((Slvs_hParam)(*aParIt)->id());
1792         if (aParam.group != (Slvs_hParam)GID_OUTOFGROUP) {
1793           aParam.group = (Slvs_hParam)GID_OUTOFGROUP;
1794           updateParameter(aParam);
1795         }
1796       }
1797   }
1798 }
1799
1800
1801 void SolveSpaceSolver_Storage::adjustArc(const Slvs_Entity& theArc)
1802 {
1803   double anArcPoints[3][2];
1804   double aDist[3] = {0.0};
1805   bool isFixed[3] = {false};
1806   for (int i = 0; i < 3; ++i) {
1807     Slvs_Entity aPoint = getEntity(theArc.point[i]);
1808     isFixed[i] = (aPoint.group != (Slvs_hGroup)myGroupID);
1809     anArcPoints[i][0] = getParameter(aPoint.param[0]).val;
1810     anArcPoints[i][1] = getParameter(aPoint.param[1]).val;
1811     if (i > 0) {
1812       anArcPoints[i][0] -= anArcPoints[0][0];
1813       anArcPoints[i][1] -= anArcPoints[0][1];
1814       aDist[i] = sqrt(anArcPoints[i][0] * anArcPoints[i][0] + 
1815                       anArcPoints[i][1] * anArcPoints[i][1]);
1816     }
1817   }
1818
1819   if (fabs(aDist[1] - aDist[2]) < tolerance)
1820     return;
1821
1822   int anInd = 2;
1823   while (anInd > 0 && isFixed[anInd])
1824     --anInd;
1825   if (anInd < 1)
1826     return; // adjust only start or end point of the arc
1827
1828   anArcPoints[anInd][0] /= aDist[anInd];
1829   anArcPoints[anInd][1] /= aDist[anInd];
1830
1831   Slvs_Entity aPoint = getEntity(theArc.point[anInd]);
1832   for (int i = 0; i < 2; ++i) {
1833     Slvs_Param aParam = getParameter(aPoint.param[i]);
1834     aParam.val = anArcPoints[0][i] + aDist[3-anInd] * anArcPoints[anInd][i];
1835     updateParameter(aParam);
1836   }
1837 }
1838
1839
1840
1841
1842
1843
1844
1845 // ========================================================
1846 // =========      Auxiliary functions       ===============
1847 // ========================================================
1848
1849 template<typename T>
1850 int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
1851 {
1852   int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
1853   int aVecSize = theEntities.size();
1854   if (theEntities.empty())
1855     return 1;
1856   while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
1857     aResIndex--;
1858   while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
1859     aResIndex++;
1860   if (aResIndex == -1 || (aResIndex < aVecSize && theEntities[aResIndex].h != theEntityID))
1861     aResIndex = aVecSize;
1862   return aResIndex;
1863 }
1864
1865 bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2)
1866 {
1867   return fabs(theParam1.val - theParam2.val) > tolerance;
1868 }
1869
1870 bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2)
1871 {
1872   int i = 0;
1873   for (; theEntity1.param[i] != 0 && i < 4; i++)
1874     if (theEntity1.param[i] != theEntity2.param[i])
1875       return true;
1876   i = 0;
1877   for (; theEntity1.point[i] != 0 && i < 4; i++)
1878     if (theEntity1.point[i] != theEntity2.point[i])
1879       return true;
1880   return false;
1881 }
1882
1883 bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2)
1884 {
1885   return theConstraint1.ptA != theConstraint2.ptA ||
1886          theConstraint1.ptB != theConstraint2.ptB ||
1887          theConstraint1.entityA != theConstraint2.entityA ||
1888          theConstraint1.entityB != theConstraint2.entityB ||
1889          theConstraint1.entityC != theConstraint2.entityC ||
1890          theConstraint1.entityD != theConstraint2.entityD ||
1891          fabs(theConstraint1.valA - theConstraint2.valA) > tolerance;
1892 }