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