]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SketchSolver_Group.cpp
Salome HOME
Update behavior of calculation of Multi-Rotation constraint
[modules/shaper.git] / src / SketchSolver / SketchSolver_Group.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    SketchSolver_Group.cpp
4 // Created: 27 May 2014
5 // Author:  Artem ZHIDKOV
6
7 #include "SketchSolver_Group.h"
8
9 #include <SketchSolver_Builder.h>
10 #include <SketchSolver_Constraint.h>
11 #include <SketchSolver_ConstraintCoincidence.h>
12 #include <SketchSolver_Error.h>
13
14 #include <Events_Error.h>
15 #include <Events_Loop.h>
16 #include <GeomAPI_XY.h>
17 #include <GeomAPI_Dir2d.h>
18 #include <GeomAPI_Pnt2d.h>
19 #include <GeomDataAPI_Dir.h>
20 #include <GeomDataAPI_Point.h>
21 #include <GeomDataAPI_Point2D.h>
22 #include <ModelAPI_AttributeDouble.h>
23 #include <ModelAPI_Document.h>
24 #include <ModelAPI_Events.h>
25 #include <ModelAPI_ResultConstruction.h>
26
27 #include <SketchPlugin_Constraint.h>
28 #include <SketchPlugin_ConstraintEqual.h>
29 #include <SketchPlugin_ConstraintFillet.h>
30 #include <SketchPlugin_ConstraintLength.h>
31 #include <SketchPlugin_ConstraintCoincidence.h>
32 #include <SketchPlugin_ConstraintMirror.h>
33 #include <SketchPlugin_ConstraintRigid.h>
34 #include <SketchPlugin_ConstraintTangent.h>
35 #include <SketchPlugin_Feature.h>
36 #include <SketchPlugin_MultiRotation.h>
37 #include <SketchPlugin_MultiTranslation.h>
38
39 #include <SketchPlugin_Arc.h>
40 #include <SketchPlugin_Circle.h>
41 #include <SketchPlugin_Line.h>
42 #include <SketchPlugin_Point.h>
43 #include <SketchPlugin_Sketch.h>
44
45 #include <math.h>
46 #include <assert.h>
47
48
49 /// \brief This class is used to give unique index to the groups
50 class GroupIndexer
51 {
52 public:
53   /// \brief Return vacant index
54   static Slvs_hGroup NEW_GROUP() { return ++myGroupIndex; }
55   /// \brief Removes the index
56   static void REMOVE_GROUP(const Slvs_hGroup& theIndex) {
57     if (myGroupIndex == theIndex)
58       myGroupIndex--;
59   }
60
61 private:
62   GroupIndexer() {};
63
64   static Slvs_hGroup myGroupIndex; ///< index of the group
65 };
66
67 Slvs_hGroup GroupIndexer::myGroupIndex = 0;
68
69
70
71 // ========================================================
72 // =========  SketchSolver_Group  ===============
73 // ========================================================
74
75 SketchSolver_Group::SketchSolver_Group(
76     std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
77     : myID(GroupIndexer::NEW_GROUP())
78 {
79   // Initialize workplane
80   myWorkplaneID = SLVS_E_UNKNOWN;
81 #ifndef NDEBUG
82   assert(addWorkplane(theWorkplane));
83 #else
84   addWorkplane(theWorkplane);
85 #endif
86 }
87
88 SketchSolver_Group::~SketchSolver_Group()
89 {
90   myConstraints.clear();
91   GroupIndexer::REMOVE_GROUP(myID);
92 }
93
94 // ============================================================================
95 //  Function: isBaseWorkplane
96 //  Class:    SketchSolver_Group
97 //  Purpose:  verify the group is based on the given workplane
98 // ============================================================================
99 bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const
100 {
101   return theWorkplane == mySketch;
102 }
103
104 // ============================================================================
105 //  Function: isInteract
106 //  Class:    SketchSolver_Group
107 //  Purpose:  verify are there any entities in the group used by given constraint
108 // ============================================================================
109 bool SketchSolver_Group::isInteract(
110     std::shared_ptr<SketchPlugin_Feature> theFeature) const
111 {
112   // Empty group interacts with everything
113   if (isEmpty()) return true;
114   ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
115   if (aConstraint)
116     return myFeatureStorage->isInteract(aConstraint);
117   return myFeatureStorage->isInteract(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
118 }
119
120 // ============================================================================
121 //  Function: getFeatureId
122 //  Class:    SketchSolver_Group
123 //  Purpose:  Find the identifier of the feature, if it already exists in the group
124 // ============================================================================
125 Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const
126 {
127   Slvs_hEntity aResult = SLVS_E_UNKNOWN;
128   if (!myFeatureStorage)
129     return aResult;
130   std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theFeature);
131   if (aConstraints.empty())
132     return aResult;
133   std::set<ConstraintPtr>::iterator aConstrIter = aConstraints.begin();
134   for (; aConstrIter != aConstraints.end(); aConstrIter++) {
135     ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstrIter);
136     if (aCIter == myConstraints.end())
137       continue;
138     aResult = aCIter->second->getId(theFeature);
139     if (aResult != SLVS_E_UNKNOWN)
140       return aResult;
141   }
142   return SLVS_E_UNKNOWN;
143 }
144
145 // ============================================================================
146 //  Function: getAttributeId
147 //  Class:    SketchSolver_Group
148 //  Purpose:  Find the identifier of the attribute, if it already exists in the group
149 // ============================================================================
150 Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const
151 {
152   Slvs_hEntity aResult = SLVS_E_UNKNOWN;
153   if (!myFeatureStorage)
154     return aResult;
155   std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theAttribute);
156   if (aConstraints.empty())
157     return aResult;
158   std::set<ConstraintPtr>::iterator aConstrIter = aConstraints.begin();
159   for (; aConstrIter != aConstraints.end(); aConstrIter++) {
160     ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstrIter);
161     if (aCIter == myConstraints.end())
162       continue;
163     aResult = aCIter->second->getId(theAttribute);
164     if (aResult != SLVS_E_UNKNOWN)
165       return aResult;
166   }
167   return SLVS_E_UNKNOWN;
168 }
169
170 // ============================================================================
171 //  Function: changeConstraint
172 //  Class:    SketchSolver_Group
173 //  Purpose:  create/update the constraint in the group
174 // ============================================================================
175 bool SketchSolver_Group::changeConstraint(
176     std::shared_ptr<SketchPlugin_Constraint> theConstraint)
177 {
178   // There is no workplane yet, something wrong
179   if (myWorkplaneID == SLVS_E_UNKNOWN)
180     return false;
181
182   if (!theConstraint)
183     return false;
184
185   bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end();
186   if (isNewConstraint) {
187     // Add constraint to the current group
188     SolverConstraintPtr aConstraint =
189         SketchSolver_Builder::getInstance()->createConstraint(theConstraint);
190     if (!aConstraint)
191       return false;
192     aConstraint->setGroup(this);
193     aConstraint->setStorage(myStorage);
194     if (!aConstraint->error().empty()) {
195       if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
196         return false; // some attribute are not initialized yet, don't show message
197       Events_Error::send(aConstraint->error(), this);
198     }
199
200     // Additional verification of coincidence of several points
201     if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
202       ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
203       for (; aCIter != myConstraints.end(); aCIter++) {
204         std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoincidence =
205           std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aCIter->second);
206         if (!aCoincidence)
207           continue;
208         std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoinc2 =
209           std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aConstraint);
210         if (aCoincidence != aCoinc2 && aCoincidence->isCoincide(aCoinc2)) {
211           aCoincidence->attach(aCoinc2);
212           aConstraint = aCoincidence;
213         }
214       }
215     }
216     myConstraints[theConstraint] = aConstraint;
217   }
218   else
219     myConstraints[theConstraint]->update();
220
221   // Fix base features for fillet
222   if (isNewConstraint && theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
223     std::list<AttributePtr> anAttrList =
224         theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
225     std::list<AttributePtr>::iterator anAttrIter = anAttrList.begin();
226     for (; anAttrIter != anAttrList.end(); anAttrIter++) {
227       AttributeRefAttrPtr aRefAttr =
228           std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
229       if (!aRefAttr || !aRefAttr->isObject())
230         continue;
231       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
232       SolverConstraintPtr aConstraint =
233           SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
234       if (!aConstraint)
235         continue;
236       aConstraint->setGroup(this);
237       aConstraint->setStorage(myStorage);
238       setTemporary(aConstraint);
239     }
240   }
241   // Fix mirror line
242   if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
243     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
244         theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_A()));
245     if (aRefAttr && aRefAttr->isObject()) {
246       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
247       if (aFeature) {
248         SolverConstraintPtr aConstraint =
249             SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
250         if (aConstraint) {
251           aConstraint->setGroup(this);
252           aConstraint->setStorage(myStorage);
253           setTemporary(aConstraint);
254         }
255       }
256     }
257   }
258
259   if (!myFeatureStorage)
260     myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
261   myFeatureStorage->changeConstraint(theConstraint);
262
263   return true;
264 }
265
266
267 bool SketchSolver_Group::updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
268 {
269   std::set<ConstraintPtr> aConstraints =
270       myFeatureStorage->getConstraints(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
271   if (aConstraints.empty())
272     return false;
273   std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
274   std::set<SolverConstraintPtr> aPostponed; // postponed constraints Multi-Rotation and Multi-Translation
275   for (; aCIter != aConstraints.end(); aCIter++) {
276     ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter);
277     if (aSolConIter == myConstraints.end() || !aSolConIter->first->data() ||
278         !aSolConIter->first->data()->isValid())
279       continue;
280     myFeatureStorage->changeFeature(theFeature, aSolConIter->first);
281
282     if (aSolConIter->first->getKind() == SketchPlugin_MultiRotation::ID() ||
283         aSolConIter->first->getKind() == SketchPlugin_MultiTranslation::ID()) {
284       aPostponed.insert(aSolConIter->second);
285       continue;
286     }
287     aSolConIter->second->addFeature(theFeature);
288     aSolConIter->second->update();
289   }
290
291   // Update postponed constraints
292   std::set<SolverConstraintPtr>::iterator aSCIter = aPostponed.begin();
293   for (; aSCIter != aPostponed.end(); ++aSCIter) {
294     (*aSCIter)->addFeature(theFeature);
295     (*aSCIter)->update();
296   }
297   return true;
298 }
299
300 void SketchSolver_Group::moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
301 {
302   // Firstly, create temporary rigid constraint
303   SolverConstraintPtr aConstraint =
304       SketchSolver_Builder::getInstance()->createMovementConstraint(theFeature);
305   if (!aConstraint)
306     return;
307   aConstraint->setGroup(this);
308   aConstraint->setStorage(myStorage);
309   if (aConstraint->error().empty())
310     setTemporary(aConstraint);
311   // Secondly, update the feature
312   updateFeature(theFeature);
313 }
314
315 // ============================================================================
316 //  Function: fixFeaturesList
317 //  Class:    SketchSolver_Group
318 //  Purpose:  Apply temporary rigid constraints for the list of features
319 // ============================================================================
320 void SketchSolver_Group::fixFeaturesList(AttributeRefListPtr theList)
321 {
322   std::list<ObjectPtr> aList = theList->list();
323   std::list<ObjectPtr>::iterator anIt = aList.begin();
324   std::list<FeaturePtr> aFeatures;
325   // Sort features, at begining there are features used by Equal constraint
326   for (; anIt != aList.end(); anIt++) {
327     if (!(*anIt))
328       continue;
329     FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
330     std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(aFeature);
331     std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
332     for (; aCIter != aConstraints.end(); aCIter++)
333       if ((*aCIter)->getKind() == SketchPlugin_ConstraintEqual::ID())
334         break;
335     if (aCIter != aConstraints.end())
336       aFeatures.push_front(aFeature);
337     else
338       aFeatures.push_back(aFeature);
339   }
340
341   std::list<FeaturePtr>::iterator aFeatIter = aFeatures.begin();
342   for (; aFeatIter != aFeatures.end(); aFeatIter++) {
343     SolverConstraintPtr aConstraint =
344         SketchSolver_Builder::getInstance()->createRigidConstraint(*aFeatIter);
345     if (!aConstraint)
346       continue;
347     aConstraint->setGroup(this);
348     aConstraint->setStorage(myStorage);
349     setTemporary(aConstraint);
350   }
351 }
352
353 // ============================================================================
354 //  Function: addWorkplane
355 //  Class:    SketchSolver_Group
356 //  Purpose:  create workplane for the group
357 // ============================================================================
358 bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch)
359 {
360   if (myWorkplaneID != SLVS_E_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID())
361     return false;  // the workplane already exists or the function parameter is not Sketch
362
363   mySketch = theSketch;
364   updateWorkplane();
365   return true;
366 }
367
368 // ============================================================================
369 //  Function: updateWorkplane
370 //  Class:    SketchSolver_Group
371 //  Purpose:  update parameters of workplane
372 // ============================================================================
373 bool SketchSolver_Group::updateWorkplane()
374 {
375   if (!myStorage) // Create storage if not exists
376     myStorage = StoragePtr(new SketchSolver_Storage);
377   SketchSolver_Builder* aBuilder = SketchSolver_Builder::getInstance();
378
379   std::vector<Slvs_Entity> anEntities;
380   std::vector<Slvs_Param> aParams;
381   if (!aBuilder->createWorkplane(mySketch, anEntities, aParams))
382     return false;
383
384   if (myWorkplaneID == SLVS_E_UNKNOWN) {
385     myWorkplaneID = anEntities.back().h;
386     // Add new workplane elements
387     std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
388     for (; aParIter != aParams.end(); aParIter++) {
389       aParIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
390       aParIter->group = myID;
391       aParIter->h = myStorage->addParameter(*aParIter);
392     }
393     std::vector<Slvs_Entity>::iterator anEntIter = anEntities.begin();
394     for (; anEntIter != anEntities.end(); anEntIter++) {
395       anEntIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
396       anEntIter->group = myID;
397       anEntIter->wrkpl = myWorkplaneID;
398       for (int i = 0; i < 4; i++)
399         if (anEntIter->param[i] != SLVS_E_UNKNOWN)
400           anEntIter->param[i] = aParams[anEntIter->param[i]-1].h;
401       for (int i = 0; i < 4; i++)
402         if (anEntIter->point[i] != SLVS_E_UNKNOWN)
403           anEntIter->point[i] = anEntities[anEntIter->point[i]-1].h;
404       anEntIter->h = myStorage->addEntity(*anEntIter);
405     }
406   } else {
407     // Update existent workplane
408     const Slvs_Entity& aWP = myStorage->getEntity(myWorkplaneID);
409     const Slvs_Entity& anOrigin = myStorage->getEntity(aWP.point[0]);
410     const Slvs_Entity& aNormal = myStorage->getEntity(aWP.normal);
411     // Get parameters and update them
412     Slvs_hParam aWPParams[7] = {
413         anOrigin.param[0], anOrigin.param[1], anOrigin.param[2],
414         aNormal.param[0], aNormal.param[1], aNormal.param[2], aNormal.param[3]
415       };
416     std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
417     for (int i = 0; aParIter != aParams.end(); aParIter++, i++) {
418       Slvs_Param aParam = myStorage->getParameter(aWPParams[i]);
419       aParam.val = aParIter->val;
420       myStorage->updateParameter(aParam);
421     }
422   }
423   return myWorkplaneID > 0;
424 }
425
426 // ============================================================================
427 //  Function: resolveConstraints
428 //  Class:    SketchSolver_Group
429 //  Purpose:  solve the set of constraints for the current group
430 // ============================================================================
431 bool SketchSolver_Group::resolveConstraints()
432 {
433   bool aResolved = false;
434   if (myStorage->isNeedToResolve() && !isEmpty()) {
435     myConstrSolver.setGroupID(myID);
436     myStorage->initializeSolver(myConstrSolver);
437
438     int aResult = SLVS_RESULT_OKAY;
439     try {
440       if (myStorage->hasDuplicatedConstraint())
441         aResult = SLVS_RESULT_INCONSISTENT;
442       else {
443         // To avoid overconstraint situation, we will remove temporary constraints one-by-one
444         // and try to find the case without overconstraint
445         bool isLastChance = false;
446         int aNbTemp = myStorage->numberTemporary();
447         while (true) {
448           aResult = myConstrSolver.solve();
449           if (aResult == SLVS_RESULT_OKAY || isLastChance)
450             break;
451           if (aNbTemp <= 0) {
452             // try to update parameters and resolve once again
453             ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin();
454             for (; aConstrIt != myConstraints.end(); ++aConstrIt)
455               aConstrIt->second->update();
456             isLastChance = true;
457           } else
458             aNbTemp = myStorage->deleteTemporaryConstraint();
459           myStorage->initializeSolver(myConstrSolver);
460         }
461       }
462     } catch (...) {
463       Events_Error::send(SketchSolver_Error::SOLVESPACE_CRASH(), this);
464       return false;
465     }
466     if (aResult == SLVS_RESULT_OKAY) {  // solution succeeded, store results into correspondent attributes
467       myFeatureStorage->blockEvents(true);
468       ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
469       for (; aConstrIter != myConstraints.end(); aConstrIter++)
470         aConstrIter->second->refresh();
471       myFeatureStorage->blockEvents(false);
472     } else if (!myConstraints.empty())
473       Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
474
475     aResolved = true;
476   }
477   removeTemporaryConstraints();
478   myStorage->setNeedToResolve(false);
479   return aResolved;
480 }
481
482 // ============================================================================
483 //  Function: mergeGroups
484 //  Class:    SketchSolver_Group
485 //  Purpose:  append specified group to the current group
486 // ============================================================================
487 void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
488 {
489   // If specified group is empty, no need to merge
490   if (theGroup.isEmpty())
491     return;
492   if (!myFeatureStorage)
493     myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
494
495   std::vector<ConstraintPtr> aComplexConstraints;
496   ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
497   // append simple constraints
498   for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++)
499     if (isComplexConstraint(aConstrIter->first))
500       aComplexConstraints.push_back(aConstrIter->first);
501     else
502       changeConstraint(aConstrIter->first);
503   // append complex constraints
504   std::vector<ConstraintPtr>::iterator aComplexIter = aComplexConstraints.begin();
505   for (; aComplexIter != aComplexConstraints.end(); aComplexIter++)
506       changeConstraint(*aComplexIter);
507 }
508
509 // ============================================================================
510 //  Function: splitGroup
511 //  Class:    SketchSolver_Group
512 //  Purpose:  divide the group into several subgroups
513 // ============================================================================
514 void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
515 {
516   // Obtain constraints, which should be separated
517   FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage);
518   std::vector<ConstraintPtr> anUnusedConstraints;
519   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
520   for ( ; aCIter != myConstraints.end(); aCIter++) {
521     std::list<ConstraintPtr> aBaseConstraints = aCIter->second->constraints();
522     std::list<ConstraintPtr>::iterator anIter = aBaseConstraints.begin();
523     for (; anIter != aBaseConstraints.end(); anIter++)
524       if (aNewFeatStorage->isInteract(*anIter)) {
525         aNewFeatStorage->changeConstraint(*anIter);
526       } else
527         anUnusedConstraints.push_back(*anIter);
528   }
529
530   // Check the unused constraints once again, because they may become interacted with new storage since adding constraints
531   std::vector<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
532   while (aUnuseIt != anUnusedConstraints.end()) {
533     if (aNewFeatStorage->isInteract(*aUnuseIt)) {
534       size_t aShift = aUnuseIt - anUnusedConstraints.begin();
535       anUnusedConstraints.erase(aUnuseIt);
536       aUnuseIt = anUnusedConstraints.begin() + aShift;
537       continue;
538     }
539     aUnuseIt++;
540   }
541
542   std::vector<SketchSolver_Group*>::iterator aCutsIter;
543   aUnuseIt = anUnusedConstraints.begin();
544   for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) {
545     // Remove unused constraints
546     removeConstraint(*aUnuseIt);
547     // Try to append constraint to already existent group
548     for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); aCutsIter++)
549       if ((*aCutsIter)->isInteract(*aUnuseIt)) {
550         (*aCutsIter)->changeConstraint(*aUnuseIt);
551         break;
552       }
553     if (aCutsIter == theCuts.end()) {
554       // Add new group
555       SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch);
556       aGroup->changeConstraint(*aUnuseIt);
557       theCuts.push_back(aGroup);
558     }
559   }
560 }
561
562 // ============================================================================
563 //  Function: isConsistent
564 //  Class:    SketchSolver_Group
565 //  Purpose:  search removed entities and constraints
566 // ============================================================================
567 bool SketchSolver_Group::isConsistent()
568 {
569   if (!myFeatureStorage) // no one constraint is initialized yet
570     return true;
571
572   bool aResult = myFeatureStorage->isConsistent();
573   if (!aResult) {
574     // remove invalid entities
575     ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
576     while (aCIter != myConstraints.end()) {
577       std::list<ConstraintPtr> aConstraints = aCIter->second->constraints();
578       std::list<ConstraintPtr>::iterator anIt = aConstraints.begin();
579       for (; anIt != aConstraints.end(); anIt++)
580         if (!(*anIt)->data() || !(*anIt)->data()->isValid())
581           if (aCIter->second->remove(*anIt)) {
582             // the constraint is fully removed, detach it from the list
583             ConstraintConstraintMap::iterator aTmpIt = aCIter++;
584             myFeatureStorage->removeConstraint(aTmpIt->first);
585             myConstraints.erase(aTmpIt);
586             break;
587           }
588       if (anIt == aConstraints.end())
589         aCIter++;
590     }
591   }
592   return aResult;
593 }
594
595 // ============================================================================
596 //  Function: removeTemporaryConstraints
597 //  Class:    SketchSolver_Group
598 //  Purpose:  remove all transient SLVS_C_WHERE_DRAGGED constraints after
599 //            resolving the set of constraints
600 // ============================================================================
601 void SketchSolver_Group::removeTemporaryConstraints()
602 {
603   myTempConstraints.clear();
604   while (myStorage->numberTemporary())
605     myStorage->deleteTemporaryConstraint();
606   // Clean lists of removed entities in the storage
607   std::set<Slvs_hParam> aRemPar;
608   std::set<Slvs_hEntity> aRemEnt;
609   std::set<Slvs_hConstraint> aRemCon;
610   myStorage->getRemoved(aRemPar, aRemEnt, aRemCon);
611   myStorage->setNeedToResolve(false);
612 }
613
614 // ============================================================================
615 //  Function: removeConstraint
616 //  Class:    SketchSolver_Group
617 //  Purpose:  remove constraint and all unused entities
618 // ============================================================================
619 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
620 {
621   myFeatureStorage->removeConstraint(theConstraint);
622   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
623   for (; aCIter != myConstraints.end(); aCIter++)
624     if (aCIter->second->hasConstraint(theConstraint)) {
625       if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed
626         aCIter = myConstraints.end();
627       break;
628     }
629   if (aCIter != myConstraints.end())
630     myConstraints.erase(aCIter);
631 }
632
633 // ============================================================================
634 //  Function: isComplexConstraint
635 //  Class:    SketchSolver_Group
636 //  Purpose:  verifies the constraint is complex, i.e. it needs another constraints to be created before
637 // ============================================================================
638 bool SketchSolver_Group::isComplexConstraint(FeaturePtr theConstraint)
639 {
640   return theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID() ||
641          theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID() ||
642          theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID();
643 }
644
645 // ============================================================================
646 //  Function: setTemporary
647 //  Class:    SketchSolver_Group
648 //  Purpose:  append given constraint to th group of temporary constraints
649 // ============================================================================
650 void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
651 {
652   theConstraint->makeTemporary();
653   myTempConstraints.insert(theConstraint);
654 }
655