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