]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp
Salome HOME
Update Multi-Translation and Multi-Rotation to work correct with decreasing of copies
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintMultiTranslation.cpp
1 #include <SketchSolver_ConstraintMultiTranslation.h>
2 #include <SketchSolver_Group.h>
3 #include <SketchSolver_Error.h>
4
5 #include <SketchPlugin_Arc.h>
6 #include <SketchPlugin_MultiTranslation.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
19 void SketchSolver_ConstraintMultiTranslation::getAttributes(
20     Slvs_hEntity& theStartPoint, Slvs_hEntity& theEndPoint,
21     std::vector<std::vector<Slvs_hEntity> >& thePoints,
22     std::vector<std::vector<Slvs_hEntity> >& theCircular)
23 {
24   DataPtr aData = myBaseConstraint->data();
25   AttributePtr aStartPointAttr = aData->attribute(SketchPlugin_MultiTranslation::START_POINT_ID());
26   AttributePtr aEndPointAttr = aData->attribute(SketchPlugin_MultiTranslation::END_POINT_ID());
27   if (!aStartPointAttr || !aStartPointAttr->isInitialized() ||
28       !aEndPointAttr || !aEndPointAttr->isInitialized()) {
29     myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
30     return;
31   }
32
33   int aType = SLVS_E_UNKNOWN; // type of created entity
34   Slvs_hEntity anEntityID = myGroup->getAttributeId(aStartPointAttr);
35   if (anEntityID == SLVS_E_UNKNOWN)
36     anEntityID = changeEntity(aStartPointAttr, aType);
37   theStartPoint = anEntityID;
38   anEntityID = myGroup->getAttributeId(aEndPointAttr);
39   if (anEntityID == SLVS_E_UNKNOWN)
40     anEntityID = changeEntity(aEndPointAttr, aType);
41   theEndPoint = anEntityID;
42
43   // Lists of objects and number of copies
44   AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
45       aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
46   myNumberOfObjects = anInitialRefList->size();
47   myNumberOfCopies = (size_t)std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
48       aData->attribute(SketchPlugin_MultiTranslation::NUMBER_OF_COPIES_ID()))->value();
49   AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
50       myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
51   if (!aRefList) {
52     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
53     return;
54   }
55
56   // Obtain all points of initial features and store them into separate lists
57   // containing their translated copies.
58   // Also all circles and arc collected too, because they will be constrained by equal radii.
59   FeaturePtr aFeature;
60   ResultConstructionPtr aRC;
61   std::vector<Slvs_hEntity> aPoints[2]; // lists of points of features
62   std::vector<Slvs_hEntity> aCircs;     // list of circular objects
63   std::list<ObjectPtr> anObjectList = aRefList->list();
64   std::list<ObjectPtr>::iterator anObjectIter = anObjectList.begin();
65   while (anObjectIter != anObjectList.end()) {
66     aPoints[0].clear();
67     aPoints[1].clear();
68     aCircs.clear();
69
70     for (size_t i = 0; i <= myNumberOfCopies && anObjectIter != anObjectList.end(); i++, anObjectIter++) {
71       aFeature = ModelAPI_Feature::feature(*anObjectIter);
72       if (!aFeature)
73         continue;
74       anEntityID = changeEntity(aFeature, aType);
75       Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
76       switch (aType) {
77       case SLVS_E_POINT_IN_2D:
78       case SLVS_E_POINT_IN_3D:
79         aPoints[0].push_back(anEntityID);
80         break;
81       case SLVS_E_LINE_SEGMENT:
82         aPoints[0].push_back(anEntity.point[0]); // start point of line
83         aPoints[1].push_back(anEntity.point[1]); // end point of line
84         break;
85       case SLVS_E_CIRCLE:
86         aPoints[0].push_back(anEntity.point[0]); // center of circle
87         aCircs.push_back(anEntityID);
88         break;
89       case SLVS_E_ARC_OF_CIRCLE:
90         aPoints[0].push_back(anEntity.point[1]); // start point of arc
91         aPoints[1].push_back(anEntity.point[2]); // end point of arc
92         aCircs.push_back(anEntityID);
93         break;
94       default:
95         myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
96         return;
97       }
98     }
99
100     if (!aPoints[0].empty())
101       thePoints.push_back(aPoints[0]);
102     if (!aPoints[1].empty())
103       thePoints.push_back(aPoints[1]);
104     if (!aCircs.empty())
105       theCircular.push_back(aCircs);
106   }
107 }
108
109 void SketchSolver_ConstraintMultiTranslation::process()
110 {
111   cleanErrorMsg();
112   if (!myBaseConstraint || !myStorage || myGroup == 0) {
113     /// TODO: Put error message here
114     return;
115   }
116   if (!mySlvsConstraints.empty()) // some data is changed, update constraint
117     update(myBaseConstraint);
118
119   Slvs_hEntity aStartPoint, aEndPoint;
120   std::vector<std::vector<Slvs_hEntity> > aPointsAndCopies;
121   std::vector<std::vector<Slvs_hEntity> > aCircsAndCopies;
122   getAttributes(aStartPoint, aEndPoint, aPointsAndCopies, aCircsAndCopies);
123   if (!myErrorMsg.empty())
124     return;
125
126   // Create lines between neighbor translated points and make them parallel to the translation line.
127   // Also these lines should have equal lengths.
128   Slvs_Constraint aConstraint;
129   Slvs_Entity aTranslationLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
130       myGroup->getWorkplaneId(), aStartPoint, aEndPoint);
131   aTranslationLine.h = myStorage->addEntity(aTranslationLine);
132   myTranslationLine = aTranslationLine.h;
133   std::vector<std::vector<Slvs_hEntity> >::iterator aCopyIter = aPointsAndCopies.begin();
134   for (; aCopyIter != aPointsAndCopies.end(); aCopyIter++) {
135     size_t aSize = aCopyIter->size();
136     for (size_t i = 0; i < aSize - 1; i++) {
137       Slvs_Entity aLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
138           myGroup->getWorkplaneId(), (*aCopyIter)[i], (*aCopyIter)[i+1]);
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, aTranslationLine.h, aLine.h);
144       aConstraint.h = myStorage->addConstraint(aConstraint);
145       mySlvsConstraints.push_back(aConstraint.h);
146       // Parallel constraint
147       aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
148           SLVS_C_PARALLEL, myGroup->getWorkplaneId(), 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
149           aTranslationLine.h, aLine.h);
150       aConstraint.h = myStorage->addConstraint(aConstraint);
151       mySlvsConstraints.push_back(aConstraint.h);
152     }
153   }
154   // Equal radii constraints
155   for (aCopyIter = aCircsAndCopies.begin(); aCopyIter != aCircsAndCopies.end(); aCopyIter++) {
156     size_t aSize = aCopyIter->size();
157     for (size_t i = 0; i < aSize - 1; i++) {
158       aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
159           SLVS_C_EQUAL_RADIUS, myGroup->getWorkplaneId(), 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
160           (*aCopyIter)[i], (*aCopyIter)[i+1]);
161       aConstraint.h = myStorage->addConstraint(aConstraint);
162       mySlvsConstraints.push_back(aConstraint.h);
163     }
164   }
165
166   // Set the translation line unchanged during constraint recalculation
167   for (int i = 0; i < 2; i++) {
168     if (myStorage->isPointFixed(aTranslationLine.point[i], aConstraint.h, true))
169       continue;
170     aConstraint = Slvs_MakeConstraint(
171         SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
172         aTranslationLine.point[i], 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_ConstraintMultiTranslation::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     AttributeDoublePtr aNbCopies = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
187         myBaseConstraint->attribute(SketchPlugin_MultiTranslation::NUMBER_OF_COPIES_ID()));
188     if (anInitialRefList->size() != myNumberOfObjects ||
189         (size_t)aNbCopies->value() != myNumberOfCopies) {
190       remove(myBaseConstraint);
191       process();
192       return;
193     }
194   }
195   SketchSolver_Constraint::update();
196 }
197
198 bool SketchSolver_ConstraintMultiTranslation::remove(ConstraintPtr theConstraint)
199 {
200   cleanErrorMsg();
201   if (theConstraint && theConstraint != myBaseConstraint)
202     return false;
203   bool isFullyRemoved = true;
204   std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
205   for (; aCIter != mySlvsConstraints.end(); aCIter++)
206    isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
207   mySlvsConstraints.clear();
208
209   std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
210   for (; aFeatIt != myFeatureMap.end(); aFeatIt++)
211     myStorage->removeEntity(aFeatIt->second);
212
213   if (isFullyRemoved) {
214     myFeatureMap.clear();
215     myAttributeMap.clear();
216     myValueMap.clear();
217   } else
218     cleanRemovedEntities();
219   return true;
220 }
221
222 void SketchSolver_ConstraintMultiTranslation::adjustConstraint()
223 {
224   Slvs_Entity aTranslationLine = myStorage->getEntity(myTranslationLine);
225   // Check if the distance between point is 0, no need to resolve constraints (just wait another values)
226   double aXY[4];
227   for (int i = 0; i < 2; i++) {
228     Slvs_Entity aPnt = myStorage->getEntity(aTranslationLine.point[i]);
229     aXY[2*i] = myStorage->getParameter(aPnt.param[0]).val;
230     aXY[2*i+1] = myStorage->getParameter(aPnt.param[1]).val;
231   }
232   double aDelta[2] = {aXY[2] - aXY[0], aXY[3] - aXY[1]};
233   if (fabs(aDelta[0]) + fabs(aDelta[1]) < tolerance) {
234     myStorage->setNeedToResolve(false);
235     return;
236   }
237
238   // Update positions of all points to satisfy distances
239   std::list<Slvs_Constraint> aParallel = myStorage->getConstraintsByType(SLVS_C_PARALLEL);
240   std::list<Slvs_Constraint>::iterator aParIt = aParallel.begin();
241   std::vector<Slvs_hConstraint>::iterator aCIt;
242   Slvs_hConstraint aFixed; // temporary variable
243   for (; aParIt != aParallel.end(); aParIt++) {
244     for (aCIt = mySlvsConstraints.begin(); aCIt != mySlvsConstraints.end(); aCIt++)
245       if (aParIt->h == *aCIt)
246         break;
247     if (aCIt == mySlvsConstraints.end())
248       continue;
249     Slvs_Entity aLine = myStorage->getEntity(aParIt->entityB);
250     if (myStorage->isPointFixed(aLine.point[1], aFixed))
251       continue;
252     Slvs_Entity aStart = myStorage->getEntity(aLine.point[0]);
253     Slvs_Entity aEnd = myStorage->getEntity(aLine.point[1]);
254     for (int i = 0; i < 2; i++) {
255       Slvs_Param aFrom = myStorage->getParameter(aStart.param[i]);
256       Slvs_Param aTo = myStorage->getParameter(aEnd.param[i]);
257       aTo.val = aFrom.val + aDelta[i];
258       myStorage->updateParameter(aTo);
259     }
260   }
261
262   // update positions of centers of arcs for correct radius calculation
263   std::list<Slvs_Constraint> aRadii = myStorage->getConstraintsByType(SLVS_C_EQUAL_RADIUS);
264   std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt;
265   for (aParIt = aRadii.begin(); aParIt != aRadii.end(); aParIt++) {
266     int aNbFound = 0; // number of arcs used in translation
267     for (aFeatIt = myFeatureMap.begin(); aFeatIt != myFeatureMap.end(); aFeatIt++)
268       if (aFeatIt->second == aParIt->entityA || aFeatIt->second == aParIt->entityB) {
269         if (aFeatIt->first->getKind() == SketchPlugin_Arc::ID())
270           aNbFound++;
271         else
272           break;
273       }
274     if (aNbFound != 2)
275       continue;
276     // two arcs were found, update their centers
277     Slvs_Entity anArcA = myStorage->getEntity(aParIt->entityA);
278     Slvs_Entity anArcB = myStorage->getEntity(aParIt->entityB);
279     if (myStorage->isPointFixed(anArcB.point[0], aFixed))
280       continue;
281     Slvs_Entity aCenterA = myStorage->getEntity(anArcA.point[0]);
282     Slvs_Entity aCenterB = myStorage->getEntity(anArcB.point[0]);
283     for (int i = 0; i < 2; i++) {
284       Slvs_Param aFrom = myStorage->getParameter(aCenterA.param[i]);
285       Slvs_Param aTo = myStorage->getParameter(aCenterB.param[i]);
286       aTo.val = aFrom.val + aDelta[i];
287       myStorage->updateParameter(aTo);
288     }
289   }
290 }