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 (!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 ////const ParameterWrapperPtr& SketchSolver_Storage::parameter(const AttributeDoublePtr& theAttribute) const
177 ////{
178 ////  static ParameterWrapperPtr aDummy;
179 ////
180 ////  std::map<AttributeDoublePtr, ParameterWrapperPtr>::const_iterator
181 ////      aFound = myParametersMap.find(theAttribute);
182 ////  if (aFound != myParametersMap.end())
183 ////    return aFound->second;
184 ////  return aDummy;
185 ////}
186
187
188 bool SketchSolver_Storage::isInteract(const FeaturePtr& theFeature) const
189 {
190   if (!theFeature)
191     return false;
192   if (myConstraintMap.empty())
193     return true; // empty storage interacts with each feature
194
195   ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
196   if (aConstraint) {
197     if (myConstraintMap.find(aConstraint) != myConstraintMap.end())
198       return true;
199   } else if (myFeatureMap.find(theFeature) != myFeatureMap.end())
200     return true;
201
202   std::list<AttributePtr> anAttrList = theFeature->data()->attributes(std::string());
203   std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
204   for (; anIt != anAttrList.end(); ++anIt)
205     if (isInteract(*anIt))
206       return true;
207
208   return false;
209 }
210
211 bool SketchSolver_Storage::isInteract(const AttributePtr& theAttribute) const
212 {
213   if (!theAttribute)
214     return false;
215
216   AttributeRefAttrPtr aRefAttr =
217       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
218   if (!aRefAttr)
219     return myAttributeMap.find(theAttribute) != myAttributeMap.end();
220   if (!aRefAttr->isObject())
221     return myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end();
222
223   FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
224   return isInteract(aFeature);
225 }
226
227 bool SketchSolver_Storage::isConsistent() const
228 {
229   // Check the constraints are valid
230   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
231       aCIter = myConstraintMap.begin();
232   for (; aCIter != myConstraintMap.end(); ++aCIter)
233     if (!aCIter->first->data() || !aCIter->first->data()->isValid())
234       return false;
235   // Check the features are valid
236   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
237   for (; aFIter != myFeatureMap.end(); aFIter++)
238     if (!aFIter->first->data() || !aFIter->first->data()->isValid())
239       return false;
240   return true;
241 }
242
243 void SketchSolver_Storage::removeInvalidEntities()
244 {
245   // Remove invalid constraints
246   std::list<ConstraintPtr> anInvalidConstraints;
247   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
248       aCIter = myConstraintMap.begin();
249   for (; aCIter != myConstraintMap.end(); ++aCIter)
250     if (!aCIter->first->data() || !aCIter->first->data()->isValid())
251       anInvalidConstraints.push_back(aCIter->first);
252   std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
253   for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
254     removeConstraint(*anInvCIt);
255   // Remove invalid features
256   std::list<FeaturePtr> anInvalidFeatures;
257   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
258   for (; aFIter != myFeatureMap.end(); aFIter++)
259     if (!aFIter->first->data() || !aFIter->first->data()->isValid())
260       anInvalidFeatures.push_back(aFIter->first);
261   std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
262   for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
263     removeEntity(*anInvFIt);
264 }
265
266 EntityWrapperPtr SketchSolver_Storage::getNormal() const
267 {
268   EntityWrapperPtr aSketch = sketch();
269   if (!aSketch)
270     return aSketch;
271
272   // Find normal entity
273   const std::list<EntityWrapperPtr>& aSketchSubs = aSketch->subEntities();
274   std::list<EntityWrapperPtr>::const_iterator aSIt = aSketchSubs.begin();
275   for (; aSIt != aSketchSubs.end(); ++aSIt)
276     if ((*aSIt)->type() == ENTITY_NORMAL)
277       return *aSIt;
278   return EntityWrapperPtr();
279 }
280
281 const EntityWrapperPtr& SketchSolver_Storage::sketch() const
282 {
283   static EntityWrapperPtr aDummySketch;
284
285   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
286   for (; aFIt != myFeatureMap.end(); ++aFIt)
287     if (aFIt->second->type() == ENTITY_SKETCH)
288       break;
289   if (aFIt == myFeatureMap.end())
290     return aDummySketch;
291   return aFIt->second;
292 }
293
294 void SketchSolver_Storage::setSketch(const EntityWrapperPtr& theSketch)
295 {
296   if (sketch())
297     return;
298   addEntity(FeaturePtr(), theSketch);
299 }
300
301 void SketchSolver_Storage::blockEvents(bool isBlocked) const
302 {
303   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
304       aCIter = myConstraintMap.begin();
305   for (; aCIter != myConstraintMap.end(); aCIter++)
306     if (aCIter->first->data() && aCIter->first->data()->isValid())
307       aCIter->first->data()->blockSendAttributeUpdated(isBlocked);
308
309   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
310   for (; aFIter != myFeatureMap.end(); aFIter++)
311     if (aFIter->first->data() && aFIter->first->data()->isValid())
312       aFIter->first->data()->blockSendAttributeUpdated(isBlocked);
313
314   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAtIter = myAttributeMap.begin();
315   for (; anAtIter != myAttributeMap.end(); anAtIter++)
316     if (anAtIter->first->owner() && anAtIter->first->owner()->data() &&
317         anAtIter->first->owner()->data()->isValid())
318       anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked);
319 }
320
321
322
323
324
325
326 // ==============   Auxiliary functions   ====================================
327 bool isEqual(const std::list<ConstraintWrapperPtr>& theCVec1,
328              const std::list<ConstraintWrapperPtr>& theCVec2)
329 {
330   if (theCVec1.size() != theCVec2.size())
331     return false;
332
333   std::list<bool> aChecked(theCVec2.size(), false);
334   std::list<ConstraintWrapperPtr>::const_iterator anIt1 = theCVec1.begin();
335   for (; anIt1 != theCVec1.end(); ++anIt1) {
336     std::list<ConstraintWrapperPtr>::const_iterator anIt2 = theCVec2.begin();
337     std::list<bool>::iterator aCheckIt = aChecked.begin();
338     while (aCheckIt != aChecked.end() && *aCheckIt) {
339       ++aCheckIt;
340       ++anIt2;
341     }
342     for (; anIt2 != theCVec2.end(); ++anIt2, ++aCheckIt)
343       if (!(*aCheckIt) && (*anIt1)->isEqual(*anIt2)) {
344         *aCheckIt = true;
345         break;
346       }
347     // the same constraint is not found
348     if (anIt2 == theCVec2.end())
349       return false;
350   }
351   return true;
352 }