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