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