Salome HOME
Task 2.5 Show where the remaining degrees of freedom are (issue #2997)
[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 = 1.e4 * 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)
228     PlaneGCSSolver_Tools::recalculateArcParameters(aRelated);
229
230   return isUpdated;
231 }
232
233 bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce)
234 {
235   if (!theAttribute->isInitialized())
236     return false;
237
238   AttributePtr anAttribute = theAttribute;
239   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
240   if (aRefAttr) {
241     if (aRefAttr->isObject()) {
242       FeaturePtr aFeature;
243       /// TODO: Check resultToFeatureOrAttribute() precisely.
244       resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute);
245       if (aFeature)
246         return update(aFeature, theForce);
247     } else
248       anAttribute = aRefAttr->attr();
249   }
250
251   EntityWrapperPtr aRelated = entity(anAttribute);
252   FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
253   if (!aRelated) { // Attribute does not exist, create it.
254     // First of all check if the parent feature exists. If not, add it.
255     if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
256       return update(aFeature, theForce); // theAttribute has been processed while adding feature
257     return aRelated.get() != 0;
258   }
259
260   bool isUpdated = updateValues(anAttribute, aRelated);
261   if (isUpdated) {
262     setNeedToResolve(true);
263     notify(aFeature);
264   }
265   return isUpdated;
266 }
267
268 void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity)
269 {
270   if (theEntity->isExternal())
271     return;
272
273   removeAuxiliaryConstraints(theEntity);
274
275   GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
276   mySketchSolver->removeParameters(aParameters);
277   theEntity->setExternal(true);
278   myNeedToResolve = true;
279 }
280
281 void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity)
282 {
283   if (!theEntity->isExternal())
284     return;
285
286   GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
287   mySketchSolver->addParameters(aParameters);
288   theEntity->setExternal(false);
289
290   createAuxiliaryConstraints(theEntity);
291
292   myNeedToResolve = true;
293 }
294
295
296 static void createArcConstraints(const EntityWrapperPtr& theArc,
297                                  const SolverPtr& theSolver,
298                                  const ConstraintID theConstraintID,
299                                  std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
300 {
301   EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theArc);
302   std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
303
304   // Additional constaints to fix arc's extra DoF (if the arc is not external):
305   std::list<GCSConstraintPtr> anArcConstraints;
306   // 1. distances from center till start and end points are equal to radius
307   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
308       anArc->center, anArc->start, anArc->rad)));
309   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
310       anArc->center, anArc->end, anArc->rad)));
311   // 2. angles of start and end points should be equal to the arc angles
312   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
313       anArc->center, anArc->start, anArc->startAngle)));
314   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
315       anArc->center, anArc->end, anArc->endAngle)));
316
317   ConstraintWrapperPtr aWrapper(
318     new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
319   aWrapper->setId(theConstraintID);
320   constraintsToSolver(aWrapper, theSolver);
321
322   theConstraints[theArc] = aWrapper;
323 }
324
325 static void createEllipseConstraints(
326     const EntityWrapperPtr& theEllipse,
327     const SolverPtr& theSolver,
328     const ConstraintID theConstraintID,
329     std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
330 {
331   EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipse);
332   std::shared_ptr<GCS::Ellipse> anEllipse =
333       std::dynamic_pointer_cast<GCS::Ellipse>(anEdge->entity());
334
335   // Additional constaints to fix ellipse's extra points
336   std::list<GCSConstraintPtr> anEllipseConstraints;
337
338   const std::map<std::string, EntityWrapperPtr>& anAttributes = theEllipse->additionalAttributes();
339   for (std::map<std::string, EntityWrapperPtr>::const_iterator anIt = anAttributes.begin();
340        anIt != anAttributes.end(); ++anIt) {
341     std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
342         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
343     if (!aPoint)
344       continue;
345
346     GCS::InternalAlignmentType anAlignmentX, anAlignmentY;
347     if (anIt->first == SketchPlugin_Ellipse::SECOND_FOCUS_ID())
348       anAlignmentX = GCS::EllipseFocus2X;
349     else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID())
350       anAlignmentX = GCS::EllipseNegativeMajorX;
351     else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID())
352       anAlignmentX = GCS::EllipsePositiveMajorX;
353     else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_START_ID())
354       anAlignmentX = GCS::EllipseNegativeMinorX;
355     else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_END_ID())
356       anAlignmentX = GCS::EllipsePositiveMinorX;
357
358     anEllipseConstraints.push_back(GCSConstraintPtr(
359         new GCS::ConstraintInternalAlignmentPoint2Ellipse(
360         *anEllipse, *(aPoint->point()), anAlignmentX)));
361     anAlignmentY = (GCS::InternalAlignmentType)((int)anAlignmentX + 1);
362     anEllipseConstraints.push_back(GCSConstraintPtr(
363         new GCS::ConstraintInternalAlignmentPoint2Ellipse(
364         *anEllipse, *(aPoint->point()), anAlignmentY)));
365   }
366
367   // constraint to bind the major radius value
368   std::shared_ptr<PlaneGCSSolver_PointWrapper> aMajorAxisStart =
369       std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
370       anAttributes.at(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()));
371   ScalarWrapperPtr aMajorRadius =
372       std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(
373       anAttributes.at(SketchPlugin_Ellipse::MAJOR_RADIUS_ID()));
374   anEllipseConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
375       anEllipse->center, *(aMajorAxisStart->point()), aMajorRadius->scalar())));
376
377   ConstraintWrapperPtr aWrapper(
378     new PlaneGCSSolver_ConstraintWrapper(anEllipseConstraints, CONSTRAINT_UNKNOWN));
379   aWrapper->setId(theConstraintID);
380   if (theSolver)
381     constraintsToSolver(aWrapper, theSolver);
382
383   theConstraints[theEllipse] = aWrapper;
384 }
385
386 static void createEllipticArcConstraints(
387     const EntityWrapperPtr& theEllipticArc,
388     const SolverPtr& theSolver,
389     const ConstraintID theConstraintID,
390     std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
391 {
392   // create base constraints for the ellipse without adding them to solver
393   createEllipseConstraints(theEllipticArc, SolverPtr(), theConstraintID, theConstraints);
394
395   ConstraintWrapperPtr& aConstraint = theConstraints[theEllipticArc];
396   std::list<GCSConstraintPtr> anEllArcConstraints = aConstraint->constraints();
397
398   // constrain extremities of the elliptic arc
399   EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipticArc);
400   std::shared_ptr<GCS::ArcOfEllipse> anArc =
401       std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
402
403   anEllArcConstraints.push_back(GCSConstraintPtr(
404       new GCS::ConstraintCurveValue(anArc->start, anArc->start.x, *anArc, anArc->startAngle)));
405   anEllArcConstraints.push_back(GCSConstraintPtr(
406       new GCS::ConstraintCurveValue(anArc->start, anArc->start.y, *anArc, anArc->startAngle)));
407   anEllArcConstraints.push_back(GCSConstraintPtr(
408       new GCS::ConstraintCurveValue(anArc->end, anArc->end.x, *anArc, anArc->endAngle)));
409   anEllArcConstraints.push_back(GCSConstraintPtr(
410       new GCS::ConstraintCurveValue(anArc->end, anArc->end.y, *anArc, anArc->endAngle)));
411
412   aConstraint->setConstraints(anEllArcConstraints);
413   constraintsToSolver(aConstraint, theSolver);
414 }
415
416 void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
417 {
418   if (!theEntity || theEntity->isExternal())
419     return;
420
421   if (theEntity->type() == ENTITY_ARC)
422     createArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
423   else if (theEntity->type() == ENTITY_ELLIPSE)
424     createEllipseConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
425   else if (theEntity->type() == ENTITY_ELLIPTIC_ARC) {
426     createEllipticArcConstraints(theEntity, mySketchSolver,
427                                  ++myConstraintLastID, myAuxConstraintMap);
428   }
429 }
430
431 void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
432 {
433   std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator
434       aFound = myAuxConstraintMap.find(theEntity);
435   if (aFound != myAuxConstraintMap.end()) {
436     mySketchSolver->removeConstraint(aFound->second->id());
437     myAuxConstraintMap.erase(aFound);
438   }
439 }
440
441 template <typename ARCTYPE>
442 void adjustArcParametrization(ARCTYPE& theArc, bool theReversed)
443 {
444   // tune start angle of the arc to be in [0, 2PI]
445   while (*theArc.startAngle < -PI)
446     *theArc.startAngle += 2.0 * PI;
447   while (*theArc.startAngle >= PI)
448     *theArc.startAngle -= 2.0 * PI;
449   // adjust end angle of the arc
450   if (theReversed) {
451     while (*theArc.endAngle > *theArc.startAngle)
452       *theArc.endAngle -= 2.0 * PI;
453     while (*theArc.endAngle + 2 * PI < *theArc.startAngle)
454       *theArc.endAngle += 2.0 * PI;
455   }
456   else {
457     while (*theArc.endAngle < *theArc.startAngle)
458       *theArc.endAngle += 2.0 * PI;
459     while (*theArc.endAngle > *theArc.startAngle + 2 * PI)
460       *theArc.endAngle -= 2.0 * PI;
461   }
462 }
463
464 void PlaneGCSSolver_Storage::adjustParametrizationOfArcs()
465 {
466   std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator anIt = myAuxConstraintMap.begin();
467   for (; anIt != myAuxConstraintMap.end(); ++anIt) {
468     EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(anIt->first);
469     std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
470     if (anArc)
471       adjustArcParametrization(*anArc, anEdge->isReversed());
472     else {
473       std::shared_ptr<GCS::ArcOfEllipse> aEllArc =
474           std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
475       if (aEllArc)
476         adjustArcParametrization(*aEllArc, anEdge->isReversed());
477     }
478   }
479
480   // update parameters of Middle point constraint for point on arc
481   std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator aCIt = myConstraintMap.begin();
482   for (; aCIt != myConstraintMap.end(); ++aCIt)
483     if (aCIt->second->type() == CONSTRAINT_MIDDLE_POINT) {
484       notify(aCIt->first);
485     }
486 }
487
488
489 bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
490 {
491   std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator
492       aFound = myConstraintMap.find(theConstraint);
493   if (aFound != myConstraintMap.end()) {
494     ConstraintWrapperPtr aCW = aFound->second;
495     ConstraintID anID = aCW->id();
496
497     // Remove solver's constraints
498     mySketchSolver->removeConstraint(anID);
499
500     // Remove value if exists
501     const ScalarWrapperPtr& aValue = aCW->valueParameter();
502     if (aValue) {
503       GCS::SET_pD aParToRemove;
504       aParToRemove.insert(aValue->scalar());
505       removeParameters(aParToRemove);
506     }
507
508     // Remove constraint
509     myConstraintMap.erase(aFound);
510
511     if (anID != CID_MOVEMENT)
512       myNeedToResolve = true;
513
514     // notify subscibers
515     notify(theConstraint);
516   }
517   return true;
518 }
519
520 void PlaneGCSSolver_Storage::removeInvalidEntities()
521 {
522   PlaneGCSSolver_EntityDestroyer aDestroyer;
523
524   // Remove invalid constraints
525   std::list<ConstraintPtr> anInvalidConstraints;
526   std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
527       aCIter = myConstraintMap.begin();
528   for (; aCIter != myConstraintMap.end(); ++aCIter)
529     if (!aCIter->first->data() || !aCIter->first->data()->isValid())
530       anInvalidConstraints.push_back(aCIter->first);
531   std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
532   for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
533     removeConstraint(*anInvCIt);
534
535   // Remove invalid features
536   std::list<FeaturePtr> anInvalidFeatures;
537   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
538   for (; aFIter != myFeatureMap.end(); aFIter++)
539     if (!aFIter->first->data() || !aFIter->first->data()->isValid()) {
540       anInvalidFeatures.push_back(aFIter->first);
541       if (aFIter->second)
542         aDestroyer.remove(aFIter->second);
543
544       // remove invalid arc
545       removeAuxiliaryConstraints(aFIter->second);
546     }
547   std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
548   for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
549     removeFeature(*anInvFIt);
550
551   // Remove invalid attributes
552   std::list<AttributePtr> anInvalidAttributes;
553   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAttrIt = myAttributeMap.begin();
554   for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
555     FeaturePtr anOwner = ModelAPI_Feature::feature(anAttrIt->first->owner());
556     if (!anOwner || !anOwner->data() || !anOwner->data()->isValid()) {
557       anInvalidAttributes.push_back(anAttrIt->first);
558       aDestroyer.remove(anAttrIt->second);
559     }
560   }
561   std::list<AttributePtr>::const_iterator anInvAtIt = anInvalidAttributes.begin();
562   for (; anInvAtIt != anInvalidAttributes.end(); ++anInvAtIt)
563     removeAttribute(*anInvAtIt);
564
565   // free memory occupied by parameters
566   removeParameters(aDestroyer.parametersToRemove());
567
568   /// TODO: Think on optimization of checking invalid features and attributes
569 }
570
571
572
573 double* PlaneGCSSolver_Storage::createParameter()
574 {
575   return mySketchSolver->createParameter();
576 }
577
578 void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams)
579 {
580   mySketchSolver->removeParameters(theParams);
581 }
582
583 // indicates attribute containing in the external feature
584 static bool isExternalAttribute(const AttributePtr& theAttribute)
585 {
586   if (!theAttribute)
587     return false;
588   std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
589       std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
590   return aSketchFeature.get() && aSketchFeature->isExternal();
591 }
592
593 static void addOwnerToSet(const AttributePtr& theAttribute, std::set<FeaturePtr>& theFeatures)
594 {
595   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
596   if (anOwner)
597     theFeatures.insert(anOwner);
598 }
599
600 void PlaneGCSSolver_Storage::refresh() const
601 {
602   const double aTol = 1000. * tolerance; // tolerance to prevent frequent updates
603
604   std::set<FeaturePtr> anUpdatedFeatures;
605
606   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
607   for (; anIt != myAttributeMap.end(); ++anIt) {
608     if (!anIt->first->isInitialized())
609       continue;
610
611     // the external feature always should keep the up to date values, so,
612     // refresh from the solver is never needed
613     if (isExternalAttribute(anIt->first))
614       continue;
615
616     std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
617         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
618     if (aPoint2D) {
619       std::shared_ptr<PlaneGCSSolver_PointWrapper> aPointWrapper =
620           std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
621       GCSPointPtr aGCSPoint = aPointWrapper->point();
622       if (fabs(aPoint2D->x() - (*aGCSPoint->x)) > aTol ||
623           fabs(aPoint2D->y() - (*aGCSPoint->y)) > aTol) {
624         aPoint2D->setValue(*aGCSPoint->x, *aGCSPoint->y);
625         addOwnerToSet(anIt->first, anUpdatedFeatures);
626       }
627       continue;
628     }
629     AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
630     if (aScalar) {
631       ScalarWrapperPtr aScalarWrapper =
632           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
633       if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol) {
634         aScalar->setValue(aScalarWrapper->value());
635         addOwnerToSet(anIt->first, anUpdatedFeatures);
636       }
637       continue;
638     }
639   }
640
641   // notify listeners about features update
642   std::set<FeaturePtr>::const_iterator aFIt = anUpdatedFeatures.begin();
643   for (; aFIt != anUpdatedFeatures.end(); ++aFIt)
644     notify(*aFIt);
645 }
646
647 PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeometry() const
648 {
649   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
650   for (; aFIt != myFeatureMap.end(); ++aFIt) {
651     EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aFIt->second);
652     if (anEdge && anEdge->isDegenerated())
653       return PlaneGCSSolver_Solver::STATUS_DEGENERATED;
654   }
655   return PlaneGCSSolver_Solver::STATUS_OK;
656 }
657
658
659 void PlaneGCSSolver_Storage::getUnderconstrainedGeometry(std::set<FeaturePtr>& theFeatures) const
660 {
661   std::vector<double*> aFreeParams;
662   mySketchSolver->getFreeParameters(aFreeParams);
663   if (aFreeParams.empty())
664     return;
665
666   std::map<double*, FeaturePtr> aParamOfFeatures;
667   for (std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
668        aFIt != myFeatureMap.end(); ++aFIt) {
669     GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(aFIt->second);
670     for (GCS::SET_pD::iterator aPIt = aParams.begin(); aPIt != aParams.end(); ++aPIt)
671       aParamOfFeatures[*aPIt] = aFIt->first;
672   }
673
674   for (std::vector<double*>::iterator anIt = aFreeParams.begin();
675        anIt != aFreeParams.end(); ++anIt) {
676     std::map<double*, FeaturePtr>::iterator aFound = aParamOfFeatures.find(*anIt);
677     if (aFound != aParamOfFeatures.end())
678       theFeatures.insert(aFound->second);
679   }
680 }