Salome HOME
Merge branch 'Dev_1.1.0' of newgeom:newgeom into Dev_1.1.0
[modules/shaper.git] / src / SketchSolver / SketchSolver_Constraint.cpp
1 #include <SketchSolver_Constraint.h>
2 #include <SketchSolver_Group.h>
3 #include <SketchSolver_Error.h>
4
5 #include <SketchPlugin_Arc.h>
6 #include <SketchPlugin_Circle.h>
7 #include <SketchPlugin_Line.h>
8 #include <SketchPlugin_Point.h>
9
10 #include <GeomDataAPI_Point.h>
11 #include <GeomDataAPI_Point2D.h>
12 #include <ModelAPI_AttributeDouble.h>
13 #include <ModelAPI_ResultConstruction.h>
14
15 #include <math.h>
16
17 SketchSolver_Constraint::SketchSolver_Constraint(
18     ConstraintPtr  theConstraint)
19   : myBaseConstraint(theConstraint),
20     myGroup(0)
21 {
22 }
23
24 SketchSolver_Constraint::~SketchSolver_Constraint()
25 {
26   std::map<AttributePtr, Slvs_hParam>::const_iterator anIt1 = myValueMap.begin();
27   for (; anIt1 != myValueMap.end(); anIt1++)
28     myStorage->removeParameter(anIt1->second);
29   myValueMap.clear();
30
31   std::map<AttributePtr, Slvs_hEntity>::const_iterator anIt2 = myAttributeMap.begin();
32   for (; anIt2 != myAttributeMap.end(); anIt2++)
33     myStorage->removeEntity(anIt2->second);
34   myAttributeMap.clear();
35
36   std::map<FeaturePtr, Slvs_hEntity>::iterator anIt3 =  myFeatureMap.begin();
37   while (!myFeatureMap.empty()) {
38     std::shared_ptr<SketchPlugin_Feature> aFeature =
39         std::dynamic_pointer_cast<SketchPlugin_Feature>(anIt3->first);
40     Slvs_hEntity anEnt = anIt3->second;
41     std::map<FeaturePtr, Slvs_hEntity>::iterator aRemIt = anIt3++;
42     myFeatureMap.erase(aRemIt);
43     if (!myGroup->isInteract(aFeature))
44       myStorage->removeEntity(anEnt);
45   }
46
47   std::vector<Slvs_hConstraint>::const_iterator anIt4 = mySlvsConstraints.begin();
48   for (; anIt4 != mySlvsConstraints.end(); anIt4++)
49     myStorage->removeConstraint(*anIt4);
50   mySlvsConstraints.clear();
51 }
52
53 void SketchSolver_Constraint::setStorage(StoragePtr theStorage)
54 {
55   myStorage = theStorage;
56   process();
57 }
58
59 void SketchSolver_Constraint::setGroup(SketchSolver_Group* theGroup)
60 {
61   myGroup = theGroup;
62   process();
63 }
64
65 void SketchSolver_Constraint::addFeature(FeaturePtr theFeature)
66 {
67   int aType;
68   changeEntity(theFeature, aType);
69 }
70
71
72 void SketchSolver_Constraint::process()
73 {
74   cleanErrorMsg();
75   if (!myBaseConstraint || !myStorage || myGroup == 0) {
76     /// TODO: Put error message here
77     return;
78   }
79   if (!mySlvsConstraints.empty()) // some data is changed, update constraint
80     update(myBaseConstraint);
81
82   int aConstrType = getType();
83   double aValue = 0.0;
84   std::vector<Slvs_hEntity> anAttributes;
85   getAttributes(aValue, anAttributes);
86   if (!myErrorMsg.empty())
87     return;
88
89   Slvs_hGroup aGroupID = myGroup->getId();
90   Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
91   Slvs_Constraint aConstraint;
92   if (mySlvsConstraints.empty())
93     aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, aGroupID, aConstrType, aWorkplaneID,
94         aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
95   else {
96     aConstraint = myStorage->getConstraint(mySlvsConstraints[0]);
97     aConstraint.valA = aValue;
98     static const int aNbAttrs = 6;
99     Slvs_hEntity* aConstrAttrs[aNbAttrs] = {
100         &aConstraint.ptA, &aConstraint.ptB,
101         &aConstraint.entityA, &aConstraint.entityB,
102         &aConstraint.entityC, &aConstraint.entityD};
103     std::vector<Slvs_hEntity>::const_iterator anIter = anAttributes.begin();
104     for (int i = 0; i < aNbAttrs && anIter != anAttributes.end(); i++, anIter++)
105       *(aConstrAttrs[i]) = *anIter;
106   }
107
108   Slvs_hConstraint anID = myStorage->addConstraint(aConstraint);
109   if (mySlvsConstraints.empty())
110     mySlvsConstraints.push_back(anID);
111   else
112     mySlvsConstraints[0] = anID;
113   adjustConstraint();
114 }
115
116 void SketchSolver_Constraint::update(ConstraintPtr theConstraint)
117 {
118   cleanErrorMsg();
119   if (theConstraint && theConstraint != myBaseConstraint) {
120     if (theConstraint->getKind() != myBaseConstraint->getKind())
121       return;
122     remove(myBaseConstraint);
123     myBaseConstraint = theConstraint;
124     process();
125   }
126
127   // Update all attributes
128   int aType;
129   std::map<Slvs_hEntity, Slvs_hEntity> aRelocationMap;
130   std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myFeatureMap.begin();
131   for (; aFeatIter != myFeatureMap.end(); aFeatIter++) {
132     Slvs_hEntity aPrevID = aFeatIter->second;
133     aFeatIter->second = changeEntity(aFeatIter->first, aType);
134     if (aFeatIter->second != aPrevID)
135       aRelocationMap[aPrevID] = aFeatIter->second;
136   }
137   std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
138   for (; anAttrIter != myAttributeMap.end(); anAttrIter++) {
139     Slvs_hEntity aPrevID = anAttrIter->second;
140     anAttrIter->second = changeEntity(anAttrIter->first, aType);
141     if (anAttrIter->second != aPrevID)
142       aRelocationMap[aPrevID] = anAttrIter->second;
143   }
144
145   // Value if exists
146   DataPtr aData = myBaseConstraint->data();
147   if (!aData) return;
148   AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
149     myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE()));
150   double aValue = aValueAttr ? aValueAttr->value() : 0.0;
151
152   // Update constraint
153   std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
154   for (; aCIter != mySlvsConstraints.end(); aCIter++) {
155     Slvs_Constraint aConstraint = myStorage->getConstraint(*aCIter);
156     aConstraint.valA = aValue;
157     Slvs_hEntity* aCoeffs[6] = {
158         &aConstraint.ptA, &aConstraint.ptB,
159         &aConstraint.entityA, &aConstraint.entityB,
160         &aConstraint.entityC, &aConstraint.entityD};
161     for (int i = 0; i < 6; i++) {
162       if (*(aCoeffs[i]) == SLVS_E_UNKNOWN)
163         continue;
164       std::map<Slvs_hEntity, Slvs_hEntity>::iterator aFound = aRelocationMap.find(*(aCoeffs[i]));
165       if (aFound != aRelocationMap.end())
166         *(aCoeffs[i]) = aFound->second;
167     }
168     *aCIter = myStorage->addConstraint(aConstraint);
169   }
170   adjustConstraint();
171 }
172
173 bool SketchSolver_Constraint::remove(ConstraintPtr theConstraint)
174 {
175   cleanErrorMsg();
176   if (theConstraint && theConstraint != myBaseConstraint)
177     return false;
178   if (mySlvsConstraints.empty())
179     return true;
180   bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints.front());
181   if (isFullyRemoved) {
182     myFeatureMap.clear();
183     myAttributeMap.clear();
184     myValueMap.clear();
185   } else
186     cleanRemovedEntities();
187   mySlvsConstraints.clear();
188   return true;
189 }
190
191 void SketchSolver_Constraint::cleanRemovedEntities()
192 {
193   std::set<Slvs_hParam> aRemovedParams;
194   std::set<Slvs_hEntity> aRemovedEntities;
195   std::set<Slvs_hConstraint> aRemovedConstraints;
196   myStorage->getRemoved(aRemovedParams, aRemovedEntities, aRemovedConstraints);
197   std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
198   while (aFeatIt != myFeatureMap.end()) {
199     if (aRemovedEntities.find(aFeatIt->second) == aRemovedEntities.end()) {
200       aFeatIt++;
201       continue;
202     }
203     std::map<FeaturePtr, Slvs_hEntity>::iterator aTmpIter = aFeatIt++;
204     myFeatureMap.erase(aTmpIter);
205   }
206   std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIt = myAttributeMap.begin();
207   while (anAttrIt != myAttributeMap.end()) {
208     if (aRemovedEntities.find(anAttrIt->second) == aRemovedEntities.end()) {
209       anAttrIt++;
210       continue;
211     }
212     std::map<AttributePtr, Slvs_hEntity>::iterator aTmpIter = anAttrIt++;
213     myAttributeMap.erase(aTmpIter);
214   }
215   std::map<AttributePtr, Slvs_hParam>::iterator aValIt = myValueMap.begin();
216   while (aValIt != myValueMap.end()) {
217     if (aRemovedParams.find(aValIt->second) == aRemovedParams.end()) {
218       aValIt++;
219       continue;
220     }
221     std::map<AttributePtr, Slvs_hParam>::iterator aTmpIter = aValIt++;
222     myValueMap.erase(aTmpIter);
223   }
224 }
225
226 void SketchSolver_Constraint::getAttributes(
227     double& theValue,
228     std::vector<Slvs_hEntity>& theAttributes)
229 {
230   static const int anInitNbOfAttr = 4;
231   theAttributes.assign(anInitNbOfAttr, SLVS_E_UNKNOWN);
232
233   DataPtr aData = myBaseConstraint->data();
234
235   AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
236     aData->attribute(SketchPlugin_Constraint::VALUE()));
237   theValue = aValueAttr ? aValueAttr->value() : 0.0;
238
239   int aPtInd = 0; // index of first point in the list of attributes
240   int aEntInd = 2; // index of first antity in the list of attributes
241   std::list<AttributePtr> aConstrAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId());
242   std::list<AttributePtr>::iterator anIter = aConstrAttrs.begin();
243   for (; anIter != aConstrAttrs.end(); anIter++) {
244     AttributeRefAttrPtr aRefAttr =
245         std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
246     if (!aRefAttr || !aRefAttr->isInitialized()) {
247       myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
248       return;
249     }
250
251     int aType = SLVS_E_UNKNOWN; // type of created entity
252     Slvs_hEntity anEntity = myGroup->getAttributeId(aRefAttr);
253     if (anEntity == SLVS_E_UNKNOWN)
254       anEntity = changeEntity(aRefAttr, aType);
255     else {
256       Slvs_Entity anEnt = myStorage->getEntity(anEntity);
257       aType = anEnt.type;
258     }
259
260     if (aType == SLVS_E_UNKNOWN)
261       continue;
262     else if (aType == SLVS_E_POINT_IN_2D || aType == SLVS_E_POINT_IN_3D)
263       theAttributes[aPtInd++] = anEntity; // the point is created
264     else { // another entity (not a point) is created
265       if (aEntInd < anInitNbOfAttr)
266         theAttributes[aEntInd] = anEntity;
267       else
268         theAttributes.push_back(anEntity);
269       aEntInd++;
270     }
271   }
272 }
273
274 Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributeRefAttrPtr theAttribute, int& theType)
275 {
276   // Convert the object of the attribute to the feature
277   FeaturePtr aFeature;
278   if (theAttribute->isObject() && theAttribute->object()) {
279     ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
280         theAttribute->object());
281     if (!aRC) {
282       myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
283       return SLVS_E_UNKNOWN;
284     }
285     std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
286     aFeature = aDoc->feature(aRC);
287
288     return changeEntity(aFeature, theType);
289   }
290
291   return changeEntity(theAttribute->attr(), theType);
292 }
293
294 Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& theType)
295 {
296   Slvs_hEntity aResult = SLVS_E_UNKNOWN;
297   if (!theEntity || !isInitialized(theEntity))
298     return SLVS_E_UNKNOWN;
299
300   // If the entity is already in the group, try to find it
301   std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
302       myAttributeMap.find(theEntity);
303   Slvs_Entity aCurrentEntity;
304   aCurrentEntity.h = SLVS_E_UNKNOWN;
305   if (anEntIter != myAttributeMap.end())
306     aCurrentEntity = myStorage->getEntity(anEntIter->second);
307   else {
308     aResult = myGroup->getAttributeId(theEntity);
309     if (aResult != SLVS_E_UNKNOWN) {
310       Slvs_Entity anEnt = myStorage->getEntity(aResult);
311       theType = anEnt.type;
312       myAttributeMap[theEntity] = aResult;
313       return aResult;
314     }
315   }
316
317   Slvs_hGroup aGroupID = myGroup->getId();
318   // Point in 3D
319   std::shared_ptr<GeomDataAPI_Point> aPoint =
320       std::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
321   if (aPoint) {
322     double aXYZ[3] = {aPoint->x(), aPoint->y(), aPoint->z()};
323     Slvs_hParam aParams[3];
324     for (int i = 0; i < 3; i++) {
325       Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
326           myStorage->getParameter(aCurrentEntity.param[i]) :
327           Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
328       aPar.val = aXYZ[i];
329       aParams[i] = myStorage->addParameter(aPar);
330     }
331
332     if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
333       aCurrentEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, aGroupID, aParams[0], aParams[1], aParams[2]);
334     else { // update entity data
335       for (int i = 0; i < 3; i++)
336         aCurrentEntity.param[i] = aParams[i];
337     }
338     aResult = myStorage->addEntity(aCurrentEntity);
339   } else {
340     // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
341     Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
342     if (aWorkplaneID == SLVS_E_UNKNOWN)
343       return SLVS_E_UNKNOWN;
344
345     // Point in 2D
346     std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
347         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
348     if (aPoint2D) {
349       double aXY[2] = {aPoint2D->x(), aPoint2D->y()};
350       Slvs_hParam aParams[2];
351       for (int i = 0; i < 2; i++) {
352         Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
353             myStorage->getParameter(aCurrentEntity.param[i]) :
354             Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
355         aPar.val = aXY[i];
356         aParams[i] = myStorage->addParameter(aPar);
357       }
358
359       if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
360         aCurrentEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aParams[0], aParams[1]);
361       else { // update entity data
362         for (int i = 0; i < 2; i++)
363           aCurrentEntity.param[i] = aParams[i];
364       }
365       aResult = myStorage->addEntity(aCurrentEntity);
366     } else {
367       // Scalar value (used for the distance entities)
368       AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
369       if (aScalar) {
370         Slvs_Param aParam = aCurrentEntity.h != SLVS_E_UNKNOWN ?
371             myStorage->getParameter(aCurrentEntity.param[0]) :
372             Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
373         aParam.val = aScalar->value();
374         Slvs_hParam aValue = myStorage->addParameter(aParam);
375
376         if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
377           aCurrentEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aValue);
378         else
379           aCurrentEntity.param[0] = aValue;
380         aResult = myStorage->addEntity(aCurrentEntity);
381       }
382     }
383   }
384
385   myAttributeMap[theEntity] = aResult;
386   theType = aCurrentEntity.type;
387   return aResult;
388 }
389
390 Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& theType)
391 {
392   Slvs_hEntity aResult = SLVS_E_UNKNOWN;
393   if (!theEntity || !theEntity->data() || !theEntity->data()->isValid())
394     return SLVS_E_UNKNOWN;
395   // If the entity is already in the group, try to find it
396   std::map<FeaturePtr, Slvs_hEntity>::const_iterator anEntIter = myFeatureMap.find(theEntity);
397   Slvs_Entity aCurrentEntity;
398   aCurrentEntity.h = SLVS_E_UNKNOWN;
399   if (anEntIter != myFeatureMap.end())
400     aCurrentEntity = myStorage->getEntity(anEntIter->second);
401   else {
402     aResult = myGroup->getFeatureId(theEntity);
403     if (aResult != SLVS_E_UNKNOWN) {
404       Slvs_Entity anEnt = myStorage->getEntity(aResult);
405       theType = anEnt.type;
406       myFeatureMap[theEntity] = aResult;
407       return aResult;
408     }
409   }
410
411   Slvs_hGroup aGroupID = myGroup->getId();
412   Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
413   DataPtr aData = theEntity->data();
414
415   // SketchPlugin features
416   const std::string& aFeatureKind = theEntity->getKind();
417   AttributePtr anAttribute;
418   int anAttrType;
419   // Line
420   if (aFeatureKind == SketchPlugin_Line::ID()) {
421     anAttribute = aData->attribute(SketchPlugin_Line::START_ID());
422     if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
423     Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
424
425     anAttribute = aData->attribute(SketchPlugin_Line::END_ID());
426     if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
427     Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
428
429     if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
430       aCurrentEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aStart, aEnd);
431     else {
432       aCurrentEntity.point[0] = aStart;
433       aCurrentEntity.point[1] = aEnd;
434     }
435     aResult = myStorage->addEntity(aCurrentEntity);
436   }
437   // Circle
438   else if (aFeatureKind == SketchPlugin_Circle::ID()) {
439     anAttribute = aData->attribute(SketchPlugin_Circle::CENTER_ID());
440     if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
441     Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
442
443     anAttribute = aData->attribute(SketchPlugin_Circle::RADIUS_ID());
444     if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
445     Slvs_hEntity aRadius = changeEntity(anAttribute, anAttrType);
446
447     if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
448       Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
449       aCurrentEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
450                                         aCenter, aWorkplane.normal, aRadius);
451     } else {
452       aCurrentEntity.point[0] = aCenter;
453       aCurrentEntity.distance = aRadius;
454     }
455     aResult = myStorage->addEntity(aCurrentEntity);
456   }
457   // Arc
458   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
459     anAttribute = aData->attribute(SketchPlugin_Arc::CENTER_ID());
460     if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
461     Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
462
463     anAttribute = aData->attribute(SketchPlugin_Arc::START_ID());
464     if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
465     Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
466
467     anAttribute = aData->attribute(SketchPlugin_Arc::END_ID());
468     if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
469     Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
470
471     if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
472       Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
473       aCurrentEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
474                                             aWorkplane.normal, aCenter, aStart, aEnd);
475     } else {
476       aCurrentEntity.point[0] = aCenter;
477       aCurrentEntity.point[1] = aStart;
478       aCurrentEntity.point[2] = aEnd;
479     }
480     aResult = myStorage->addEntity(aCurrentEntity);
481   }
482   // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
483   else if (aFeatureKind == SketchPlugin_Point::ID()) {
484     anAttribute = aData->attribute(SketchPlugin_Point::COORD_ID());
485     if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
486     // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
487     aResult = changeEntity(anAttribute, anAttrType);
488     aCurrentEntity.type = SLVS_E_POINT_IN_3D;
489   }
490
491   if (aResult != SLVS_E_UNKNOWN) {
492     myFeatureMap[theEntity] = aResult;
493     theType = aCurrentEntity.type;
494   }
495   return aResult;
496 }
497
498 std::list<ConstraintPtr> SketchSolver_Constraint::constraints() const
499 {
500   std::list<ConstraintPtr> aConstraints;
501   aConstraints.push_back(myBaseConstraint);
502   return aConstraints;
503 }
504
505 void SketchSolver_Constraint::refresh()
506 {
507   cleanErrorMsg();
508   std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
509   for (; anAttrIter != myAttributeMap.end(); anAttrIter++) {
510     std::shared_ptr<GeomDataAPI_Point> aPoint =
511         std::dynamic_pointer_cast<GeomDataAPI_Point>(anAttrIter->first);
512     if (aPoint) {
513       Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
514       double aXYZ[3];
515       for (int i = 0; i < 3; i++) {
516         Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
517         aXYZ[i] = aPar.val;
518       }
519       if (fabs(aPoint->x() - aXYZ[0]) > tolerance ||
520           fabs(aPoint->y() - aXYZ[1]) > tolerance ||
521           fabs(aPoint->z() - aXYZ[2]) > tolerance)
522         aPoint->setValue(aXYZ[0], aXYZ[1], aXYZ[2]);
523     } else {
524       // Point in 2D
525       std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
526           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrIter->first);
527       if (aPoint2D) {
528         Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
529         double aXY[2];
530         for (int i = 0; i < 2; i++) {
531           Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
532           aXY[i] = aPar.val;
533         }
534         if (fabs(aPoint2D->x() - aXY[0]) > tolerance ||
535             fabs(aPoint2D->y() - aXY[1]) > tolerance)
536           aPoint2D->setValue(aXY[0], aXY[1]);
537       } else {
538         // Scalar value (used for the distance entities)
539         AttributeDoublePtr aScalar =
540             std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
541         if (aScalar) {
542           Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
543           Slvs_Param aPar = myStorage->getParameter(anEntity.param[0]);
544           if (fabs(aScalar->value() - aPar.val) > tolerance)
545             aScalar->setValue(aPar.val);
546         }
547       }
548     }
549   }
550
551   std::map<AttributePtr, Slvs_hParam>::iterator aValIter = myValueMap.begin();
552   for (; aValIter != myValueMap.end(); aValIter++) {
553     AttributeDoublePtr aScalar =
554         std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
555     if (aScalar) {
556       Slvs_Param aPar = myStorage->getParameter(anAttrIter->second);
557       aScalar->setValue(aPar.val);
558     }
559   }
560 }
561
562 Slvs_hEntity SketchSolver_Constraint::getId(FeaturePtr theFeature) const
563 {
564   std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFIter = myFeatureMap.find(theFeature);
565   if (aFIter == myFeatureMap.end())
566     return SLVS_E_UNKNOWN;
567   return aFIter->second;
568 }
569
570 Slvs_hEntity SketchSolver_Constraint::getId(AttributePtr theAttribute) const
571 {
572   std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrIter = myAttributeMap.find(theAttribute);
573   if (anAttrIter == myAttributeMap.end())
574     return SLVS_E_UNKNOWN;
575   return anAttrIter->second;
576 }
577
578 bool SketchSolver_Constraint::isInitialized(AttributePtr theAttribute)
579 {
580   if (theAttribute->isInitialized())
581     return true;
582   myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
583   return false;
584 }
585
586
587 void SketchSolver_Constraint::calculateMiddlePoint(
588     const Slvs_Entity& theEntity, double theCoeff, double& theX, double& theY) const
589 {
590   if (theEntity.type == SLVS_E_LINE_SEGMENT) {
591     double aStartEndXY[2][2];
592     Slvs_Entity aPoint;
593     for (int i = 0; i < 2; i++) {
594       aPoint = myStorage->getEntity(theEntity.point[i]);
595       for (int j = 0; j < 2; j++)
596         aStartEndXY[i][j] = myStorage->getParameter(aPoint.param[j]).val;
597     }
598     theX = (1.0 - theCoeff) * aStartEndXY[0][0] + theCoeff * aStartEndXY[1][0];
599     theY = (1.0 - theCoeff) * aStartEndXY[0][1] + theCoeff * aStartEndXY[1][1];
600   } else if (theEntity.type == SLVS_E_ARC_OF_CIRCLE) {
601     double anArcPoint[3][2];
602     Slvs_Entity aPoint;
603     for (int i = 0; i < 3; i++) {
604       aPoint = myStorage->getEntity(theEntity.point[i]);
605       for (int j = 0; j < 2; j++)
606         anArcPoint[i][j] = myStorage->getParameter(aPoint.param[j]).val;
607     }
608     // project last point of arc on the arc
609     double x = anArcPoint[1][0] - anArcPoint[0][0];
610     double y = anArcPoint[1][1] - anArcPoint[0][1];
611     double aRad = sqrt(x*x + y*y);
612     x = anArcPoint[2][0] - anArcPoint[0][0];
613     y = anArcPoint[2][1] - anArcPoint[0][1];
614     double aNorm = sqrt(x*x + y*y);
615     if (aNorm >= tolerance) {
616       anArcPoint[2][0] = x * aRad / aNorm;
617       anArcPoint[2][1] = y * aRad / aNorm;
618     }
619     anArcPoint[1][0] -= anArcPoint[0][0];
620     anArcPoint[1][1] -= anArcPoint[0][1];
621     if (theCoeff < tolerance) {
622       theX = anArcPoint[0][0] + anArcPoint[1][0];
623       theY = anArcPoint[0][1] + anArcPoint[1][1];
624       return;
625     } else if (1 - theCoeff < tolerance) {
626       theX = anArcPoint[0][0] + anArcPoint[2][0];
627       theY = anArcPoint[0][1] + anArcPoint[2][1];
628       return;
629     }
630
631     double xStart = anArcPoint[1][0] / aRad, xEnd = anArcPoint[2][0] / aRad;
632     double yStart = anArcPoint[1][1] / aRad, yEnd = anArcPoint[2][1] / aRad;
633     double aTanStart = abs(xStart) < tolerance ? yStart : yStart / xStart;
634     double aTanEnd   = abs(xEnd) < tolerance   ? yEnd   : yEnd / xEnd;
635     double aCotStart = abs(yStart) < tolerance ? xStart : xStart / yStart;
636     double aCotEnd   = abs(yEnd) < tolerance   ? xEnd   : xEnd / yEnd;
637     if (anArcPoint[1][0] * anArcPoint[2][0] < 0.0) {
638       if (anArcPoint[1][0] > 0.0)
639         yEnd = 2.0 - yEnd;
640       else
641         yStart = -2.0 - yStart;
642     } else {
643       if (aTanStart > aTanEnd) {
644         if (yStart > yEnd) {
645           yStart = 2.0 - yStart;
646           yEnd = -2.0 - yEnd;
647         } else {
648           yStart = -2.0 - yStart;
649           yEnd = 2.0 - yEnd;
650         }
651       }
652     }
653     if (anArcPoint[1][1] * anArcPoint[2][1] < 0.0) {
654       if (anArcPoint[1][1] > 0.0)
655         xEnd = 2.0 - xEnd;
656       else
657         xStart = -2.0 - xStart;
658     } else {
659       if (aCotStart < aCotEnd) {
660         if (xStart > xEnd) {
661           xStart = 2.0 - xStart;
662           xEnd = -2.0 - xEnd;
663         } else {
664           xStart = -2.0 - xStart;
665           xEnd = 2.0 - xEnd;
666         }
667       }
668     }
669     x = (1.0 - theCoeff) * xStart + theCoeff * xEnd;
670     y = (1.0 - theCoeff) * yStart + theCoeff * yEnd;
671     if (x > 1.0) x = 2.0 - x;
672     if (x < -1.0) x = -2.0 - x;
673     if (y > 1.0) y = 2.0 - y;
674     if (y < -1.0) y = -2.0 - y;
675
676     aNorm = sqrt(x*x + y*y);
677     if (aNorm >= tolerance) {
678       x *= aRad / aNorm;
679       y *= aRad / aNorm;
680     } else {
681       x = -0.5 * (anArcPoint[2][1] + anArcPoint[1][1]);
682       y = -0.5 * (anArcPoint[2][0] + anArcPoint[1][0]);
683     }
684     theX = anArcPoint[0][0] + x;
685     theY = anArcPoint[0][1] + y;
686   }
687 }
688
689 void SketchSolver_Constraint::makeTemporary() const
690 {
691   std::vector<Slvs_hConstraint>::const_iterator anIt = mySlvsConstraints.begin();
692   for (; anIt != mySlvsConstraints.end(); anIt++)
693     myStorage->addTemporaryConstraint(*anIt);
694 }
695