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