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