Salome HOME
250ce7e564e1fb49ae4c8f463727631a0da19c27
[modules/shaper.git] / src / SketchSolver / SketchSolver_Storage.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    SketchSolver_Storage.cpp
4 // Created: 18 Mar 2015
5 // Author:  Artem ZHIDKOV
6
7 #include <SketchSolver_Storage.h>
8
9 #include <math.h>
10
11 /** \brief Search the entity/parameter with specified ID in the list of elements
12  *  \param[in] theEntityID unique ID of the element
13  *  \param[in] theEntities list of elements
14  *  \return position of the found element or -1 if the element is not found
15  */
16 template<typename T>
17 static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
18
19 /// \brief Compare two parameters to be different
20 static bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2);
21 /// \brief Compare two entities to be different
22 static bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2);
23 /// \brief Compare two constriants to be different
24 static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2);
25
26
27 SketchSolver_Storage::SketchSolver_Storage()
28   : myParamMaxID(SLVS_E_UNKNOWN),
29     myEntityMaxID(SLVS_E_UNKNOWN),
30     myConstrMaxID(SLVS_C_UNKNOWN),
31     myFixed(SLVS_E_UNKNOWN),
32     myNeedToResolve(false),
33     myDuplicatedConstraint(false)
34 {
35 }
36
37 Slvs_hParam SketchSolver_Storage::addParameter(const Slvs_Param& theParam)
38 {
39   if (theParam.h > 0 && theParam.h <= myParamMaxID) {
40     // parameter is already used, rewrite it
41     return updateParameter(theParam);
42   }
43
44   Slvs_Param aParam = theParam;
45   if (aParam.h > myParamMaxID)
46     myParamMaxID = aParam.h;
47   else
48     aParam.h = ++myParamMaxID;
49   myParameters.push_back(aParam);
50   myNeedToResolve = true;
51   return aParam.h;
52 }
53
54 Slvs_hParam SketchSolver_Storage::updateParameter(const Slvs_Param& theParam)
55 {
56   if (theParam.h > 0 && theParam.h <= myParamMaxID) {
57     // parameter already used, rewrite it
58     int aPos = Search(theParam.h, myParameters);
59     if (aPos >= 0 && aPos < (int)myParameters.size()) {
60       myNeedToResolve = myNeedToResolve || IsNotEqual(myParameters[aPos], theParam);
61       myParameters[aPos] = theParam;
62       return theParam.h;
63     }
64   }
65
66   // Parameter is not found, add new one
67   Slvs_Param aParam = theParam;
68   aParam.h = 0;
69   return addParameter(aParam);
70 }
71
72 bool SketchSolver_Storage::removeParameter(const Slvs_hParam& theParamID)
73 {
74   int aPos = Search(theParamID, myParameters);
75   if (aPos >= 0 && aPos < (int)myParameters.size()) {
76     // Firstly, search the parametes is not used elsewhere
77     std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
78     for (; anEntIter != myEntities.end(); anEntIter++) {
79       for (int i = 0; i < 4; i++)
80         if (anEntIter->param[i] == theParamID)
81           return false;
82     }
83     // Remove parameter
84     myParameters.erase(myParameters.begin() + aPos);
85     myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h;
86     myNeedToResolve = true;
87     myRemovedParameters.insert(theParamID);
88     return true;
89   }
90   return false;
91 }
92
93 const Slvs_Param& SketchSolver_Storage::getParameter(const Slvs_hParam& theParamID) const
94 {
95   int aPos = Search(theParamID, myParameters);
96   if (aPos >= 0 && aPos < (int)myParameters.size())
97     return myParameters[aPos];
98
99   // Parameter is not found, return empty object
100   static Slvs_Param aDummy;
101   aDummy.h = 0;
102   return aDummy;
103 }
104
105
106 Slvs_hEntity SketchSolver_Storage::addEntity(const Slvs_Entity& theEntity)
107 {
108   if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
109     // Entity is already used, rewrite it
110     return updateEntity(theEntity);
111   }
112
113   Slvs_Entity aEntity = theEntity;
114   if (aEntity.h > myEntityMaxID)
115     myEntityMaxID = aEntity.h;
116   else
117     aEntity.h = ++myEntityMaxID;
118   myEntities.push_back(aEntity);
119   myNeedToResolve = true;
120   return aEntity.h;
121 }
122
123 Slvs_hEntity SketchSolver_Storage::updateEntity(const Slvs_Entity& theEntity)
124 {
125   if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
126     // Entity already used, rewrite it
127     int aPos = Search(theEntity.h, myEntities);
128     if (aPos >= 0 && aPos < (int)myEntities.size()) {
129       myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity);
130       myEntities[aPos] = theEntity;
131       return theEntity.h;
132     }
133   }
134
135   // Entity is not found, add new one
136   Slvs_Entity aEntity = theEntity;
137   aEntity.h = 0;
138   return addEntity(aEntity);
139 }
140
141 bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
142 {
143   bool aResult = true;
144   int aPos = Search(theEntityID, myEntities);
145   if (aPos >= 0 && aPos < (int)myEntities.size()) {
146     // Firstly, check the entity and its attributes is not used elsewhere
147     std::set<Slvs_hEntity> anEntAndSubs;
148     anEntAndSubs.insert(theEntityID);
149     for (int i = 0; i < 4; i++)
150       if (myEntities[aPos].point[i] != SLVS_E_UNKNOWN)
151         anEntAndSubs.insert(myEntities[aPos].point[i]);
152
153     std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
154     for (; anEntIter != myEntities.end(); anEntIter++) {
155       for (int i = 0; i < 4; i++)
156         if (anEntAndSubs.find(anEntIter->point[i]) != anEntAndSubs.end())
157           return false;
158       if (anEntAndSubs.find(anEntIter->distance) != anEntAndSubs.end())
159         return false;
160     }
161     std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
162     for (; aConstrIter != myConstraints.end(); aConstrIter++) {
163       Slvs_hEntity anEntIDs[6] = {aConstrIter->ptA, aConstrIter->ptB,
164           aConstrIter->entityA, aConstrIter->entityB,
165           aConstrIter->entityC, aConstrIter->entityD};
166       for (int i = 0; i < 6; i++)
167         if (anEntAndSubs.find(anEntIDs[i]) != anEntAndSubs.end())
168           return false;
169     }
170     // The entity is not used, remove it and its parameters
171     Slvs_Entity anEntity = myEntities[aPos];
172     myEntities.erase(myEntities.begin() + aPos);
173     myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
174     if (anEntity.distance != SLVS_E_UNKNOWN)
175       aResult = aResult && removeParameter(anEntity.distance);
176     for (int i = 0; i < 4; i++)
177       if (anEntity.param[i] != SLVS_E_UNKNOWN)
178         aResult = removeParameter(anEntity.param[i]) && aResult;
179     for (int i = 0; i < 4; i++)
180       if (anEntity.point[i] != SLVS_E_UNKNOWN)
181         aResult = removeEntity(anEntity.point[i]) && aResult;
182     myNeedToResolve = true;
183     myRemovedEntities.insert(theEntityID);
184     if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D)
185       removeCoincidentPoint(theEntityID);
186   }
187   return aResult;
188 }
189
190 const Slvs_Entity& SketchSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const
191 {
192   int aPos = Search(theEntityID, myEntities);
193   if (aPos >= 0 && aPos < (int)myEntities.size())
194     return myEntities[aPos];
195
196   // Entity is not found, return empty object
197   static Slvs_Entity aDummy;
198   aDummy.h = SLVS_E_UNKNOWN;
199   return aDummy;
200 }
201
202 Slvs_hEntity SketchSolver_Storage::copyEntity(const Slvs_hEntity& theCopied)
203 {
204   int aPos = Search(theCopied, myEntities);
205   if (aPos < 0 || aPos >= (int)myEntities.size())
206     return SLVS_E_UNKNOWN;
207
208   Slvs_Entity aCopy = myEntities[aPos];
209   aCopy.h = SLVS_E_UNKNOWN;
210   int i = 0;
211   while (aCopy.point[i] != SLVS_E_UNKNOWN) {
212     aCopy.point[i] = copyEntity(aCopy.point[i]);
213     i++;
214   }
215   if (aCopy.param[0] != SLVS_E_UNKNOWN) {
216     aPos = Search(aCopy.param[0], myParameters);
217     i = 0;
218     while (aCopy.param[i] != SLVS_E_UNKNOWN) {
219       Slvs_Param aNewParam = myParameters[aPos];
220       aNewParam.h = SLVS_E_UNKNOWN;
221       aCopy.param[i] = addParameter(aNewParam);
222       i++;
223       aPos++;
224     }
225   }
226   return addEntity(aCopy);
227 }
228
229 void SketchSolver_Storage::copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo)
230 {
231   int aPosFrom = Search(theFrom, myEntities);
232   int aPosTo = Search(theTo, myEntities);
233   if (aPosFrom < 0 || aPosFrom >= (int)myEntities.size() || 
234       aPosTo < 0 || aPosTo >= (int)myEntities.size())
235     return;
236
237   Slvs_Entity aEntFrom = myEntities[aPosFrom];
238   Slvs_Entity aEntTo = myEntities[aPosTo];
239   int i = 0;
240   while (aEntFrom.point[i] != SLVS_E_UNKNOWN) {
241     copyEntity(aEntFrom.point[i], aEntTo.point[i]);
242     i++;
243   }
244   if (aEntFrom.param[0] != SLVS_E_UNKNOWN) {
245     aPosFrom = Search(aEntFrom.param[0], myParameters);
246     aPosTo = Search(aEntTo.param[0], myParameters);
247     i = 0;
248     while (aEntFrom.param[i] != SLVS_E_UNKNOWN) {
249       myParameters[aPosTo++].val = myParameters[aPosFrom++].val;
250       i++;
251     }
252   }
253 }
254
255
256 bool SketchSolver_Storage::isPointFixed(
257     const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate) const
258 {
259   // Search the set of coincident points
260   std::set<Slvs_hEntity> aCoincident;
261   aCoincident.insert(thePointID);
262   std::vector< std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
263   for (; aCPIter != myCoincidentPoints.end(); aCPIter++)
264     if (aCPIter->find(thePointID) != aCPIter->end()) {
265       aCoincident = *aCPIter;
266       break;
267     }
268
269   // Search the Rigid constraint
270   std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
271   for (; aConstrIter != myConstraints.end(); aConstrIter++)
272     if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
273         aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
274       theFixed = aConstrIter->h;
275       return true;
276     }
277
278   if (theAccurate) {
279     // Try to find the fixed entity which uses such point or its coincidence
280     std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
281     for (; anEntIter != myEntities.end(); anEntIter++) {
282       for (int i = 0; i < 4; i++) {
283         Slvs_hEntity aPt = anEntIter->point[i];
284         if (aPt != SLVS_E_UNKNOWN &&
285             (aPt == thePointID || aCoincident.find(aPt) != aCoincident.end())) {
286           if (isEntityFixed(anEntIter->h, true))
287             return true;
288         }
289       }
290     }
291   }
292   return SLVS_E_UNKNOWN;
293 }
294
295 bool SketchSolver_Storage::isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate) const
296 {
297   int aPos = Search(theEntityID, myEntities);
298   if (aPos < 0 || aPos >= (int)myEntities.size())
299     return false;
300
301   // Firstly, find how many points are under Rigid constraint
302   int aNbFixed = 0;
303   for (int i = 0; i < 4; i++) {
304     Slvs_hEntity aPoint = myEntities[aPos].point[i];
305     if (aPoint == SLVS_E_UNKNOWN)
306       continue;
307
308     std::set<Slvs_hEntity> aCoincident;
309     aCoincident.insert(aPoint);
310     std::vector< std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
311     for (; aCPIter != myCoincidentPoints.end(); aCPIter++)
312       if (aCPIter->find(aPoint) != aCPIter->end()) {
313         aCoincident = *aCPIter;
314         break;
315       }
316
317     // Search the Rigid constraint
318     std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
319     for (; aConstrIter != myConstraints.end(); aConstrIter++)
320       if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
321           aCoincident.find(aConstrIter->ptA) != aCoincident.end())
322         aNbFixed++;
323   }
324
325   std::list<Slvs_Constraint> aList;
326   std::list<Slvs_Constraint>::iterator anIt;
327   Slvs_hConstraint aTempID; // used in isPointFixed() method
328
329   if (myEntities[aPos].type == SLVS_E_LINE_SEGMENT) {
330     if (aNbFixed == 2)
331       return true;
332     else if (aNbFixed == 0 || !theAccurate)
333       return false;
334     // Additional check (the line may be fixed if it is used by different constraints):
335     // 1. The line is used in Equal constraint, another entity is fixed and there is a fixed point on line
336     aList = getConstraintsByType(SLVS_C_PT_ON_LINE);
337     for (anIt = aList.begin(); anIt != aList.end(); anIt++)
338       if (anIt->entityA == theEntityID && isPointFixed(anIt->ptA, aTempID))
339         break;
340     if (anIt != aList.end()) {
341       aList = getConstraintsByType(SLVS_C_EQUAL_LENGTH_LINES);
342       aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
343       for (anIt = aList.begin(); anIt != aList.end(); anIt++)
344         if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
345           Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
346           if (isEntityFixed(anOther, false))
347             return true;
348         }
349     }
350     // 2. The line is used in Parallel/Perpendicular/Vertical/Horizontal and Length constraints
351     aList = getConstraintsByType(SLVS_C_PARALLEL);
352     aList.splice(aList.end(), getConstraintsByType(SLVS_C_PERPENDICULAR));
353     aList.splice(aList.end(), getConstraintsByType(SLVS_C_VERTICAL));
354     aList.splice(aList.end(), getConstraintsByType(SLVS_C_HORIZONTAL));
355     for (anIt = aList.begin(); anIt != aList.end(); anIt++)
356       if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
357         Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
358         if (isEntityFixed(anOther, false))
359           break;
360       }
361     if (anIt != aList.end()) {
362       aList = getConstraintsByType(SLVS_C_PT_PT_DISTANCE);
363       for (anIt = aList.begin(); anIt != aList.end(); anIt++)
364         if ((anIt->ptA == myEntities[aPos].point[0] && anIt->ptB == myEntities[aPos].point[1]) ||
365             (anIt->ptA == myEntities[aPos].point[1] && anIt->ptB == myEntities[aPos].point[0]))
366           return true;
367     }
368     // 3. Another verifiers ...
369   } else if (myEntities[aPos].type == SLVS_E_CIRCLE) {
370     if (aNbFixed == 0)
371       return false;
372     // Search for Diameter constraint
373     aList = getConstraintsByType(SLVS_C_DIAMETER);
374     for (anIt = aList.begin(); anIt != aList.end(); anIt++)
375       if (anIt->entityA == theEntityID)
376         return true;
377     if (!theAccurate)
378       return false;
379     // Additional check (the circle may be fixed if it is used by different constraints):
380     // 1. The circle is used in Equal constraint and another entity is fixed
381     aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
382     for (anIt = aList.begin(); anIt != aList.end(); anIt++)
383       if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
384         Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
385         if (isEntityFixed(anOther, false))
386           return true;
387       }
388     // 2. Another verifiers ...
389   } else if (myEntities[aPos].type == SLVS_E_ARC_OF_CIRCLE) {
390     if (aNbFixed > 2)
391       return true;
392     else if (aNbFixed <= 1)
393       return false;
394     // Search for Diameter constraint
395     aList = getConstraintsByType(SLVS_C_DIAMETER);
396     for (anIt = aList.begin(); anIt != aList.end(); anIt++)
397       if (anIt->entityA == theEntityID)
398         return true;
399     if (!theAccurate)
400       return false;
401     // Additional check (the arc may be fixed if it is used by different constraints):
402     // 1. The arc is used in Equal constraint and another entity is fixed
403     aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
404     aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
405     for (anIt = aList.begin(); anIt != aList.end(); anIt++)
406       if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
407         Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
408         if (isEntityFixed(anOther, false))
409           return true;
410       }
411     // 2. Another verifiers ...
412   }
413   return false;
414 }
415
416
417 Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
418 {
419   if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
420     // Constraint is already used, rewrite it
421     return updateConstraint(theConstraint);
422   }
423
424   Slvs_Constraint aConstraint = theConstraint;
425
426   // Find a constraint with same type uses same arguments to show user overconstraint situation
427   std::vector<Slvs_Constraint>::iterator aCIt = myConstraints.begin();
428   for (; aCIt != myConstraints.end(); aCIt++) {
429     if (aConstraint.type != aCIt->type)
430       continue;
431     if (aConstraint.ptA == aCIt->ptA && aConstraint.ptB == aCIt->ptB &&
432         aConstraint.entityA == aCIt->entityA && aConstraint.entityB == aCIt->entityB &&
433         aConstraint.entityC == aCIt->entityC && aConstraint.entityD == aCIt->entityD)
434       myDuplicatedConstraint = true;
435   }
436
437   if (aConstraint.h > myConstrMaxID)
438     myConstrMaxID = aConstraint.h;
439   else
440     aConstraint.h = ++myConstrMaxID;
441   myConstraints.push_back(aConstraint);
442   myNeedToResolve = true;
443   if (aConstraint.type == SLVS_C_POINTS_COINCIDENT)
444     addCoincidentPoints(aConstraint.ptA, aConstraint.ptB);
445   return aConstraint.h;
446 }
447
448 Slvs_hConstraint SketchSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint)
449 {
450   if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
451     // Constraint already used, rewrite it
452     int aPos = Search(theConstraint.h, myConstraints);
453     if (aPos >= 0 && aPos < (int)myConstraints.size()) {
454       myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint);
455       myConstraints[aPos] = theConstraint;
456       if (theConstraint.type == SLVS_C_POINTS_COINCIDENT)
457         addCoincidentPoints(theConstraint.ptA, theConstraint.ptB);
458       return theConstraint.h;
459     }
460   }
461
462   // Constraint is not found, add new one
463   Slvs_Constraint aConstraint = theConstraint;
464   aConstraint.h = 0;
465   return addConstraint(aConstraint);
466 }
467
468 bool SketchSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID)
469 {
470   bool aResult = true;
471   int aPos = Search(theConstraintID, myConstraints);
472   if (aPos >= 0 && aPos < (int)myConstraints.size()) {
473     Slvs_Constraint aConstraint = myConstraints[aPos];
474     myConstraints.erase(myConstraints.begin() + aPos);
475     myConstrMaxID = myConstraints.empty() ? SLVS_E_UNKNOWN : myConstraints.back().h;
476     myNeedToResolve = true;
477     myRemovedConstraints.insert(theConstraintID);
478     // Remove all entities
479     Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB,
480         aConstraint.entityA, aConstraint.entityB,
481         aConstraint.entityC, aConstraint.entityD};
482     for (int i = 0; i < 6; i++)
483       if (anEntities[i] != SLVS_E_UNKNOWN)
484         aResult = removeEntity(anEntities[i]) && aResult;
485     // remove temporary fixed point, if available
486     if (myFixed == theConstraintID)
487       myFixed = SLVS_E_UNKNOWN;
488     if (myDuplicatedConstraint) {
489       // Check the duplicated constraints are still available
490       myDuplicatedConstraint = false;
491       std::vector<Slvs_Constraint>::const_iterator anIt1 = myConstraints.begin();
492       std::vector<Slvs_Constraint>::const_iterator anIt2 = myConstraints.begin();
493       for (; anIt1 != myConstraints.end() && !myDuplicatedConstraint; anIt1++)
494         for (anIt2 = anIt1+1; anIt2 != myConstraints.end() && !myDuplicatedConstraint; anIt2++) {
495           if (anIt1->type != anIt2->type)
496             continue;
497           if (anIt1->ptA == anIt2->ptA && anIt1->ptB == anIt2->ptB &&
498               anIt1->entityA == anIt2->entityA && anIt1->entityB == anIt2->entityB &&
499               anIt1->entityC == anIt2->entityC && anIt1->entityD == anIt2->entityD)
500             myDuplicatedConstraint = true;
501         }
502     }
503   }
504   return aResult;
505 }
506
507 const Slvs_Constraint& SketchSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const
508 {
509   int aPos = Search(theConstraintID, myConstraints);
510   if (aPos >= 0 && aPos < (int)myConstraints.size())
511     return myConstraints[aPos];
512
513   // Constraint is not found, return empty object
514   static Slvs_Constraint aDummy;
515   aDummy.h = 0;
516   return aDummy;
517 }
518
519 std::list<Slvs_Constraint> SketchSolver_Storage::getConstraintsByType(int theConstraintType) const
520 {
521   std::list<Slvs_Constraint> aResult;
522   std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
523   for (; aCIter != myConstraints.end(); aCIter++)
524     if (aCIter->type == theConstraintType)
525       aResult.push_back(*aCIter);
526   return aResult;
527 }
528
529
530 void SketchSolver_Storage::addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID)
531 {
532   if (myFixed != SLVS_E_UNKNOWN)
533     return; // the point is already fixed
534   int aPos = Search(theConstraintID, myConstraints);
535   if (aPos >= 0 && aPos < (int)myConstraints.size())
536     myFixed = theConstraintID;
537 }
538
539 void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
540 {
541   myTemporaryConstraints.insert(theConstraintID);
542 }
543
544 void SketchSolver_Storage::removeTemporaryConstraints()
545 {
546   myTemporaryConstraints.clear();
547 }
548
549 int SketchSolver_Storage::removeFirstTemporaryConstraint()
550 {
551   if (myTemporaryConstraints.empty())
552     return 0;
553   removeConstraint(*myTemporaryConstraints.begin());
554   myTemporaryConstraints.erase(myTemporaryConstraints.begin());
555   return (int)myTemporaryConstraints.size();
556 }
557
558 bool SketchSolver_Storage::isTemporary(const Slvs_hConstraint& theConstraintID) const
559 {
560   return myTemporaryConstraints.find(theConstraintID) != myTemporaryConstraints.end();
561 }
562
563
564 void SketchSolver_Storage::getRemoved(
565     std::set<Slvs_hParam>& theParameters,
566     std::set<Slvs_hEntity>& theEntities,
567     std::set<Slvs_hConstraint>& theConstraints)
568 {
569   theParameters = myRemovedParameters;
570   theEntities = myRemovedEntities;
571   theConstraints = myRemovedConstraints;
572
573   myRemovedParameters.clear();
574   myRemovedEntities.clear();
575   myRemovedConstraints.clear();
576 }
577
578 void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver)
579 {
580   theSolver.setParameters(myParameters.data(), (int)myParameters.size());
581   theSolver.setEntities(myEntities.data(), (int)myEntities.size());
582
583   // Copy constraints excluding the fixed one
584   std::vector<Slvs_Constraint> aConstraints = myConstraints;
585   if (myFixed != SLVS_E_UNKNOWN) {
586     Slvs_hEntity aFixedPoint = SLVS_E_UNKNOWN;
587     std::vector<Slvs_Constraint>::iterator anIt = aConstraints.begin();
588     for (; anIt != aConstraints.end(); anIt++)
589       if (anIt->h == myFixed) {
590         aFixedPoint = anIt->ptA;
591         aConstraints.erase(anIt);
592         break;
593       }
594     // set dragged parameters
595     int aPos = Search(aFixedPoint, myEntities);
596     theSolver.setDraggedParameters(myEntities[aPos].param);
597   }
598   theSolver.setConstraints(aConstraints.data(), (int)aConstraints.size());
599 }
600
601 void SketchSolver_Storage::addCoincidentPoints(
602     const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2)
603 {
604   std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
605   std::vector< std::set<Slvs_hEntity> >::iterator aFoundIter = myCoincidentPoints.end(); // already found coincidence
606   bool isFound = false;
607   for (; aCIter != myCoincidentPoints.end(); aCIter++) {
608     bool isFirstFound = aCIter->find(thePoint1) != aCIter->end();
609     bool isSecondFound = aCIter->find(thePoint2) != aCIter->end();
610     isFound = isFound || isFirstFound || isSecondFound;
611     if (isFirstFound && isSecondFound)
612       break; // already coincident
613     else if (isFirstFound || isSecondFound) {
614       if (aFoundIter != myCoincidentPoints.end()) {
615         // merge two sets
616         aFoundIter->insert(aCIter->begin(), aCIter->end());
617         myCoincidentPoints.erase(aCIter);
618         break;
619       }
620       aCIter->insert(thePoint1);
621       aCIter->insert(thePoint2);
622     }
623   }
624   // coincident points not found
625   if (!isFound) {
626     std::set<Slvs_hEntity> aNewSet;
627     aNewSet.insert(thePoint1);
628     aNewSet.insert(thePoint2);
629     myCoincidentPoints.push_back(aNewSet);
630   }
631 }
632
633 void SketchSolver_Storage::removeCoincidentPoint(const Slvs_hEntity& thePoint)
634 {
635   std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
636   for (; aCIter != myCoincidentPoints.end(); aCIter++)
637     if (aCIter->find(thePoint) != aCIter->end()) {
638       aCIter->erase(thePoint);
639       if (aCIter->size() <= 1)
640         myCoincidentPoints.erase(aCIter);
641       break;
642     }
643 }
644
645 bool SketchSolver_Storage::isCoincident(
646     const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const
647 {
648   std::vector< std::set<Slvs_hEntity> >::const_iterator aCIter = myCoincidentPoints.begin();
649   for (; aCIter != myCoincidentPoints.end(); aCIter++)
650     if (aCIter->find(thePoint1) != aCIter->end() && aCIter->find(thePoint2) != aCIter->end())
651       return true;
652   return false;
653 }
654
655
656
657
658 // ========================================================
659 // =========      Auxiliary functions       ===============
660 // ========================================================
661
662 template<typename T>
663 int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
664 {
665   int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
666   int aVecSize = theEntities.size();
667   if (theEntities.empty())
668     return 1;
669   while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
670     aResIndex--;
671   while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
672     aResIndex++;
673   if (aResIndex == -1 || (aResIndex < aVecSize && theEntities[aResIndex].h != theEntityID))
674     aResIndex = aVecSize;
675   return aResIndex;
676 }
677
678 bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2)
679 {
680   return fabs(theParam1.val - theParam2.val) > tolerance;
681 }
682
683 bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2)
684 {
685   int i = 0;
686   for (; theEntity1.param[i] != 0 && i < 4; i++)
687     if (theEntity1.param[i] != theEntity2.param[i])
688       return true;
689   i = 0;
690   for (; theEntity1.point[i] != 0 && i < 4; i++)
691     if (theEntity1.point[i] != theEntity2.point[i])
692       return true;
693   return false;
694 }
695
696 bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2)
697 {
698   return theConstraint1.ptA != theConstraint2.ptA ||
699          theConstraint1.ptB != theConstraint2.ptB ||
700          theConstraint1.entityA != theConstraint2.entityA ||
701          theConstraint1.entityB != theConstraint2.entityB ||
702          theConstraint1.entityC != theConstraint2.entityC ||
703          theConstraint1.entityD != theConstraint2.entityD ||
704          fabs(theConstraint1.valA - theConstraint2.valA) > tolerance;
705 }