Salome HOME
Update Multi-Rotation tool to be used by solver
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintMultiRotation.cpp
1 #include <SketchSolver_ConstraintMultiRotation.h>
2 #include <SketchSolver_Group.h>
3 #include <SketchSolver_Error.h>
4
5 #include <SketchPlugin_Arc.h>
6 #include <SketchPlugin_MultiRotation.h>
7
8 #include <ModelAPI_AttributeDouble.h>
9 #include <ModelAPI_AttributeRefAttr.h>
10 #include <ModelAPI_AttributeRefList.h>
11 #include <ModelAPI_ResultConstruction.h>
12
13 #include <GeomAPI_Dir2d.h>
14 #include <GeomAPI_XY.h>
15
16 #include <math.h>
17
18 #define PI 3.1415926535897932
19
20 void SketchSolver_ConstraintMultiRotation::getAttributes(
21     Slvs_hEntity& theCenter, double& theAngle,
22     std::vector<std::vector<Slvs_hEntity> >& thePoints,
23     std::vector<std::vector<Slvs_hEntity> >& theCircular)
24 {
25   DataPtr aData = myBaseConstraint->data();
26   theAngle = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
27       aData->attribute(SketchPlugin_MultiRotation::ANGLE_ID()))->value();
28
29   AttributePtr aCenterAttr = aData->attribute(SketchPlugin_MultiRotation::CENTER_ID());
30   if (!aCenterAttr || !aCenterAttr->isInitialized()) {
31     myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
32     return;
33   }
34   int aType = SLVS_E_UNKNOWN; // type of created entity
35   Slvs_hEntity anEntityID = myGroup->getAttributeId(aCenterAttr);
36   if (anEntityID == SLVS_E_UNKNOWN)
37     anEntityID = changeEntity(aCenterAttr, aType);
38   theCenter = anEntityID;
39
40   // Lists of objects and number of copies
41   AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
42       aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
43   myNumberOfObjects = anInitialRefList->size();
44   myNumberOfCopies = (size_t)std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
45       aData->attribute(SketchPlugin_MultiRotation::NUMBER_OF_COPIES_ID()))->value();
46   AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
47       myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
48   if (!aRefList) {
49     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
50     return;
51   }
52
53   // Obtain all points of initial features and store them into separate lists
54   // containing their translated copies.
55   // Also all circles and arc collected too, because they will be constrained by equal radii.
56   FeaturePtr aFeature;
57   ResultConstructionPtr aRC;
58   std::vector<Slvs_hEntity> aPoints[2]; // lists of points of features
59   std::vector<Slvs_hEntity> aCircs;     // list of circular objects
60   std::list<ObjectPtr> anObjectList = aRefList->list();
61   std::list<ObjectPtr>::iterator anObjectIter = anObjectList.begin();
62   while (anObjectIter != anObjectList.end()) {
63     aPoints[0].clear();
64     aPoints[1].clear();
65     aCircs.clear();
66
67     for (size_t i = 0; i <= myNumberOfCopies && anObjectIter != anObjectList.end(); i++, anObjectIter++) {
68       aFeature = ModelAPI_Feature::feature(*anObjectIter);
69       if (!aFeature)
70         continue;
71       anEntityID = changeEntity(aFeature, aType);
72       Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
73       switch (aType) {
74       case SLVS_E_POINT_IN_2D:
75       case SLVS_E_POINT_IN_3D:
76         aPoints[0].push_back(anEntityID);
77         break;
78       case SLVS_E_LINE_SEGMENT:
79         aPoints[0].push_back(anEntity.point[0]); // start point of line
80         aPoints[1].push_back(anEntity.point[1]); // end point of line
81         break;
82       case SLVS_E_CIRCLE:
83         aPoints[0].push_back(anEntity.point[0]); // center of circle
84         aCircs.push_back(anEntityID);
85         break;
86       case SLVS_E_ARC_OF_CIRCLE:
87         aPoints[0].push_back(anEntity.point[1]); // start point of arc
88         aPoints[1].push_back(anEntity.point[2]); // end point of arc
89         aCircs.push_back(anEntityID);
90         break;
91       default:
92         myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
93         return;
94       }
95     }
96
97     if (!aPoints[0].empty())
98       thePoints.push_back(aPoints[0]);
99     if (!aPoints[1].empty())
100       thePoints.push_back(aPoints[1]);
101     if (!aCircs.empty())
102       theCircular.push_back(aCircs);
103   }
104 }
105
106 void SketchSolver_ConstraintMultiRotation::process()
107 {
108   cleanErrorMsg();
109   if (!myBaseConstraint || !myStorage || myGroup == 0) {
110     /// TODO: Put error message here
111     return;
112   }
113   if (!mySlvsConstraints.empty()) // some data is changed, update constraint
114     update(myBaseConstraint);
115
116   Slvs_hEntity aCenter;
117   std::vector<std::vector<Slvs_hEntity> > aPointsAndCopies;
118   std::vector<std::vector<Slvs_hEntity> > aCircsAndCopies;
119   getAttributes(aCenter, myAngle, aPointsAndCopies, aCircsAndCopies);
120   if (!myErrorMsg.empty())
121     return;
122
123   // Create lines between neighbor rotated points and make angle between them equal to anAngle.
124   // Also these lines should have equal lengths.
125   Slvs_Constraint aConstraint;
126   myRotationCenter = aCenter;
127   Slvs_Entity aPrevLine;
128   std::vector<std::vector<Slvs_hEntity> >::iterator aCopyIter = aPointsAndCopies.begin();
129   for (; aCopyIter != aPointsAndCopies.end(); aCopyIter++) {
130     size_t aSize = aCopyIter->size();
131     if (aSize <= 1) continue;
132
133     aPrevLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
134           myGroup->getWorkplaneId(), aCenter, (*aCopyIter)[0]);
135     aPrevLine.h = myStorage->addEntity(aPrevLine);
136     for (size_t i = 1; i < aSize; i++) {
137       Slvs_Entity aLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
138           myGroup->getWorkplaneId(), aCenter, (*aCopyIter)[i]);
139       aLine.h = myStorage->addEntity(aLine);
140       // Equal length constraint
141       aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
142           SLVS_C_EQUAL_LENGTH_LINES, myGroup->getWorkplaneId(), 0.0,
143           SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aPrevLine.h, aLine.h);
144       aConstraint.h = myStorage->addConstraint(aConstraint);
145       mySlvsConstraints.push_back(aConstraint.h);
146       // Angle constraint
147       aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
148           SLVS_C_ANGLE, myGroup->getWorkplaneId(), fabs(myAngle), SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
149           aPrevLine.h, aLine.h);
150       if (myAngle < 0.0) // clockwise rotation
151         aConstraint.other = true;
152       aConstraint.h = myStorage->addConstraint(aConstraint);
153       mySlvsConstraints.push_back(aConstraint.h);
154
155       aPrevLine = aLine;
156     }
157   }
158   // Equal radii constraints
159   for (aCopyIter = aCircsAndCopies.begin(); aCopyIter != aCircsAndCopies.end(); aCopyIter++) {
160     size_t aSize = aCopyIter->size();
161     for (size_t i = 0; i < aSize - 1; i++) {
162       aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
163           SLVS_C_EQUAL_RADIUS, myGroup->getWorkplaneId(), 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
164           (*aCopyIter)[i], (*aCopyIter)[i+1]);
165       aConstraint.h = myStorage->addConstraint(aConstraint);
166       mySlvsConstraints.push_back(aConstraint.h);
167     }
168   }
169
170   // Set the rotation center unchanged during constraint recalculation
171   if (!myStorage->isPointFixed(myRotationCenter, aConstraint.h, true)) {
172     aConstraint = Slvs_MakeConstraint(
173         SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
174         myRotationCenter, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
175     aConstraint.h = myStorage->addConstraint(aConstraint);
176     mySlvsConstraints.push_back(aConstraint.h);
177   }
178
179   adjustConstraint();
180 }
181
182 void SketchSolver_ConstraintMultiRotation::update(ConstraintPtr theConstraint)
183 {
184   cleanErrorMsg();
185   if (!theConstraint || theConstraint == myBaseConstraint) {
186     AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
187         myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
188     if (anInitialRefList->size() != myNumberOfObjects) {
189       remove(myBaseConstraint);
190       process();
191       return;
192     }
193   }
194
195   // update angle value
196   myAngle = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
197       myBaseConstraint->attribute(SketchPlugin_MultiRotation::ANGLE_ID()))->value();
198
199   SketchSolver_Constraint::update();
200 }
201
202 bool SketchSolver_ConstraintMultiRotation::remove(ConstraintPtr theConstraint)
203 {
204   cleanErrorMsg();
205   if (theConstraint && theConstraint != myBaseConstraint)
206     return false;
207   bool isFullyRemoved = true;
208   std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
209   for (; aCIter != mySlvsConstraints.end(); aCIter++)
210    isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
211   mySlvsConstraints.clear();
212
213   std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
214   for (; aFeatIt != myFeatureMap.end(); aFeatIt++)
215     myStorage->removeEntity(aFeatIt->second);
216
217   if (isFullyRemoved) {
218     myFeatureMap.clear();
219     myAttributeMap.clear();
220     myValueMap.clear();
221   } else
222     cleanRemovedEntities();
223   return true;
224 }
225
226 void SketchSolver_ConstraintMultiRotation::adjustConstraint()
227 {
228   if (abs(myAngle) < tolerance) {
229     myStorage->setNeedToResolve(false);
230     return;
231   }
232
233   // Obtain coordinates of rotation center
234   Slvs_Entity aRotCenter = myStorage->getEntity(myRotationCenter);
235   double aCenterXY[2];
236   for (int i = 0; i < 2; i++)
237     aCenterXY[i] = myStorage->getParameter(aRotCenter.param[i]).val;
238
239   double cosA = cos(myAngle * PI / 180.0);
240   double sinA = sin(myAngle * PI / 180.0);
241
242   // Update positions of all points to satisfy angles
243   std::list<Slvs_Constraint> aConstrAngle = myStorage->getConstraintsByType(SLVS_C_ANGLE);
244   std::list<Slvs_Constraint>::iterator anAngIt = aConstrAngle.begin();
245   std::vector<Slvs_hConstraint>::iterator aCIt;
246   Slvs_hConstraint aFixed; // temporary variable
247   double aVec[2]; // coordinates of vector defining a line
248   Slvs_Param aTarget[2]; // parameter to be changed
249   for (; anAngIt != aConstrAngle.end(); anAngIt++) {
250     for (aCIt = mySlvsConstraints.begin(); aCIt != mySlvsConstraints.end(); aCIt++)
251       if (anAngIt->h == *aCIt)
252         break;
253     if (aCIt == mySlvsConstraints.end())
254       continue;
255     Slvs_Entity aLineA = myStorage->getEntity(anAngIt->entityA);
256     Slvs_Entity aLineB = myStorage->getEntity(anAngIt->entityB);
257     if (myStorage->isPointFixed(aLineB.point[1], aFixed))
258       continue;
259     Slvs_Entity aPointA = myStorage->getEntity(aLineA.point[1]);
260     Slvs_Entity aPointB = myStorage->getEntity(aLineB.point[1]);
261     for (int i = 0; i < 2; i++) {
262       aVec[i] = myStorage->getParameter(aPointA.param[i]).val - aCenterXY[i];
263       aTarget[i] = myStorage->getParameter(aPointB.param[i]);
264     }
265     aTarget[0].val = aCenterXY[0] + aVec[0] * cosA - aVec[1] * sinA;
266     aTarget[1].val = aCenterXY[1] + aVec[0] * sinA + aVec[1] * cosA;
267     myStorage->updateParameter(aTarget[0]);
268     myStorage->updateParameter(aTarget[1]);
269
270     anAngIt->valA = myAngle;
271     myStorage->updateConstraint(*anAngIt);
272   }
273
274   // update positions of centers of arcs for correct radius calculation
275   std::list<Slvs_Constraint> aRadii = myStorage->getConstraintsByType(SLVS_C_EQUAL_RADIUS);
276   std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt;
277   for (anAngIt = aRadii.begin(); anAngIt != aRadii.end(); anAngIt++) {
278     int aNbFound = 0; // number of arcs used in translation
279     for (aFeatIt = myFeatureMap.begin(); aFeatIt != myFeatureMap.end(); aFeatIt++)
280       if (aFeatIt->second == anAngIt->entityA || aFeatIt->second == anAngIt->entityB) {
281         if (aFeatIt->first->getKind() == SketchPlugin_Arc::ID())
282           aNbFound++;
283         else
284           break;
285       }
286     if (aNbFound != 2)
287       continue;
288     // two arcs were found, update their centers
289     Slvs_Entity anArcA = myStorage->getEntity(anAngIt->entityA);
290     Slvs_Entity anArcB = myStorage->getEntity(anAngIt->entityB);
291     if (myStorage->isPointFixed(anArcB.point[0], aFixed))
292       continue;
293     Slvs_Entity aCenterA = myStorage->getEntity(anArcA.point[0]);
294     Slvs_Entity aCenterB = myStorage->getEntity(anArcB.point[0]);
295     for (int i = 0; i < 2; i++) {
296       aVec[i] = myStorage->getParameter(aCenterA.param[i]).val - aCenterXY[i];
297       aTarget[i] = myStorage->getParameter(aCenterB.param[i]);
298     }
299     aTarget[0].val = aCenterXY[0] + aVec[0] * cosA - aVec[1] * sinA;
300     aTarget[1].val = aCenterXY[1] + aVec[0] * sinA + aVec[1] * cosA;
301     myStorage->updateParameter(aTarget[0]);
302     myStorage->updateParameter(aTarget[1]);
303   }
304 }