Salome HOME
crash fix: mirror (line, axis of sketch), select with rectangle, delete
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_Storage.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    PlaneGCSSolver_Storage.cpp
4 // Created: 14 Dec 2015
5 // Author:  Artem ZHIDKOV
6
7 #include <PlaneGCSSolver_Storage.h>
8 #include <PlaneGCSSolver_Builder.h>
9 #include <PlaneGCSSolver_Solver.h>
10 #include <PlaneGCSSolver_ConstraintWrapper.h>
11 #include <PlaneGCSSolver_EntityWrapper.h>
12 #include <PlaneGCSSolver_PointWrapper.h>
13 #include <PlaneGCSSolver_ScalarWrapper.h>
14 #include <PlaneGCSSolver_ParameterWrapper.h>
15
16 #include <GeomAPI_Edge.h>
17 #include <GeomAPI_Dir2d.h>
18 #include <GeomAPI_Pnt2d.h>
19 #include <GeomAPI_XY.h>
20 #include <GeomDataAPI_Point2D.h>
21 #include <SketchPlugin_Arc.h>
22
23 #include <cmath>
24
25
26 PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const GroupID& theGroup)
27   : SketchSolver_Storage(theGroup),
28     myEntityLastID(EID_SKETCH),
29     myConstraintLastID(CID_UNKNOWN)
30 {
31 }
32
33 void PlaneGCSSolver_Storage::addConstraint(
34     ConstraintPtr                   theConstraint,
35     std::list<ConstraintWrapperPtr> theSolverConstraints)
36 {
37   SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraints);
38
39   // update point-point coincidence
40   if (!theSolverConstraints.empty() &&
41       theSolverConstraints.front()->type() == CONSTRAINT_PT_PT_COINCIDENT) {
42     std::list<ConstraintWrapperPtr>::iterator aCIt = theSolverConstraints.begin();
43     for (; aCIt != theSolverConstraints.end(); ++aCIt)
44       update(*aCIt);
45   }
46 }
47
48
49 bool PlaneGCSSolver_Storage::update(ConstraintWrapperPtr theConstraint)
50 {
51   bool isUpdated = false;
52   std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
53       std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
54
55   // point-Line distance should be positive
56   if (aConstraint->type() == CONSTRAINT_PT_LINE_DISTANCE && aConstraint->value() < 0.0)
57     aConstraint->setValue(-aConstraint->value());
58
59   // make value of constraint unchangeable
60   ParameterWrapperPtr aValue = aConstraint->valueParameter();
61   if (aValue)
62     isUpdated = update(aValue) || isUpdated;
63
64   // update constrained entities
65   std::list<EntityWrapperPtr> anEntities = theConstraint->entities();
66   std::list<EntityWrapperPtr>::iterator anIt = anEntities.begin();
67   for (; anIt != anEntities.end(); ++anIt)
68     isUpdated = update(*anIt) || isUpdated;
69
70   // Change ID of constraints
71   if (aConstraint->id() == CID_UNKNOWN)
72     aConstraint->setId(++myConstraintLastID);
73
74   return isUpdated;
75 }
76
77 /// \brief Update coordinates of the point or scalar using its base attribute
78 static bool updateValues(EntityWrapperPtr& theEntity)
79 {
80   bool isUpdated = false;
81   AttributePtr anAttr = theEntity->baseAttribute();
82   const std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
83
84   double aCoord[2];
85
86   std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
87       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
88   if (aPoint2D) {
89     aCoord[0] = aPoint2D->x();
90     aCoord[1] = aPoint2D->y();
91   } else {
92     AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttr);
93     if (aScalar)
94       aCoord[0] = aScalar->value();
95   }
96
97   std::list<ParameterWrapperPtr>::const_iterator anIt = aParams.begin();
98   for (int i = 0; anIt != aParams.end(); ++anIt, ++i)
99     if (fabs((*anIt)->value() - aCoord[i]) > tolerance) {
100       (*anIt)->setValue(aCoord[i]);
101       isUpdated = true;
102     }
103   return isUpdated;
104 }
105
106 bool PlaneGCSSolver_Storage::update(EntityWrapperPtr theEntity)
107 {
108   if (theEntity->type() == ENTITY_SKETCH)
109     return true; // sketch is not necessary for PlaneGCS, so it is always says true
110
111   bool isUpdated = false;
112
113   if (theEntity->baseAttribute()) {
114     isUpdated = updateValues(theEntity);
115     if (isUpdated)
116       setNeedToResolve(true);
117   }
118
119   // update parameters
120   std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
121   std::list<ParameterWrapperPtr>::iterator aPIt = aParams.begin();
122   for (; aPIt != aParams.end(); ++aPIt)
123     isUpdated = update(*aPIt) || isUpdated;
124
125   // update sub-entities
126   std::list<EntityWrapperPtr> aSubEntities = theEntity->subEntities();
127   std::list<EntityWrapperPtr>::iterator aSIt = aSubEntities.begin();
128   for (; aSIt != aSubEntities.end(); ++aSIt)
129     isUpdated = update(*aSIt) || isUpdated;
130
131   // additional constraints for the arc processing
132   if (theEntity->type() == ENTITY_ARC)
133     processArc(theEntity);
134
135   // Change entity's ID, if necessary
136   if (theEntity->id() == EID_UNKNOWN) {
137     if (theEntity->type() == ENTITY_POINT) {
138       std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
139           std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity);
140       if (!aPoint) {
141         aPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
142             theEntity->subEntities().front());
143       }
144       aPoint->setId(++myEntityLastID);
145     } else if (theEntity->type() == ENTITY_SCALAR) {
146       std::shared_ptr<PlaneGCSSolver_ScalarWrapper> aScalar =
147           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theEntity);
148       aScalar->setId(++myEntityLastID);
149     } else {
150       std::shared_ptr<PlaneGCSSolver_EntityWrapper> aGCSEnt =
151           std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theEntity);
152       aGCSEnt->setId(++myEntityLastID);
153     }
154   }
155   return isUpdated;
156 }
157
158 bool PlaneGCSSolver_Storage::update(ParameterWrapperPtr theParameter)
159 {
160   std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam =
161       std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(theParameter);
162   if (aParam->isProcessed())
163     return false;
164   if (theParameter->group() != myGroupID || theParameter->isParametric())
165     myConst.push_back(aParam->parameter());
166   else
167     myParameters.push_back(aParam->parameter());
168   aParam->setProcessed(true);
169   return true;
170 }
171
172
173 bool PlaneGCSSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
174 {
175   std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
176     std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
177
178   bool isFullyRemoved = true;
179   const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
180   std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
181   for (; aSIt != aSubs.end(); ++ aSIt)
182     isFullyRemoved = remove(*aSIt) && isFullyRemoved;
183
184   if (aConstraint->valueParameter())
185     isFullyRemoved = remove(aConstraint->valueParameter()) && isFullyRemoved;
186   if (!isFullyRemoved && aConstraint->baseConstraint() &&
187      (!aConstraint->baseConstraint()->data() || !aConstraint->baseConstraint()->data()->isValid()))
188     isFullyRemoved = true;
189   setNeedToResolve(true);
190   myRemovedConstraints.insert(myRemovedConstraints.end(),
191       aConstraint->constraints().begin(), aConstraint->constraints().end());
192
193   if (isFullyRemoved && theConstraint->id() == myConstraintLastID)
194     --myConstraintLastID;
195
196   return isFullyRemoved;
197 }
198
199 bool PlaneGCSSolver_Storage::remove(EntityWrapperPtr theEntity)
200 {
201   if ((theEntity->baseAttribute() && isUsed(theEntity->baseAttribute())) ||
202       (theEntity->baseFeature() && isUsed(theEntity->baseFeature())))
203     return false;
204
205   bool isFullyRemoved = SketchSolver_Storage::remove(theEntity);
206   if (isFullyRemoved && theEntity->id() == myEntityLastID)
207     --myEntityLastID;
208   return isFullyRemoved;
209 }
210
211 bool PlaneGCSSolver_Storage::remove(ParameterWrapperPtr theParameter)
212 {
213   std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam =
214       std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(theParameter);
215   if (aParam->isProcessed()) {
216     double* aValPtr = aParam->parameter();
217     GCS::VEC_pD::iterator anIt =  myParameters.begin();
218     for (; anIt != myParameters.end(); ++anIt)
219       if (*anIt == aValPtr)
220         break;
221     if (anIt != myParameters.end()) {
222       myParameters.erase(anIt);
223       setNeedToResolve(true);
224     }
225     else {
226       for (anIt = myConst.begin(); anIt != myConst.end(); ++anIt)
227         if (*anIt == aValPtr)
228           break;
229       if (anIt != myConst.end()) {
230         myConst.erase(anIt);
231         setNeedToResolve(true);
232       }
233     }
234   }
235   aParam->setProcessed(false);
236   return true;
237 }
238
239
240 void PlaneGCSSolver_Storage::addCoincidentPoints(
241     EntityWrapperPtr theMaster, EntityWrapperPtr theSlave)
242 {
243   if (theMaster->type() != ENTITY_POINT || theSlave->type() != ENTITY_POINT)
244     return;
245
246   std::shared_ptr<PlaneGCSSolver_PointWrapper> aMaster =
247       std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theMaster);
248   if (!aMaster)
249     aMaster = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
250       std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theMaster)->subEntities().front());
251   std::shared_ptr<PlaneGCSSolver_PointWrapper> aSlave =
252       std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSlave);
253   if (!aSlave)
254     aSlave = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
255       std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theSlave)->subEntities().front());
256
257   // Search available coincidence
258   CoincidentPointsMap::iterator aMasterFound = myCoincidentPoints.find(aMaster);
259   CoincidentPointsMap::iterator aSlaveFound = myCoincidentPoints.find(aSlave);
260   if (aMasterFound == myCoincidentPoints.end() &&  aSlaveFound == myCoincidentPoints.end()) {
261     // try to find master and slave points in the lists of slaves of already existent coincidences
262     CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin();
263     for (; anIt != myCoincidentPoints.end(); ++anIt) {
264       if (anIt->second.find(aMaster) != anIt->second.end())
265         aMasterFound = anIt;
266       else if (anIt->second.find(aSlave) != anIt->second.end())
267         aSlaveFound = anIt;
268
269       if (aMasterFound != myCoincidentPoints.end() &&  aSlaveFound != myCoincidentPoints.end())
270         break;
271     }
272   }
273
274   if (aMasterFound == myCoincidentPoints.end()) {
275     // create new group
276     myCoincidentPoints[aMaster] = std::set<EntityWrapperPtr>();
277     aMasterFound = myCoincidentPoints.find(aMaster);
278   } else if (aMasterFound == aSlaveFound)
279     return; // already coincident
280
281   if (aSlaveFound != myCoincidentPoints.end()) {
282     // A slave has been found, we need to attach all points coincident with it to the new master
283     std::set<EntityWrapperPtr> aNewSlaves = aSlaveFound->second;
284     aNewSlaves.insert(aSlaveFound->first);
285     myCoincidentPoints.erase(aSlaveFound);
286
287     std::set<EntityWrapperPtr>::const_iterator aSlIt = aNewSlaves.begin();
288     for (; aSlIt != aNewSlaves.end(); ++aSlIt)
289       addCoincidentPoints(aMaster, *aSlIt);
290   } else {
291     //std::list<ParameterWrapperPtr> aSlaveParams = aSlave->parameters();
292     //aSlave->setParameters(aMaster->parameters());
293
294     //// Remove slave's parameters
295     //std::list<ParameterWrapperPtr>::iterator aParIt = aSlaveParams.begin();
296     //for (; aParIt != aSlaveParams.end(); ++aParIt)
297     //  remove(*aParIt);
298
299     aMasterFound->second.insert(aSlave);
300   }
301 }
302
303
304 void PlaneGCSSolver_Storage::changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup)
305 {
306   theEntity->setGroup(theGroup);
307   if (theGroup == myGroupID)
308     makeVariable(theEntity);
309   else {
310     if (theEntity->type() == ENTITY_POINT)
311       update(theEntity);
312     makeConstant(theEntity);
313   }
314 }
315
316 void PlaneGCSSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup)
317 {
318   // TODO
319 }
320
321 void PlaneGCSSolver_Storage::verifyFixed()
322 {
323   // TODO
324 }
325
326 void PlaneGCSSolver_Storage::processArc(const EntityWrapperPtr& theArc)
327 {
328   // Calculate additional parameters necessary for PlaneGCS
329   const std::list<EntityWrapperPtr>& aSubs = theArc->subEntities();
330   std::list<EntityWrapperPtr>::const_iterator aSubIt = aSubs.begin();
331   while ((*aSubIt)->type() == ENTITY_POINT) // search scalar entities
332     ++aSubIt;
333   double* aStartAngle = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt++)->scalar();
334   double* aEndAngle   = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt++)->scalar();
335   double* aRadius     = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt)->scalar();
336
337   FeaturePtr anArcFeature = theArc->baseFeature();
338   std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
339       anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()));
340   std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
341       anArcFeature->attribute(SketchPlugin_Arc::START_ID()));
342   std::shared_ptr<GeomDataAPI_Point2D> aEndAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
343       anArcFeature->attribute(SketchPlugin_Arc::END_ID()));
344   if (!aCenterAttr || !aStartAttr || !aEndAttr)
345     return;
346   std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = aCenterAttr->pnt();
347   std::shared_ptr<GeomAPI_Pnt2d> aStartPnt  = aStartAttr->pnt();
348   std::shared_ptr<GeomAPI_Pnt2d> aEndPnt    = aEndAttr->pnt();
349
350   *aRadius = aCenterPnt->distance(aStartPnt);
351   if (!anArcFeature->lastResult())
352     return;
353   std::shared_ptr<GeomAPI_Edge> anArcEdge =
354       std::dynamic_pointer_cast<GeomAPI_Edge>(anArcFeature->lastResult()->shape());
355   if (!anArcEdge)
356     return;
357   anArcEdge->getRange(*aStartAngle, *aEndAngle);
358
359   // No need to add constraints if they are already exist
360   std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >::const_iterator
361       aFound = myArcConstraintMap.find(theArc);
362   if (aFound != myArcConstraintMap.end())
363     return;
364
365   // Prepare additional constraints to produce the arc
366   std::vector<GCSConstraintPtr> anArcConstraints;
367   std::shared_ptr<PlaneGCSSolver_EntityWrapper> anArcEnt =
368       std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theArc);
369   std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anArcEnt->entity());
370   // Distances from center till start and end points are equal to radius
371   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
372       anArc->center, anArc->start, anArc->rad)));
373   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
374       anArc->center, anArc->end, anArc->rad)));
375   // Angles of start and end points should be equal to given angles
376   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
377       anArc->center, anArc->start, anArc->startAngle)));
378   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
379       anArc->center, anArc->end, anArc->endAngle)));
380
381   myArcConstraintMap[theArc] = anArcConstraints;
382 }
383
384
385 void PlaneGCSSolver_Storage::makeConstant(const EntityWrapperPtr& theEntity)
386 {
387   toggleEntity(theEntity, myParameters, myConst);
388   if (theEntity->type() == ENTITY_POINT)
389     updateCoincident(theEntity);
390 }
391
392 void PlaneGCSSolver_Storage::makeVariable(const EntityWrapperPtr& theEntity)
393 {
394   toggleEntity(theEntity, myConst, myParameters);
395 }
396
397 static void getParametersToMove(const EntityWrapperPtr& theEntity, std::set<double*>& theParamList)
398 {
399   const std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
400   std::list<ParameterWrapperPtr>::const_iterator aPIt = aParams.begin();
401   for (; aPIt != aParams.end(); ++aPIt)
402     theParamList.insert(
403         std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(*aPIt)->parameter());
404
405   const std::list<EntityWrapperPtr> aSubs = theEntity->subEntities();
406   std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
407
408   if (theEntity->type() == ENTITY_ARC) {
409     // workaround for the arc processing, because the arc is fixed by a set of constraints,
410     // which will conflict with all parameters fixed:
411     // 1. take center
412     getParametersToMove(*aSIt++, theParamList);
413     // 2. take start point
414     getParametersToMove(*aSIt++, theParamList);
415     // 3. skip end point, radius and start angle, but take end angle parameter
416     getParametersToMove(*(++aSIt), theParamList);
417   } else {
418     for (; aSIt != aSubs.end(); ++aSIt)
419       getParametersToMove(*aSIt, theParamList);
420   }
421 }
422
423 void PlaneGCSSolver_Storage::toggleEntity(
424     const EntityWrapperPtr& theEntity, GCS::VEC_pD& theFrom, GCS::VEC_pD& theTo)
425 {
426   std::set<double*> aParamsToMove;
427   getParametersToMove(theEntity, aParamsToMove);
428
429   GCS::VEC_pD::iterator anIt = theFrom.begin();
430   while (anIt != theFrom.end()) {
431     if (aParamsToMove.find(*anIt) == aParamsToMove.end()) {
432       ++anIt;
433       continue;
434     }
435
436     theTo.push_back(*anIt);
437     int aShift = anIt - theFrom.begin();
438     theFrom.erase(anIt);
439     anIt = theFrom.begin() + aShift;
440   }
441 }
442
443 void PlaneGCSSolver_Storage::updateCoincident(const EntityWrapperPtr& thePoint)
444 {
445   CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin();
446   for (; anIt != myCoincidentPoints.end(); ++anIt) {
447     if (anIt->first == thePoint || anIt->second.find(thePoint) != anIt->second.end()) {
448       std::set<EntityWrapperPtr> aCoincident = anIt->second;
449       aCoincident.insert(anIt->first);
450
451       const std::list<ParameterWrapperPtr>& aBaseParams = thePoint->parameters();
452       std::list<ParameterWrapperPtr> aParams;
453       std::list<ParameterWrapperPtr>::const_iterator aBaseIt, anUpdIt;
454
455       std::set<EntityWrapperPtr>::const_iterator aCoincIt = aCoincident.begin();
456       for (; aCoincIt != aCoincident.end(); ++aCoincIt)
457         if (*aCoincIt != thePoint && (*aCoincIt)->group() != GID_OUTOFGROUP) {
458           aParams = (*aCoincIt)->parameters();
459           aBaseIt = aBaseParams.begin();
460           for (anUpdIt = aParams.begin(); anUpdIt != aParams.end(); ++anUpdIt, ++aBaseIt)
461             (*anUpdIt)->setValue((*aBaseIt)->value());
462         }
463
464       break;
465     }
466   }
467 }
468
469
470 bool PlaneGCSSolver_Storage::isRedundant(
471     GCSConstraintPtr theCheckedConstraint,
472     ConstraintWrapperPtr theParentConstraint) const
473 {
474   if (theParentConstraint->type() == CONSTRAINT_SYMMETRIC) {
475     if (theCheckedConstraint->getTypeId() == GCS::Perpendicular) {
476       BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
477       // check the initial point is placed on the mirror line
478       std::list<EntityWrapperPtr> aSubs = theParentConstraint->entities();
479       std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(aSubs.front());
480       std::shared_ptr<GeomAPI_Lin2d> aLine = aBuilder->line(aSubs.back());
481       return aLine->distance(aPoint) < tolerance;
482     }
483   }
484
485   return false;
486 }
487
488 void PlaneGCSSolver_Storage::initializeSolver(SolverPtr theSolver)
489 {
490   std::shared_ptr<PlaneGCSSolver_Solver> aSolver =
491       std::dynamic_pointer_cast<PlaneGCSSolver_Solver>(theSolver);
492   if (!aSolver)
493     return;
494
495   if (myExistArc)
496     processArcs();
497
498   // initialize constraints
499   std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
500       aCIt = myConstraintMap.begin();
501   for (; aCIt != myConstraintMap.end(); ++aCIt) {
502     std::list<ConstraintWrapperPtr>::const_iterator aCWIt = aCIt->second.begin();
503     for (; aCWIt != aCIt->second.end(); ++ aCWIt) {
504       std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aGCS =
505           std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(*aCWIt);
506       std::list<GCSConstraintPtr>::const_iterator anIt = aGCS->constraints().begin();
507       for (; anIt != aGCS->constraints().end(); ++anIt)
508         if (!isRedundant(*anIt, aGCS))
509           aSolver->addConstraint(*anIt);
510     }
511   }
512   // additional constraints for arcs
513   std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >::const_iterator
514       anArcIt = myArcConstraintMap.begin();
515   for (; anArcIt != myArcConstraintMap.end(); ++anArcIt) {
516     std::vector<GCSConstraintPtr>::const_iterator anIt = anArcIt->second.begin();
517     for (; anIt != anArcIt->second.end(); ++anIt)
518       aSolver->addConstraint(*anIt);
519   }
520   // removed waste constraints
521   std::list<GCSConstraintPtr>::const_iterator aRemIt = myRemovedConstraints.begin();
522   for (; aRemIt != myRemovedConstraints.end(); ++aRemIt)
523     aSolver->removeConstraint(*aRemIt);
524   myRemovedConstraints.clear();
525   // initialize unknowns
526   aSolver->setParameters(myParameters);
527 }
528
529 void PlaneGCSSolver_Storage::refresh(bool theFixedOnly) const
530 {
531   //blockEvents(true);
532
533   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
534   std::list<ParameterWrapperPtr> aParams;
535   std::list<ParameterWrapperPtr>::const_iterator aParIt;
536   for (; anIt != myAttributeMap.end(); ++anIt) {
537     // the external feature always should keep the up to date values, so, 
538     // refresh from the solver is never needed
539     bool isExternal = false;
540     if (anIt->first.get()) {
541       std::shared_ptr<SketchPlugin_Feature> aSketchFeature = 
542         std::dynamic_pointer_cast<SketchPlugin_Feature>(anIt->first->owner());
543       if (aSketchFeature.get() && aSketchFeature->isExternal())
544         isExternal = true;
545     }
546
547     // update parameter wrappers and obtain values of attributes
548     aParams = anIt->second->parameters();
549     double aCoords[3];
550     bool isUpd[3] = {false};
551     int i = 0;
552     for (aParIt = aParams.begin(); i < 3 && aParIt != aParams.end(); ++aParIt, ++i) {
553       if (!theFixedOnly || isExternal ||
554           (*aParIt)->group() == GID_OUTOFGROUP || (*aParIt)->isParametric()) {
555         aCoords[i] = (*aParIt)->value();
556         isUpd[i] = true;
557       }
558     }
559     if (!isUpd[0] && !isUpd[1] && !isUpd[2])
560       continue; // nothing is updated
561
562     std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
563         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
564     if (aPoint2D) {
565       if ((isUpd[0] && fabs(aPoint2D->x() - aCoords[0]) > tolerance) ||
566           (isUpd[1] && fabs(aPoint2D->y() - aCoords[1]) > tolerance) || isExternal) {
567         if (!isUpd[0] || isExternal) aCoords[0] = aPoint2D->x();
568         if (!isUpd[1] || isExternal) aCoords[1] = aPoint2D->y();
569         aPoint2D->setValue(aCoords[0], aCoords[1]);
570         // Find points coincident with this one (probably not in GID_OUTOFGROUP)
571         CoincidentPointsMap::const_iterator aCoincIt = myCoincidentPoints.begin();
572         for (; aCoincIt != myCoincidentPoints.end(); ++aCoincIt)
573           if (aCoincIt->first == anIt->second ||
574               aCoincIt->second.find(anIt->second) != aCoincIt->second.end())
575             break;
576         if (aCoincIt != myCoincidentPoints.end()) {
577           aPoint2D = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
578               aCoincIt->first->baseAttribute());
579           if (aPoint2D)
580             aPoint2D->setValue(aCoords[0], aCoords[1]);
581           std::set<EntityWrapperPtr>::const_iterator aSlaveIt = aCoincIt->second.begin();
582           for (; aSlaveIt != aCoincIt->second.end(); ++aSlaveIt) {
583             aPoint2D = std::dynamic_pointer_cast<GeomDataAPI_Point2D>((*aSlaveIt)->baseAttribute());
584             if (aPoint2D)
585               aPoint2D->setValue(aCoords[0], aCoords[1]);
586           }
587         }
588       }
589       continue;
590     }
591     AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
592     if (aScalar && !isExternal) {
593       if (isUpd[0] && fabs(aScalar->value() - aCoords[0]) > tolerance)
594         aScalar->setValue(aCoords[0]);
595       continue;
596     }
597   }
598
599   //blockEvents(false);
600 }
601
602 EntityWrapperPtr PlaneGCSSolver_Storage::calculateMiddlePoint(
603     EntityWrapperPtr theBase, double theCoeff)
604 {
605   std::shared_ptr<PlaneGCSSolver_Builder> aBuilder =
606       std::dynamic_pointer_cast<PlaneGCSSolver_Builder>(PlaneGCSSolver_Builder::getInstance());
607
608   std::shared_ptr<GeomAPI_XY> aMidPoint;
609   if (theBase->type() == ENTITY_LINE) {
610     std::shared_ptr<GeomAPI_Pnt2d> aPoints[2];
611     const std::list<EntityWrapperPtr>& aSubs = theBase->subEntities();
612     std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
613     for (int i = 0; i < 2; ++i, ++anIt)
614       aPoints[i] = aBuilder->point(*anIt);
615     aMidPoint = aPoints[0]->xy()->multiplied(1.0 - theCoeff)->added(
616         aPoints[1]->xy()->multiplied(theCoeff));
617   }
618   else if (theBase->type() == ENTITY_ARC) {
619     double theX, theY;
620     double anArcPoint[3][2];
621     const std::list<EntityWrapperPtr>& aSubs = theBase->subEntities();
622     std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
623     for (int i = 0; i < 3; ++i, ++anIt) {
624       std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(*anIt);
625       anArcPoint[i][0] = aPoint->x();
626       anArcPoint[i][1] = aPoint->y();
627     }
628     // project last point of arc on the arc
629     double x = anArcPoint[1][0] - anArcPoint[0][0];
630     double y = anArcPoint[1][1] - anArcPoint[0][1];
631     double aRad = sqrt(x*x + y*y);
632     x = anArcPoint[2][0] - anArcPoint[0][0];
633     y = anArcPoint[2][1] - anArcPoint[0][1];
634     double aNorm = sqrt(x*x + y*y);
635     if (aNorm >= tolerance) {
636       anArcPoint[2][0] = x * aRad / aNorm;
637       anArcPoint[2][1] = y * aRad / aNorm;
638     }
639     anArcPoint[1][0] -= anArcPoint[0][0];
640     anArcPoint[1][1] -= anArcPoint[0][1];
641     if (theCoeff < tolerance) {
642       theX = anArcPoint[0][0] + anArcPoint[1][0];
643       theY = anArcPoint[0][1] + anArcPoint[1][1];
644     } else if (1 - theCoeff < tolerance) {
645       theX = anArcPoint[0][0] + anArcPoint[2][0];
646       theY = anArcPoint[0][1] + anArcPoint[2][1];
647     } else {
648       std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1]));
649       std::shared_ptr<GeomAPI_Dir2d> aEndDir(new GeomAPI_Dir2d(anArcPoint[2][0], anArcPoint[2][1]));
650       double anAngle = aStartDir->angle(aEndDir);
651       if (anAngle < 0)
652         anAngle += 2.0 * PI;
653       anAngle *= theCoeff;
654       double aCos = cos(anAngle);
655       double aSin = sin(anAngle);
656       theX = anArcPoint[0][0] + anArcPoint[1][0] * aCos - anArcPoint[1][1] * aSin;
657       theY = anArcPoint[0][1] + anArcPoint[1][0] * aSin + anArcPoint[1][1] * aCos;
658     }
659     aMidPoint = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(theX, theY));
660   }
661
662   if (!aMidPoint)
663     return EntityWrapperPtr();
664
665   std::list<ParameterWrapperPtr> aParameters;
666   aParameters.push_back(aBuilder->createParameter(myGroupID, aMidPoint->x()));
667   aParameters.push_back(aBuilder->createParameter(myGroupID, aMidPoint->y()));
668   // Create entity (parameters are not filled)
669   GCSPointPtr aPnt(new GCS::Point);
670   aPnt->x = std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(aParameters.front())->parameter();
671   aPnt->y = std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(aParameters.back())->parameter();
672
673   EntityWrapperPtr aResult(new PlaneGCSSolver_PointWrapper(AttributePtr(), aPnt));
674   aResult->setGroup(myGroupID);
675   aResult->setParameters(aParameters);
676
677   update(aResult);
678   return aResult;
679 }