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