Salome HOME
acefc6396f92eab1282fd7eda5deec61f8910077
[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: 30 Nov 2015
5 // Author:  Artem ZHIDKOV
6
7 #include <SketchSolver_Storage.h>
8 #include <SketchSolver_Manager.h>
9
10 #include <GeomDataAPI_Point2D.h>
11 #include <ModelAPI_AttributeRefAttr.h>
12 #include <ModelAPI_AttributeRefList.h>
13 #include <SketchPlugin_Arc.h>
14 #include <SketchPlugin_Circle.h>
15
16
17 /// \brief Verify two vectors of constraints are equal.
18 ///        Vectors differ by the order of elements are equal.
19 static bool isEqual(const std::list<ConstraintWrapperPtr>& theCVec1,
20                     const std::list<ConstraintWrapperPtr>& theCVec2);
21
22
23 void SketchSolver_Storage::addConstraint(ConstraintPtr        theConstraint,
24                                          ConstraintWrapperPtr theSolverConstraint)
25 {
26   if (theSolverConstraint) {
27     std::list<ConstraintWrapperPtr> aConstrList(1, theSolverConstraint);
28     addConstraint(theConstraint, aConstrList);
29   } else
30     addConstraint(theConstraint, std::list<ConstraintWrapperPtr>());
31 }
32
33 void SketchSolver_Storage::addConstraint(
34     ConstraintPtr                   theConstraint,
35     std::list<ConstraintWrapperPtr> theSolverConstraints)
36 {
37   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
38       aFound = myConstraintMap.find(theConstraint);
39   if (aFound == myConstraintMap.end() || !isEqual(aFound->second, theSolverConstraints))
40     setNeedToResolve(true);
41
42   if (theSolverConstraints.empty()) {
43     // constraint links to the empty list, add its attributes linked to the empty entities
44     std::list<AttributePtr> aRefAttrs =
45         theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
46     std::list<AttributePtr>::const_iterator anAttrIt = aRefAttrs.begin();
47     for (; anAttrIt != aRefAttrs.end(); ++anAttrIt) {
48       AttributeRefAttrPtr aRef = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIt);
49       if (aRef->isObject()) {
50         FeaturePtr aFeature = ModelAPI_Feature::feature(aRef->object());
51         if (aFeature) addEntity(aFeature, EntityWrapperPtr());
52       } else
53         addEntity(aRef->attr(), EntityWrapperPtr());
54     }
55     std::list<AttributePtr> aRefLists =
56         theConstraint->data()->attributes(ModelAPI_AttributeRefList::typeId());
57     for (anAttrIt = aRefLists.begin(); anAttrIt != aRefLists.end(); ++anAttrIt) {
58       AttributeRefListPtr aRef = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrIt);
59       std::list<ObjectPtr> anObj = aRef->list();
60       std::list<ObjectPtr>::iterator anIt = anObj.begin();
61       for (; anIt != anObj.end(); ++anIt) {
62         FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
63         if (aFeature) addEntity(aFeature, EntityWrapperPtr());
64       }
65     }
66   }
67   else if (theSolverConstraints.front()->type() != CONSTRAINT_PT_PT_COINCIDENT) {
68     // Do not add point-point coincidence, because it is already made by setting
69     // the same parameters for both points
70     std::list<ConstraintWrapperPtr>::iterator aCIt = theSolverConstraints.begin();
71     for (; aCIt != theSolverConstraints.end(); ++aCIt)
72       update(*aCIt);
73   }
74   myConstraintMap[theConstraint] = theSolverConstraints;
75   // block events if necessary
76   if (myEventsBlocked && theConstraint->data() && theConstraint->data()->isValid())
77     theConstraint->data()->blockSendAttributeUpdated(myEventsBlocked);
78 }
79
80 void SketchSolver_Storage::addEntity(FeaturePtr       theFeature,
81                                      EntityWrapperPtr theSolverEntity)
82 {
83   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFound = myFeatureMap.find(theFeature);
84   if (aFound == myFeatureMap.end() || !aFound->second ||
85      (theSolverEntity && !aFound->second->isEqual(theSolverEntity)))
86     setNeedToResolve(true); // the entity is new or modified
87
88   if (!theSolverEntity) {
89     // feature links to the empty entity, add its attributes
90     std::list<AttributePtr> aPntAttrs =
91         theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
92     std::list<AttributePtr>::const_iterator anAttrIt = aPntAttrs.begin();
93     for (; anAttrIt != aPntAttrs.end(); ++anAttrIt)
94         addEntity(*anAttrIt, EntityWrapperPtr());
95     if (aFound == myFeatureMap.end())
96       myFeatureMap[theFeature] = theSolverEntity;
97   } else
98     myFeatureMap[theFeature] = theSolverEntity;
99
100   // block events if necessary
101   if (myEventsBlocked && theFeature->data() && theFeature->data()->isValid())
102     theFeature->data()->blockSendAttributeUpdated(myEventsBlocked);
103 }
104
105 void SketchSolver_Storage::addEntity(AttributePtr     theAttribute,
106                                      EntityWrapperPtr theSolverEntity)
107 {
108   std::map<AttributePtr, EntityWrapperPtr>::const_iterator aFound = myAttributeMap.find(theAttribute);
109   if (aFound == myAttributeMap.end() || !aFound->second ||
110      (theSolverEntity && !aFound->second->isEqual(theSolverEntity)))
111     setNeedToResolve(true); // the entity is new or modified
112
113   if (theSolverEntity || aFound == myAttributeMap.end())
114     myAttributeMap[theAttribute] = theSolverEntity;
115   // block events if necessary
116   if (myEventsBlocked && theAttribute->owner() &&
117       theAttribute->owner()->data() && theAttribute->owner()->data()->isValid())
118     theAttribute->owner()->data()->blockSendAttributeUpdated(myEventsBlocked);
119 }
120
121
122 bool SketchSolver_Storage::update(FeaturePtr theFeature, const GroupID& theGroup)
123 {
124   bool isUpdated = false;
125   EntityWrapperPtr aRelated = entity(theFeature);
126   if (!aRelated) { // Feature is not exist, create it
127     std::list<EntityWrapperPtr> aSubs;
128     // Reserve the feature in the map of features (do not want to add several copies of it)
129     myFeatureMap[theFeature] = aRelated;
130     // Firstly, create/update its attributes
131     std::list<AttributePtr> anAttrs =
132         theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
133     std::list<AttributePtr>::const_iterator anIt = anAttrs.begin();
134     for (; anIt != anAttrs.end(); ++anIt) {
135       isUpdated = update(*anIt, theGroup) || isUpdated;
136       aSubs.push_back(entity(*anIt));
137     }
138     // If the feature is a circle, add its radius as a sub
139     if (theFeature->getKind() == SketchPlugin_Circle::ID()) {
140       AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
141       isUpdated = update(aRadius, theGroup) || isUpdated;
142       aSubs.push_back(entity(aRadius));
143     }
144     // If the feature if circle or arc, we need to add normal of the sketch to the list of subs
145     if (theFeature->getKind() == SketchPlugin_Arc::ID() ||
146         theFeature->getKind() == SketchPlugin_Circle::ID()) {
147       EntityWrapperPtr aNormal = getNormal();
148       if (aNormal) aSubs.push_back(aNormal);
149     }
150     // Secondly, convert feature
151     BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
152     GroupID aGroup = theGroup != GID_UNKNOWN ? theGroup : myGroupID;
153     aRelated = aBuilder->createFeature(theFeature, aSubs, aGroup);
154     if (!aRelated)
155       return false;
156     addEntity(theFeature, aRelated);
157   } else if (theGroup != GID_UNKNOWN)
158     changeGroup(aRelated, theGroup);
159   return update(aRelated) || isUpdated;
160 }
161
162 bool SketchSolver_Storage::update(AttributePtr theAttribute, const GroupID& theGroup)
163 {
164   AttributePtr anAttribute = theAttribute;
165   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
166   if (aRefAttr) {
167     if (aRefAttr->isObject()) {
168       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
169       return update(aFeature, theGroup);
170     } else
171       anAttribute = aRefAttr->attr();
172   }
173
174   EntityWrapperPtr aRelated = entity(anAttribute);
175   if (!aRelated) { // Attribute is not exist, create it
176     // verify the attribute is a point of arc and add whole arc
177     if (anAttribute->owner()) {
178       FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
179       if (aFeature->getKind() == SketchPlugin_Arc::ID() &&
180           myFeatureMap.find(aFeature) == myFeatureMap.end()) {
181         // Additional checking that all attributes are initialized
182         if (aFeature->attribute(SketchPlugin_Arc::CENTER_ID())->isInitialized() && 
183             aFeature->attribute(SketchPlugin_Arc::START_ID())->isInitialized() && 
184             aFeature->attribute(SketchPlugin_Arc::END_ID())->isInitialized()) {
185 ////          myFeatureMap[aFeature] = EntityWrapperPtr();
186           return SketchSolver_Storage::update(aFeature);
187         }
188       }
189     }
190     BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
191     GroupID aGroup = theGroup != GID_UNKNOWN ? theGroup : myGroupID;
192     aRelated = aBuilder->createAttribute(anAttribute, aGroup);
193     if (!aRelated)
194       return false;
195     addEntity(anAttribute, aRelated);
196   } else if (theGroup != GID_UNKNOWN)
197     changeGroup(aRelated, theGroup);
198   return update(aRelated);
199 }
200
201
202
203 const std::list<ConstraintWrapperPtr>& SketchSolver_Storage::constraint(
204     const ConstraintPtr& theConstraint) const
205 {
206   static std::list<ConstraintWrapperPtr> aDummy;
207
208   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr>>::const_iterator
209       aFound = myConstraintMap.find(theConstraint);
210   if (aFound != myConstraintMap.end())
211     return aFound->second;
212   return aDummy;
213 }
214
215 const EntityWrapperPtr& SketchSolver_Storage::entity(const FeaturePtr& theFeature) const
216 {
217   static EntityWrapperPtr aDummy;
218
219   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFound = myFeatureMap.find(theFeature);
220   if (aFound != myFeatureMap.end())
221     return aFound->second;
222   return aDummy;
223 }
224
225 const EntityWrapperPtr& SketchSolver_Storage::entity(const AttributePtr& theAttribute) const
226 {
227   static EntityWrapperPtr aDummy;
228
229   std::map<AttributePtr, EntityWrapperPtr>::const_iterator
230       aFound = myAttributeMap.find(theAttribute);
231   if (aFound != myAttributeMap.end())
232     return aFound->second;
233
234   AttributeRefAttrPtr aRefAttr =
235       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
236   if (aRefAttr) {
237     if (aRefAttr->isObject()) {
238       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
239       return entity(aFeature);
240     } else
241       return entity(aRefAttr->attr());
242   }
243   return aDummy;
244 }
245
246 bool SketchSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
247 {
248   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::iterator
249       aFound = myConstraintMap.find(theConstraint);
250   if (aFound == myConstraintMap.end())
251     return true; // no constraint, already deleted
252
253   // Remove constraint
254   std::list<ConstraintWrapperPtr> aConstrList = aFound->second;
255   myConstraintMap.erase(aFound);
256   // Remove SolveSpace constraints
257   bool isFullyRemoved = true;
258   std::list<ConstraintWrapperPtr>::iterator anIt = aConstrList.begin();
259   while (anIt != aConstrList.end()) {
260     if (remove(*anIt)) {
261       std::list<ConstraintWrapperPtr>::iterator aRemoveIt = anIt++;
262       aConstrList.erase(aRemoveIt);
263     } else {
264       isFullyRemoved = false;
265       ++anIt;
266     }
267   }
268   return isFullyRemoved;
269 }
270
271 template <class ENT_TYPE>
272 static bool isUsed(ConstraintWrapperPtr theConstraint, ENT_TYPE theEntity)
273 {
274   std::list<EntityWrapperPtr>::const_iterator anEntIt = theConstraint->entities().begin();
275   for (; anEntIt != theConstraint->entities().end(); ++anEntIt)
276     if ((*anEntIt)->isBase(theEntity))
277       return true;
278   return false;
279 }
280
281 static bool isUsed(EntityWrapperPtr theFeature, AttributePtr theSubEntity)
282 {
283   std::list<EntityWrapperPtr>::const_iterator aSubIt = theFeature->subEntities().begin();
284   for (; aSubIt != theFeature->subEntities().end(); ++aSubIt)
285     if ((*aSubIt)->isBase(theSubEntity))
286       return true;
287   return false;
288 }
289
290 bool SketchSolver_Storage::isUsed(FeaturePtr theFeature) const
291 {
292   if (myFeatureMap.find(theFeature) != myFeatureMap.end())
293     return true;
294   // check constraints
295   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
296       aCIt = myConstraintMap.begin();
297   std::list<ConstraintWrapperPtr>::const_iterator aCWIt;
298   for (; aCIt != myConstraintMap.end(); ++aCIt)
299     for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt)
300       if (::isUsed(*aCWIt, theFeature))
301         return true;
302   // check attributes
303   std::list<AttributePtr> anAttrList = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
304   std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
305   for (; anIt != anAttrList.end(); ++anIt)
306     if (isUsed(*anIt))
307       return true;
308   return false;
309 }
310
311 bool SketchSolver_Storage::isUsed(AttributePtr theAttribute) const
312 {
313   AttributePtr anAttribute = theAttribute;
314   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
315   if (aRefAttr) {
316     if (aRefAttr->isObject())
317       return isUsed(ModelAPI_Feature::feature(aRefAttr->object()));
318     else
319       anAttribute = aRefAttr->attr();
320   }
321
322   if (myAttributeMap.find(theAttribute) != myAttributeMap.end())
323     return true;
324   // check in constraints
325   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
326       aCIt = myConstraintMap.begin();
327   std::list<ConstraintWrapperPtr>::const_iterator aCWIt;
328   for (; aCIt != myConstraintMap.end(); ++aCIt)
329     for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt)
330       if (::isUsed(*aCWIt, anAttribute))
331         return true;
332   // check in features
333   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
334   for (; aFIt != myFeatureMap.end(); ++aFIt)
335     if (::isUsed(aFIt->second, anAttribute))
336       return true;
337   return false;
338 }
339
340
341 bool SketchSolver_Storage::removeEntity(FeaturePtr theFeature)
342 {
343   std::map<FeaturePtr, EntityWrapperPtr>::iterator aFound = myFeatureMap.find(theFeature);
344   if (aFound == myFeatureMap.end())
345     return false; // feature not found, nothing to delete
346
347   EntityWrapperPtr anEntity = aFound->second;
348   myFeatureMap.erase(aFound);
349
350   // Check if the feature is not used by constraints, remove it
351   if (!isUsed(theFeature) && remove(anEntity))
352     return true;
353
354   // feature is not removed, revert operation
355   myFeatureMap[theFeature] = anEntity;
356   update(anEntity);
357   return false;
358 }
359
360 bool SketchSolver_Storage::removeEntity(AttributePtr theAttribute)
361 {
362   std::map<AttributePtr, EntityWrapperPtr>::iterator aFound = myAttributeMap.find(theAttribute);
363   if (aFound == myAttributeMap.end())
364     return false; // attribute not found, nothing to delete
365
366   EntityWrapperPtr anEntity = aFound->second;
367   myAttributeMap.erase(aFound);
368
369   // Check if the attribute is not used by constraints and features, remove it
370   if (!isUsed(theAttribute) && remove(anEntity))
371     return true;
372
373   // attribute is not removed, revert operation
374   myAttributeMap[theAttribute] = anEntity;
375   update(anEntity);
376   return false;
377 }
378
379
380 bool SketchSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
381 {
382   bool isFullyRemoved = true;
383   std::list<EntityWrapperPtr>::const_iterator anIt = theConstraint->entities().begin();
384   for (; anIt != theConstraint->entities().end(); ++anIt) {
385     FeaturePtr aBaseFeature = (*anIt)->baseFeature();
386     if (aBaseFeature)
387       isFullyRemoved = SketchSolver_Storage::removeEntity(aBaseFeature) && isFullyRemoved;
388     else
389       isFullyRemoved = SketchSolver_Storage::removeEntity((*anIt)->baseAttribute()) && isFullyRemoved;
390   }
391   return isFullyRemoved;
392 }
393
394 bool SketchSolver_Storage::remove(EntityWrapperPtr theEntity)
395 {
396   bool isFullyRemoved = true;
397   std::list<EntityWrapperPtr>::const_iterator anEntIt = theEntity->subEntities().begin();
398   for (; anEntIt != theEntity->subEntities().end(); ++anEntIt) {
399     FeaturePtr aBaseFeature = (*anEntIt)->baseFeature();
400     if (aBaseFeature)
401       isFullyRemoved = SketchSolver_Storage::removeEntity(aBaseFeature) && isFullyRemoved;
402     else
403       isFullyRemoved = SketchSolver_Storage::removeEntity((*anEntIt)->baseAttribute()) && isFullyRemoved;
404   }
405
406   std::list<ParameterWrapperPtr>::const_iterator aParIt = theEntity->parameters().begin();
407   for (; aParIt != theEntity->parameters().end(); ++aParIt)
408     isFullyRemoved = remove(*aParIt) && isFullyRemoved;
409   return isFullyRemoved;
410 }
411
412
413 bool SketchSolver_Storage::isInteract(const FeaturePtr& theFeature) const
414 {
415   if (!theFeature)
416     return false;
417   if (myConstraintMap.empty())
418     return true; // empty storage interacts with each feature
419
420   ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
421   if (aConstraint) {
422     if (myConstraintMap.find(aConstraint) != myConstraintMap.end())
423       return true;
424   } else if (myFeatureMap.find(theFeature) != myFeatureMap.end())
425     return true;
426
427   std::list<AttributePtr> anAttrList = theFeature->data()->attributes(std::string());
428   std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
429   for (; anIt != anAttrList.end(); ++anIt)
430     if (isInteract(*anIt))
431       return true;
432
433   return false;
434 }
435
436 bool SketchSolver_Storage::isInteract(const AttributePtr& theAttribute) const
437 {
438   if (!theAttribute)
439     return false;
440
441   AttributeRefListPtr aRefList = 
442       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
443   if (aRefList) {
444     std::list<ObjectPtr> anObjects = aRefList->list();
445     std::list<ObjectPtr>::iterator anObjIt = anObjects.begin();
446     for (; anObjIt != anObjects.end(); ++anObjIt) {
447       FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt);
448       if (isInteract(aFeature))
449         return true;
450     }
451     return false;
452   }
453
454   AttributeRefAttrPtr aRefAttr =
455       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
456   if (!aRefAttr)
457     return myAttributeMap.find(theAttribute) != myAttributeMap.end();
458   if (!aRefAttr->isObject())
459     return myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end();
460
461   FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
462   return isInteract(aFeature);
463 }
464
465 bool SketchSolver_Storage::isConsistent() const
466 {
467   // Check the constraints are valid
468   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
469       aCIter = myConstraintMap.begin();
470   for (; aCIter != myConstraintMap.end(); ++aCIter)
471     if (!aCIter->first->data() || !aCIter->first->data()->isValid())
472       return false;
473   // Check the features are valid
474   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
475   for (; aFIter != myFeatureMap.end(); aFIter++)
476     if (!aFIter->first->data() || !aFIter->first->data()->isValid())
477       return false;
478   return true;
479 }
480
481 bool SketchSolver_Storage::isFixed(EntityWrapperPtr theEntity) const
482 {
483   if (theEntity->group() != myGroupID)
484     return true;
485   // no need additional checking for entities differ than point
486   if (theEntity->type() != ENTITY_POINT)
487     return false;
488
489   CoincidentPointsMap::const_iterator anIt = myCoincidentPoints.begin();
490   for (; anIt != myCoincidentPoints.end(); ++anIt)
491     if (anIt->first == theEntity || anIt->second.find(theEntity) != anIt->second.end()) {
492       if (anIt->first->group() != myGroupID)
493         return true;
494       std::set<EntityWrapperPtr>::const_iterator anEntIt = anIt->second.begin();
495       for (; anEntIt != anIt->second.end(); ++anEntIt)
496         if ((*anEntIt)->group() != myGroupID)
497           return true;
498     }
499
500   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator aCIt = myConstraintMap.begin();
501   std::list<ConstraintWrapperPtr>::const_iterator aCWIt;
502   for (; aCIt != myConstraintMap.end(); ++aCIt) {
503     if (aCIt->second.empty())
504       continue;
505     aCWIt = aCIt->second.begin();
506     if ((*aCWIt)->type() != CONSTRAINT_FIXED)
507       continue;
508     for (; aCWIt != aCIt->second.end(); ++aCIt)
509       if ((theEntity->baseAttribute() && (*aCWIt)->isUsed(theEntity->baseAttribute())) ||
510           (theEntity->baseFeature() && (*aCWIt)->isUsed(theEntity->baseFeature())))
511         return true;
512   }
513
514   return false;
515 }
516
517 void SketchSolver_Storage::removeInvalidEntities()
518 {
519   // Remove invalid constraints
520   std::list<ConstraintPtr> anInvalidConstraints;
521   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
522       aCIter = myConstraintMap.begin();
523   for (; aCIter != myConstraintMap.end(); ++aCIter)
524     if (!aCIter->first->data() || !aCIter->first->data()->isValid())
525       anInvalidConstraints.push_back(aCIter->first);
526   std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
527   for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
528     removeConstraint(*anInvCIt);
529   // Remove invalid features
530   std::list<FeaturePtr> anInvalidFeatures;
531   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
532   for (; aFIter != myFeatureMap.end(); aFIter++)
533     if (!aFIter->first->data() || !aFIter->first->data()->isValid())
534       anInvalidFeatures.push_back(aFIter->first);
535   std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
536   for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
537     removeEntity(*anInvFIt);
538 }
539
540 EntityWrapperPtr SketchSolver_Storage::getNormal() const
541 {
542   EntityWrapperPtr aSketch = sketch();
543   if (!aSketch)
544     return aSketch;
545
546   // Find normal entity
547   const std::list<EntityWrapperPtr>& aSketchSubs = aSketch->subEntities();
548   std::list<EntityWrapperPtr>::const_iterator aSIt = aSketchSubs.begin();
549   for (; aSIt != aSketchSubs.end(); ++aSIt)
550     if ((*aSIt)->type() == ENTITY_NORMAL)
551       return *aSIt;
552   return EntityWrapperPtr();
553 }
554
555 const EntityWrapperPtr& SketchSolver_Storage::sketch() const
556 {
557   static EntityWrapperPtr aDummySketch;
558
559   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
560   for (; aFIt != myFeatureMap.end(); ++aFIt)
561     if (aFIt->second && aFIt->second->type() == ENTITY_SKETCH)
562       break;
563   if (aFIt == myFeatureMap.end())
564     return aDummySketch;
565   return aFIt->second;
566 }
567
568 void SketchSolver_Storage::setSketch(const EntityWrapperPtr& theSketch)
569 {
570   if (sketch())
571     return;
572   addEntity(FeaturePtr(), theSketch);
573 }
574
575 void SketchSolver_Storage::blockEvents(bool isBlocked)
576 {
577   if (isBlocked == myEventsBlocked)
578     return;
579
580   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
581       aCIter = myConstraintMap.begin();
582   for (; aCIter != myConstraintMap.end(); aCIter++)
583     if (aCIter->first->data() && aCIter->first->data()->isValid())
584       aCIter->first->data()->blockSendAttributeUpdated(isBlocked);
585
586   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
587   for (; aFIter != myFeatureMap.end(); aFIter++)
588     if (aFIter->first->data() && aFIter->first->data()->isValid())
589       aFIter->first->data()->blockSendAttributeUpdated(isBlocked);
590
591   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAtIter = myAttributeMap.begin();
592   for (; anAtIter != myAttributeMap.end(); anAtIter++)
593     if (anAtIter->first->owner() && anAtIter->first->owner()->data() &&
594         anAtIter->first->owner()->data()->isValid())
595       anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked);
596   myEventsBlocked = isBlocked;
597 }
598
599
600
601
602
603
604 // ==============   Auxiliary functions   ====================================
605 bool isEqual(const std::list<ConstraintWrapperPtr>& theCVec1,
606              const std::list<ConstraintWrapperPtr>& theCVec2)
607 {
608   if (theCVec1.size() != theCVec2.size())
609     return false;
610
611   std::list<bool> aChecked(theCVec2.size(), false);
612   std::list<ConstraintWrapperPtr>::const_iterator anIt1 = theCVec1.begin();
613   for (; anIt1 != theCVec1.end(); ++anIt1) {
614     std::list<ConstraintWrapperPtr>::const_iterator anIt2 = theCVec2.begin();
615     std::list<bool>::iterator aCheckIt = aChecked.begin();
616     while (aCheckIt != aChecked.end() && *aCheckIt) {
617       ++aCheckIt;
618       ++anIt2;
619     }
620     for (; anIt2 != theCVec2.end(); ++anIt2, ++aCheckIt)
621       if (!(*aCheckIt) && (*anIt1)->isEqual(*anIt2)) {
622         *aCheckIt = true;
623         break;
624       }
625     // the same constraint is not found
626     if (anIt2 == theCVec2.end())
627       return false;
628   }
629   return true;
630 }