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