Salome HOME
eabf3a5fa05a4f44c493ef661f80db746f313e61
[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 /** \brief Search the entity/parameter with specified ID in the list of elements
10  *  \param[in] theEntityID unique ID of the element
11  *  \param[in] theEntities list of elements
12  *  \return position of the found element or -1 if the element is not found
13  */
14 template<typename T>
15 static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
16
17 /// \brief Compare two parameters to be different
18 static bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2);
19 /// \brief Compare two entities to be different
20 static bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2);
21 /// \brief Compare two constriants to be different
22 static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2);
23
24
25 SketchSolver_Storage::SketchSolver_Storage()
26   : myParamMaxID(SLVS_E_UNKNOWN),
27     myEntityMaxID(SLVS_E_UNKNOWN),
28     myConstrMaxID(SLVS_C_UNKNOWN),
29     myFixed(SLVS_E_UNKNOWN),
30     myNeedToResolve(false)
31 {
32 }
33
34 Slvs_hParam SketchSolver_Storage::addParameter(const Slvs_Param& theParam)
35 {
36   if (theParam.h > 0 && theParam.h <= myParamMaxID) {
37     // parameter is already used, rewrite it
38     return updateParameter(theParam);
39   }
40
41   Slvs_Param aParam = theParam;
42   if (aParam.h > myParamMaxID)
43     myParamMaxID = aParam.h;
44   else
45     aParam.h = ++myParamMaxID;
46   myParameters.push_back(aParam);
47   myNeedToResolve = true;
48   return aParam.h;
49 }
50
51 Slvs_hParam SketchSolver_Storage::updateParameter(const Slvs_Param& theParam)
52 {
53   if (theParam.h > 0 && theParam.h <= myParamMaxID) {
54     // parameter already used, rewrite it
55     int aPos = Search(theParam.h, myParameters);
56     if (aPos >= 0 && aPos < (int)myParameters.size()) {
57       myNeedToResolve = myNeedToResolve || IsNotEqual(myParameters[aPos], theParam);
58       myParameters[aPos] = theParam;
59       return theParam.h;
60     }
61   }
62
63   // Parameter is not found, add new one
64   Slvs_Param aParam = theParam;
65   aParam.h = 0;
66   return addParameter(aParam);
67 }
68
69 bool SketchSolver_Storage::removeParameter(const Slvs_hParam& theParamID)
70 {
71   int aPos = Search(theParamID, myParameters);
72   if (aPos >= 0 && aPos < (int)myParameters.size()) {
73     // Firstly, search the parametes is not used elsewhere
74     std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
75     for (; anEntIter != myEntities.end(); anEntIter++) {
76       for (int i = 0; i < 4; i++)
77         if (anEntIter->param[i] == theParamID)
78           return false;
79     }
80     // Remove parameter
81     myParameters.erase(myParameters.begin() + aPos);
82     myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h;
83     myNeedToResolve = true;
84     myRemovedParameters.insert(theParamID);
85     return true;
86   }
87   return false;
88 }
89
90 const Slvs_Param& SketchSolver_Storage::getParameter(const Slvs_hParam& theParamID) const
91 {
92   int aPos = Search(theParamID, myParameters);
93   if (aPos >= 0 && aPos < (int)myParameters.size())
94     return myParameters[aPos];
95
96   // Parameter is not found, return empty object
97   static Slvs_Param aDummy;
98   aDummy.h = 0;
99   return aDummy;
100 }
101
102
103 Slvs_hEntity SketchSolver_Storage::addEntity(const Slvs_Entity& theEntity)
104 {
105   if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
106     // Entity is already used, rewrite it
107     return updateEntity(theEntity);
108   }
109
110   Slvs_Entity aEntity = theEntity;
111   if (aEntity.h > myEntityMaxID)
112     myEntityMaxID = aEntity.h;
113   else
114     aEntity.h = ++myEntityMaxID;
115   myEntities.push_back(aEntity);
116   myNeedToResolve = true;
117   return aEntity.h;
118 }
119
120 Slvs_hEntity SketchSolver_Storage::updateEntity(const Slvs_Entity& theEntity)
121 {
122   if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
123     // Entity already used, rewrite it
124     int aPos = Search(theEntity.h, myEntities);
125     if (aPos >= 0 && aPos < (int)myEntities.size()) {
126       myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity);
127       myEntities[aPos] = theEntity;
128       return theEntity.h;
129     }
130   }
131
132   // Entity is not found, add new one
133   Slvs_Entity aEntity = theEntity;
134   aEntity.h = 0;
135   return addEntity(aEntity);
136 }
137
138 bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
139 {
140   bool aResult = true;
141   int aPos = Search(theEntityID, myEntities);
142   if (aPos >= 0 && aPos < (int)myEntities.size()) {
143     // Firstly, check the entity is not used elsewhere
144     std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
145     for (; anEntIter != myEntities.end(); anEntIter++) {
146       for (int i = 0; i < 4; i++)
147         if (anEntIter->point[i] == theEntityID)
148           return false;
149       if (anEntIter->distance == theEntityID)
150         return false;
151     }
152     std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
153     for (; aConstrIter != myConstraints.end(); aConstrIter++) {
154       Slvs_hEntity anEntIDs[6] = {aConstrIter->ptA, aConstrIter->ptB,
155           aConstrIter->entityA, aConstrIter->entityB,
156           aConstrIter->entityC, aConstrIter->entityD};
157       for (int i = 0; i < 6; i++)
158         if (anEntIDs[i] == theEntityID)
159           return false;
160     }
161     // The entity is not used, remove it and its parameters
162     Slvs_Entity anEntity = myEntities[aPos];
163     myEntities.erase(myEntities.begin() + aPos);
164     myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
165     if (anEntity.distance != SLVS_E_UNKNOWN)
166       aResult = aResult && removeParameter(anEntity.distance);
167     for (int i = 0; i < 4; i++)
168       if (anEntity.param[i] != SLVS_E_UNKNOWN)
169         aResult = removeParameter(anEntity.param[i]) && aResult;
170     for (int i = 0; i < 4; i++)
171       if (anEntity.point[i] != SLVS_E_UNKNOWN)
172         aResult = removeEntity(anEntity.point[i]) && aResult;
173     myNeedToResolve = true;
174     myRemovedEntities.insert(theEntityID);
175     if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D)
176       removeCoincidentPoint(theEntityID);
177   }
178   return aResult;
179 }
180
181 const Slvs_Entity& SketchSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const
182 {
183   int aPos = Search(theEntityID, myEntities);
184   if (aPos >= 0 && aPos < (int)myEntities.size())
185     return myEntities[aPos];
186
187   // Entity is not found, return empty object
188   static Slvs_Entity aDummy;
189   aDummy.h = 0;
190   return aDummy;
191 }
192
193 Slvs_hConstraint SketchSolver_Storage::isPointFixed(const Slvs_hEntity& thePointID) const
194 {
195   // Search the set of coincident points
196   std::vector< std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
197   for (; aCPIter != myCoincidentPoints.end(); aCPIter++)
198     if (aCPIter->find(thePointID) != aCPIter->end())
199       break;
200   if (aCPIter == myCoincidentPoints.end()) {
201     std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
202     for (; aConstrIter != myConstraints.end(); aConstrIter++)
203       if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
204           aConstrIter->ptA == thePointID)
205         return aConstrIter->h;
206     return SLVS_E_UNKNOWN;
207   }
208
209   // Search the Rigid constraint
210   std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
211   for (; aConstrIter != myConstraints.end(); aConstrIter++)
212     if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
213         aCPIter->find(aConstrIter->ptA) != aCPIter->end())
214       return aConstrIter->h;
215   return SLVS_E_UNKNOWN;
216 }
217
218
219 Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
220 {
221   if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
222     // Constraint is already used, rewrite it
223     return updateConstraint(theConstraint);
224   }
225
226   Slvs_Constraint aConstraint = theConstraint;
227   if (aConstraint.h > myConstrMaxID)
228     myConstrMaxID = aConstraint.h;
229   else
230     aConstraint.h = ++myConstrMaxID;
231   myConstraints.push_back(aConstraint);
232   myNeedToResolve = true;
233   if (aConstraint.type == SLVS_C_POINTS_COINCIDENT)
234     addCoincidentPoints(aConstraint.ptA, aConstraint.ptB);
235   return aConstraint.h;
236 }
237
238 Slvs_hConstraint SketchSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint)
239 {
240   if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
241     // Constraint already used, rewrite it
242     int aPos = Search(theConstraint.h, myConstraints);
243     if (aPos >= 0 && aPos < (int)myConstraints.size()) {
244       myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint);
245       myConstraints[aPos] = theConstraint;
246       if (theConstraint.type == SLVS_C_POINTS_COINCIDENT)
247         addCoincidentPoints(theConstraint.ptA, theConstraint.ptB);
248       return theConstraint.h;
249     }
250   }
251
252   // Constraint is not found, add new one
253   Slvs_Constraint aConstraint = theConstraint;
254   aConstraint.h = 0;
255   return addConstraint(aConstraint);
256 }
257
258 bool SketchSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID)
259 {
260   bool aResult = true;
261   int aPos = Search(theConstraintID, myConstraints);
262   if (aPos >= 0 && aPos < (int)myConstraints.size()) {
263     Slvs_Constraint aConstraint = myConstraints[aPos];
264     myConstraints.erase(myConstraints.begin() + aPos);
265     myConstrMaxID = myConstraints.empty() ? SLVS_E_UNKNOWN : myConstraints.back().h;
266     myNeedToResolve = true;
267     myRemovedConstraints.insert(theConstraintID);
268     // Remove all entities
269     Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB,
270         aConstraint.entityA, aConstraint.entityB,
271         aConstraint.entityC, aConstraint.entityD};
272     for (int i = 0; i < 6; i++)
273       if (anEntities[i] != SLVS_E_UNKNOWN)
274         aResult = removeEntity(anEntities[i]) && aResult;
275     // remove temporary fixed point, if available
276     if (myFixed == theConstraintID)
277       myFixed = SLVS_E_UNKNOWN;
278   }
279   return aResult;
280 }
281
282 const Slvs_Constraint& SketchSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const
283 {
284   int aPos = Search(theConstraintID, myConstraints);
285   if (aPos >= 0 && aPos < (int)myConstraints.size())
286     return myConstraints[aPos];
287
288   // Constraint is not found, return empty object
289   static Slvs_Constraint aDummy;
290   aDummy.h = 0;
291   return aDummy;
292 }
293
294 void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
295 {
296   if (myFixed != SLVS_E_UNKNOWN)
297     return; // the point is already fixed
298   int aPos = Search(theConstraintID, myConstraints);
299   if (aPos >= 0 && aPos < (int)myConstraints.size())
300     myFixed = theConstraintID;
301 }
302
303 void SketchSolver_Storage::getRemoved(
304     std::set<Slvs_hParam>& theParameters,
305     std::set<Slvs_hEntity>& theEntities,
306     std::set<Slvs_hConstraint>& theConstraints)
307 {
308   theParameters = myRemovedParameters;
309   theEntities = myRemovedEntities;
310   theConstraints = myRemovedConstraints;
311
312   myRemovedParameters.clear();
313   myRemovedEntities.clear();
314   myRemovedConstraints.clear();
315 }
316
317 void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver)
318 {
319   theSolver.setParameters(myParameters.data(), (int)myParameters.size());
320   theSolver.setEntities(myEntities.data(), (int)myEntities.size());
321
322   // Copy constraints excluding the fixed one
323   std::vector<Slvs_Constraint> aConstraints = myConstraints;
324   if (myFixed != SLVS_E_UNKNOWN) {
325     Slvs_hEntity aFixedPoint = SLVS_E_UNKNOWN;
326     std::vector<Slvs_Constraint>::iterator anIt = aConstraints.begin();
327     for (; anIt != aConstraints.end(); anIt++)
328       if (anIt->h == myFixed) {
329         aFixedPoint = anIt->ptA;
330         aConstraints.erase(anIt);
331         break;
332       }
333     // set dragged parameters
334     int aPos = Search(aFixedPoint, myEntities);
335     theSolver.setDraggedParameters(myEntities[aPos].param);
336   }
337   theSolver.setConstraints(aConstraints.data(), (int)aConstraints.size());
338 }
339
340 void SketchSolver_Storage::addCoincidentPoints(
341     const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2)
342 {
343   std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
344   std::vector< std::set<Slvs_hEntity> >::iterator aFoundIter = myCoincidentPoints.end(); // already found coincidence
345   bool isFound = false;
346   for (; aCIter != myCoincidentPoints.end(); aCIter++) {
347     bool isFirstFound = aCIter->find(thePoint1) != aCIter->end();
348     bool isSecondFound = aCIter->find(thePoint2) != aCIter->end();
349     isFound = isFound || isFirstFound || isSecondFound;
350     if (isFirstFound && isSecondFound)
351       break; // already coincident
352     else if (isFirstFound || isSecondFound) {
353       if (aFoundIter != myCoincidentPoints.end()) {
354         // merge two sets
355         aFoundIter->insert(aCIter->begin(), aCIter->end());
356         myCoincidentPoints.erase(aCIter);
357         break;
358       }
359       aCIter->insert(thePoint1);
360       aCIter->insert(thePoint2);
361     }
362   }
363   // coincident points not found
364   if (!isFound) {
365     std::set<Slvs_hEntity> aNewSet;
366     aNewSet.insert(thePoint1);
367     aNewSet.insert(thePoint2);
368     myCoincidentPoints.push_back(aNewSet);
369   }
370 }
371
372 void SketchSolver_Storage::removeCoincidentPoint(const Slvs_hEntity& thePoint)
373 {
374   std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
375   for (; aCIter != myCoincidentPoints.end(); aCIter++)
376     if (aCIter->find(thePoint) != aCIter->end()) {
377       aCIter->erase(thePoint);
378       if (aCIter->size() <= 1)
379         myCoincidentPoints.erase(aCIter);
380       break;
381     }
382 }
383
384 bool SketchSolver_Storage::isCoincident(
385     const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const
386 {
387   std::vector< std::set<Slvs_hEntity> >::const_iterator aCIter = myCoincidentPoints.begin();
388   for (; aCIter != myCoincidentPoints.end(); aCIter++)
389     if (aCIter->find(thePoint1) != aCIter->end() && aCIter->find(thePoint2) != aCIter->end())
390       return true;
391   return false;
392 }
393
394
395
396
397 // ========================================================
398 // =========      Auxiliary functions       ===============
399 // ========================================================
400
401 template<typename T>
402 int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
403 {
404   int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
405   int aVecSize = theEntities.size();
406   while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
407     aResIndex--;
408   while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
409     aResIndex++;
410   if (aResIndex == -1)
411     aResIndex = aVecSize;
412   return aResIndex;
413 }
414
415 bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2)
416 {
417   return fabs(theParam1.val - theParam2.val) > tolerance;
418 }
419
420 bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2)
421 {
422   int i = 0;
423   for (; theEntity1.param[i] != 0 && i < 4; i++)
424     if (theEntity1.param[i] != theEntity2.param[i])
425       return true;
426   i = 0;
427   for (; theEntity1.point[i] != 0 && i < 4; i++)
428     if (theEntity1.point[i] != theEntity2.point[i])
429       return true;
430   return false;
431 }
432
433 bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2)
434 {
435   return theConstraint1.ptA != theConstraint2.ptA ||
436          theConstraint1.ptB != theConstraint2.ptB ||
437          theConstraint1.entityA != theConstraint2.entityA ||
438          theConstraint1.entityB != theConstraint2.entityB ||
439          theConstraint1.entityC != theConstraint2.entityC ||
440          theConstraint1.entityD != theConstraint2.entityD ||
441          fabs(theConstraint1.valA - theConstraint2.valA) > tolerance;
442 }