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