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