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