]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp
Salome HOME
Issue #17347: B-Splines in Sketcher
[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_PointArrayWrapper.h>
27 #include <PlaneGCSSolver_ScalarArrayWrapper.h>
28 #include <PlaneGCSSolver_Tools.h>
29
30 #include <PlaneGCSSolver_AttributeBuilder.h>
31 #include <PlaneGCSSolver_FeatureBuilder.h>
32 #include <PlaneGCSSolver_EntityDestroyer.h>
33
34 #include <GeomAPI_Dir2d.h>
35 #include <GeomAPI_Pnt2d.h>
36 #include <GeomAPI_XY.h>
37 #include <GeomDataAPI_Point2D.h>
38 #include <GeomDataAPI_Point2DArray.h>
39 #include <ModelAPI_AttributeDoubleArray.h>
40 #include <ModelAPI_AttributeRefAttr.h>
41 #include <SketchPlugin_BSpline.h>
42 #include <SketchPlugin_Ellipse.h>
43 #include <SketchPlugin_Projection.h>
44
45 #include <cmath>
46
47
48 static void constraintsToSolver(const ConstraintWrapperPtr& theConstraint,
49                                 const SolverPtr& theSolver)
50 {
51   const std::list<GCSConstraintPtr>& aConstraints =
52       std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint)->constraints();
53   theSolver->addConstraint(theConstraint->id(), aConstraints);
54 }
55
56
57 PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const SolverPtr& theSolver)
58   : SketchSolver_Storage(theSolver),
59     myConstraintLastID(CID_UNKNOWN)
60 {
61 }
62
63 void PlaneGCSSolver_Storage::addConstraint(
64     ConstraintPtr        theConstraint,
65     ConstraintWrapperPtr theSolverConstraint)
66 {
67   SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraint);
68
69   theSolverConstraint->setId(++myConstraintLastID);
70   constraintsToSolver(theSolverConstraint, mySketchSolver);
71 }
72
73 void PlaneGCSSolver_Storage::addMovementConstraint(
74     const ConstraintWrapperPtr& theSolverConstraint)
75 {
76   // before adding movement constraint to solver, re-check its DOF
77   if (mySketchSolver->dof() == 0)
78     mySketchSolver->diagnose();
79
80   theSolverConstraint->setId(CID_MOVEMENT);
81   constraintsToSolver(theSolverConstraint, mySketchSolver);
82 }
83
84
85 EntityWrapperPtr PlaneGCSSolver_Storage::createFeature(
86     const FeaturePtr&             theFeature,
87     PlaneGCSSolver_EntityBuilder* theBuilder)
88 {
89   std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
90   std::list<AttributePtr>::const_iterator anIt = anAttributes.begin();
91   for (; anIt != anAttributes.end(); ++anIt)
92     createAttribute(*anIt, theBuilder);
93
94   EntityWrapperPtr aResult = theBuilder->createFeature(theFeature);
95   if (aResult)
96     addEntity(theFeature, aResult);
97   return aResult;
98 }
99
100 EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute(
101     const AttributePtr&           theAttribute,
102     PlaneGCSSolver_EntityBuilder* theBuilder)
103 {
104   EntityWrapperPtr aResult = theBuilder->createAttribute(theAttribute);
105   if (aResult)
106     addEntity(theAttribute, aResult);
107   return aResult;
108 }
109
110 static bool hasReference(std::shared_ptr<SketchPlugin_Feature> theFeature,
111                          const std::string& theFeatureKind)
112 {
113   const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
114   for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
115        aRefIt != aRefs.end(); ++aRefIt) {
116      FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
117      if (anOwner && anOwner->getKind() == theFeatureKind)
118        return true;
119   }
120   return false;
121 }
122
123 static bool isCopyFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
124 {
125   return theFeature && theFeature->isCopy();
126 }
127
128 bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
129 {
130   bool sendNotify = false;
131   bool isUpdated = false;
132   std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
133       std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
134   EntityWrapperPtr aRelated = entity(theFeature);
135   if (aRelated) // send signal to subscribers
136     sendNotify = true;
137   else { // Feature is not exist, create it
138     bool isCopy = isCopyFeature(aSketchFeature);
139     bool isProjReferred = hasReference(aSketchFeature, SketchPlugin_Projection::ID());
140     // the feature is a copy in "Multi" constraint and does not used in other constraints
141     if (!theForce && (isCopy && !isProjReferred) &&
142         myFeatureMap.find(theFeature) == myFeatureMap.end())
143       return false;
144
145     // external feature processing
146     bool isExternal =
147         (aSketchFeature && (aSketchFeature->isExternal() || isCopy || isProjReferred));
148
149     PlaneGCSSolver_FeatureBuilder aBuilder(isExternal ? 0 : this);
150
151     // Reserve the feature in the map of features
152     // (do not want to add several copies of it while adding attributes)
153     aRelated = createFeature(theFeature, &aBuilder);
154     myFeatureMap[theFeature] = aRelated;
155     createAuxiliaryConstraints(aRelated);
156     isUpdated = true;
157   }
158
159   std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
160   std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
161   for (; anAttrIt != anAttributes.end(); ++anAttrIt)
162     if (PlaneGCSSolver_Tools::isAttributeApplicable((*anAttrIt)->id(), theFeature->getKind()))
163       isUpdated = update(*anAttrIt) || isUpdated;
164
165   // check external attribute is changed
166   bool isExternal = aSketchFeature &&
167                    (aSketchFeature->isExternal() || isCopyFeature(aSketchFeature));
168   if (aRelated && isExternal != aRelated->isExternal()) {
169     if (isExternal)
170       makeExternal(aRelated);
171     else
172       makeNonExternal(aRelated);
173     isUpdated = true;
174   }
175
176   // send notification to listeners due to at least one attribute is changed
177   if (sendNotify && isUpdated)
178     notify(theFeature);
179
180   // update arc
181   if (aRelated)
182     PlaneGCSSolver_Tools::recalculateArcParameters(aRelated);
183
184   return isUpdated;
185 }
186
187 bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce)
188 {
189   if (!theAttribute->isInitialized())
190     return false;
191
192   AttributePtr anAttribute = theAttribute;
193   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
194   if (aRefAttr) {
195     if (aRefAttr->isObject()) {
196       FeaturePtr aFeature;
197       /// TODO: Check resultToFeatureOrAttribute() precisely.
198       resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute);
199       if (aFeature)
200         return update(aFeature, theForce);
201     } else
202       anAttribute = aRefAttr->attr();
203   }
204
205   EntityWrapperPtr aRelated = entity(anAttribute);
206   FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
207   if (!aRelated) { // Attribute does not exist, create it.
208     // First of all check if the parent feature exists. If not, add it.
209     if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
210       return update(aFeature, theForce); // theAttribute has been processed while adding feature
211     return aRelated.get() != 0;
212   }
213
214   PlaneGCSSolver_AttributeBuilder aBuilder(aRelated->isExternal() ? 0 : this);
215   bool isUpdated = aBuilder.updateAttribute(anAttribute, aRelated);
216   if (isUpdated) {
217     setNeedToResolve(true);
218     notify(aFeature);
219   }
220   return isUpdated;
221 }
222
223 void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity)
224 {
225   if (theEntity->isExternal())
226     return;
227
228   removeAuxiliaryConstraints(theEntity);
229
230   GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
231   mySketchSolver->removeParameters(aParameters);
232   theEntity->setExternal(true);
233   myNeedToResolve = true;
234 }
235
236 void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity)
237 {
238   if (!theEntity->isExternal())
239     return;
240
241   GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
242   mySketchSolver->addParameters(aParameters);
243   theEntity->setExternal(false);
244
245   createAuxiliaryConstraints(theEntity);
246
247   myNeedToResolve = true;
248 }
249
250
251 static void createArcConstraints(const EntityWrapperPtr& theArc,
252                                  const SolverPtr& theSolver,
253                                  const ConstraintID theConstraintID,
254                                  std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
255 {
256   EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theArc);
257   std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
258
259   // Additional constaints to fix arc's extra DoF (if the arc is not external):
260   std::list<GCSConstraintPtr> anArcConstraints;
261   // 1. distances from center till start and end points are equal to radius
262   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
263       anArc->center, anArc->start, anArc->rad)));
264   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
265       anArc->center, anArc->end, anArc->rad)));
266   // 2. angles of start and end points should be equal to the arc angles
267   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
268       anArc->center, anArc->start, anArc->startAngle)));
269   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
270       anArc->center, anArc->end, anArc->endAngle)));
271
272   ConstraintWrapperPtr aWrapper(
273     new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
274   aWrapper->setId(theConstraintID);
275   constraintsToSolver(aWrapper, theSolver);
276
277   theConstraints[theArc] = aWrapper;
278 }
279
280 static void createEllipseConstraints(
281     const EntityWrapperPtr& theEllipse,
282     const SolverPtr& theSolver,
283     const ConstraintID theConstraintID,
284     std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
285 {
286   EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipse);
287   std::shared_ptr<GCS::Ellipse> anEllipse =
288       std::dynamic_pointer_cast<GCS::Ellipse>(anEdge->entity());
289
290   // Additional constaints to fix ellipse's extra points
291   std::list<GCSConstraintPtr> anEllipseConstraints;
292
293   const std::map<std::string, EntityWrapperPtr>& anAttributes = theEllipse->additionalAttributes();
294   for (std::map<std::string, EntityWrapperPtr>::const_iterator anIt = anAttributes.begin();
295        anIt != anAttributes.end(); ++anIt) {
296     std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
297         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
298     if (!aPoint)
299       continue;
300
301     GCS::InternalAlignmentType anAlignmentX, anAlignmentY;
302     if (anIt->first == SketchPlugin_Ellipse::SECOND_FOCUS_ID())
303       anAlignmentX = GCS::EllipseFocus2X;
304     else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID())
305       anAlignmentX = GCS::EllipseNegativeMajorX;
306     else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID())
307       anAlignmentX = GCS::EllipsePositiveMajorX;
308     else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_START_ID())
309       anAlignmentX = GCS::EllipseNegativeMinorX;
310     else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_END_ID())
311       anAlignmentX = GCS::EllipsePositiveMinorX;
312
313     anEllipseConstraints.push_back(GCSConstraintPtr(
314         new GCS::ConstraintInternalAlignmentPoint2Ellipse(
315         *anEllipse, *(aPoint->point()), anAlignmentX)));
316     anAlignmentY = (GCS::InternalAlignmentType)((int)anAlignmentX + 1);
317     anEllipseConstraints.push_back(GCSConstraintPtr(
318         new GCS::ConstraintInternalAlignmentPoint2Ellipse(
319         *anEllipse, *(aPoint->point()), anAlignmentY)));
320   }
321
322   // constraint to bind the major radius value
323   std::shared_ptr<PlaneGCSSolver_PointWrapper> aMajorAxisStart =
324       std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
325       anAttributes.at(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()));
326   ScalarWrapperPtr aMajorRadius =
327       std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(
328       anAttributes.at(SketchPlugin_Ellipse::MAJOR_RADIUS_ID()));
329   anEllipseConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
330       anEllipse->center, *(aMajorAxisStart->point()), aMajorRadius->scalar())));
331
332   ConstraintWrapperPtr aWrapper(
333     new PlaneGCSSolver_ConstraintWrapper(anEllipseConstraints, CONSTRAINT_UNKNOWN));
334   aWrapper->setId(theConstraintID);
335   if (theSolver)
336     constraintsToSolver(aWrapper, theSolver);
337
338   theConstraints[theEllipse] = aWrapper;
339 }
340
341 static void createEllipticArcConstraints(
342     const EntityWrapperPtr& theEllipticArc,
343     const SolverPtr& theSolver,
344     const ConstraintID theConstraintID,
345     std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
346 {
347   // create base constraints for the ellipse without adding them to solver
348   createEllipseConstraints(theEllipticArc, SolverPtr(), theConstraintID, theConstraints);
349
350   ConstraintWrapperPtr& aConstraint = theConstraints[theEllipticArc];
351   std::list<GCSConstraintPtr> anEllArcConstraints = aConstraint->constraints();
352
353   // constrain extremities of the elliptic arc
354   EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipticArc);
355   std::shared_ptr<GCS::ArcOfEllipse> anArc =
356       std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
357
358   anEllArcConstraints.push_back(GCSConstraintPtr(
359       new GCS::ConstraintCurveValue(anArc->start, anArc->start.x, *anArc, anArc->startAngle)));
360   anEllArcConstraints.push_back(GCSConstraintPtr(
361       new GCS::ConstraintCurveValue(anArc->start, anArc->start.y, *anArc, anArc->startAngle)));
362   anEllArcConstraints.push_back(GCSConstraintPtr(
363       new GCS::ConstraintCurveValue(anArc->end, anArc->end.x, *anArc, anArc->endAngle)));
364   anEllArcConstraints.push_back(GCSConstraintPtr(
365       new GCS::ConstraintCurveValue(anArc->end, anArc->end.y, *anArc, anArc->endAngle)));
366
367   aConstraint->setConstraints(anEllArcConstraints);
368   constraintsToSolver(aConstraint, theSolver);
369 }
370
371 static void createBSplineConstraints(
372     const EntityWrapperPtr& theCurve,
373     const SolverPtr& theSolver,
374     const ConstraintID theConstraintID,
375     std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
376 {
377   // set start and end point of B-spline equal to first and last pole correspondingly
378   EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theCurve);
379   std::shared_ptr<GCS::BSpline> aBSpline =
380       std::dynamic_pointer_cast<GCS::BSpline>(anEdge->entity());
381
382   std::list<GCSConstraintPtr> aBSplineConstraints;
383
384   const std::map<std::string, EntityWrapperPtr>& anAdditional = anEdge->additionalAttributes();
385   PointWrapperPtr aStartPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
386       anAdditional.at(SketchPlugin_BSpline::START_ID()));
387
388   const GCS::Point& sp = *aStartPoint->point();
389   const GCS::Point& p0 = aBSpline->poles.front();
390   aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.x, sp.x)));
391   aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.y, sp.y)));
392
393   PointWrapperPtr aEndPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
394       anAdditional.at(SketchPlugin_BSpline::END_ID()));
395
396   const GCS::Point& ep = *aEndPoint->point();
397   const GCS::Point& pN = aBSpline->poles.back();
398   aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.x, ep.x)));
399   aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.y, ep.y)));
400
401   ConstraintWrapperPtr aWrapper(
402       new PlaneGCSSolver_ConstraintWrapper(aBSplineConstraints, CONSTRAINT_UNKNOWN));
403   aWrapper->setId(theConstraintID);
404   if (theSolver)
405     constraintsToSolver(aWrapper, theSolver);
406
407   theConstraints[theCurve] = aWrapper;
408 }
409
410 void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
411 {
412   if (!theEntity || theEntity->isExternal())
413     return;
414
415   if (theEntity->type() == ENTITY_ARC)
416     createArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
417   else if (theEntity->type() == ENTITY_ELLIPSE)
418     createEllipseConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
419   else if (theEntity->type() == ENTITY_ELLIPTIC_ARC) {
420     createEllipticArcConstraints(theEntity, mySketchSolver,
421                                  ++myConstraintLastID, myAuxConstraintMap);
422   }
423   else if (theEntity->type() == ENTITY_BSPLINE)
424     createBSplineConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
425 }
426
427 void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
428 {
429   std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator
430       aFound = myAuxConstraintMap.find(theEntity);
431   if (aFound != myAuxConstraintMap.end()) {
432     mySketchSolver->removeConstraint(aFound->second->id());
433     myAuxConstraintMap.erase(aFound);
434   }
435 }
436
437 template <typename ARCTYPE>
438 void adjustArcParametrization(ARCTYPE& theArc, bool theReversed)
439 {
440   // tune start angle of the arc to be in [0, 2PI]
441   while (*theArc.startAngle < -PI)
442     *theArc.startAngle += 2.0 * PI;
443   while (*theArc.startAngle >= PI)
444     *theArc.startAngle -= 2.0 * PI;
445   // adjust end angle of the arc
446   if (theReversed) {
447     while (*theArc.endAngle > *theArc.startAngle)
448       *theArc.endAngle -= 2.0 * PI;
449     while (*theArc.endAngle + 2 * PI < *theArc.startAngle)
450       *theArc.endAngle += 2.0 * PI;
451   }
452   else {
453     while (*theArc.endAngle < *theArc.startAngle)
454       *theArc.endAngle += 2.0 * PI;
455     while (*theArc.endAngle > *theArc.startAngle + 2 * PI)
456       *theArc.endAngle -= 2.0 * PI;
457   }
458 }
459
460 void PlaneGCSSolver_Storage::adjustParametrizationOfArcs()
461 {
462   std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator anIt = myAuxConstraintMap.begin();
463   for (; anIt != myAuxConstraintMap.end(); ++anIt) {
464     EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(anIt->first);
465     std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
466     if (anArc)
467       adjustArcParametrization(*anArc, anEdge->isReversed());
468     else {
469       std::shared_ptr<GCS::ArcOfEllipse> aEllArc =
470           std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
471       if (aEllArc)
472         adjustArcParametrization(*aEllArc, anEdge->isReversed());
473     }
474   }
475
476   // update parameters of Middle point constraint for point on arc
477   std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator aCIt = myConstraintMap.begin();
478   for (; aCIt != myConstraintMap.end(); ++aCIt)
479     if (aCIt->second->type() == CONSTRAINT_MIDDLE_POINT) {
480       notify(aCIt->first);
481     }
482 }
483
484
485 bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
486 {
487   std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator
488       aFound = myConstraintMap.find(theConstraint);
489   if (aFound != myConstraintMap.end()) {
490     ConstraintWrapperPtr aCW = aFound->second;
491     ConstraintID anID = aCW->id();
492
493     // Remove solver's constraints
494     mySketchSolver->removeConstraint(anID);
495
496     // Remove value if exists
497     const ScalarWrapperPtr& aValue = aCW->valueParameter();
498     if (aValue) {
499       GCS::SET_pD aParToRemove;
500       aParToRemove.insert(aValue->scalar());
501       removeParameters(aParToRemove);
502     }
503
504     // Remove constraint
505     myConstraintMap.erase(aFound);
506
507     if (anID != CID_MOVEMENT)
508       myNeedToResolve = true;
509
510     // notify subscibers
511     notify(theConstraint);
512   }
513   return true;
514 }
515
516 void PlaneGCSSolver_Storage::removeInvalidEntities()
517 {
518   PlaneGCSSolver_EntityDestroyer aDestroyer;
519
520   // Remove invalid constraints
521   std::list<ConstraintPtr> anInvalidConstraints;
522   std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
523       aCIter = myConstraintMap.begin();
524   for (; aCIter != myConstraintMap.end(); ++aCIter)
525     if (!aCIter->first->data() || !aCIter->first->data()->isValid())
526       anInvalidConstraints.push_back(aCIter->first);
527   std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
528   for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
529     removeConstraint(*anInvCIt);
530
531   // Remove invalid features
532   std::list<FeaturePtr> anInvalidFeatures;
533   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
534   for (; aFIter != myFeatureMap.end(); aFIter++)
535     if (!aFIter->first->data() || !aFIter->first->data()->isValid()) {
536       anInvalidFeatures.push_back(aFIter->first);
537       if (aFIter->second)
538         aDestroyer.remove(aFIter->second);
539
540       // remove invalid arc
541       removeAuxiliaryConstraints(aFIter->second);
542     }
543   std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
544   for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
545     removeFeature(*anInvFIt);
546
547   // Remove invalid attributes
548   std::list<AttributePtr> anInvalidAttributes;
549   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAttrIt = myAttributeMap.begin();
550   for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
551     FeaturePtr anOwner = ModelAPI_Feature::feature(anAttrIt->first->owner());
552     if (!anOwner || !anOwner->data() || !anOwner->data()->isValid()) {
553       anInvalidAttributes.push_back(anAttrIt->first);
554       aDestroyer.remove(anAttrIt->second);
555     }
556   }
557   std::list<AttributePtr>::const_iterator anInvAtIt = anInvalidAttributes.begin();
558   for (; anInvAtIt != anInvalidAttributes.end(); ++anInvAtIt)
559     removeAttribute(*anInvAtIt);
560
561   // free memory occupied by parameters
562   removeParameters(aDestroyer.parametersToRemove());
563
564   /// TODO: Think on optimization of checking invalid features and attributes
565 }
566
567
568
569 double* PlaneGCSSolver_Storage::createParameter()
570 {
571   return mySketchSolver->createParameter();
572 }
573
574 void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams)
575 {
576   mySketchSolver->removeParameters(theParams);
577   for (GCS::SET_pD::iterator it = theParams.begin(); it != theParams.end(); ++it)
578     delete *it;
579 }
580
581 // indicates attribute containing in the external feature
582 static bool isExternalAttribute(const AttributePtr& theAttribute)
583 {
584   if (!theAttribute)
585     return false;
586   std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
587       std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
588   return aSketchFeature.get() && aSketchFeature->isExternal();
589 }
590
591 static void addOwnerToSet(const AttributePtr& theAttribute, std::set<FeaturePtr>& theFeatures)
592 {
593   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
594   if (anOwner)
595     theFeatures.insert(anOwner);
596 }
597
598 void PlaneGCSSolver_Storage::refresh() const
599 {
600   const double aTol = 1000. * tolerance; // tolerance to prevent frequent updates
601
602   std::set<FeaturePtr> anUpdatedFeatures;
603
604   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
605   for (; anIt != myAttributeMap.end(); ++anIt) {
606     if (!anIt->first->isInitialized())
607       continue;
608
609     // the external feature always should keep the up to date values, so,
610     // refresh from the solver is never needed
611     if (isExternalAttribute(anIt->first))
612       continue;
613
614     std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
615         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
616     if (aPoint2D) {
617       std::shared_ptr<PlaneGCSSolver_PointWrapper> aPointWrapper =
618           std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
619       GCSPointPtr aGCSPoint = aPointWrapper->point();
620       if (fabs(aPoint2D->x() - (*aGCSPoint->x)) > aTol ||
621           fabs(aPoint2D->y() - (*aGCSPoint->y)) > aTol) {
622         aPoint2D->setValue(*aGCSPoint->x, *aGCSPoint->y);
623         addOwnerToSet(anIt->first, anUpdatedFeatures);
624       }
625       continue;
626     }
627     std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
628         std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anIt->first);
629     if (aPointArray) {
630       std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> anArrayWrapper =
631           std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
632       int aSize = aPointArray->size();
633       for (int anIndex = 0; anIndex < aSize; ++anIndex) {
634         GeomPnt2dPtr anOriginal = aPointArray->pnt(anIndex);
635         GCSPointPtr aGCSPoint = anArrayWrapper->value(anIndex)->point();
636         if (fabs(anOriginal->x() - (*aGCSPoint->x)) > aTol ||
637             fabs(anOriginal->y() - (*aGCSPoint->y)) > aTol) {
638           aPointArray->setPnt(anIndex, *aGCSPoint->x, *aGCSPoint->y);
639           addOwnerToSet(anIt->first, anUpdatedFeatures);
640         }
641       }
642       continue;
643     }
644     AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
645     if (aScalar) {
646       ScalarWrapperPtr aScalarWrapper =
647           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
648       if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol) {
649         aScalar->setValue(aScalarWrapper->value());
650         addOwnerToSet(anIt->first, anUpdatedFeatures);
651       }
652       continue;
653     }
654     AttributeDoubleArrayPtr aRealArray =
655         std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(anIt->first);
656     if (aRealArray) {
657       std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> anArrayWrapper =
658           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
659       int aSize = aRealArray->size();
660       for (int anIndex = 0; anIndex < aSize; ++anIndex) {
661         if (fabs(aRealArray->value(anIndex) - *anArrayWrapper->array()[anIndex]) > aTol) {
662           aRealArray->setValue(anIndex, *anArrayWrapper->array()[anIndex]);
663           addOwnerToSet(anIt->first, anUpdatedFeatures);
664         }
665       }
666       continue;
667     }
668   }
669
670   // notify listeners about features update
671   std::set<FeaturePtr>::const_iterator aFIt = anUpdatedFeatures.begin();
672   for (; aFIt != anUpdatedFeatures.end(); ++aFIt)
673     notify(*aFIt);
674 }
675
676 PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeometry() const
677 {
678   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
679   for (; aFIt != myFeatureMap.end(); ++aFIt) {
680     EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aFIt->second);
681     if (anEdge && anEdge->isDegenerated())
682       return PlaneGCSSolver_Solver::STATUS_DEGENERATED;
683   }
684   return PlaneGCSSolver_Solver::STATUS_OK;
685 }
686
687
688 void PlaneGCSSolver_Storage::getUnderconstrainedGeometry(std::set<ObjectPtr>& theFeatures) const
689 {
690   std::set<double*> aFreeParams;
691   mySketchSolver->getFreeParameters(aFreeParams);
692   if (aFreeParams.empty())
693     return;
694
695   for (std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
696        aFIt != myFeatureMap.end(); ++aFIt) {
697     if (!aFIt->second)
698       continue;
699     GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(aFIt->second);
700     for (GCS::SET_pD::iterator aPIt = aParams.begin(); aPIt != aParams.end(); ++aPIt)
701       if (aFreeParams.find(*aPIt) != aFreeParams.end()) {
702         theFeatures.insert(aFIt->first);
703         break;
704       }
705   }
706 }