]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp
Salome HOME
Task 2.11. Ability to impose a midpoint on an arc (refers issue #3002)
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_Storage.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <PlaneGCSSolver_Storage.h>
21 #include <PlaneGCSSolver_Solver.h>
22 #include <PlaneGCSSolver_BooleanWrapper.h>
23 #include <PlaneGCSSolver_ConstraintWrapper.h>
24 #include <PlaneGCSSolver_EdgeWrapper.h>
25 #include <PlaneGCSSolver_PointWrapper.h>
26 #include <PlaneGCSSolver_Tools.h>
27
28 #include <PlaneGCSSolver_AttributeBuilder.h>
29 #include <PlaneGCSSolver_FeatureBuilder.h>
30 #include <PlaneGCSSolver_EntityDestroyer.h>
31
32 #include <GeomAPI_Dir2d.h>
33 #include <GeomAPI_Pnt2d.h>
34 #include <GeomAPI_XY.h>
35 #include <GeomDataAPI_Point2D.h>
36 #include <ModelAPI_AttributeRefAttr.h>
37 #include <SketchPlugin_Ellipse.h>
38 #include <SketchPlugin_Projection.h>
39
40 #include <cmath>
41
42
43 static void constraintsToSolver(const ConstraintWrapperPtr& theConstraint,
44                                 const SolverPtr& theSolver)
45 {
46   const std::list<GCSConstraintPtr>& aConstraints =
47       std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint)->constraints();
48   theSolver->addConstraint(theConstraint->id(), aConstraints);
49 }
50
51
52 PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const SolverPtr& theSolver)
53   : SketchSolver_Storage(theSolver),
54     myConstraintLastID(CID_UNKNOWN)
55 {
56 }
57
58 void PlaneGCSSolver_Storage::addConstraint(
59     ConstraintPtr        theConstraint,
60     ConstraintWrapperPtr theSolverConstraint)
61 {
62   SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraint);
63
64   theSolverConstraint->setId(++myConstraintLastID);
65   constraintsToSolver(theSolverConstraint, mySketchSolver);
66 }
67
68 void PlaneGCSSolver_Storage::addMovementConstraint(
69     const ConstraintWrapperPtr& theSolverConstraint)
70 {
71   // before adding movement constraint to solver, re-check its DOF
72   if (mySketchSolver->dof() == 0)
73     mySketchSolver->diagnose();
74
75   theSolverConstraint->setId(CID_MOVEMENT);
76   constraintsToSolver(theSolverConstraint, mySketchSolver);
77 }
78
79
80 EntityWrapperPtr PlaneGCSSolver_Storage::createFeature(
81     const FeaturePtr&             theFeature,
82     PlaneGCSSolver_EntityBuilder* theBuilder)
83 {
84   std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
85   std::list<AttributePtr>::const_iterator anIt = anAttributes.begin();
86   for (; anIt != anAttributes.end(); ++anIt)
87     createAttribute(*anIt, theBuilder);
88
89   EntityWrapperPtr aResult = theBuilder->createFeature(theFeature);
90   if (aResult)
91     addEntity(theFeature, aResult);
92   return aResult;
93 }
94
95 EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute(
96     const AttributePtr&           theAttribute,
97     PlaneGCSSolver_EntityBuilder* theBuilder)
98 {
99   EntityWrapperPtr aResult = theBuilder->createAttribute(theAttribute);
100   if (aResult)
101     addEntity(theAttribute, aResult);
102   return aResult;
103 }
104
105 /// \brief Update value
106 static bool updateValue(const double& theSource, double& theDest)
107 {
108   static const double aTol = 1000. * tolerance;
109   bool isUpdated = fabs(theSource - theDest) > aTol;
110   if (isUpdated)
111     theDest = theSource;
112   return isUpdated;
113 }
114
115 /// \brief Update coordinates of the point or scalar using its base attribute
116 static bool updateValues(AttributePtr& theAttribute, EntityWrapperPtr& theEntity)
117 {
118   bool isUpdated = false;
119
120   std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
121       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
122   if (aPoint2D) {
123     const GCSPointPtr& aGCSPoint =
124         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity)->point();
125     isUpdated = updateValue(aPoint2D->x(), *(aGCSPoint->x)) || isUpdated;
126     isUpdated = updateValue(aPoint2D->y(), *(aGCSPoint->y)) || isUpdated;
127   } else {
128     AttributeDoublePtr aScalar =
129         std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
130     if (aScalar) {
131       ScalarWrapperPtr aWrapper =
132           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theEntity);
133       // There is possible angular value, which is converted between degrees and radians.
134       // So, we use its value instead of using direct pointer to value.
135       double aValue = aWrapper->value();
136       isUpdated = updateValue(aScalar->value(), aValue);
137       if (isUpdated)
138         aWrapper->setValue(aValue);
139     } else {
140       AttributeBooleanPtr aBoolean =
141           std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(theAttribute);
142       if (aBoolean) {
143         BooleanWrapperPtr aWrapper =
144             std::dynamic_pointer_cast<PlaneGCSSolver_BooleanWrapper>(theEntity);
145         isUpdated = aWrapper->value() != aBoolean->value();
146         aWrapper->setValue(aBoolean->value());
147       }
148     }
149   }
150
151   return isUpdated;
152 }
153
154 static bool hasReference(std::shared_ptr<SketchPlugin_Feature> theFeature,
155                          const std::string& theFeatureKind)
156 {
157   const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
158   for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
159        aRefIt != aRefs.end(); ++aRefIt) {
160      FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
161      if (anOwner && anOwner->getKind() == theFeatureKind)
162        return true;
163   }
164   return false;
165 }
166
167 static bool isCopyFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
168 {
169   return theFeature && theFeature->isCopy();
170 }
171
172 bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
173 {
174   bool sendNotify = false;
175   bool isUpdated = false;
176   std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
177       std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
178   EntityWrapperPtr aRelated = entity(theFeature);
179   if (aRelated) // send signal to subscribers
180     sendNotify = true;
181   else { // Feature is not exist, create it
182     bool isCopy = isCopyFeature(aSketchFeature);
183     bool isProjReferred = hasReference(aSketchFeature, SketchPlugin_Projection::ID());
184     // the feature is a copy in "Multi" constraint and does not used in other constraints
185     if (!theForce && (isCopy && !isProjReferred) &&
186         myFeatureMap.find(theFeature) == myFeatureMap.end())
187       return false;
188
189     // external feature processing
190     bool isExternal =
191         (aSketchFeature && (aSketchFeature->isExternal() || isCopy || isProjReferred));
192
193     PlaneGCSSolver_FeatureBuilder aBuilder(isExternal ? 0 : this);
194
195     // Reserve the feature in the map of features
196     // (do not want to add several copies of it while adding attributes)
197     aRelated = createFeature(theFeature, &aBuilder);
198     myFeatureMap[theFeature] = aRelated;
199     createAuxiliaryConstraints(aRelated);
200     isUpdated = true;
201   }
202
203   std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
204   std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
205   for (; anAttrIt != anAttributes.end(); ++anAttrIt)
206     if ((*anAttrIt)->attributeType() == GeomDataAPI_Point2D::typeId() ||
207         (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId() ||
208         (*anAttrIt)->attributeType() == ModelAPI_AttributeBoolean::typeId())
209       isUpdated = update(*anAttrIt) || isUpdated;
210
211   // check external attribute is changed
212   bool isExternal = aSketchFeature &&
213                    (aSketchFeature->isExternal() || isCopyFeature(aSketchFeature));
214   if (aRelated && isExternal != aRelated->isExternal()) {
215     if (isExternal)
216       makeExternal(aRelated);
217     else
218       makeNonExternal(aRelated);
219     isUpdated = true;
220   }
221
222   // send notification to listeners due to at least one attribute is changed
223   if (sendNotify && isUpdated)
224     notify(theFeature);
225
226   // update arc
227   if (aRelated && aRelated->type() == ENTITY_ARC) {
228     /// TODO: this code should be shared with FeatureBuilder somehow
229
230     std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity =
231       std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aRelated);
232     std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEntity->entity());
233
234     static std::shared_ptr<GeomAPI_Dir2d> OX(new GeomAPI_Dir2d(1.0, 0.0));
235     std::shared_ptr<GeomAPI_Pnt2d> aCenter(
236       new GeomAPI_Pnt2d(*anArc->center.x, *anArc->center.y));
237     std::shared_ptr<GeomAPI_Pnt2d> aStart(
238       new GeomAPI_Pnt2d(*anArc->start.x, *anArc->start.y));
239
240     *anArc->rad = aStart->distance(aCenter);
241
242     std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy())));
243     *anArc->startAngle = OX->angle(aDir);
244
245     aDir = std::shared_ptr<GeomAPI_Dir2d>(
246       new GeomAPI_Dir2d((*anArc->end.x) - aCenter->x(), (*anArc->end.y) - aCenter->y()));
247     *anArc->endAngle = OX->angle(aDir);
248   }
249
250   return isUpdated;
251 }
252
253 bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce)
254 {
255   if (!theAttribute->isInitialized())
256     return false;
257
258   AttributePtr anAttribute = theAttribute;
259   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
260   if (aRefAttr) {
261     if (aRefAttr->isObject()) {
262       FeaturePtr aFeature;
263       /// TODO: Check resultToFeatureOrAttribute() precisely.
264       resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute);
265       if (aFeature)
266         return update(aFeature, theForce);
267     } else
268       anAttribute = aRefAttr->attr();
269   }
270
271   EntityWrapperPtr aRelated = entity(anAttribute);
272   FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
273   if (!aRelated) { // Attribute does not exist, create it.
274     // First of all check if the parent feature exists. If not, add it.
275     if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
276       return update(aFeature, theForce); // theAttribute has been processed while adding feature
277     return aRelated.get() != 0;
278   }
279
280   bool isUpdated = updateValues(anAttribute, aRelated);
281   if (isUpdated) {
282     setNeedToResolve(true);
283     notify(aFeature);
284   }
285   return isUpdated;
286 }
287
288 void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity)
289 {
290   if (theEntity->isExternal())
291     return;
292
293   removeAuxiliaryConstraints(theEntity);
294
295   GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
296   mySketchSolver->removeParameters(aParameters);
297   theEntity->setExternal(true);
298   myNeedToResolve = true;
299 }
300
301 void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity)
302 {
303   if (!theEntity->isExternal())
304     return;
305
306   GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
307   mySketchSolver->addParameters(aParameters);
308   theEntity->setExternal(false);
309
310   createAuxiliaryConstraints(theEntity);
311
312   myNeedToResolve = true;
313 }
314
315
316 static void createArcConstraints(const EntityWrapperPtr& theArc,
317                                  const SolverPtr& theSolver,
318                                  const ConstraintID theConstraintID,
319                                  std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
320 {
321   EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theArc);
322   std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
323
324   // Additional constaints to fix arc's extra DoF (if the arc is not external):
325   std::list<GCSConstraintPtr> anArcConstraints;
326   // 1. distances from center till start and end points are equal to radius
327   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
328       anArc->center, anArc->start, anArc->rad)));
329   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
330       anArc->center, anArc->end, anArc->rad)));
331   // 2. angles of start and end points should be equal to the arc angles
332   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
333       anArc->center, anArc->start, anArc->startAngle)));
334   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
335       anArc->center, anArc->end, anArc->endAngle)));
336
337   ConstraintWrapperPtr aWrapper(
338     new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
339   aWrapper->setId(theConstraintID);
340   constraintsToSolver(aWrapper, theSolver);
341
342   theConstraints[theArc] = aWrapper;
343 }
344
345 static void createEllipseConstraints(
346     const EntityWrapperPtr& theEllipse,
347     const SolverPtr& theSolver,
348     const ConstraintID theConstraintID,
349     std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
350 {
351   EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipse);
352   std::shared_ptr<GCS::Ellipse> anEllipse =
353       std::dynamic_pointer_cast<GCS::Ellipse>(anEdge->entity());
354
355   // Additional constaints to fix ellipse's extra points
356   std::list<GCSConstraintPtr> anEllipseConstraints;
357
358   const std::map<std::string, EntityWrapperPtr>& anAttributes = theEllipse->additionalAttributes();
359   for (std::map<std::string, EntityWrapperPtr>::const_iterator anIt = anAttributes.begin();
360        anIt != anAttributes.end(); ++anIt) {
361     std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
362         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
363     if (!aPoint)
364       continue;
365
366     GCS::InternalAlignmentType anAlignmentX, anAlignmentY;
367     if (anIt->first == SketchPlugin_Ellipse::SECOND_FOCUS_ID())
368       anAlignmentX = GCS::EllipseFocus2X;
369     else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID())
370       anAlignmentX = GCS::EllipseNegativeMajorX;
371     else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID())
372       anAlignmentX = GCS::EllipsePositiveMajorX;
373     else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_START_ID())
374       anAlignmentX = GCS::EllipseNegativeMinorX;
375     else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_END_ID())
376       anAlignmentX = GCS::EllipsePositiveMinorX;
377
378     anEllipseConstraints.push_back(GCSConstraintPtr(
379         new GCS::ConstraintInternalAlignmentPoint2Ellipse(
380         *anEllipse, *(aPoint->point()), anAlignmentX)));
381     anAlignmentY = (GCS::InternalAlignmentType)((int)anAlignmentX + 1);
382     anEllipseConstraints.push_back(GCSConstraintPtr(
383         new GCS::ConstraintInternalAlignmentPoint2Ellipse(
384         *anEllipse, *(aPoint->point()), anAlignmentY)));
385   }
386
387   // constraint to bind the major radius value
388   std::shared_ptr<PlaneGCSSolver_PointWrapper> aMajorAxisStart =
389       std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
390       anAttributes.at(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()));
391   ScalarWrapperPtr aMajorRadius =
392       std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(
393       anAttributes.at(SketchPlugin_Ellipse::MAJOR_RADIUS_ID()));
394   anEllipseConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
395       anEllipse->center, *(aMajorAxisStart->point()), aMajorRadius->scalar())));
396
397   ConstraintWrapperPtr aWrapper(
398     new PlaneGCSSolver_ConstraintWrapper(anEllipseConstraints, CONSTRAINT_UNKNOWN));
399   aWrapper->setId(theConstraintID);
400   constraintsToSolver(aWrapper, theSolver);
401
402   theConstraints[theEllipse] = aWrapper;
403 }
404
405 void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
406 {
407   if (!theEntity || theEntity->isExternal())
408     return;
409
410   if (theEntity->type() == ENTITY_ARC)
411     createArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
412   else if (theEntity->type() == ENTITY_ELLIPSE)
413     createEllipseConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
414 }
415
416 void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
417 {
418   std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator
419       aFound = myAuxConstraintMap.find(theEntity);
420   if (aFound != myAuxConstraintMap.end()) {
421     mySketchSolver->removeConstraint(aFound->second->id());
422     myAuxConstraintMap.erase(aFound);
423   }
424 }
425
426 void PlaneGCSSolver_Storage::adjustParametrizationOfArcs()
427 {
428   std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator anIt = myAuxConstraintMap.begin();
429   for (; anIt != myAuxConstraintMap.end(); ++anIt) {
430     EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(anIt->first);
431     std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
432     if (!anArc)
433       continue;
434     // tune start angle of the arc to be in [0, 2PI]
435     while (*anArc->startAngle < -PI)
436       *anArc->startAngle += 2.0 * PI;
437     while (*anArc->startAngle >= PI)
438       *anArc->startAngle -= 2.0 * PI;
439     // adjust end angle of the arc
440     if (anEdge->isReversed()) {
441       while (*anArc->endAngle > *anArc->startAngle)
442         *anArc->endAngle -= 2.0 * PI;
443       while (*anArc->endAngle + 2 * PI < *anArc->startAngle)
444         *anArc->endAngle += 2.0 * PI;
445     } else {
446       while (*anArc->endAngle < *anArc->startAngle)
447         *anArc->endAngle += 2.0 * PI;
448       while (*anArc->endAngle > *anArc->startAngle + 2 * PI)
449         *anArc->endAngle -= 2.0 * PI;
450     }
451   }
452
453   // update parameters of Middle point constraint for point on arc
454   std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator aCIt = myConstraintMap.begin();
455   for (; aCIt != myConstraintMap.end(); ++aCIt)
456     if (aCIt->second->type() == CONSTRAINT_MIDDLE_POINT) {
457       notify(aCIt->first);
458     }
459 }
460
461
462 bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
463 {
464   std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator
465       aFound = myConstraintMap.find(theConstraint);
466   if (aFound != myConstraintMap.end()) {
467     ConstraintWrapperPtr aCW = aFound->second;
468     ConstraintID anID = aCW->id();
469
470     // Remove solver's constraints
471     mySketchSolver->removeConstraint(anID);
472
473     // Remove value if exists
474     const ScalarWrapperPtr& aValue = aCW->valueParameter();
475     if (aValue) {
476       GCS::SET_pD aParToRemove;
477       aParToRemove.insert(aValue->scalar());
478       removeParameters(aParToRemove);
479     }
480
481     // Remove constraint
482     myConstraintMap.erase(aFound);
483
484     if (anID != CID_MOVEMENT)
485       myNeedToResolve = true;
486
487     // notify subscibers
488     notify(theConstraint);
489   }
490   return true;
491 }
492
493 void PlaneGCSSolver_Storage::removeInvalidEntities()
494 {
495   PlaneGCSSolver_EntityDestroyer aDestroyer;
496
497   // Remove invalid constraints
498   std::list<ConstraintPtr> anInvalidConstraints;
499   std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
500       aCIter = myConstraintMap.begin();
501   for (; aCIter != myConstraintMap.end(); ++aCIter)
502     if (!aCIter->first->data() || !aCIter->first->data()->isValid())
503       anInvalidConstraints.push_back(aCIter->first);
504   std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
505   for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
506     removeConstraint(*anInvCIt);
507
508   // Remove invalid features
509   std::list<FeaturePtr> anInvalidFeatures;
510   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
511   for (; aFIter != myFeatureMap.end(); aFIter++)
512     if (!aFIter->first->data() || !aFIter->first->data()->isValid()) {
513       anInvalidFeatures.push_back(aFIter->first);
514       if (aFIter->second)
515         aDestroyer.remove(aFIter->second);
516
517       // remove invalid arc
518       removeAuxiliaryConstraints(aFIter->second);
519     }
520   std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
521   for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
522     removeFeature(*anInvFIt);
523
524   // Remove invalid attributes
525   std::list<AttributePtr> anInvalidAttributes;
526   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAttrIt = myAttributeMap.begin();
527   for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
528     FeaturePtr anOwner = ModelAPI_Feature::feature(anAttrIt->first->owner());
529     if (!anOwner || !anOwner->data() || !anOwner->data()->isValid()) {
530       anInvalidAttributes.push_back(anAttrIt->first);
531       aDestroyer.remove(anAttrIt->second);
532     }
533   }
534   std::list<AttributePtr>::const_iterator anInvAtIt = anInvalidAttributes.begin();
535   for (; anInvAtIt != anInvalidAttributes.end(); ++anInvAtIt)
536     removeAttribute(*anInvAtIt);
537
538   // free memory occupied by parameters
539   removeParameters(aDestroyer.parametersToRemove());
540
541   /// TODO: Think on optimization of checking invalid features and attributes
542 }
543
544
545
546 double* PlaneGCSSolver_Storage::createParameter()
547 {
548   return mySketchSolver->createParameter();
549 }
550
551 void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams)
552 {
553   mySketchSolver->removeParameters(theParams);
554 }
555
556 // indicates attribute containing in the external feature
557 static bool isExternalAttribute(const AttributePtr& theAttribute)
558 {
559   if (!theAttribute)
560     return false;
561   std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
562       std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
563   return aSketchFeature.get() && aSketchFeature->isExternal();
564 }
565
566 static void addOwnerToSet(const AttributePtr& theAttribute, std::set<FeaturePtr>& theFeatures)
567 {
568   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
569   if (anOwner)
570     theFeatures.insert(anOwner);
571 }
572
573 void PlaneGCSSolver_Storage::refresh() const
574 {
575   const double aTol = 1000. * tolerance; // tolerance to prevent frequent updates
576
577   std::set<FeaturePtr> anUpdatedFeatures;
578
579   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
580   for (; anIt != myAttributeMap.end(); ++anIt) {
581     if (!anIt->first->isInitialized())
582       continue;
583
584     // the external feature always should keep the up to date values, so,
585     // refresh from the solver is never needed
586     if (isExternalAttribute(anIt->first))
587       continue;
588
589     std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
590         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
591     if (aPoint2D) {
592       std::shared_ptr<PlaneGCSSolver_PointWrapper> aPointWrapper =
593           std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
594       GCSPointPtr aGCSPoint = aPointWrapper->point();
595       if (fabs(aPoint2D->x() - (*aGCSPoint->x)) > aTol ||
596           fabs(aPoint2D->y() - (*aGCSPoint->y)) > aTol) {
597         aPoint2D->setValue(*aGCSPoint->x, *aGCSPoint->y);
598         addOwnerToSet(anIt->first, anUpdatedFeatures);
599       }
600       continue;
601     }
602     AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
603     if (aScalar) {
604       ScalarWrapperPtr aScalarWrapper =
605           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
606       if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol) {
607         aScalar->setValue(aScalarWrapper->value());
608         addOwnerToSet(anIt->first, anUpdatedFeatures);
609       }
610       continue;
611     }
612   }
613
614   // notify listeners about features update
615   std::set<FeaturePtr>::const_iterator aFIt = anUpdatedFeatures.begin();
616   for (; aFIt != anUpdatedFeatures.end(); ++aFIt)
617     notify(*aFIt);
618 }
619
620 PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeometry() const
621 {
622   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
623   for (; aFIt != myFeatureMap.end(); ++aFIt) {
624     EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aFIt->second);
625     if (anEdge && anEdge->isDegenerated())
626       return PlaneGCSSolver_Solver::STATUS_DEGENERATED;
627   }
628   return PlaneGCSSolver_Solver::STATUS_OK;
629 }