Salome HOME
Merge remote-tracking branch 'remotes/origin/master' into azv/SketchSolver_Refactoring
[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 <PlaneGCSSolver_UpdateCoincidence.h>
9 #include <PlaneGCSSolver_UpdateFeature.h>
10
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 SketchSolver_Storage::SketchSolver_Storage(SolverPtr theSolver)
24   : mySketchSolver(theSolver),
25     myNeedToResolve(false),
26     myEventsBlocked(false)
27 {
28   // create updaters (constraints processed at first)
29   UpdaterPtr aFeatureUpdater(new PlaneGCSSolver_UpdateFeature);
30   myUpdaters = UpdaterPtr(new PlaneGCSSolver_UpdateCoincidence(aFeatureUpdater));
31 }
32
33 void SketchSolver_Storage::addConstraint(ConstraintPtr        theConstraint,
34                                          ConstraintWrapperPtr theSolverConstraint)
35 {
36   std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
37       aFound = myConstraintMap.find(theConstraint);
38   if (aFound == myConstraintMap.end() || aFound->second != theSolverConstraint)
39     setNeedToResolve(true);
40
41 ////  if (theSolverConstraints.empty()) {
42 ////    // constraint links to the empty list, add its attributes linked to the empty entities
43 ////    std::list<AttributePtr> aRefAttrs =
44 ////        theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
45 ////    std::list<AttributePtr>::const_iterator anAttrIt = aRefAttrs.begin();
46 ////    for (; anAttrIt != aRefAttrs.end(); ++anAttrIt) {
47 ////      AttributeRefAttrPtr aRef =
48 ////          std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIt);
49 ////      if (aRef->isObject()) {
50 ////        FeaturePtr aFeature = ModelAPI_Feature::feature(aRef->object());
51 ////        if (aFeature) addEntity(aFeature, EntityWrapperPtr());
52 ////      } else
53 ////        addEntity(aRef->attr(), EntityWrapperPtr());
54 ////    }
55 ////    std::list<AttributePtr> aRefLists =
56 ////        theConstraint->data()->attributes(ModelAPI_AttributeRefList::typeId());
57 ////    for (anAttrIt = aRefLists.begin(); anAttrIt != aRefLists.end(); ++anAttrIt) {
58 ////      AttributeRefListPtr aRef =
59 ////          std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrIt);
60 ////      std::list<ObjectPtr> anObj = aRef->list();
61 ////      std::list<ObjectPtr>::iterator anIt = anObj.begin();
62 ////      for (; anIt != anObj.end(); ++anIt) {
63 ////        FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
64 ////        if (aFeature) addEntity(aFeature, EntityWrapperPtr());
65 ////      }
66 ////    }
67 ////  }
68 ////  else if (theSolverConstraints.front()->type() != CONSTRAINT_PT_PT_COINCIDENT) {
69 ////    // Do not add point-point coincidence, because it is already made by setting
70 ////    // the same parameters for both points
71 ////    std::list<ConstraintWrapperPtr>::iterator aCIt = theSolverConstraints.begin();
72 ////    for (; aCIt != theSolverConstraints.end(); ++aCIt)
73 ////      update(*aCIt);
74 ////  }
75
76   if (!theSolverConstraint || aFound == myConstraintMap.end())
77     myConstraintMap[theConstraint] = theSolverConstraint;
78   // block events if necessary
79   if (myEventsBlocked && theConstraint && theConstraint->data() && theConstraint->data()->isValid())
80     theConstraint->data()->blockSendAttributeUpdated(myEventsBlocked);
81 }
82
83 static std::list<AttributePtr> pointAttributes(FeaturePtr theFeature)
84 {
85   std::list<AttributePtr> aPoints;
86   if (!theFeature->data() || !theFeature->data()->isValid())
87     return 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            theFeature->getKind() == SketchPlugin_IntersectionPoint::ID())
101     aPoints.push_back(theFeature->attribute(SketchPlugin_Point::COORD_ID()));
102   return aPoints;
103 }
104
105 void SketchSolver_Storage::addEntity(FeaturePtr       theFeature,
106                                      EntityWrapperPtr theSolverEntity)
107 {
108   if (theSolverEntity) {
109     myFeatureMap[theFeature] = theSolverEntity;
110     setNeedToResolve(true);
111   } else {
112     // feature links to the empty entity, add its attributes
113     std::list<AttributePtr> aPntAttrs = pointAttributes(theFeature);
114     std::list<AttributePtr>::const_iterator anAttrIt = aPntAttrs.begin();
115     for (; anAttrIt != aPntAttrs.end(); ++anAttrIt)
116       addEntity(*anAttrIt, EntityWrapperPtr());
117     myFeatureMap[theFeature] = theSolverEntity;
118   }
119
120   // block events if necessary
121   if (myEventsBlocked && theFeature->data() && theFeature->data()->isValid())
122     theFeature->data()->blockSendAttributeUpdated(myEventsBlocked);
123 }
124
125 void SketchSolver_Storage::addEntity(AttributePtr     theAttribute,
126                                      EntityWrapperPtr theSolverEntity)
127 {
128   if (theSolverEntity) {
129     myAttributeMap[theAttribute] = theSolverEntity;
130     setNeedToResolve(true);
131   }
132
133   // block events if necessary
134   if (myEventsBlocked && theAttribute->owner() &&
135       theAttribute->owner()->data() && theAttribute->owner()->data()->isValid())
136     theAttribute->owner()->data()->blockSendAttributeUpdated(myEventsBlocked);
137 }
138
139
140
141 const ConstraintWrapperPtr& SketchSolver_Storage::constraint(
142     const ConstraintPtr& theConstraint) const
143 {
144   static ConstraintWrapperPtr aDummy;
145
146   std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
147       aFound = myConstraintMap.find(theConstraint);
148   if (aFound != myConstraintMap.end())
149     return aFound->second;
150   return aDummy;
151 }
152
153 const EntityWrapperPtr& SketchSolver_Storage::entity(const FeaturePtr& theFeature) const
154 {
155   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFound = myFeatureMap.find(theFeature);
156   if (aFound != myFeatureMap.end())
157     return aFound->second;
158
159   static EntityWrapperPtr aDummy;
160   return aDummy;
161 }
162
163 const EntityWrapperPtr& SketchSolver_Storage::entity(const AttributePtr& theAttribute) const
164 {
165   std::map<AttributePtr, EntityWrapperPtr>::const_iterator
166       aFound = myAttributeMap.find(theAttribute);
167   if (aFound != myAttributeMap.end())
168     return aFound->second;
169
170   AttributeRefAttrPtr aRefAttr =
171       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
172   if (aRefAttr) {
173     AttributePtr anAttribute;
174
175     if (aRefAttr->isObject()) {
176       /// TODO: Check resultToFeatureOrAttribute() precisely. Create additional unit-test
177       FeaturePtr aFeature;
178       resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute);
179       if (aFeature)
180         return entity(aFeature);
181     } else
182       anAttribute = aRefAttr->attr();
183
184     return entity(anAttribute);
185   }
186
187   static EntityWrapperPtr aDummy;
188   return aDummy;
189 }
190
191
192 void SketchSolver_Storage::removeFeature(FeaturePtr theFeature)
193 {
194   myFeatureMap.erase(theFeature);
195 }
196
197 void SketchSolver_Storage::removeAttribute(AttributePtr theAttribute)
198 {
199   myAttributeMap.erase(theAttribute);
200 }
201
202
203 bool SketchSolver_Storage::isConsistent() const
204 {
205   // Check the constraints are valid
206   std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
207       aCIter = myConstraintMap.begin();
208   for (; aCIter != myConstraintMap.end(); ++aCIter)
209     if (!aCIter->first->data() || !aCIter->first->data()->isValid())
210       return false;
211   // Check the features are valid
212   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
213   for (; aFIter != myFeatureMap.end(); aFIter++)
214     if (!aFIter->first->data() || !aFIter->first->data()->isValid())
215       return false;
216   return true;
217 }
218
219 void SketchSolver_Storage::blockEvents(bool isBlocked)
220 {
221   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
222   for (; aFIter != myFeatureMap.end(); aFIter++)
223     if (aFIter->first->data() && aFIter->first->data()->isValid())
224       aFIter->first->data()->blockSendAttributeUpdated(isBlocked);
225
226   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAtIter = myAttributeMap.begin();
227   for (; anAtIter != myAttributeMap.end(); anAtIter++)
228     if (anAtIter->first->owner() && anAtIter->first->owner()->data() &&
229         anAtIter->first->owner()->data()->isValid())
230       anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked);
231
232   myEventsBlocked = isBlocked;
233 }
234
235 std::set<ObjectPtr> SketchSolver_Storage::getConflictingConstraints(SolverPtr theSolver) const
236 {
237   std::set<ObjectPtr> aConflicting;
238   std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
239       aConstrIt = myConstraintMap.begin();
240   for (; aConstrIt != myConstraintMap.end(); ++aConstrIt) {
241     if (theSolver->isConflicting(aConstrIt->second->id())) {
242       aConflicting.insert(aConstrIt->first);
243       break;
244     }
245   }
246   return aConflicting;
247 }
248
249 void SketchSolver_Storage::subscribeUpdates(
250     SketchSolver_Constraint* theSubscriber, const std::string& theGroup) const
251 {
252   myUpdaters->attach(theSubscriber, theGroup);
253 }
254
255 void SketchSolver_Storage::unsubscribeUpdates(SketchSolver_Constraint* theSubscriber) const
256 {
257   myUpdaters->detach(theSubscriber);
258 }
259
260 void SketchSolver_Storage::notify(const FeaturePtr & theFeature) const
261 {
262   myUpdaters->update(theFeature);
263 }
264
265 void SketchSolver_Storage::resultToFeatureOrAttribute(const ObjectPtr& theResult,
266     FeaturePtr& theFeature, AttributePtr& theAttribute)
267 {
268   FeaturePtr aFeature = ModelAPI_Feature::feature(theResult);
269   if (!aFeature)
270     return;
271
272   // if the feature has several results, we choose which one is referred
273   const std::list<ResultPtr>& aResults = aFeature->results();
274   if (aResults.size() > 1 && theResult != aFeature->lastResult()) {
275     // actually, the attribute refers to center of arc or circle,
276     // but not the edge, get correct attributes
277     std::string anAttrName;
278     if (aFeature->getKind() == SketchPlugin_Arc::ID())
279       anAttrName = SketchPlugin_Arc::CENTER_ID();
280     else if (aFeature->getKind() == SketchPlugin_Circle::ID())
281       anAttrName = SketchPlugin_Circle::CENTER_ID();
282     if (!anAttrName.empty()) {
283       theAttribute = aFeature->attribute(anAttrName);
284       aFeature = FeaturePtr();
285     }
286   }
287   theFeature = aFeature;
288 }