]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SketchSolver_Storage.cpp
Salome HOME
Issue #1578: arc problems
[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(ConstraintPtr theConstraint, AttributePtr theAttribute)
363 {
364   if (!theConstraint || !theAttribute)
365     return false;
366   std::list<AttributePtr> anAttrList = theConstraint->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(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 aRefAttrA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
509           aConstrIt->first->attribute(SketchPlugin_Constraint::ENTITY_A()));
510       AttributeRefAttrPtr aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
511           aConstrIt->first->attribute(SketchPlugin_Constraint::ENTITY_B()));
512       AttributePtr anAttrA, anAttrB;
513       if (aConstrIt->first->data()->isValid()) {
514         if (!aRefAttrA || !aRefAttrB || aRefAttrA->isObject() || aRefAttrB->isObject())
515           continue;
516         anAttrA = aRefAttrA->attr();
517         anAttrB = aRefAttrB->attr();
518       } else {
519         // obtain attributes from the constraint wrapper
520         ConstraintWrapperPtr aWrapper = aConstrIt->second.front();
521         anAttrA = aWrapper->entities().front()->baseAttribute();
522         anAttrB = aWrapper->entities().back()->baseAttribute();
523       }
524       std::map<AttributePtr, EntityWrapperPtr>::iterator
525           aFound = myAttributeMap.find(anAttrA);
526       if (aFound != myAttributeMap.end())
527         aNotCoinc.erase(aFound->second);
528       aFound = myAttributeMap.find(anAttrB);
529       if (aFound != myAttributeMap.end())
530         aNotCoinc.erase(aFound->second);
531     }
532   if (aNotCoinc.empty())
533     return false;
534   std::list<EntityWrapperPtr>::const_iterator aNewPIt;
535   for (aPIt = aPoints.begin(), aNewPIt = aNewPoints.begin();
536        aPIt != aPoints.end(); ++aPIt, ++aNewPIt) {
537     if (aNotCoinc.find(*aPIt) != aNotCoinc.end())
538       aNotCoinc[*aPIt] = *aNewPIt;
539   }
540
541   // Find all features and constraints uses coincident points
542   std::map<EntityWrapperPtr, EntityWrapperPtr>::iterator aNotCIt;
543   std::set<EntityWrapperPtr> anUpdFeatures;
544   std::map<FeaturePtr, EntityWrapperPtr>::iterator aFIt = myFeatureMap.begin();
545   for (; aFIt != myFeatureMap.end(); ++aFIt) {
546     if (!aFIt->second)
547       continue; // avoid not completed arcs
548     for (aNotCIt = aNotCoinc.begin(); aNotCIt != aNotCoinc.end(); ++aNotCIt) {
549       if (!aNotCIt->second || !aFIt->second->isUsed(aNotCIt->first->baseAttribute()))
550         continue;
551       std::list<EntityWrapperPtr> aSubs = aFIt->second->subEntities();
552       std::list<EntityWrapperPtr>::iterator aSIt = aSubs.begin();
553       bool isUpd = false;
554       for (; aSIt != aSubs.end(); ++aSIt)
555         if (*aSIt == aNotCIt->first) {
556           *aSIt = aNotCIt->second;
557           isUpd = true;
558         }
559       if (isUpd) {
560         aFIt->second->setSubEntities(aSubs);
561         anUpdFeatures.insert(aFIt->second);
562       }
563     }
564   }
565   // update features
566   std::set<EntityWrapperPtr>::iterator anUpdIt = anUpdFeatures.begin();
567   for (; anUpdIt != anUpdFeatures.end(); ++anUpdIt)
568     update(EntityWrapperPtr(*anUpdIt));
569
570   // remove not coincident points
571   for (aNotCIt = aNotCoinc.begin(); aNotCIt != aNotCoinc.end(); ++aNotCIt) {
572     if (aPtPtIt->second.size() <= 1) {
573       myCoincidentPoints.erase(aPtPtIt);
574       break;
575     }
576     if (aPtPtIt->first == aNotCIt->first) {
577       std::set<EntityWrapperPtr> aSlaves = aPtPtIt->second;
578       EntityWrapperPtr aNewMaster = *aSlaves.begin();
579       aSlaves.erase(aSlaves.begin());
580       myCoincidentPoints.erase(aPtPtIt);
581       myCoincidentPoints[aNewMaster] = aSlaves;
582       aPtPtIt = myCoincidentPoints.find(aNewMaster);
583     } else
584       aPtPtIt->second.erase(aNotCIt->first);
585   }
586   return true;
587 }
588
589 bool SketchSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
590 {
591   bool isFullyRemoved = true;
592   std::list<EntityWrapperPtr>::const_iterator anIt = theConstraint->entities().begin();
593   for (; anIt != theConstraint->entities().end(); ++anIt) {
594     FeaturePtr aBaseFeature = (*anIt)->baseFeature();
595     if (aBaseFeature)
596       isFullyRemoved = SketchSolver_Storage::removeEntity(aBaseFeature) && isFullyRemoved;
597     else
598       isFullyRemoved = SketchSolver_Storage::removeEntity((*anIt)->baseAttribute()) && isFullyRemoved;
599   }
600   return isFullyRemoved;
601 }
602
603 bool SketchSolver_Storage::remove(EntityWrapperPtr theEntity)
604 {
605   bool isFullyRemoved = true;
606   std::list<EntityWrapperPtr>::const_iterator anEntIt = theEntity->subEntities().begin();
607   for (; anEntIt != theEntity->subEntities().end(); ++anEntIt) {
608     FeaturePtr aBaseFeature = (*anEntIt)->baseFeature();
609     if (aBaseFeature)
610       isFullyRemoved = SketchSolver_Storage::removeEntity(aBaseFeature) && isFullyRemoved;
611     else {
612       AttributePtr aBaseAttr = (*anEntIt)->baseAttribute();
613       if (aBaseAttr)
614         isFullyRemoved = SketchSolver_Storage::removeEntity(aBaseAttr) && isFullyRemoved;
615       else
616         remove(*anEntIt);
617     }
618   }
619
620   std::list<ParameterWrapperPtr>::const_iterator aParIt = theEntity->parameters().begin();
621   for (; aParIt != theEntity->parameters().end(); ++aParIt)
622     isFullyRemoved = remove(*aParIt) && isFullyRemoved;
623   return isFullyRemoved;
624 }
625
626
627 bool SketchSolver_Storage::isInteract(const FeaturePtr& theFeature) const
628 {
629   if (!theFeature)
630     return false;
631   if (myConstraintMap.empty())
632     return true; // empty storage interacts with each feature
633
634   ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
635   if (aConstraint) {
636     if (myConstraintMap.find(aConstraint) != myConstraintMap.end())
637       return true;
638   } else if (myFeatureMap.find(theFeature) != myFeatureMap.end())
639     return true;
640
641   std::list<AttributePtr> anAttrList = theFeature->data()->attributes(std::string());
642   std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
643   for (; anIt != anAttrList.end(); ++anIt)
644     if (isInteract(*anIt))
645       return true;
646
647   return false;
648 }
649
650 bool SketchSolver_Storage::isInteract(const AttributePtr& theAttribute) const
651 {
652   if (!theAttribute)
653     return false;
654
655   AttributeRefListPtr aRefList = 
656       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
657   if (aRefList) {
658     std::list<ObjectPtr> anObjects = aRefList->list();
659     std::list<ObjectPtr>::iterator anObjIt = anObjects.begin();
660     for (; anObjIt != anObjects.end(); ++anObjIt) {
661       FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt);
662       if (isInteract(aFeature))
663         return true;
664     }
665     return false;
666   }
667
668   AttributeRefAttrPtr aRefAttr =
669       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
670   if (!aRefAttr)
671     return myAttributeMap.find(theAttribute) != myAttributeMap.end();
672   if (!aRefAttr->isObject())
673     return myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end();
674
675   FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
676   return isInteract(aFeature);
677 }
678
679 bool SketchSolver_Storage::isConsistent() const
680 {
681   // Check the constraints are valid
682   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
683       aCIter = myConstraintMap.begin();
684   for (; aCIter != myConstraintMap.end(); ++aCIter)
685     if (!aCIter->first->data() || !aCIter->first->data()->isValid())
686       return false;
687   // Check the features are valid
688   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
689   for (; aFIter != myFeatureMap.end(); aFIter++)
690     if (!aFIter->first->data() || !aFIter->first->data()->isValid())
691       return false;
692   return true;
693 }
694
695 bool SketchSolver_Storage::isFixed(EntityWrapperPtr theEntity) const
696 {
697   if (theEntity->group() != myGroupID)
698     return true;
699   // no need additional checking for entities differ than point
700   if (theEntity->type() != ENTITY_POINT)
701     return false;
702
703   CoincidentPointsMap::const_iterator anIt = myCoincidentPoints.begin();
704   for (; anIt != myCoincidentPoints.end(); ++anIt)
705     if (anIt->first == theEntity || anIt->second.find(theEntity) != anIt->second.end()) {
706       if (anIt->first->group() != myGroupID)
707         return true;
708       std::set<EntityWrapperPtr>::const_iterator anEntIt = anIt->second.begin();
709       for (; anEntIt != anIt->second.end(); ++anEntIt)
710         if ((*anEntIt)->group() != myGroupID)
711           return true;
712     }
713
714   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator aCIt = myConstraintMap.begin();
715   std::list<ConstraintWrapperPtr>::const_iterator aCWIt;
716   for (; aCIt != myConstraintMap.end(); ++aCIt) {
717     if (aCIt->second.empty())
718       continue;
719     aCWIt = aCIt->second.begin();
720     if ((*aCWIt)->type() != CONSTRAINT_FIXED)
721       continue;
722     for (; aCWIt != aCIt->second.end(); ++aCIt)
723       if ((theEntity->baseAttribute() && (*aCWIt)->isUsed(theEntity->baseAttribute())) ||
724           (theEntity->baseFeature() && (*aCWIt)->isUsed(theEntity->baseFeature())))
725         return true;
726   }
727
728   return false;
729 }
730
731 void SketchSolver_Storage::removeInvalidEntities()
732 {
733   // Remove invalid constraints
734   std::list<ConstraintPtr> anInvalidConstraints;
735   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
736       aCIter = myConstraintMap.begin();
737   for (; aCIter != myConstraintMap.end(); ++aCIter)
738     if (!aCIter->first->data() || !aCIter->first->data()->isValid())
739       anInvalidConstraints.push_back(aCIter->first);
740   std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
741   for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
742     removeConstraint(*anInvCIt);
743   // Remove invalid features
744   std::list<FeaturePtr> anInvalidFeatures;
745   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
746   for (; aFIter != myFeatureMap.end(); aFIter++)
747     if (!aFIter->first->data() || !aFIter->first->data()->isValid())
748       anInvalidFeatures.push_back(aFIter->first);
749   std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
750   for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
751     removeEntity(*anInvFIt);
752 }
753
754 EntityWrapperPtr SketchSolver_Storage::getNormal() const
755 {
756   EntityWrapperPtr aSketch = sketch();
757   if (!aSketch)
758     return aSketch;
759
760   // Find normal entity
761   const std::list<EntityWrapperPtr>& aSketchSubs = aSketch->subEntities();
762   std::list<EntityWrapperPtr>::const_iterator aSIt = aSketchSubs.begin();
763   for (; aSIt != aSketchSubs.end(); ++aSIt)
764     if ((*aSIt)->type() == ENTITY_NORMAL)
765       return *aSIt;
766   return EntityWrapperPtr();
767 }
768
769 const EntityWrapperPtr& SketchSolver_Storage::sketch() const
770 {
771   static EntityWrapperPtr aDummySketch;
772
773   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
774   for (; aFIt != myFeatureMap.end(); ++aFIt)
775     if (aFIt->second && aFIt->second->type() == ENTITY_SKETCH)
776       break;
777   if (aFIt == myFeatureMap.end())
778     return aDummySketch;
779   return aFIt->second;
780 }
781
782 void SketchSolver_Storage::setSketch(const EntityWrapperPtr& theSketch)
783 {
784   if (sketch())
785     return;
786   addEntity(FeaturePtr(), theSketch);
787 }
788
789 void SketchSolver_Storage::processArcs()
790 {
791   myExistArc = false;
792   std::map<FeaturePtr, EntityWrapperPtr>::iterator aFIt = myFeatureMap.begin();
793   for (; aFIt != myFeatureMap.end(); ++aFIt)
794     if (!aFIt->second && aFIt->first->getKind() == SketchPlugin_Arc::ID()) {
795       // Additional checking the attributes are initialized
796       if (aFIt->first->attribute(SketchPlugin_Arc::CENTER_ID())->isInitialized() && 
797           aFIt->first->attribute(SketchPlugin_Arc::START_ID())->isInitialized() && 
798           aFIt->first->attribute(SketchPlugin_Arc::END_ID())->isInitialized())
799         update(aFIt->first);
800       else
801         myExistArc = true;
802     }
803 }
804
805 void SketchSolver_Storage::blockEvents(bool isBlocked)
806 {
807   if (isBlocked == myEventsBlocked)
808     return;
809
810   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
811       aCIter = myConstraintMap.begin();
812   for (; aCIter != myConstraintMap.end(); aCIter++)
813     if (aCIter->first->data() && aCIter->first->data()->isValid())
814       aCIter->first->data()->blockSendAttributeUpdated(isBlocked);
815
816   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
817   for (; aFIter != myFeatureMap.end(); aFIter++)
818     if (aFIter->first->data() && aFIter->first->data()->isValid())
819       aFIter->first->data()->blockSendAttributeUpdated(isBlocked);
820
821   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAtIter = myAttributeMap.begin();
822   for (; anAtIter != myAttributeMap.end(); anAtIter++)
823     if (anAtIter->first->owner() && anAtIter->first->owner()->data() &&
824         anAtIter->first->owner()->data()->isValid())
825       anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked);
826   myEventsBlocked = isBlocked;
827 }
828
829 std::set<ObjectPtr> SketchSolver_Storage::getConflictingConstraints(SolverPtr theSolver) const
830 {
831   std::set<ObjectPtr> aConflicting;
832   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
833       aConstrIt = myConstraintMap.begin();
834   for (; aConstrIt != myConstraintMap.end(); ++aConstrIt) {
835     std::list<ConstraintWrapperPtr>::const_iterator anIt = aConstrIt->second.begin();
836     for (; anIt != aConstrIt->second.end(); ++anIt)
837       if (theSolver->isConflicting((*anIt)->id())) {
838         aConflicting.insert(aConstrIt->first);
839         break;
840       }
841   }
842   return aConflicting;
843 }
844
845
846
847
848
849 // ==============   Auxiliary functions   ====================================
850 bool isEqual(const std::list<ConstraintWrapperPtr>& theCVec1,
851              const std::list<ConstraintWrapperPtr>& theCVec2)
852 {
853   if (theCVec1.size() != theCVec2.size())
854     return false;
855
856   std::list<bool> aChecked(theCVec2.size(), false);
857   std::list<ConstraintWrapperPtr>::const_iterator anIt1 = theCVec1.begin();
858   for (; anIt1 != theCVec1.end(); ++anIt1) {
859     std::list<ConstraintWrapperPtr>::const_iterator anIt2 = theCVec2.begin();
860     std::list<bool>::iterator aCheckIt = aChecked.begin();
861     while (aCheckIt != aChecked.end() && *aCheckIt) {
862       ++aCheckIt;
863       ++anIt2;
864     }
865     for (; anIt2 != theCVec2.end(); ++anIt2, ++aCheckIt)
866       if (!(*aCheckIt) && (*anIt1)->isEqual(*anIt2)) {
867         *aCheckIt = true;
868         break;
869       }
870     // the same constraint is not found
871     if (anIt2 == theCVec2.end())
872       return false;
873   }
874   return true;
875 }