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