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