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