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