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