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