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