Salome HOME
First phase of 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 <SketchSolver_Manager.h>
9
10 #include <GeomDataAPI_Point2D.h>
11 #include <ModelAPI_AttributeRefAttr.h>
12 #include <SketchPlugin_Arc.h>
13 #include <SketchPlugin_Circle.h>
14
15
16 /// \brief Verify two vectors of constraints are equal.
17 ///        Vectors differ by the order of elements are equal.
18 static bool isEqual(const std::list<ConstraintWrapperPtr>& theCVec1,
19                     const std::list<ConstraintWrapperPtr>& theCVec2);
20
21
22 void SketchSolver_Storage::addConstraint(ConstraintPtr        theConstraint,
23                                          ConstraintWrapperPtr theSolverConstraint)
24 {
25   std::list<ConstraintWrapperPtr> aConstrList(1, theSolverConstraint);
26   addConstraint(theConstraint, aConstrList);
27 }
28
29 void SketchSolver_Storage::addConstraint(
30     ConstraintPtr                   theConstraint,
31     std::list<ConstraintWrapperPtr> theSolverConstraints)
32 {
33   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
34       aFound = myConstraintMap.find(theConstraint);
35   if (aFound == myConstraintMap.end() || !isEqual(aFound->second, theSolverConstraints))
36     setNeedToResolve(true);
37
38   // Do not add point-point coincidence, because it is already made by setting
39   // the same parameters for both points
40   if (!theSolverConstraints.empty() &&
41       theSolverConstraints.front()->type() != CONSTRAINT_PT_PT_COINCIDENT) {
42     std::list<ConstraintWrapperPtr>::iterator aCIt = theSolverConstraints.begin();
43     for (; aCIt != theSolverConstraints.end(); ++aCIt)
44       update(*aCIt);
45   }
46   myConstraintMap[theConstraint] = theSolverConstraints;
47 }
48
49 void SketchSolver_Storage::addEntity(FeaturePtr       theFeature,
50                                      EntityWrapperPtr theSolverEntity)
51 {
52   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFound = myFeatureMap.find(theFeature);
53   if (aFound == myFeatureMap.end() || !aFound->second->isEqual(theSolverEntity))
54     setNeedToResolve(true); // the entity is new or modified
55
56   myFeatureMap[theFeature] = theSolverEntity;
57 }
58
59 void SketchSolver_Storage::addEntity(AttributePtr     theAttribute,
60                                      EntityWrapperPtr theSolverEntity)
61 {
62   std::map<AttributePtr, EntityWrapperPtr>::const_iterator aFound = myAttributeMap.find(theAttribute);
63   if (aFound == myAttributeMap.end() || !aFound->second->isEqual(theSolverEntity))
64     setNeedToResolve(true); // the entity is new or modified
65
66   myAttributeMap[theAttribute] = theSolverEntity;
67 }
68
69
70 bool SketchSolver_Storage::update(FeaturePtr theFeature, const GroupID& theGroup)
71 {
72   bool isUpdated = false;
73   EntityWrapperPtr aRelated = entity(theFeature);
74   if (!aRelated) { // Feature is not exist, create it
75     std::list<EntityWrapperPtr> aSubs;
76     // Firstly, create/update its attributes
77     std::list<AttributePtr> anAttrs =
78         theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
79     std::list<AttributePtr>::const_iterator anIt = anAttrs.begin();
80     for (; anIt != anAttrs.end(); ++anIt) {
81       isUpdated = update(*anIt, theGroup) || isUpdated;
82       aSubs.push_back(entity(*anIt));
83     }
84     // If the feature is a circle, add its radius as a sub
85     if (theFeature->getKind() == SketchPlugin_Circle::ID()) {
86       AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
87       isUpdated = update(aRadius, theGroup) || isUpdated;
88       aSubs.push_back(entity(aRadius));
89     }
90     // If the feature if circle or arc, we need to add normal of the sketch to the list of subs
91     if (theFeature->getKind() == SketchPlugin_Arc::ID() ||
92         theFeature->getKind() == SketchPlugin_Circle::ID()) {
93       EntityWrapperPtr aNormal = getNormal();
94       if (aNormal) aSubs.push_back(aNormal);
95     }
96     // Secondly, convert feature
97     BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
98     aRelated = aBuilder->createFeature(theFeature, aSubs, theGroup);
99     if (!aRelated)
100       return false;
101     addEntity(theFeature, aRelated);
102   } else if (theGroup != GID_UNKNOWN)
103     changeGroup(aRelated, theGroup);
104   return update(aRelated) || isUpdated;
105 }
106
107 bool SketchSolver_Storage::update(AttributePtr theAttribute, const GroupID& theGroup)
108 {
109   AttributePtr anAttribute = theAttribute;
110   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
111   if (aRefAttr) {
112     if (aRefAttr->isObject()) {
113       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
114       return update(aFeature, theGroup);
115     } else
116       anAttribute = aRefAttr->attr();
117   }
118
119   EntityWrapperPtr aRelated = entity(anAttribute);
120   if (!aRelated) { // Attribute is not exist, create it
121     BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
122     aRelated = aBuilder->createAttribute(anAttribute, theGroup);
123     if (!aRelated)
124       return false;
125     addEntity(anAttribute, aRelated);
126   } else if (theGroup != GID_UNKNOWN)
127     changeGroup(aRelated, theGroup);
128   return update(aRelated);
129 }
130
131
132
133 const std::list<ConstraintWrapperPtr>& SketchSolver_Storage::constraint(
134     const ConstraintPtr& theConstraint) const
135 {
136   static std::list<ConstraintWrapperPtr> aDummy;
137
138   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr>>::const_iterator
139       aFound = myConstraintMap.find(theConstraint);
140   if (aFound != myConstraintMap.end())
141     return aFound->second;
142   return aDummy;
143 }
144
145 const EntityWrapperPtr& SketchSolver_Storage::entity(const FeaturePtr& theFeature) const
146 {
147   static EntityWrapperPtr aDummy;
148
149   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFound = myFeatureMap.find(theFeature);
150   if (aFound != myFeatureMap.end())
151     return aFound->second;
152   return aDummy;
153 }
154
155 const EntityWrapperPtr& SketchSolver_Storage::entity(const AttributePtr& theAttribute) const
156 {
157   static EntityWrapperPtr aDummy;
158
159   std::map<AttributePtr, EntityWrapperPtr>::const_iterator
160       aFound = myAttributeMap.find(theAttribute);
161   if (aFound != myAttributeMap.end())
162     return aFound->second;
163
164   AttributeRefAttrPtr aRefAttr =
165       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
166   if (aRefAttr) {
167     if (aRefAttr->isObject()) {
168       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
169       return entity(aFeature);
170     } else
171       return entity(aRefAttr->attr());
172   }
173   return aDummy;
174 }
175
176 bool SketchSolver_Storage::isInteract(const FeaturePtr& theFeature) const
177 {
178   if (!theFeature)
179     return false;
180   if (myConstraintMap.empty())
181     return true; // empty storage interacts with each feature
182
183   ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
184   if (aConstraint) {
185     if (myConstraintMap.find(aConstraint) != myConstraintMap.end())
186       return true;
187   } else if (myFeatureMap.find(theFeature) != myFeatureMap.end())
188     return true;
189
190   std::list<AttributePtr> anAttrList = theFeature->data()->attributes(std::string());
191   std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
192   for (; anIt != anAttrList.end(); ++anIt)
193     if (isInteract(*anIt))
194       return true;
195
196   return false;
197 }
198
199 bool SketchSolver_Storage::isInteract(const AttributePtr& theAttribute) const
200 {
201   if (!theAttribute)
202     return false;
203
204   AttributeRefAttrPtr aRefAttr =
205       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
206   if (!aRefAttr)
207     return myAttributeMap.find(theAttribute) != myAttributeMap.end();
208   if (!aRefAttr->isObject())
209     return myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end();
210
211   FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
212   return isInteract(aFeature);
213 }
214
215 bool SketchSolver_Storage::isConsistent() const
216 {
217   // Check the constraints are valid
218   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
219       aCIter = myConstraintMap.begin();
220   for (; aCIter != myConstraintMap.end(); ++aCIter)
221     if (!aCIter->first->data() || !aCIter->first->data()->isValid())
222       return false;
223   // Check the features are valid
224   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
225   for (; aFIter != myFeatureMap.end(); aFIter++)
226     if (!aFIter->first->data() || !aFIter->first->data()->isValid())
227       return false;
228   return true;
229 }
230
231 void SketchSolver_Storage::removeInvalidEntities()
232 {
233   // Remove invalid constraints
234   std::list<ConstraintPtr> anInvalidConstraints;
235   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
236       aCIter = myConstraintMap.begin();
237   for (; aCIter != myConstraintMap.end(); ++aCIter)
238     if (!aCIter->first->data() || !aCIter->first->data()->isValid())
239       anInvalidConstraints.push_back(aCIter->first);
240   std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
241   for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
242     removeConstraint(*anInvCIt);
243   // Remove invalid features
244   std::list<FeaturePtr> anInvalidFeatures;
245   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
246   for (; aFIter != myFeatureMap.end(); aFIter++)
247     if (!aFIter->first->data() || !aFIter->first->data()->isValid())
248       anInvalidFeatures.push_back(aFIter->first);
249   std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
250   for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
251     removeEntity(*anInvFIt);
252 }
253
254 EntityWrapperPtr SketchSolver_Storage::getNormal() const
255 {
256   EntityWrapperPtr aSketch = sketch();
257   if (!aSketch)
258     return aSketch;
259
260   // Find normal entity
261   const std::list<EntityWrapperPtr>& aSketchSubs = aSketch->subEntities();
262   std::list<EntityWrapperPtr>::const_iterator aSIt = aSketchSubs.begin();
263   for (; aSIt != aSketchSubs.end(); ++aSIt)
264     if ((*aSIt)->type() == ENTITY_NORMAL)
265       return *aSIt;
266   return EntityWrapperPtr();
267 }
268
269 const EntityWrapperPtr& SketchSolver_Storage::sketch() const
270 {
271   static EntityWrapperPtr aDummySketch;
272
273   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
274   for (; aFIt != myFeatureMap.end(); ++aFIt)
275     if (aFIt->second->type() == ENTITY_SKETCH)
276       break;
277   if (aFIt == myFeatureMap.end())
278     return aDummySketch;
279   return aFIt->second;
280 }
281
282 void SketchSolver_Storage::setSketch(const EntityWrapperPtr& theSketch)
283 {
284   if (sketch())
285     return;
286   addEntity(FeaturePtr(), theSketch);
287 }
288
289 void SketchSolver_Storage::blockEvents(bool isBlocked) const
290 {
291   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
292       aCIter = myConstraintMap.begin();
293   for (; aCIter != myConstraintMap.end(); aCIter++)
294     if (aCIter->first->data() && aCIter->first->data()->isValid())
295       aCIter->first->data()->blockSendAttributeUpdated(isBlocked);
296
297   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
298   for (; aFIter != myFeatureMap.end(); aFIter++)
299     if (aFIter->first->data() && aFIter->first->data()->isValid())
300       aFIter->first->data()->blockSendAttributeUpdated(isBlocked);
301
302   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAtIter = myAttributeMap.begin();
303   for (; anAtIter != myAttributeMap.end(); anAtIter++)
304     if (anAtIter->first->owner() && anAtIter->first->owner()->data() &&
305         anAtIter->first->owner()->data()->isValid())
306       anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked);
307 }
308
309
310
311
312
313
314 // ==============   Auxiliary functions   ====================================
315 bool isEqual(const std::list<ConstraintWrapperPtr>& theCVec1,
316              const std::list<ConstraintWrapperPtr>& theCVec2)
317 {
318   if (theCVec1.size() != theCVec2.size())
319     return false;
320
321   std::list<bool> aChecked(theCVec2.size(), false);
322   std::list<ConstraintWrapperPtr>::const_iterator anIt1 = theCVec1.begin();
323   for (; anIt1 != theCVec1.end(); ++anIt1) {
324     std::list<ConstraintWrapperPtr>::const_iterator anIt2 = theCVec2.begin();
325     std::list<bool>::iterator aCheckIt = aChecked.begin();
326     while (aCheckIt != aChecked.end() && *aCheckIt) {
327       ++aCheckIt;
328       ++anIt2;
329     }
330     for (; anIt2 != theCVec2.end(); ++anIt2, ++aCheckIt)
331       if (!(*aCheckIt) && (*anIt1)->isEqual(*anIt2)) {
332         *aCheckIt = true;
333         break;
334       }
335     // the same constraint is not found
336     if (anIt2 == theCVec2.end())
337       return false;
338   }
339   return true;
340 }