1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: SketchSolver_Storage.cpp
4 // Created: 18 Mar 2015
5 // Author: Artem ZHIDKOV
7 #include <SketchSolver_Storage.h>
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
15 static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
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);
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)
34 Slvs_hParam SketchSolver_Storage::addParameter(const Slvs_Param& theParam)
36 if (theParam.h > 0 && theParam.h <= myParamMaxID) {
37 // parameter is already used, rewrite it
38 return updateParameter(theParam);
41 Slvs_Param aParam = theParam;
42 if (aParam.h > myParamMaxID)
43 myParamMaxID = aParam.h;
45 aParam.h = ++myParamMaxID;
46 myParameters.push_back(aParam);
47 myNeedToResolve = true;
51 Slvs_hParam SketchSolver_Storage::updateParameter(const Slvs_Param& theParam)
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;
63 // Parameter is not found, add new one
64 Slvs_Param aParam = theParam;
66 return addParameter(aParam);
69 bool SketchSolver_Storage::removeParameter(const Slvs_hParam& theParamID)
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)
81 myParameters.erase(myParameters.begin() + aPos);
82 myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h;
83 myNeedToResolve = true;
84 myRemovedParameters.insert(theParamID);
90 const Slvs_Param& SketchSolver_Storage::getParameter(const Slvs_hParam& theParamID) const
92 int aPos = Search(theParamID, myParameters);
93 if (aPos >= 0 && aPos < (int)myParameters.size())
94 return myParameters[aPos];
96 // Parameter is not found, return empty object
97 static Slvs_Param aDummy;
103 Slvs_hEntity SketchSolver_Storage::addEntity(const Slvs_Entity& theEntity)
105 if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
106 // Entity is already used, rewrite it
107 return updateEntity(theEntity);
110 Slvs_Entity aEntity = theEntity;
111 if (aEntity.h > myEntityMaxID)
112 myEntityMaxID = aEntity.h;
114 aEntity.h = ++myEntityMaxID;
115 myEntities.push_back(aEntity);
116 myNeedToResolve = true;
120 Slvs_hEntity SketchSolver_Storage::updateEntity(const Slvs_Entity& theEntity)
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;
132 // Entity is not found, add new one
133 Slvs_Entity aEntity = theEntity;
135 return addEntity(aEntity);
138 bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
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)
149 if (anEntIter->distance == theEntityID)
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)
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);
181 const Slvs_Entity& SketchSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const
183 int aPos = Search(theEntityID, myEntities);
184 if (aPos >= 0 && aPos < (int)myEntities.size())
185 return myEntities[aPos];
187 // Entity is not found, return empty object
188 static Slvs_Entity aDummy;
193 Slvs_hConstraint SketchSolver_Storage::isPointFixed(const Slvs_hEntity& thePointID) const
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())
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;
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;
219 Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
221 if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
222 // Constraint is already used, rewrite it
223 return updateConstraint(theConstraint);
226 Slvs_Constraint aConstraint = theConstraint;
227 if (aConstraint.h > myConstrMaxID)
228 myConstrMaxID = aConstraint.h;
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;
238 Slvs_hConstraint SketchSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint)
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;
252 // Constraint is not found, add new one
253 Slvs_Constraint aConstraint = theConstraint;
255 return addConstraint(aConstraint);
258 bool SketchSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID)
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;
282 const Slvs_Constraint& SketchSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const
284 int aPos = Search(theConstraintID, myConstraints);
285 if (aPos >= 0 && aPos < (int)myConstraints.size())
286 return myConstraints[aPos];
288 // Constraint is not found, return empty object
289 static Slvs_Constraint aDummy;
294 void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
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;
303 void SketchSolver_Storage::getRemoved(
304 std::set<Slvs_hParam>& theParameters,
305 std::set<Slvs_hEntity>& theEntities,
306 std::set<Slvs_hConstraint>& theConstraints)
308 theParameters = myRemovedParameters;
309 theEntities = myRemovedEntities;
310 theConstraints = myRemovedConstraints;
312 myRemovedParameters.clear();
313 myRemovedEntities.clear();
314 myRemovedConstraints.clear();
317 void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver)
319 theSolver.setParameters(myParameters.data(), (int)myParameters.size());
320 theSolver.setEntities(myEntities.data(), (int)myEntities.size());
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);
333 // set dragged parameters
334 int aPos = Search(aFixedPoint, myEntities);
335 theSolver.setDraggedParameters(myEntities[aPos].param);
337 theSolver.setConstraints(aConstraints.data(), (int)aConstraints.size());
340 void SketchSolver_Storage::addCoincidentPoints(
341 const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2)
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()) {
355 aFoundIter->insert(aCIter->begin(), aCIter->end());
356 myCoincidentPoints.erase(aCIter);
359 aCIter->insert(thePoint1);
360 aCIter->insert(thePoint2);
363 // coincident points not found
365 std::set<Slvs_hEntity> aNewSet;
366 aNewSet.insert(thePoint1);
367 aNewSet.insert(thePoint2);
368 myCoincidentPoints.push_back(aNewSet);
372 void SketchSolver_Storage::removeCoincidentPoint(const Slvs_hEntity& thePoint)
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);
386 // ========================================================
387 // ========= Auxiliary functions ===============
388 // ========================================================
391 int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
393 int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
394 int aVecSize = theEntities.size();
395 while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
397 while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
400 aResIndex = aVecSize;
404 bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2)
406 return fabs(theParam1.val - theParam2.val) > tolerance;
409 bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2)
412 for (; theEntity1.param[i] != 0 && i < 4; i++)
413 if (theEntity1.param[i] != theEntity2.param[i])
416 for (; theEntity1.point[i] != 0 && i < 4; i++)
417 if (theEntity1.point[i] != theEntity2.point[i])
422 bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2)
424 return theConstraint1.ptA != theConstraint2.ptA ||
425 theConstraint1.ptB != theConstraint2.ptB ||
426 theConstraint1.entityA != theConstraint2.entityA ||
427 theConstraint1.entityB != theConstraint2.entityB ||
428 theConstraint1.entityC != theConstraint2.entityC ||
429 theConstraint1.entityD != theConstraint2.entityD ||
430 fabs(theConstraint1.valA - theConstraint2.valA) > tolerance;