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