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