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