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