]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp
Salome HOME
Second phase of SketchSolver refactoring
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_Builder.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    PlaneGCSSolver_Builder.cpp
4 // Created: 14 Dec 2015
5 // Author:  Artem ZHIDKOV
6
7 #include <PlaneGCSSolver_Builder.h>
8 #include <PlaneGCSSolver_Solver.h>
9 #include <PlaneGCSSolver_Storage.h>
10 #include <PlaneGCSSolver_ParameterWrapper.h>
11 #include <PlaneGCSSolver_AngleWrapper.h>
12 #include <PlaneGCSSolver_EntityWrapper.h>
13 #include <PlaneGCSSolver_PointWrapper.h>
14 #include <PlaneGCSSolver_ScalarWrapper.h>
15 #include <PlaneGCSSolver_ConstraintWrapper.h>
16
17 #include <SketchSolver_Manager.h>
18
19 #include <GeomAPI_Dir2d.h>
20 #include <GeomAPI_Pnt2d.h>
21 #include <GeomAPI_XY.h>
22 #include <GeomDataAPI_Dir.h>
23 #include <GeomDataAPI_Point.h>
24 #include <GeomDataAPI_Point2D.h>
25 #include <ModelAPI_Attribute.h>
26 #include <ModelAPI_AttributeRefAttr.h>
27
28 #include <SketchPlugin_Arc.h>
29 #include <SketchPlugin_Circle.h>
30 #include <SketchPlugin_Line.h>
31 #include <SketchPlugin_Point.h>
32 #include <SketchPlugin_ConstraintAngle.h>
33
34 #include <math.h>
35
36
37 #define GCS_ENTITY_WRAPPER(x) std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(x)
38 #define GCS_POINT_WRAPPER(x) std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(x)
39 #define GCS_PARAMETER_WRAPPER(x) std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(x)
40
41
42 /// \brief Converts a value to SolveSpace parameter
43 /// \param theGroup [in]  group to store parameter
44 /// \param theValue [in]  value of parameter
45 /// \param theExpr  [in]  shows the parameter is given by expression
46 /// \return Created parameter's wrapper
47 static ParameterWrapperPtr createParameter(const GroupID& theGroup,
48                                            const double theValue = 0.0,
49                                            const bool theExpr = false);
50
51 static ParameterWrapperPtr createParamAngle(const GroupID& theGroup,
52                                             const double& theValue = 0.0);
53
54 static std::shared_ptr<PlaneGCSSolver_ScalarWrapper>
55     createScalar(const GroupID& theGroupID,
56                  AttributeDoublePtr theDoubleAttr = AttributeDoublePtr());
57
58 static EntityWrapperPtr createLine(FeaturePtr theFeature,
59                                    const std::list<EntityWrapperPtr>& theAttributes,
60                                    const GroupID& theGroupID);
61 static EntityWrapperPtr createCircle(FeaturePtr theFeature,
62                                      const std::list<EntityWrapperPtr>& theAttributes,
63                                      const GroupID& theGroupID);
64 static EntityWrapperPtr createArc(FeaturePtr theFeature,
65                                   const std::list<EntityWrapperPtr>& theAttributes,
66                                   const GroupID& theGroupID);
67
68
69 static ConstraintWrapperPtr
70   createConstraintCoincidence(ConstraintPtr theConstraint, 
71                               const GroupID& theGroupID,
72                               std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
73                               std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2);
74 static ConstraintWrapperPtr
75   createConstraintPointOnEntity(ConstraintPtr theConstraint, 
76                                 const GroupID& theGroupID,
77                                 const SketchSolver_ConstraintType& theType,
78                                 std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
79                                 std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity);
80 static ConstraintWrapperPtr
81   createConstraintDistancePointPoint(ConstraintPtr theConstraint,
82                                      const GroupID& theGroupID,
83                                      std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
84                                      std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
85                                      std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2);
86 static ConstraintWrapperPtr
87   createConstraintDistancePointLine(ConstraintPtr theConstraint,
88                                     const GroupID& theGroupID,
89                                     std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
90                                     std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
91                                     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity);
92 static ConstraintWrapperPtr
93   createConstraintRadius(ConstraintPtr theConstraint,
94                          const GroupID& theGroupID,
95                          std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
96                          std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity);
97 static ConstraintWrapperPtr
98   createConstraintAngle(ConstraintPtr theConstraint,
99                         const GroupID& theGroupID,
100                         std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
101                         std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
102                         std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
103 static ConstraintWrapperPtr
104   createConstraintHorizVert(ConstraintPtr theConstraint,
105                             const GroupID& theGroupID,
106                             const SketchSolver_ConstraintType& theType,
107                             std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity);
108 static ConstraintWrapperPtr
109   createConstraintParallel(ConstraintPtr theConstraint,
110                            const GroupID& theGroupID,
111                            std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
112                            std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
113 static ConstraintWrapperPtr
114   createConstraintPerpendicular(ConstraintPtr theConstraint,
115                                 const GroupID& theGroupID,
116                                 std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
117                                 std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
118 static ConstraintWrapperPtr
119   createConstraintEqual(ConstraintPtr theConstraint,
120                         const GroupID& theGroupID,
121                         const SketchSolver_ConstraintType& theType,
122                         std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
123                         std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2,
124                         std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theIntermed);
125 static ConstraintWrapperPtr
126   createConstraintTangent(ConstraintPtr theConstraint,
127                           const GroupID& theGroupID,
128                           const SketchSolver_ConstraintType& theType,
129                           std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
130                           std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
131
132
133
134 /// \brief Set flags for angle constraint
135 static void adjustAngle(ConstraintWrapperPtr theConstraint);
136 /// \brief Update mirror points
137 static void adjustMirror(ConstraintWrapperPtr theConstraint);
138 /// \brief Update positions of rotated features
139 static void adjustMultiRotation(ConstraintWrapperPtr theConstraint);
140 /// \brief Update positions of translated features
141 static void adjustMultiTranslation(ConstraintWrapperPtr theConstraint);
142
143 /// \brief Transform points to be symmetric regarding to the mirror line
144 static void makeMirrorPoints(EntityWrapperPtr theOriginal,
145                              EntityWrapperPtr theMirrored,
146                              EntityWrapperPtr theMirrorLine);
147
148
149
150 // Initialization of constraint builder self pointer
151 BuilderPtr PlaneGCSSolver_Builder::mySelf = PlaneGCSSolver_Builder::getInstance();
152
153 BuilderPtr PlaneGCSSolver_Builder::getInstance()
154 {
155   if (!mySelf) {
156     mySelf = BuilderPtr(new PlaneGCSSolver_Builder);
157     SketchSolver_Manager::instance()->setBuilder(mySelf);
158   }
159   return mySelf;
160 }
161
162 StoragePtr PlaneGCSSolver_Builder::createStorage(const GroupID& theGroup) const
163 {
164   return StoragePtr(new PlaneGCSSolver_Storage(theGroup));
165 }
166
167 SolverPtr PlaneGCSSolver_Builder::createSolver() const
168 {
169   return SolverPtr(new PlaneGCSSolver_Solver);
170 }
171
172
173 std::list<ConstraintWrapperPtr> PlaneGCSSolver_Builder::createConstraint(
174     ConstraintPtr theConstraint,
175     const GroupID& theGroupID,
176     const EntityID& theSketchID,
177     const SketchSolver_ConstraintType& theType,
178     const double& theValue,
179     const EntityWrapperPtr& thePoint1,
180     const EntityWrapperPtr& thePoint2,
181     const EntityWrapperPtr& theEntity1,
182     const EntityWrapperPtr& theEntity2) const
183 {
184   ConstraintWrapperPtr aResult;
185   ParameterWrapperPtr anIntermediate;
186   switch (theType) {
187   case CONSTRAINT_PT_PT_COINCIDENT:
188     aResult = createConstraintCoincidence(theConstraint, theGroupID,
189                   GCS_POINT_WRAPPER(thePoint1), GCS_POINT_WRAPPER(thePoint2));
190     break;
191   case CONSTRAINT_PT_ON_LINE:
192   case CONSTRAINT_PT_ON_CIRCLE:
193     aResult = createConstraintPointOnEntity(theConstraint, theGroupID, theType,
194                   GCS_POINT_WRAPPER(thePoint1), GCS_ENTITY_WRAPPER(theEntity1));
195     break;
196   case CONSTRAINT_PT_PT_DISTANCE:
197     aResult = createConstraintDistancePointPoint(theConstraint, theGroupID,
198                   GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)),
199                   GCS_POINT_WRAPPER(thePoint1), GCS_POINT_WRAPPER(thePoint2));
200     break;
201   case CONSTRAINT_PT_LINE_DISTANCE:
202     aResult = createConstraintDistancePointLine(theConstraint, theGroupID,
203                   GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)),
204                   GCS_POINT_WRAPPER(thePoint1), GCS_ENTITY_WRAPPER(theEntity1));
205     break;
206   case CONSTRAINT_RADIUS:
207     aResult = createConstraintRadius(theConstraint, theGroupID,
208                   GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)),
209                   GCS_ENTITY_WRAPPER(theEntity1));
210     break;
211   case CONSTRAINT_ANGLE:
212     aResult = createConstraintAngle(theConstraint, theGroupID,
213                   GCS_PARAMETER_WRAPPER(createParamAngle(GID_OUTOFGROUP, theValue)),
214                   GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
215     break;
216   case CONSTRAINT_FIXED:
217     break;
218   case CONSTRAINT_HORIZONTAL:
219   case CONSTRAINT_VERTICAL:
220     aResult = createConstraintHorizVert(theConstraint, theGroupID, theType,
221                   GCS_ENTITY_WRAPPER(theEntity1));
222     break;
223   case CONSTRAINT_PARALLEL:
224     aResult = createConstraintParallel(theConstraint, theGroupID,
225                   GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
226     break;
227   case CONSTRAINT_PERPENDICULAR:
228     aResult = createConstraintPerpendicular(theConstraint, theGroupID,
229                   GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
230     break;
231   case CONSTRAINT_EQUAL_LINES:
232     anIntermediate = createParameter(theGroupID);
233   case CONSTRAINT_EQUAL_LINE_ARC:
234   case CONSTRAINT_EQUAL_RADIUS:
235     aResult = createConstraintEqual(theConstraint, theGroupID, theType,
236                   GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2),
237                   GCS_PARAMETER_WRAPPER(anIntermediate));
238     break;
239   case CONSTRAINT_TANGENT_ARC_LINE:
240   case CONSTRAINT_TANGENT_ARC_ARC:
241     aResult = createConstraintTangent(theConstraint, theGroupID, theType,
242                   GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
243     break;
244   case CONSTRAINT_MULTI_TRANSLATION:
245   case CONSTRAINT_MULTI_ROTATION:
246     break;
247   case CONSTRAINT_SYMMETRIC:
248     return createMirror(theConstraint, theGroupID, theSketchID,
249                         thePoint1, thePoint2, theEntity1);
250   default:
251     break;
252   }
253
254   if (!aResult)
255     return std::list<ConstraintWrapperPtr>();
256   adjustConstraint(aResult);
257   return std::list<ConstraintWrapperPtr>(1, aResult);
258 }
259
260 std::list<ConstraintWrapperPtr> PlaneGCSSolver_Builder::createConstraint(
261     ConstraintPtr theConstraint,
262     const GroupID& theGroupID,
263     const EntityID& theSketchID,
264     const SketchSolver_ConstraintType& theType,
265     const double& theValue,
266     const EntityWrapperPtr& thePoint1,
267     const EntityWrapperPtr& thePoint2,
268     const std::list<EntityWrapperPtr>& theTrsfEnt) const
269 {
270   ParameterWrapperPtr anAngleParam;
271   if (theType == CONSTRAINT_MULTI_ROTATION)
272     anAngleParam = createParamAngle(theGroupID, theValue);
273   else if (theType != CONSTRAINT_MULTI_TRANSLATION)
274     return std::list<ConstraintWrapperPtr>();
275
276   std::list<EntityWrapperPtr> aConstrAttrList = theTrsfEnt;
277   if (thePoint2)
278     aConstrAttrList.push_front(thePoint2);
279   aConstrAttrList.push_front(thePoint1);
280
281   std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
282       new PlaneGCSSolver_ConstraintWrapper(theConstraint, std::list<GCSConstraintPtr>(), theType));
283   aResult->setGroup(theGroupID);
284   aResult->setEntities(aConstrAttrList);
285   if (anAngleParam)
286     aResult->setValueParameter(anAngleParam);
287   return std::list<ConstraintWrapperPtr>(1, aResult);
288 }
289
290
291 std::list<ConstraintWrapperPtr> PlaneGCSSolver_Builder::createMirror(
292     ConstraintPtr theConstraint,
293     const GroupID& theGroupID,
294     const EntityID& theSketchID,
295     const EntityWrapperPtr& theEntity1,
296     const EntityWrapperPtr& theEntity2,
297     const EntityWrapperPtr& theMirrorLine) const
298 {
299   std::list<ConstraintWrapperPtr> aResult;
300   std::list<EntityWrapperPtr> aConstrAttrList;
301   if (theEntity1->type() == ENTITY_POINT) {
302     if (theEntity2->group() == theGroupID) // theEntity2 is not fixed
303       makeMirrorPoints(theEntity1, theEntity2, theMirrorLine);
304
305     std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint1 = 
306         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity1);
307     std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint2 = 
308         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity2);
309
310     std::shared_ptr<PlaneGCSSolver_EntityWrapper> aMirrorLine = 
311         std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theMirrorLine);
312     std::shared_ptr<GCS::Line> aLine =
313         std::dynamic_pointer_cast<GCS::Line>(aMirrorLine->entity());
314
315     std::list<GCSConstraintPtr> aConstrList;
316     aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintPerpendicular(
317         *(aPoint1->point()), *(aPoint2->point()), aLine->p1, aLine->p2)));
318     aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintMidpointOnLine(
319         *(aPoint1->point()), *(aPoint2->point()), aLine->p1, aLine->p2)));
320
321     ConstraintWrapperPtr aSubResult(new PlaneGCSSolver_ConstraintWrapper(
322         theConstraint, aConstrList, CONSTRAINT_SYMMETRIC));
323     aSubResult->setGroup(theGroupID);
324     std::list<EntityWrapperPtr> aSubs(1, theEntity1);
325     aSubs.push_back(theEntity2);
326     aSubs.push_back(theMirrorLine);
327     aSubResult->setEntities(aSubs);
328     aResult.push_back(aSubResult);
329   }
330   else if (theEntity1->type() == ENTITY_LINE) {
331     const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
332     const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
333     std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
334     std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
335     for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) {
336       std::list<ConstraintWrapperPtr> aMrrList =
337           createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
338       aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
339     }
340   }
341   else if (theEntity1->type() == ENTITY_CIRCLE) {
342     const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
343     std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
344     for (; anIt1 != aPoints1.end(); ++anIt1)
345       if ((*anIt1)->type() == ENTITY_POINT)
346         break;
347     const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
348     std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
349     for (; anIt2 != aPoints2.end(); ++anIt2)
350       if ((*anIt2)->type() == ENTITY_POINT)
351         break;
352
353     std::list<ConstraintWrapperPtr> aMrrList =
354         createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
355     aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
356
357     // Additional constraint for equal radii
358     aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS,
359         0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2);
360     aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
361   }
362   else if (theEntity1->type() == ENTITY_ARC) {
363     // Do not allow mirrored arc recalculate its position until coordinated of all points recalculated
364     FeaturePtr aMirrArc = theEntity2->baseFeature();
365     aMirrArc->data()->blockSendAttributeUpdated(true);
366
367     // Make mirror for center and start point of original arc
368     std::list<ConstraintWrapperPtr> aMrrList;
369     std::list<EntityWrapperPtr>::const_iterator anIt1 = theEntity1->subEntities().begin();
370     std::list<EntityWrapperPtr>::const_iterator anIt2 = theEntity2->subEntities().begin();
371     aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
372     aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
373
374     ++anIt1;
375     ++anIt2; ++anIt2;
376     aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
377     aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
378
379     // make symmetric last point of original arc and first point of mirrored arc without additional constraint
380     ++anIt1;
381     --anIt2;
382     makeMirrorPoints(*anIt1, *anIt2, theMirrorLine);
383
384     // Additionally, make equal radii...
385     aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS,
386         0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2);
387     aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
388     // ... and make parametric length of arcs the same
389     std::shared_ptr<PlaneGCSSolver_EntityWrapper> anArcEnt1 = 
390         std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theEntity1);
391     std::shared_ptr<PlaneGCSSolver_EntityWrapper> anArcEnt2 = 
392         std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theEntity2);
393     std::shared_ptr<GCS::Arc> anArc1 = std::dynamic_pointer_cast<GCS::Arc>(anArcEnt1->entity());
394     std::shared_ptr<GCS::Arc> anArc2 = std::dynamic_pointer_cast<GCS::Arc>(anArcEnt2->entity());
395     std::shared_ptr<PlaneGCSSolver_ParameterWrapper> anIntermed =
396         std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(
397         createParameter(theGroupID, *(anArc1->endAngle) - *(anArc1->startAngle)));
398     // By the way, recalculate start and end angles of mirrored arc
399     std::shared_ptr<GeomAPI_Dir2d> anOX(new GeomAPI_Dir2d(1.0, 0.0));
400     std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(
401         *(anArc2->start.x) - *(anArc2->center.x), *(anArc2->start.y) - *(anArc2->center.y)));
402     std::shared_ptr<GeomAPI_Dir2d> aEndDir(new GeomAPI_Dir2d(
403         *(anArc2->end.x) - *(anArc2->center.x), *(anArc2->end.y) - *(anArc2->center.y)));
404     *anArc2->startAngle = anOX->angle(aStartDir);
405     *anArc2->endAngle = anOX->angle(aEndDir);
406
407     std::list<GCSConstraintPtr> aConstrList;
408     aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintDifference(
409         anArc1->endAngle, anArc1->startAngle, anIntermed->parameter())));
410     aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintDifference(
411         anArc2->endAngle, anArc2->startAngle, anIntermed->parameter())));
412
413     std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aSubResult(
414         new PlaneGCSSolver_ConstraintWrapper(theConstraint, aConstrList, CONSTRAINT_SYMMETRIC));
415     aSubResult->setGroup(theGroupID);
416     std::list<EntityWrapperPtr> aSubs(1, theEntity1);
417     aSubs.push_back(theEntity2);
418     aSubs.push_back(theMirrorLine);
419     aSubResult->setEntities(aSubs);
420     aSubResult->setValueParameter(anIntermed);
421     aResult.push_back(aSubResult);
422
423     // Restore event sending
424     aMirrArc->data()->blockSendAttributeUpdated(false);
425   }
426   return aResult;
427 }
428
429 void PlaneGCSSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const
430 {
431   SketchSolver_ConstraintType aType = theConstraint->type();
432   // Update flags and parameters in constraints
433   if (aType == CONSTRAINT_ANGLE)
434     adjustAngle(theConstraint);
435 ////  else if (aType == CONSTRAINT_SYMMETRIC)
436 ////    adjustMirror(theConstraint);
437   else if (aType == CONSTRAINT_MULTI_ROTATION)
438     adjustMultiRotation(theConstraint);
439   else if (aType == CONSTRAINT_MULTI_TRANSLATION)
440     adjustMultiTranslation(theConstraint);
441 }
442
443 EntityWrapperPtr PlaneGCSSolver_Builder::createFeature(
444     FeaturePtr theFeature,
445     const std::list<EntityWrapperPtr>& theAttributes,
446     const GroupID& theGroupID,
447     const EntityID& /*theSketchID*/) const
448 {
449   static EntityWrapperPtr aDummy;
450   if (!theFeature->data()->isValid())
451     return aDummy;
452
453   // Sketch
454   CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
455   if (aSketch)
456     return createSketchEntity(aSketch, theGroupID);
457
458   // SketchPlugin features
459   std::shared_ptr<SketchPlugin_Feature> aFeature =
460       std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
461   if (!aFeature)
462     return aDummy;
463
464   // Verify the feature by its kind
465   const std::string& aFeatureKind = aFeature->getKind();
466   // Line
467   if (aFeatureKind == SketchPlugin_Line::ID())
468     return createLine(theFeature, theAttributes, theGroupID);
469   // Circle
470   else if (aFeatureKind == SketchPlugin_Circle::ID())
471     return createCircle(theFeature, theAttributes, theGroupID);
472   // Arc
473   else if (aFeatureKind == SketchPlugin_Arc::ID())
474     return createArc(theFeature, theAttributes, theGroupID);
475   // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
476   else if (aFeatureKind == SketchPlugin_Point::ID()) {
477     AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID());
478     if (!aPoint->isInitialized())
479       return aDummy;
480     EntityWrapperPtr aSub = createAttribute(aPoint, theGroupID);
481     if (!aSub)
482       return aDummy;
483
484     GCSPointPtr aSubEnt =
485         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(aSub)->point();
486     EntityWrapperPtr aNewEntity(new PlaneGCSSolver_EntityWrapper(theFeature));
487     aNewEntity->setSubEntities(std::list<EntityWrapperPtr>(1, aSub));
488     return aNewEntity;
489   }
490
491   // wrong entity
492   return aDummy;
493 }
494
495 EntityWrapperPtr PlaneGCSSolver_Builder::createAttribute(
496     AttributePtr theAttribute,
497     const GroupID& theGroupID,
498     const EntityID& theSketchID) const
499 {
500   AttributePtr anAttribute = theAttribute;
501   AttributeRefAttrPtr aRefAttr =
502       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
503   if (aRefAttr) {
504     if (aRefAttr->isObject()) {
505       // do not create features here
506       return EntityWrapperPtr();
507     } else
508       anAttribute = aRefAttr->attr();
509   }
510
511   std::list<ParameterWrapperPtr> aParameters;
512   EntityWrapperPtr aResult;
513
514   // Point in 2D
515   std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
516     std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
517   if (aPoint2D) {
518     aParameters.push_back(::createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty()));
519     aParameters.push_back(::createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty()));
520     GCSPointPtr aGCSPoint(new GCS::Point);
521     aGCSPoint->x = std::dynamic_pointer_cast<
522       PlaneGCSSolver_ParameterWrapper>(aParameters.front())->parameter();
523     aGCSPoint->y = std::dynamic_pointer_cast<
524       PlaneGCSSolver_ParameterWrapper>(aParameters.back())->parameter();
525     // Create entity (parameters are not filled)
526     aResult = EntityWrapperPtr(new PlaneGCSSolver_PointWrapper(theAttribute, aGCSPoint));
527   } else {
528     // Scalar value (used for the distance entities)
529     AttributeDoublePtr aScalar =
530       std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
531     if (aScalar)
532       return createScalar(theGroupID, aScalar);
533   }
534
535   if (!aResult) {
536     // unknown attribute type
537     return EntityWrapperPtr();
538   }
539
540   aResult->setGroup(theGroupID);
541   aResult->setParameters(aParameters);
542   return aResult;
543 }
544
545 ParameterWrapperPtr PlaneGCSSolver_Builder::createParameter(
546     const GroupID& theGroupID, double theValue) const
547 {
548   return ::createParameter(theGroupID, theValue);
549 }
550
551
552 EntityWrapperPtr PlaneGCSSolver_Builder::createSketchEntity(
553     CompositeFeaturePtr theSketch,
554     const GroupID& theGroupID) const
555 {
556   DataPtr aSketchData = theSketch->data();
557   if (!aSketchData || !aSketchData->isValid())
558     return EntityWrapperPtr(); // the sketch is incorrect
559
560   // Create dummy wrapper representing workplane
561   std::shared_ptr<PlaneGCSSolver_EntityWrapper> aSketchEnt(
562       new PlaneGCSSolver_EntityWrapper(FeaturePtr(theSketch)));
563   aSketchEnt->setGroup(theGroupID);
564   aSketchEnt->setId(EID_SKETCH);
565   return aSketchEnt;
566 }
567
568
569
570 ////EntityWrapperPtr PlaneGCSSolver_Builder::createNormal(
571 ////    AttributePtr theNormal,
572 ////    AttributePtr theDirX,
573 ////    const GroupID& theGroupID) const
574 ////{
575 ////  std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
576 ////  std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
577 ////  if (!aDirX || !aNorm ||
578 ////      (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) || 
579 ////      !aNorm->isInitialized())
580 ////    return EntityWrapperPtr();
581 ////  // calculate Y direction
582 ////  std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
583 ////
584 ////  // quaternion parameters of normal vector
585 ////  double qw, qx, qy, qz;
586 ////  Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
587 ////                      &qx, &qy, &qz);
588 ////  double aNormCoord[4] = { qw, qx, qy, qz };
589 ////
590 ////  // Create parameters of the normal
591 ////  std::list<ParameterWrapperPtr> aParameters;
592 ////  for (int i = 0; i < 4; i++)
593 ////    aParameters.push_back(createParameter(theGroupID, aNormCoord[i]));
594 ////
595 ////  // Create a normal with empty parameters
596 ////  Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
597 ////      SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
598 ////  EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt));
599 ////  aNormal->setParameters(aParameters);
600 ////  return aNormal;
601 ////}
602
603
604
605
606
607 // ================   Auxiliary functions   ==========================
608 ParameterWrapperPtr createParameter(
609     const GroupID& theGroup, const double theValue, const bool theExpr)
610 {
611   double* aParam = new double(theValue);
612   ParameterWrapperPtr aWrapper(new PlaneGCSSolver_ParameterWrapper(aParam));
613   aWrapper->setGroup(theGroup);
614   aWrapper->setIsParametric(theExpr);
615   return aWrapper;
616 }
617
618 ParameterWrapperPtr createParamAngle(const GroupID& theGroup, const double& theValue)
619 {
620   double* aParam = new double(theValue);
621   ParameterWrapperPtr aWrapper(new PlaneGCSSolver_AngleWrapper(aParam));
622   aWrapper->setGroup(theGroup);
623   return aWrapper;
624 }
625
626 std::shared_ptr<PlaneGCSSolver_ScalarWrapper> createScalar(
627     const GroupID& theGroupID,
628     AttributeDoublePtr theDoubleAttr)
629 {
630   ParameterWrapperPtr aParam = createParameter(theGroupID, theDoubleAttr ? theDoubleAttr->value() : 0.0);
631   return std::shared_ptr<PlaneGCSSolver_ScalarWrapper>(
632       new PlaneGCSSolver_ScalarWrapper(theDoubleAttr, aParam));
633 }
634
635 EntityWrapperPtr createLine(FeaturePtr theFeature,
636                             const std::list<EntityWrapperPtr>& theAttributes,
637                             const GroupID& theGroupID)
638 {
639   EntityWrapperPtr aNewEntity;
640   std::list<EntityWrapperPtr> aSubs;
641
642   AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID());
643   AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID());
644   if (!aStart->isInitialized() || !aEnd->isInitialized())
645     return aNewEntity;
646
647   std::shared_ptr<PlaneGCSSolver_PointWrapper> aStartEnt, aEndEnt;
648   std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
649   for (; anIt != theAttributes.end(); ++anIt) {
650     std::shared_ptr<PlaneGCSSolver_PointWrapper> aWrapper = 
651         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(*anIt);
652     if (!aWrapper)
653       continue;
654     if (aWrapper->isBase(aStart))
655       aStartEnt = aWrapper;
656     else if (aWrapper->isBase(aEnd))
657       aEndEnt = aWrapper;
658   }
659   if (!aStartEnt || !aEndEnt)
660     return aNewEntity;
661
662   aSubs.push_back(aStartEnt);
663   aSubs.push_back(aEndEnt);
664
665   std::shared_ptr<GCS::Line> aLine(new GCS::Line);
666   aLine->p1 = *(aStartEnt->point());
667   aLine->p2 = *(aEndEnt->point());
668
669   aNewEntity = EntityWrapperPtr(new PlaneGCSSolver_EntityWrapper(theFeature, aLine));
670   aNewEntity->setGroup(theGroupID); // sub-entities should not change their groups, therefore they are added later
671   aNewEntity->setSubEntities(aSubs);
672   return aNewEntity;
673 }
674
675 EntityWrapperPtr createCircle(FeaturePtr theFeature,
676                               const std::list<EntityWrapperPtr>& theAttributes,
677                               const GroupID& theGroupID)
678 {
679   EntityWrapperPtr aNewEntity;
680   std::list<EntityWrapperPtr> aSubs;
681
682   AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID());
683   AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
684   if (!aCenter->isInitialized() || !aRadius->isInitialized())
685     return aNewEntity;
686
687   std::shared_ptr<PlaneGCSSolver_PointWrapper> aCenterEnt;
688   std::shared_ptr<PlaneGCSSolver_ScalarWrapper> aRadiusEnt;
689   std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
690   for (; anIt != theAttributes.end(); ++anIt) {
691     if ((*anIt)->isBase(aCenter))
692       aCenterEnt = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(*anIt);
693     else if ((*anIt)->isBase(aRadius))
694       aRadiusEnt = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*anIt);
695   }
696   if (!aCenterEnt || !aRadiusEnt)
697     return aNewEntity;
698
699   aSubs.push_back(aCenterEnt);
700   aSubs.push_back(aRadiusEnt);
701
702   std::shared_ptr<GCS::Circle> aCircle(new GCS::Circle);
703   aCircle->center = *(aCenterEnt->point());
704   aCircle->rad = aRadiusEnt->scalar();
705
706   aNewEntity = EntityWrapperPtr(new PlaneGCSSolver_EntityWrapper(theFeature, aCircle));
707   aNewEntity->setGroup(theGroupID); // sub-entities should not change their groups, therefore they are added later
708   aNewEntity->setSubEntities(aSubs);
709   return aNewEntity;
710 }
711
712 EntityWrapperPtr createArc(FeaturePtr theFeature,
713                            const std::list<EntityWrapperPtr>& theAttributes,
714                            const GroupID& theGroupID)
715 {
716   EntityWrapperPtr aNewEntity;
717   std::list<EntityWrapperPtr> aSubs;
718
719   AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID());
720   AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID());
721   AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID());
722   if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
723     return aNewEntity;
724
725   std::shared_ptr<PlaneGCSSolver_PointWrapper> aCenterEnt, aStartEnt, aEndEnt;
726   std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
727   for (; anIt != theAttributes.end(); ++anIt) {
728     std::shared_ptr<PlaneGCSSolver_PointWrapper> aWrapper = 
729         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(*anIt);
730     if (!aWrapper)
731       continue;
732     if (aWrapper->isBase(aCenter))
733       aCenterEnt = aWrapper;
734     else if (aWrapper->isBase(aStart))
735       aStartEnt = aWrapper;
736     else if (aWrapper->isBase(aEnd))
737       aEndEnt = aWrapper;
738   }
739   if (!aCenterEnt || !aStartEnt || !aEndEnt)
740     return aNewEntity;
741
742   std::shared_ptr<PlaneGCSSolver_ScalarWrapper> aStartAng, aEndAng, aRadius;
743   aStartAng = createScalar(theGroupID);
744   aEndAng   = createScalar(theGroupID);
745   aRadius   = createScalar(theGroupID);
746
747   aSubs.push_back(aCenterEnt);
748   aSubs.push_back(aStartEnt);
749   aSubs.push_back(aEndEnt);
750   aSubs.push_back(aStartAng);
751   aSubs.push_back(aEndAng);
752   aSubs.push_back(aRadius);
753
754   std::shared_ptr<GCS::Arc> anArc(new GCS::Arc);
755   anArc->center     = *(aCenterEnt->point());
756   anArc->start      = *(aStartEnt->point());
757   anArc->end        = *(aEndEnt->point());
758   anArc->startAngle = aStartAng->scalar();
759   anArc->endAngle   = aEndAng->scalar();
760   anArc->rad        = aRadius->scalar();
761
762   aNewEntity = EntityWrapperPtr(new PlaneGCSSolver_EntityWrapper(theFeature, anArc));
763   aNewEntity->setGroup(theGroupID); // sub-entities should not change their groups, therefore they are added later
764   aNewEntity->setSubEntities(aSubs);
765   return aNewEntity;
766 }
767
768
769
770 ConstraintWrapperPtr createConstraintCoincidence(
771     ConstraintPtr theConstraint,
772     const GroupID& theGroupID,
773     std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
774     std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2)
775 {
776   // Create equality constraint for corresponding attributes of the points
777   std::list<GCSConstraintPtr> aConstrList;
778   std::list<ParameterWrapperPtr>::const_iterator anIt1 = thePoint1->parameters().begin();
779   std::list<ParameterWrapperPtr>::const_iterator anIt2 = thePoint2->parameters().begin();
780   for (; anIt1 != thePoint1->parameters().end(); ++anIt1, ++anIt2) {
781     if (*anIt1 == *anIt2)
782       continue; // points use same parameters, no need additional constraints
783     std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam1 =
784         std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(*anIt1);
785     std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam2 =
786         std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(*anIt2);
787     aConstrList.push_back(
788         GCSConstraintPtr(new GCS::ConstraintEqual(aParam1->parameter(), aParam2->parameter())));
789   }
790
791   ConstraintWrapperPtr aResult(new PlaneGCSSolver_ConstraintWrapper(
792       theConstraint, aConstrList, CONSTRAINT_PT_PT_COINCIDENT));
793   aResult->setGroup(theGroupID);
794   std::list<EntityWrapperPtr> aSubs(1, thePoint1);
795   aSubs.push_back(thePoint2);
796   aResult->setEntities(aSubs);
797   return aResult;
798 }
799
800 ConstraintWrapperPtr createConstraintPointOnEntity(
801     ConstraintPtr theConstraint, 
802     const GroupID& theGroupID,
803     const SketchSolver_ConstraintType& theType,
804     std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
805     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity)
806 {
807   GCSConstraintPtr aNewConstr;
808
809   switch (theEntity->type()) {
810   case ENTITY_LINE: {
811     std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity->entity());
812     aNewConstr = GCSConstraintPtr(new GCS::ConstraintPointOnLine(*(thePoint->point()), *aLine));
813     break;
814     }
815   case ENTITY_ARC:
816   case ENTITY_CIRCLE: {
817     std::shared_ptr<GCS::Circle> aCirc = std::dynamic_pointer_cast<GCS::Circle>(theEntity->entity());
818     aNewConstr = GCSConstraintPtr(
819         new GCS::ConstraintP2PDistance(*(thePoint->point()), aCirc->center, aCirc->rad));
820     break;
821     }
822   default:
823     return ConstraintWrapperPtr();
824   }
825
826   ConstraintWrapperPtr aResult(new PlaneGCSSolver_ConstraintWrapper(
827       theConstraint, aNewConstr, theType));
828   aResult->setGroup(theGroupID);
829   std::list<EntityWrapperPtr> aSubs(1, thePoint);
830   aSubs.push_back(theEntity);
831   aResult->setEntities(aSubs);
832   return aResult;
833 }
834
835 ConstraintWrapperPtr createConstraintDistancePointPoint(
836     ConstraintPtr theConstraint,
837     const GroupID& theGroupID,
838     std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
839     std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
840     std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2)
841 {
842   GCSConstraintPtr aNewConstr(new GCS::ConstraintP2PDistance(
843       *(thePoint1->point()), *(thePoint2->point()), theValue->parameter()));
844
845   std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
846       new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_PT_PT_DISTANCE));
847   aResult->setGroup(theGroupID);
848   std::list<EntityWrapperPtr> aSubs(1, thePoint1);
849   aSubs.push_back(thePoint2);
850   aResult->setEntities(aSubs);
851   aResult->setValueParameter(theValue);
852   return aResult;
853 }
854
855 ConstraintWrapperPtr createConstraintDistancePointLine(
856     ConstraintPtr theConstraint,
857     const GroupID& theGroupID,
858     std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
859     std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
860     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity)
861 {
862   std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity->entity());
863   GCSConstraintPtr aNewConstr(new GCS::ConstraintP2LDistance(
864       *(thePoint->point()), *(aLine), theValue->parameter()));
865
866   std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
867       new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_PT_LINE_DISTANCE));
868   aResult->setGroup(theGroupID);
869   std::list<EntityWrapperPtr> aSubs(1, thePoint);
870   aSubs.push_back(theEntity);
871   aResult->setEntities(aSubs);
872   aResult->setValueParameter(theValue);
873   return aResult;
874 }
875
876 ConstraintWrapperPtr createConstraintRadius(
877     ConstraintPtr theConstraint,
878     const GroupID& theGroupID,
879     std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
880     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity)
881 {
882   std::shared_ptr<GCS::Circle> aCircle = std::dynamic_pointer_cast<GCS::Circle>(theEntity->entity());
883   GCSConstraintPtr aNewConstr(new GCS::ConstraintEqual(aCircle->rad, theValue->parameter()));
884
885   std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
886       new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_RADIUS));
887   aResult->setGroup(theGroupID);
888   std::list<EntityWrapperPtr> aSubs(1, theEntity);
889   aResult->setEntities(aSubs);
890   aResult->setValueParameter(theValue);
891   return aResult;
892 }
893
894 ConstraintWrapperPtr createConstraintAngle(
895     ConstraintPtr theConstraint,
896     const GroupID& theGroupID,
897     std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
898     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
899     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
900 {
901   std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
902   std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
903   GCSConstraintPtr aNewConstr(new GCS::ConstraintL2LAngle(
904       *(aLine1), *(aLine2), theValue->parameter()));
905
906   std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
907       new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_ANGLE));
908   aResult->setGroup(theGroupID);
909   std::list<EntityWrapperPtr> aSubs(1, theEntity1);
910   aSubs.push_back(theEntity2);
911   aResult->setEntities(aSubs);
912   aResult->setValueParameter(theValue);
913   return aResult;
914 }
915
916 ConstraintWrapperPtr createConstraintHorizVert(
917     ConstraintPtr theConstraint,
918     const GroupID& theGroupID,
919     const SketchSolver_ConstraintType& theType,
920     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity)
921 {
922   std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity->entity());
923   GCSConstraintPtr aNewConstr;
924   if (theType == CONSTRAINT_HORIZONTAL)
925     aNewConstr = GCSConstraintPtr(new GCS::ConstraintEqual(aLine->p1.y, aLine->p2.y));
926   else
927     aNewConstr = GCSConstraintPtr(new GCS::ConstraintEqual(aLine->p1.x, aLine->p2.x));
928
929   ConstraintWrapperPtr aResult(new PlaneGCSSolver_ConstraintWrapper(
930       theConstraint, aNewConstr, theType));
931   aResult->setGroup(theGroupID);
932   std::list<EntityWrapperPtr> aSubs(1, theEntity);
933   aResult->setEntities(aSubs);
934   return aResult;
935 }
936
937 ConstraintWrapperPtr createConstraintParallel(
938     ConstraintPtr theConstraint,
939     const GroupID& theGroupID,
940     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
941     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
942 {
943   std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
944   std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
945   GCSConstraintPtr aNewConstr(new GCS::ConstraintParallel(*(aLine1), *(aLine2)));
946
947   std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
948       new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_PARALLEL));
949   aResult->setGroup(theGroupID);
950   std::list<EntityWrapperPtr> aSubs(1, theEntity1);
951   aSubs.push_back(theEntity2);
952   aResult->setEntities(aSubs);
953   return aResult;
954 }
955
956 ConstraintWrapperPtr createConstraintPerpendicular(
957     ConstraintPtr theConstraint,
958     const GroupID& theGroupID,
959     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
960     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
961 {
962   std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
963   std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
964   GCSConstraintPtr aNewConstr(new GCS::ConstraintPerpendicular(*(aLine1), *(aLine2)));
965
966   std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
967       new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_PERPENDICULAR));
968   aResult->setGroup(theGroupID);
969   std::list<EntityWrapperPtr> aSubs(1, theEntity1);
970   aSubs.push_back(theEntity2);
971   aResult->setEntities(aSubs);
972   return aResult;
973 }
974
975 ConstraintWrapperPtr createConstraintEqual(
976     ConstraintPtr theConstraint,
977     const GroupID& theGroupID,
978     const SketchSolver_ConstraintType& theType,
979     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
980     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2,
981     std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theIntermed)
982 {
983   if (theType == CONSTRAINT_EQUAL_LINE_ARC)
984     return ConstraintWrapperPtr(); // line-arc equivalence is not supported yet
985
986   std::list<GCSConstraintPtr> aConstrList;
987   if (theType == CONSTRAINT_EQUAL_LINES) {
988     std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
989     std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
990
991     aConstrList.push_back(GCSConstraintPtr(
992         new GCS::ConstraintP2PDistance(aLine1->p1, aLine1->p2, theIntermed->parameter())));
993     aConstrList.push_back(GCSConstraintPtr(
994         new GCS::ConstraintP2PDistance(aLine2->p1, aLine2->p2, theIntermed->parameter())));
995   } else {
996     std::shared_ptr<GCS::Circle> aCirc1 =
997         std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
998     std::shared_ptr<GCS::Circle> aCirc2 =
999         std::dynamic_pointer_cast<GCS::Circle>(theEntity2->entity());
1000
1001     aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(aCirc1->rad, aCirc2->rad)));
1002   }
1003
1004   std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
1005       new PlaneGCSSolver_ConstraintWrapper(theConstraint, aConstrList, theType));
1006   aResult->setGroup(theGroupID);
1007   std::list<EntityWrapperPtr> aSubs(1, theEntity1);
1008   aSubs.push_back(theEntity2);
1009   aResult->setEntities(aSubs);
1010   if (theIntermed)
1011     aResult->setValueParameter(theIntermed);
1012   return aResult;
1013 }
1014
1015 ConstraintWrapperPtr createConstraintTangent(
1016     ConstraintPtr theConstraint,
1017     const GroupID& theGroupID,
1018     const SketchSolver_ConstraintType& theType,
1019     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
1020     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
1021 {
1022   GCSConstraintPtr aNewConstr;
1023   if (theType == CONSTRAINT_TANGENT_ARC_LINE) {
1024     std::shared_ptr<GCS::Circle> aCirc = std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
1025     std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
1026
1027     aNewConstr = GCSConstraintPtr(new GCS::ConstraintP2LDistance(aCirc->center, *aLine, aCirc->rad));
1028   } else {
1029     std::shared_ptr<GCS::Circle> aCirc1 = std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
1030     std::shared_ptr<GCS::Circle> aCirc2 = std::dynamic_pointer_cast<GCS::Circle>(theEntity2->entity());
1031
1032     double aDX = *(aCirc1->center.x) - *(aCirc2->center.x);
1033     double aDY = *(aCirc1->center.y) - *(aCirc2->center.y);
1034     double aDist = sqrt(aDX * aDX + aDY * aDY);
1035     aNewConstr = GCSConstraintPtr(new GCS::ConstraintTangentCircumf(aCirc1->center, aCirc2->center,
1036         aCirc1->rad, aCirc2->rad, (aDist < *(aCirc1->rad) || aDist < *(aCirc2->rad))));
1037   }
1038
1039   std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
1040       new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, theType));
1041   aResult->setGroup(theGroupID);
1042   std::list<EntityWrapperPtr> aSubs(1, theEntity1);
1043   aSubs.push_back(theEntity2);
1044   aResult->setEntities(aSubs);
1045   return aResult;
1046 }
1047
1048
1049
1050
1051
1052 void adjustAngle(ConstraintWrapperPtr theConstraint)
1053 {
1054   BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
1055
1056   std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
1057     std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
1058
1059   std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
1060   const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
1061   std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
1062   for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
1063     const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
1064     std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
1065     for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt)
1066       aPoints[i][j] = aBuilder->point(*aLPIt);
1067   }
1068
1069   std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
1070     std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
1071     std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
1072   };
1073   std::shared_ptr<GeomAPI_Pnt2d> anIntersection = aLine[0]->intersect(aLine[1]);
1074   if (!anIntersection)
1075     return;
1076   double aDist[2][2];
1077   for (int i = 0; i < 2; i++) {
1078     for (int j = 0; j < 2; j++) {
1079       aDist[i][j] = anIntersection->distance(aPoints[i][j]);
1080       if (fabs(aDist[i][j]) <= tolerance)
1081         aDist[i][j] = 0.0;
1082     }
1083     if (aDist[i][0] > tolerance && aDist[i][1] > tolerance &&
1084         aDist[i][0] + aDist[i][1] < aPoints[i][0]->distance(aPoints[i][1]) + 2.0 * tolerance) {
1085       // the intersection point is an inner point of the line,
1086       // we change the sign of distance till start point to calculate correct coordinates
1087       // after rotation
1088       aDist[i][0] *= -1.0;
1089     }
1090   }
1091   std::shared_ptr<GeomAPI_Dir2d> aDir[2];
1092   for (int i = 0; i < 2; i++) {
1093     if (aDist[i][1] > fabs(aDist[i][0]))
1094       aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
1095           aPoints[i][1]->xy()->decreased(anIntersection->xy())));
1096     else {
1097       aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
1098           aPoints[i][0]->xy()->decreased(anIntersection->xy())));
1099       // main direction is opposite => change signs
1100       if (aDist[i][0] < 0.0) {
1101         aDist[i][0] *= -1.0;
1102         aDist[i][1] *= -1.0;
1103       }
1104     }
1105   }
1106
1107   bool isChange = false;
1108   for (int i = 0; i < 2; i++)
1109     if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
1110       isChange = !isChange;
1111   if (isChange)
1112     aConstraint->setValue(180.0 - aConstraint->value());
1113 }
1114
1115 ////void adjustMirror(ConstraintWrapperPtr theConstraint)
1116 ////{
1117 ////  std::vector<EntityWrapperPtr> aPoints;
1118 ////  EntityWrapperPtr aMirrorLine;
1119 ////
1120 ////  const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
1121 ////  std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
1122 ////  for (; anIt != aSubs.end(); ++anIt) {
1123 ////    if ((*anIt)->type() == ENTITY_POINT)
1124 ////      aPoints.push_back(*anIt);
1125 ////    else if ((*anIt)->type() == ENTITY_LINE)
1126 ////      aMirrorLine = *anIt;
1127 ////  }
1128 ////
1129 ////  makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
1130 ////}
1131
1132 void makeMirrorPoints(EntityWrapperPtr theOriginal,
1133                       EntityWrapperPtr theMirrored,
1134                       EntityWrapperPtr theMirrorLine)
1135 {
1136   BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
1137
1138   std::shared_ptr<GeomAPI_Lin2d> aMirrorLine = aBuilder->line(theMirrorLine);
1139   std::shared_ptr<GeomAPI_Dir2d> aMLDir = aMirrorLine->direction();
1140   // orthogonal direction
1141   aMLDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x()));
1142
1143   std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(theOriginal);
1144   std::shared_ptr<GeomAPI_XY> aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy());
1145   double aDist = aVec->dot(aMLDir->xy());
1146   aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist));
1147   double aCoord[2] = {aVec->x(), aVec->y()};
1148   std::list<ParameterWrapperPtr>::const_iterator aMIt = theMirrored->parameters().begin();
1149   for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i)
1150     (*aMIt)->setValue(aCoord[i]);
1151
1152   // update corresponding attribute
1153   AttributePtr anAttr = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theMirrored)->baseAttribute();
1154   if (anAttr) {
1155     std::shared_ptr<GeomDataAPI_Point2D> aMirroredPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
1156     aMirroredPnt->setValue(aCoord[0], aCoord[1]);
1157   }
1158 }
1159
1160 static void rotate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
1161                    std::shared_ptr<GeomAPI_Pnt2d> theCenter,
1162                    double theSin, double theCos)
1163 {
1164   if (theSource->type() == ENTITY_POINT) {
1165     // Rotate single point
1166     std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
1167         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theSource->baseAttribute());
1168     std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
1169         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theDest->baseAttribute());
1170     if (aSrcAttr && aDstAttr) {
1171       std::shared_ptr<GeomAPI_XY> aVec = aSrcAttr->pnt()->xy()->decreased(theCenter->xy());
1172       double aNewX = aVec->x() * theCos - aVec->y() * theSin;
1173       double aNewY = aVec->x() * theSin + aVec->y() * theCos;
1174       aDstAttr->setValue(theCenter->x() + aNewX, theCenter->y() + aNewY);
1175     }
1176     return;
1177   }
1178
1179   FeaturePtr aDestFeature = theDest->baseFeature();
1180   if (aDestFeature)
1181     aDestFeature->data()->blockSendAttributeUpdated(true);
1182
1183   // Rotate points of the feature
1184   const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
1185   const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
1186   std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
1187   for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
1188        aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
1189     rotate(*aSrcIt, *aDstIt, theCenter, theSin, theCos);
1190
1191   if (aDestFeature)
1192     aDestFeature->data()->blockSendAttributeUpdated(false);
1193 }
1194
1195 static void translate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
1196                       std::shared_ptr<GeomAPI_XY> theDelta)
1197 {
1198   if (theSource->type() == ENTITY_POINT) {
1199     // Translate single point
1200     std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
1201         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theSource->baseAttribute());
1202     std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
1203         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theDest->baseAttribute());
1204     if (aSrcAttr && aDstAttr)
1205       aDstAttr->setValue(aSrcAttr->x() + theDelta->x(), aSrcAttr->y() + theDelta->y());
1206     return;
1207   }
1208
1209   FeaturePtr aDestFeature = theDest->baseFeature();
1210   if (aDestFeature)
1211     aDestFeature->data()->blockSendAttributeUpdated(true);
1212
1213   // Translate points of the feature
1214   const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
1215   const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
1216   std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
1217   for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
1218        aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
1219     translate(*aSrcIt, *aDstIt, theDelta);
1220
1221   if (aDestFeature)
1222     aDestFeature->data()->blockSendAttributeUpdated(false);
1223 }
1224
1225 void adjustMultiRotation(ConstraintWrapperPtr theConstraint)
1226 {
1227   BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
1228
1229   double anAngleRad = theConstraint->value() * PI / 180.0;
1230   double aSin = sin(anAngleRad);
1231   double aCos = cos(anAngleRad);
1232
1233   const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
1234   std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
1235
1236   std::shared_ptr<GeomAPI_Pnt2d> aCenter = aBuilder->point(*aSIt++);
1237   std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
1238   for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
1239     rotate(*aPrevIt, *aSIt, aCenter, aSin, aCos);
1240 }
1241
1242 void adjustMultiTranslation(ConstraintWrapperPtr theConstraint)
1243 {
1244   BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
1245
1246   const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
1247   std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
1248
1249   std::shared_ptr<GeomAPI_Pnt2d> aStartPnt = aBuilder->point(*aSIt++);
1250   std::shared_ptr<GeomAPI_Pnt2d> aEndPnt = aBuilder->point(*aSIt++);
1251   std::shared_ptr<GeomAPI_XY> aDelta = aEndPnt->xy()->decreased(aStartPnt->xy());
1252
1253   std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
1254   for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
1255     translate(*aPrevIt, *aSIt, aDelta);
1256 }