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