Salome HOME
Issue #2073: Fatal error when mirror
[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::areFeaturesValid() const
204 {
205   // Check the features are valid
206   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
207   for (; aFIter != myFeatureMap.end(); aFIter++)
208     if (!aFIter->first->data() || !aFIter->first->data()->isValid())
209       return false;
210   return true;
211 }
212
213 void SketchSolver_Storage::blockEvents(bool isBlocked)
214 {
215   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
216   for (; aFIter != myFeatureMap.end(); aFIter++)
217     if (aFIter->first->data() && aFIter->first->data()->isValid())
218       aFIter->first->data()->blockSendAttributeUpdated(isBlocked);
219
220   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAtIter = myAttributeMap.begin();
221   for (; anAtIter != myAttributeMap.end(); anAtIter++)
222     if (anAtIter->first->owner() && anAtIter->first->owner()->data() &&
223         anAtIter->first->owner()->data()->isValid())
224       anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked);
225
226   myEventsBlocked = isBlocked;
227 }
228
229 std::set<ObjectPtr> SketchSolver_Storage::getConflictingConstraints(SolverPtr theSolver) const
230 {
231   std::set<ObjectPtr> aConflicting;
232   std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
233       aConstrIt = myConstraintMap.begin();
234   for (; aConstrIt != myConstraintMap.end(); ++aConstrIt) {
235     if (theSolver->isConflicting(aConstrIt->second->id()))
236       aConflicting.insert(aConstrIt->first);
237   }
238   return aConflicting;
239 }
240
241 void SketchSolver_Storage::subscribeUpdates(
242     SketchSolver_Constraint* theSubscriber, const std::string& theGroup) const
243 {
244   myUpdaters->attach(theSubscriber, theGroup);
245 }
246
247 void SketchSolver_Storage::unsubscribeUpdates(SketchSolver_Constraint* theSubscriber) const
248 {
249   myUpdaters->detach(theSubscriber);
250 }
251
252 void SketchSolver_Storage::notify(const FeaturePtr & theFeature) const
253 {
254   myUpdaters->update(theFeature);
255 }
256
257 void SketchSolver_Storage::resultToFeatureOrAttribute(const ObjectPtr& theResult,
258     FeaturePtr& theFeature, AttributePtr& theAttribute)
259 {
260   FeaturePtr aFeature = ModelAPI_Feature::feature(theResult);
261   if (!aFeature)
262     return;
263
264   // if the feature has several results, we choose which one is referred
265   const std::list<ResultPtr>& aResults = aFeature->results();
266   if (aResults.size() > 1 && theResult != aFeature->lastResult()) {
267     // actually, the attribute refers to center of arc or circle,
268     // but not the edge, get correct attributes
269     std::string anAttrName;
270     if (aFeature->getKind() == SketchPlugin_Arc::ID())
271       anAttrName = SketchPlugin_Arc::CENTER_ID();
272     else if (aFeature->getKind() == SketchPlugin_Circle::ID())
273       anAttrName = SketchPlugin_Circle::CENTER_ID();
274     if (!anAttrName.empty()) {
275       theAttribute = aFeature->attribute(anAttrName);
276       aFeature = FeaturePtr();
277     }
278   }
279   theFeature = aFeature;
280 }