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