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