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