Salome HOME
2D point selection in multi-rotation/multi-translation.
[modules/shaper.git] / src / SketchSolver / SolveSpaceSolver / SolveSpaceSolver_Builder.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    SolveSpaceSolver_Builder.cpp
4 // Created: 25 Mar 2015
5 // Author:  Artem ZHIDKOV
6
7 #include <SolveSpaceSolver_Builder.h>
8 #include <SolveSpaceSolver_Solver.h>
9 #include <SolveSpaceSolver_Storage.h>
10 #include <SolveSpaceSolver_ParameterWrapper.h>
11 #include <SolveSpaceSolver_EntityWrapper.h>
12 #include <SolveSpaceSolver_ConstraintWrapper.h>
13 #include <SolveSpaceSolver_ConstraintType.h>
14
15 #include <SketchSolver_Manager.h>
16
17 #include <GeomAPI_Dir2d.h>
18 #include <GeomAPI_Pnt2d.h>
19 #include <GeomAPI_XY.h>
20 #include <GeomDataAPI_Dir.h>
21 #include <GeomDataAPI_Point.h>
22 #include <GeomDataAPI_Point2D.h>
23 #include <ModelAPI_Attribute.h>
24 #include <ModelAPI_AttributeRefAttr.h>
25
26 #include <SketchPlugin_Arc.h>
27 #include <SketchPlugin_Circle.h>
28 #include <SketchPlugin_Line.h>
29 #include <SketchPlugin_Point.h>
30
31 #include <math.h>
32
33
34 static EntityWrapperPtr createLine(FeaturePtr theFeature,
35                                    const std::list<EntityWrapperPtr>& theAttributes,
36                                    const GroupID& theGroupID,
37                                    const EntityID& theSketchID);
38 static EntityWrapperPtr createCircle(FeaturePtr theFeature,
39                                      const std::list<EntityWrapperPtr>& theAttributes,
40                                      const GroupID& theGroupID,
41                                      const EntityID& theSketchID);
42 static EntityWrapperPtr createArc(FeaturePtr theFeature,
43                                   const std::list<EntityWrapperPtr>& theAttributes,
44                                   const GroupID& theGroupID,
45                                   const EntityID& theSketchID);
46
47 /// \brief Set flags of constraint to identify which points are coincident in the Tangency
48 ///        (for more information, see SolveSpace documentation)
49 static void adjustTangency(ConstraintWrapperPtr theConstraint);
50 /// \brief Set flags for angle constraint
51 static void adjustAngle(ConstraintWrapperPtr theConstraint);
52 /// \brief Update mirror points
53 static void adjustMirror(ConstraintWrapperPtr theConstraint);
54 /// \brief Update positions of rotated features
55 static void adjustMultiRotation(ConstraintWrapperPtr theConstraint);
56 /// \brief Update positions of translated features
57 static void adjustMultiTranslation(ConstraintWrapperPtr theConstraint);
58
59 /// \brief Transform points to be symmetric regarding to the mirror line
60 static void makeMirrorPoints(EntityWrapperPtr theOriginal,
61                              EntityWrapperPtr theMirrored,
62                              EntityWrapperPtr theMirrorLine);
63
64
65
66 // Initialization of constraint builder self pointer
67 BuilderPtr SolveSpaceSolver_Builder::mySelf = SolveSpaceSolver_Builder::getInstance();
68
69 BuilderPtr SolveSpaceSolver_Builder::getInstance()
70 {
71   if (!mySelf) {
72     mySelf = BuilderPtr(new SolveSpaceSolver_Builder);
73     SketchSolver_Manager::instance()->setBuilder(mySelf);
74   }
75   return mySelf;
76 }
77
78 StoragePtr SolveSpaceSolver_Builder::createStorage(const GroupID& theGroup) const
79 {
80   return StoragePtr(new SolveSpaceSolver_Storage(theGroup));
81 }
82
83 SolverPtr SolveSpaceSolver_Builder::createSolver() const
84 {
85   return SolverPtr(new SolveSpaceSolver_Solver);
86 }
87
88
89 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
90     ConstraintPtr theConstraint,
91     const GroupID& theGroupID,
92     const EntityID& theSketchID,
93     const SketchSolver_ConstraintType& theType,
94     const double& theValue,
95     const EntityWrapperPtr& thePoint1,
96     const EntityWrapperPtr& thePoint2,
97     const EntityWrapperPtr& theEntity1,
98     const EntityWrapperPtr& theEntity2) const
99 {
100   if (theType == CONSTRAINT_SYMMETRIC)
101     return createMirror(theConstraint, theGroupID, theSketchID,
102                         thePoint1, thePoint2, theEntity1);
103
104   int aType = ConstraintType::toSolveSpace(theType);
105   if (aType == SLVS_C_UNKNOWN)
106     return std::list<ConstraintWrapperPtr>();
107
108   Slvs_hEntity aSlvsEntities[4] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
109   EntityWrapperPtr anOriginal[4] = {thePoint1, thePoint2, theEntity1, theEntity2};
110   std::list<EntityWrapperPtr> aConstrAttrList; // to be filled
111   for (int i = 0; i < 4; ++i) {
112     if (!anOriginal[i])
113       continue;
114     aSlvsEntities[i] = (Slvs_hEntity)anOriginal[i]->id();
115     if (aSlvsEntities[i] == SLVS_E_UNKNOWN)
116       return std::list<ConstraintWrapperPtr>(); // entity is not added into a storage, constraint can not be created
117     aConstrAttrList.push_back(anOriginal[i]);
118   }
119
120   Slvs_Constraint aConstraint = Slvs_MakeConstraint(
121       SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
122       theValue, aSlvsEntities[0], aSlvsEntities[1], aSlvsEntities[2], aSlvsEntities[3]);
123   ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
124   aResult->setValue(theValue);
125   aResult->setEntities(aConstrAttrList);
126   adjustConstraint(aResult);
127
128   return std::list<ConstraintWrapperPtr>(1, aResult);
129 }
130
131 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
132     ConstraintPtr theConstraint,
133     const GroupID& theGroupID,
134     const EntityID& theSketchID,
135     const SketchSolver_ConstraintType& theType,
136     const double& theValue,
137     const bool& theFullValue,
138     const EntityWrapperPtr& thePoint1,
139     const EntityWrapperPtr& thePoint2,
140     const std::list<EntityWrapperPtr>& theTrsfEnt) const
141 {
142   if (theType != CONSTRAINT_MULTI_ROTATION && theType != CONSTRAINT_MULTI_TRANSLATION)
143     return std::list<ConstraintWrapperPtr>();
144
145   int aType = ConstraintType::toSolveSpace(theType);
146   if (aType == SLVS_C_UNKNOWN)
147     return std::list<ConstraintWrapperPtr>();
148
149   Slvs_Constraint aConstraint =
150       Slvs_MakeConstraint(SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
151       theValue, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
152
153   std::list<EntityWrapperPtr> aConstrAttrList = theTrsfEnt;
154   if (thePoint2)
155     aConstrAttrList.push_front(thePoint2);
156   aConstrAttrList.push_front(thePoint1);
157
158   ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
159   aResult->setValue(theValue);
160   aResult->setIsFullValue(theFullValue);
161   aResult->setEntities(aConstrAttrList);
162   return std::list<ConstraintWrapperPtr>(1, aResult);
163 }
164
165
166 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
167     ConstraintPtr theConstraint,
168     const GroupID& theGroupID,
169     const EntityID& theSketchID,
170     const EntityWrapperPtr& theEntity1,
171     const EntityWrapperPtr& theEntity2,
172     const EntityWrapperPtr& theMirrorLine) const
173 {
174   Slvs_Constraint aConstraint;
175   std::list<ConstraintWrapperPtr> aResult;
176   std::list<EntityWrapperPtr> aConstrAttrList;
177   if (theEntity1->type() == ENTITY_POINT) {
178     if (theEntity2->group() == theGroupID) // theEntity2 is not fixed
179       makeMirrorPoints(theEntity1, theEntity2, theMirrorLine);
180
181     aConstraint = Slvs_MakeConstraint(
182         SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, SLVS_C_SYMMETRIC_LINE, (Slvs_hEntity)theSketchID,
183         0.0, (Slvs_hEntity)theEntity1->id(), (Slvs_hEntity)theEntity2->id(),
184         (Slvs_hEntity)theMirrorLine->id(), SLVS_E_UNKNOWN);
185
186     aConstrAttrList.push_back(theEntity1);
187     aConstrAttrList.push_back(theEntity2);
188     aConstrAttrList.push_back(theMirrorLine);
189
190     ConstraintWrapperPtr aWrapper(new SolveSpaceSolver_ConstraintWrapper(
191         theConstraint, aConstraint));
192     aWrapper->setEntities(aConstrAttrList);
193     aResult.push_back(aWrapper);
194   }
195   else if (theEntity1->type() == ENTITY_LINE) {
196     const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
197     const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
198     std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
199     std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
200     for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) {
201       std::list<ConstraintWrapperPtr> aMrrList =
202           createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
203       aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
204     }
205   }
206   else if (theEntity1->type() == ENTITY_CIRCLE) {
207     const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
208     std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
209     for (; anIt1 != aPoints1.end(); ++anIt1)
210       if ((*anIt1)->type() == ENTITY_POINT)
211         break;
212     const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
213     std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
214     for (; anIt2 != aPoints2.end(); ++anIt2)
215       if ((*anIt2)->type() == ENTITY_POINT)
216         break;
217
218     std::list<ConstraintWrapperPtr> aMrrList =
219         createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
220     aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
221
222     // Additional constraint for equal radii
223     aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS,
224         0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2);
225     aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
226   }
227   else if (theEntity1->type() == ENTITY_ARC) {
228     // Do not allow mirrored arc recalculate its position until coordinated of all points recalculated
229     FeaturePtr aMirrArc = theEntity2->baseFeature();
230     aMirrArc->data()->blockSendAttributeUpdated(true);
231
232     std::list<ConstraintWrapperPtr> aMrrList;
233     std::list<EntityWrapperPtr>::const_iterator anIt1 = theEntity1->subEntities().begin();
234     std::list<EntityWrapperPtr>::const_iterator anIt2 = theEntity2->subEntities().begin();
235     if ((*anIt2)->group() == theGroupID) // mirrored point is not fixed
236       makeMirrorPoints(*anIt1, *anIt2, theMirrorLine);
237
238     // Workaround to avoid problems in SolveSpace.
239     // The symmetry of two arcs will be done using symmetry of three points on these arcs:
240     // start point, end point, and any other point on the arc
241     std::list<EntityWrapperPtr> aBaseArcPoints(++anIt1, theEntity1->subEntities().end());
242     std::list<EntityWrapperPtr> aMirrorArcPoints(++anIt2, theEntity2->subEntities().end());
243     // indices of points of arc, center corresponds center, first point corresponds last point
244     aMirrorArcPoints.reverse();
245
246     anIt1 = aBaseArcPoints.begin();
247     anIt2 = aMirrorArcPoints.begin();
248     for (; anIt1 != aBaseArcPoints.end(); ++anIt1, ++anIt2) {
249       aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
250       aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
251     }
252     // Restore event sending
253     aMirrArc->data()->blockSendAttributeUpdated(false);
254   }
255   return aResult;
256 }
257
258 void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const
259 {
260   SketchSolver_ConstraintType aType = theConstraint->type();
261   // Update flags in constraints
262   if (aType == CONSTRAINT_TANGENT_ARC_ARC || aType == CONSTRAINT_TANGENT_ARC_LINE)
263     adjustTangency(theConstraint);
264   else if (aType == CONSTRAINT_ANGLE)
265     adjustAngle(theConstraint);
266   else if (aType == CONSTRAINT_SYMMETRIC)
267     adjustMirror(theConstraint);
268   else if (aType == CONSTRAINT_MULTI_ROTATION)
269     adjustMultiRotation(theConstraint);
270   else if (aType == CONSTRAINT_MULTI_TRANSLATION)
271     adjustMultiTranslation(theConstraint);
272 }
273
274 EntityWrapperPtr SolveSpaceSolver_Builder::createFeature(
275     FeaturePtr theFeature,
276     const std::list<EntityWrapperPtr>& theAttributes,
277     const GroupID& theGroupID,
278     const EntityID& theSketchID) const
279 {
280   static EntityWrapperPtr aDummy;
281   if (!theFeature->data()->isValid())
282     return aDummy;
283
284   // Sketch
285   CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
286   if (aSketch)
287     return createSketchEntity(aSketch, theGroupID);
288
289   // SketchPlugin features
290   std::shared_ptr<SketchPlugin_Feature> aFeature =
291       std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
292   if (!aFeature)
293     return aDummy;
294
295   // Verify the feature by its kind
296   const std::string& aFeatureKind = aFeature->getKind();
297   // Line
298   if (aFeatureKind == SketchPlugin_Line::ID())
299     return createLine(theFeature, theAttributes, theGroupID, theSketchID);
300   // Circle
301   else if (aFeatureKind == SketchPlugin_Circle::ID())
302     return createCircle(theFeature, theAttributes,theGroupID, theSketchID);
303   // Arc
304   else if (aFeatureKind == SketchPlugin_Arc::ID())
305     return createArc(theFeature, theAttributes,theGroupID, theSketchID);
306   // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
307   else if (aFeatureKind == SketchPlugin_Point::ID()) {
308     AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID());
309     if (!aPoint->isInitialized())
310       return aDummy;
311     EntityWrapperPtr aSub = createAttribute(aPoint, theGroupID, theSketchID);
312     if (!aSub)
313       return aDummy;
314
315     const Slvs_Entity& aSubEnt =
316         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(aSub)->entity();
317     return EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, aPoint, aSubEnt));
318   }
319
320   // wrong entity
321   return aDummy;
322 }
323
324 EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute(
325     AttributePtr theAttribute,
326     const GroupID& theGroupID,
327     const EntityID& theSketchID) const
328 {
329   AttributePtr anAttribute = theAttribute;
330   AttributeRefAttrPtr aRefAttr =
331       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
332   if (aRefAttr) {
333     if (aRefAttr->isObject()) {
334       // do not create features here
335       return EntityWrapperPtr();
336     } else
337       anAttribute = aRefAttr->attr();
338   }
339
340   std::list<ParameterWrapperPtr> aParameters;
341   Slvs_Entity anEntity;
342   anEntity.type = 0;
343
344   // Point in 3D
345   std::shared_ptr<GeomDataAPI_Point> aPoint =
346       std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
347   if (aPoint) {
348     aParameters.push_back(createParameter(theGroupID, aPoint->x(), !aPoint->textX().empty()));
349     aParameters.push_back(createParameter(theGroupID, aPoint->y(), !aPoint->textY().empty()));
350     aParameters.push_back(createParameter(theGroupID, aPoint->z(), !aPoint->textZ().empty()));
351     // Create entity (parameters are not filled)
352     anEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
353         SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
354   } else {
355     // Point in 2D
356     std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
357       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
358     if (aPoint2D) {
359       aParameters.push_back(createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty()));
360       aParameters.push_back(createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty()));
361       // Create entity (parameters are not filled)
362       anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
363           (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
364     } else {
365       // Scalar value (used for the distance entities)
366       AttributeDoublePtr aScalar =
367           std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
368       if (aScalar) {
369         aParameters.push_back(createParameter(theGroupID, aScalar->value(), !aScalar->text().empty()));
370         // Create entity (parameter is not filled)
371         anEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
372           (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN);
373       }
374     }
375   }
376
377   if (anEntity.type == 0) {
378     // unknown attribute type
379     return EntityWrapperPtr();
380   }
381
382   EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theAttribute, anEntity));
383   aResult->setParameters(aParameters);
384   return aResult;
385 }
386
387
388
389 EntityWrapperPtr SolveSpaceSolver_Builder::createSketchEntity(
390     CompositeFeaturePtr theSketch,
391     const GroupID& theGroupID) const
392 {
393   DataPtr aSketchData = theSketch->data();
394   if (!aSketchData || !aSketchData->isValid())
395     return EntityWrapperPtr(); // the sketch is incorrect
396
397   // Get parameters of workplane
398   AttributePtr aDirX    = aSketchData->attribute(SketchPlugin_Sketch::DIRX_ID());
399   AttributePtr aNorm    = aSketchData->attribute(SketchPlugin_Sketch::NORM_ID());
400   AttributePtr anOrigin = aSketchData->attribute(SketchPlugin_Sketch::ORIGIN_ID());
401   if (!anOrigin->isInitialized() || !aNorm->isInitialized() || !aDirX->isInitialized())
402     return EntityWrapperPtr();
403
404   EntityWrapperPtr aNewEnt;
405   std::list<EntityWrapperPtr> aSubs;
406
407   // Create SolveSpace entity corresponding to the sketch origin
408   aNewEnt = createAttribute(anOrigin, theGroupID);
409   if (!aNewEnt)
410     return EntityWrapperPtr();
411   aSubs.push_back(aNewEnt);
412
413   // Create SolveSpace entity corresponding the the sketch normal
414   aNewEnt = createNormal(aNorm, aDirX, theGroupID);
415   if (!aNewEnt)
416     return EntityWrapperPtr();
417   aSubs.push_back(aNewEnt);
418
419   // Create workplane
420   Slvs_Entity aWorkplane = Slvs_MakeWorkplane(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
421       SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
422
423   aNewEnt = EntityWrapperPtr(
424       new SolveSpaceSolver_EntityWrapper(FeaturePtr(theSketch), aWorkplane));
425   aNewEnt->setSubEntities(aSubs);
426   return aNewEnt;
427 }
428
429 EntityWrapperPtr SolveSpaceSolver_Builder::createNormal(
430     AttributePtr theNormal,
431     AttributePtr theDirX,
432     const GroupID& theGroupID) const
433 {
434   std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
435   std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
436   if (!aDirX || !aNorm ||
437       (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) || 
438       !aNorm->isInitialized())
439     return EntityWrapperPtr();
440   // calculate Y direction
441   std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
442
443   // quaternion parameters of normal vector
444   double qw, qx, qy, qz;
445   Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
446                       &qx, &qy, &qz);
447   double aNormCoord[4] = { qw, qx, qy, qz };
448
449   // Create parameters of the normal
450   std::list<ParameterWrapperPtr> aParameters;
451   for (int i = 0; i < 4; i++)
452     aParameters.push_back(createParameter(theGroupID, aNormCoord[i]));
453
454   // Create a normal with empty parameters
455   Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
456       SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
457   EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt));
458   aNormal->setParameters(aParameters);
459   return aNormal;
460 }
461
462 ParameterWrapperPtr SolveSpaceSolver_Builder::createParameter(
463     const GroupID& theGroup, const double theValue, const bool theExpr) const
464 {
465   Slvs_Param aParam = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroup, theValue);
466   ParameterWrapperPtr aWrapper(new SolveSpaceSolver_ParameterWrapper(aParam));
467   aWrapper->setIsParametric(theExpr);
468   return aWrapper;
469 }
470
471
472
473
474
475 // ================   Auxiliary functions   ==========================
476 EntityWrapperPtr createLine(FeaturePtr theFeature,
477                             const std::list<EntityWrapperPtr>& theAttributes,
478                             const GroupID& theGroupID,
479                             const EntityID& theSketchID)
480 {
481   EntityWrapperPtr aNewEntity;
482   std::list<EntityWrapperPtr> aSubs;
483
484   AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID());
485   AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID());
486   if (!aStart->isInitialized() || !aEnd->isInitialized())
487     return aNewEntity;
488
489   EntityWrapperPtr aStartEnt, aEndEnt;
490   std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
491   for (; anIt != theAttributes.end(); ++anIt) {
492     std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity = 
493         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
494     if (aSlvsEntity->isBase(aStart))
495       aStartEnt = aSlvsEntity;
496     else if (aSlvsEntity->isBase(aEnd))
497       aEndEnt = aSlvsEntity;
498   }
499   if (!aStartEnt || !aEndEnt)
500     return aNewEntity;
501
502   aSubs.push_back(aStartEnt);
503   aSubs.push_back(aEndEnt);
504   Slvs_Entity anEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
505       (Slvs_hEntity)theSketchID, (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
506
507   aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
508   aNewEntity->setSubEntities(aSubs);
509   return aNewEntity;
510 }
511
512 EntityWrapperPtr createCircle(FeaturePtr theFeature,
513                               const std::list<EntityWrapperPtr>& theAttributes,
514                               const GroupID& theGroupID,
515                               const EntityID& theSketchID)
516 {
517   EntityWrapperPtr aNewEntity;
518   std::list<EntityWrapperPtr> aSubs;
519
520   AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID());
521   AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
522   if (!aCenter->isInitialized() || !aRadius->isInitialized())
523     return aNewEntity;
524
525   EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt;
526   std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
527   for (; anIt != theAttributes.end(); ++anIt) {
528     std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity = 
529         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
530     if (aSlvsEntity->isBase(aCenter))
531       aCenterEnt = aSlvsEntity;
532     else if (aSlvsEntity->isBase(aRadius))
533       aRadiusEnt = aSlvsEntity;
534     else if (aSlvsEntity->type() == ENTITY_NORMAL)
535       aNormalEnt = aSlvsEntity;
536   }
537   if (!aCenterEnt || !aRadiusEnt || !aNormalEnt)
538     return aNewEntity;
539
540   aSubs.push_back(aCenterEnt);
541   aSubs.push_back(aRadiusEnt);
542   Slvs_Entity anEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
543       (Slvs_hEntity)theSketchID, (Slvs_hEntity)aCenterEnt->id(),
544       (Slvs_hEntity)aNormalEnt->id(), (Slvs_hEntity)aRadiusEnt->id());
545
546   aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
547   aNewEntity->setSubEntities(aSubs);
548   return aNewEntity;
549 }
550
551 EntityWrapperPtr createArc(FeaturePtr theFeature,
552                            const std::list<EntityWrapperPtr>& theAttributes,
553                            const GroupID& theGroupID,
554                            const EntityID& theSketchID)
555 {
556   EntityWrapperPtr aNewEntity;
557   std::list<EntityWrapperPtr> aSubs;
558
559   AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID());
560   AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID());
561   AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID());
562   if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
563     return aNewEntity;
564
565   EntityWrapperPtr aCenterEnt, aStartEnt, aEndEnt, aNormalEnt;
566   std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
567   for (; anIt != theAttributes.end(); ++anIt) {
568     std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity = 
569         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
570     if (aSlvsEntity->isBase(aCenter))
571       aCenterEnt = aSlvsEntity;
572     else if (aSlvsEntity->isBase(aStart))
573       aStartEnt = aSlvsEntity;
574     else if (aSlvsEntity->isBase(aEnd))
575       aEndEnt = aSlvsEntity;
576     else if (aSlvsEntity->type() == ENTITY_NORMAL)
577       aNormalEnt = aSlvsEntity;
578   }
579   if (!aCenterEnt || !aStartEnt || !aEndEnt || !aNormalEnt)
580     return aNewEntity;
581
582   aSubs.push_back(aCenterEnt);
583   aSubs.push_back(aStartEnt);
584   aSubs.push_back(aEndEnt);
585   Slvs_Entity anEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
586       (Slvs_hEntity)theSketchID, (Slvs_hEntity)aNormalEnt->id(),
587       (Slvs_hEntity)aCenterEnt->id(), (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
588
589   aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
590   aNewEntity->setSubEntities(aSubs);
591   return aNewEntity;
592 }
593
594
595 void adjustTangency(ConstraintWrapperPtr theConstraint)
596 {
597   BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
598
599   std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
600     std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
601
602   // Collect start, end points of entities
603   std::shared_ptr<GeomAPI_Pnt2d> aStartEntPoints[2][2];
604   bool isCoinc[2][2] = {false};
605   const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
606   std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
607   for (int i = 0; aSIt != aSubs.end(); ++aSIt, ++i) {
608     const std::list<EntityWrapperPtr>& aPoints = (*aSIt)->subEntities();
609     std::list<EntityWrapperPtr>::const_iterator aPIt = aPoints.begin();
610     if ((*aSIt)->type() == ENTITY_ARC)
611       ++aPIt;
612     for (int j = 0; aPIt != aPoints.end(); ++aPIt, ++j) {
613       aStartEntPoints[i][j] = aBuilder->point(*aPIt);
614       if (i > 0) { // check coincidence
615         for (int k = 0; k < 2; ++k)
616           if (aStartEntPoints[i][j]->distance(aStartEntPoints[0][k]) < tolerance)
617             isCoinc[0][k] = isCoinc[i][j] = true;
618       }
619     }
620   }
621
622   Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
623   if (isCoinc[0][0] == false && isCoinc[0][1] == true)
624     aSlvsConstraint.other = 1;
625   else aSlvsConstraint.other = 0;
626   if (isCoinc[1][0] == false && isCoinc[1][1] == true)
627     aSlvsConstraint.other2 = 1;
628   else aSlvsConstraint.other2 = 0;
629 }
630
631 void adjustAngle(ConstraintWrapperPtr theConstraint)
632 {
633   BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
634
635   std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
636     std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
637
638   std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
639   const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
640   std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
641   for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
642     const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
643     std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
644     for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt)
645       aPoints[i][j] = aBuilder->point(*aLPIt);
646   }
647
648   std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
649     std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
650     std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
651   };
652   std::shared_ptr<GeomAPI_Pnt2d> anIntersection = aLine[0]->intersect(aLine[1]);
653   if (!anIntersection)
654     return;
655   double aDist[2][2];
656   for (int i = 0; i < 2; i++) {
657     for (int j = 0; j < 2; j++) {
658       aDist[i][j] = anIntersection->distance(aPoints[i][j]);
659       if (fabs(aDist[i][j]) <= tolerance)
660         aDist[i][j] = 0.0;
661     }
662     if (aDist[i][0] > tolerance && aDist[i][1] > tolerance &&
663         aDist[i][0] + aDist[i][1] < aPoints[i][0]->distance(aPoints[i][1]) + 2.0 * tolerance) {
664       // the intersection point is an inner point of the line,
665       // we change the sign of distance till start point to calculate correct coordinates
666       // after rotation
667       aDist[i][0] *= -1.0;
668     }
669   }
670   std::shared_ptr<GeomAPI_Dir2d> aDir[2];
671   for (int i = 0; i < 2; i++) {
672     if (aDist[i][1] > fabs(aDist[i][0]))
673       aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
674           aPoints[i][1]->xy()->decreased(anIntersection->xy())));
675     else {
676       aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
677           aPoints[i][0]->xy()->decreased(anIntersection->xy())));
678       // main direction is opposite => change signs
679       if (aDist[i][0] < 0.0) {
680         aDist[i][0] *= -1.0;
681         aDist[i][1] *= -1.0;
682       }
683     }
684   }
685
686   Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
687   aSlvsConstraint.other = false;
688   for (int i = 0; i < 2; i++)
689     if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
690       aSlvsConstraint.other = !aSlvsConstraint.other;
691 }
692
693 void adjustMirror(ConstraintWrapperPtr theConstraint)
694 {
695   std::vector<EntityWrapperPtr> aPoints;
696   EntityWrapperPtr aMirrorLine;
697
698   const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
699   std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
700   for (; anIt != aSubs.end(); ++anIt) {
701     if ((*anIt)->type() == ENTITY_POINT)
702       aPoints.push_back(*anIt);
703     else if ((*anIt)->type() == ENTITY_LINE)
704       aMirrorLine = *anIt;
705   }
706
707   makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
708 }
709
710 void makeMirrorPoints(EntityWrapperPtr theOriginal,
711                       EntityWrapperPtr theMirrored,
712                       EntityWrapperPtr theMirrorLine)
713 {
714   BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
715
716   std::shared_ptr<GeomAPI_Lin2d> aMirrorLine = aBuilder->line(theMirrorLine);
717   std::shared_ptr<GeomAPI_Dir2d> aMLDir = aMirrorLine->direction();
718   // orthogonal direction
719   aMLDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x()));
720
721   std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(theOriginal);
722   std::shared_ptr<GeomAPI_XY> aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy());
723   double aDist = aVec->dot(aMLDir->xy());
724   aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist));
725   double aCoord[2] = {aVec->x(), aVec->y()};
726   std::list<ParameterWrapperPtr>::const_iterator aMIt = theMirrored->parameters().begin();
727   for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i)
728     (*aMIt)->setValue(aCoord[i]);
729
730   // update corresponding attribute
731   AttributePtr anAttr = std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMirrored)->baseAttribute();
732   if (anAttr) {
733     std::shared_ptr<GeomDataAPI_Point2D> aMirroredPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
734     aMirroredPnt->setValue(aCoord[0], aCoord[1]);
735   }
736 }
737
738 static void rotate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
739                    std::shared_ptr<GeomAPI_Pnt2d> theCenter,
740                    double theSin, double theCos)
741 {
742   std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
743       std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
744   std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
745       std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
746
747   if (theSource->type() == ENTITY_POINT) {
748     // Rotate single point
749     std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
750         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
751     std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
752         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->baseAttribute());
753     if (aSrcAttr && aDstAttr) {
754       std::shared_ptr<GeomAPI_XY> aVec = aSrcAttr->pnt()->xy()->decreased(theCenter->xy());
755       double aNewX = aVec->x() * theCos - aVec->y() * theSin;
756       double aNewY = aVec->x() * theSin + aVec->y() * theCos;
757       aDstAttr->setValue(theCenter->x() + aNewX, theCenter->y() + aNewY);
758     }
759     return;
760   }
761
762   FeaturePtr aDestFeature = aDest->baseFeature();
763   if (aDestFeature)
764     aDestFeature->data()->blockSendAttributeUpdated(true);
765
766   // Rotate points of the feature
767   const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
768   const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
769   std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
770   for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
771        aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
772     rotate(*aSrcIt, *aDstIt, theCenter, theSin, theCos);
773
774   if (aDestFeature)
775     aDestFeature->data()->blockSendAttributeUpdated(false);
776 }
777
778 static void translate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
779                       std::shared_ptr<GeomAPI_XY> theDelta)
780 {
781   std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
782       std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
783   std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
784       std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
785
786   if (theSource->type() == ENTITY_POINT) {
787     // Translate single point
788     std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
789         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
790     std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
791         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->baseAttribute());
792     if (aSrcAttr && aDstAttr)
793       aDstAttr->setValue(aSrcAttr->x() + theDelta->x(), aSrcAttr->y() + theDelta->y());
794     return;
795   }
796
797   FeaturePtr aDestFeature = aDest->baseFeature();
798   if (aDestFeature)
799     aDestFeature->data()->blockSendAttributeUpdated(true);
800
801   // Translate points of the feature
802   const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
803   const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
804   std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
805   for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
806        aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
807     translate(*aSrcIt, *aDstIt, theDelta);
808
809   if (aDestFeature)
810     aDestFeature->data()->blockSendAttributeUpdated(false);
811 }
812
813 void adjustMultiRotation(ConstraintWrapperPtr theConstraint)
814 {
815   BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
816
817   double anAngleValue = theConstraint->value();
818   const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
819
820   bool isFullValue = theConstraint->isFullValue();
821   int aNbObjects = aSubs.size()-2;
822   if (isFullValue && aNbObjects > 0) {
823     anAngleValue /= aNbObjects;
824   }
825
826   double anAngleRad = anAngleValue * PI / 180.0;
827   double aSin = sin(anAngleRad);
828   double aCos = cos(anAngleRad);
829
830   std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
831
832   std::shared_ptr<GeomAPI_Pnt2d> aCenter = aBuilder->point(*aSIt++);
833   std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
834   for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
835     rotate(*aPrevIt, *aSIt, aCenter, aSin, aCos);
836 }
837
838 void adjustMultiTranslation(ConstraintWrapperPtr theConstraint)
839 {
840   BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
841
842   const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
843   std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
844
845   std::shared_ptr<GeomAPI_Pnt2d> aStartPnt = aBuilder->point(*aSIt++);
846   std::shared_ptr<GeomAPI_Pnt2d> aEndPnt = aBuilder->point(*aSIt++);
847   std::shared_ptr<GeomAPI_XY> aDelta = aEndPnt->xy()->decreased(aStartPnt->xy());
848
849   bool isFullValue = theConstraint->isFullValue();
850   int aNbObjects = aSubs.size()-3;
851   if (isFullValue && aNbObjects > 0) {
852     aDelta->setX(aDelta->x()/aNbObjects);
853     aDelta->setY(aDelta->y()/aNbObjects);
854   }
855
856   std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
857   for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
858     translate(*aPrevIt, *aSIt, aDelta);
859 }