Salome HOME
2e5bafbfed11aba45a55ab93c06c10c186743fc5
[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_AttributeInteger.h>
10 #include <ModelAPI_AttributeRefAttr.h>
11 #include <ModelAPI_AttributeRefList.h>
12 #include <ModelAPI_ResultConstruction.h>
13 #include <ModelAPI_Data.h>
14
15 #include <GeomAPI_Dir2d.h>
16 #include <GeomAPI_XY.h>
17
18 #include <math.h>
19
20
21 void SketchSolver_ConstraintMultiTranslation::getAttributes(
22     Slvs_hEntity& theStartPoint, Slvs_hEntity& theEndPoint,
23     std::vector<std::vector<Slvs_hEntity> >& thePoints,
24     std::vector<std::vector<Slvs_hEntity> >& theCircular)
25 {
26   DataPtr aData = myBaseConstraint->data();
27   AttributePtr aStartPointAttr = aData->attribute(SketchPlugin_MultiTranslation::START_POINT_ID());
28   AttributePtr aEndPointAttr = aData->attribute(SketchPlugin_MultiTranslation::END_POINT_ID());
29   if (!aStartPointAttr || !aStartPointAttr->isInitialized() ||
30       !aEndPointAttr || !aEndPointAttr->isInitialized()) {
31     myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
32     return;
33   }
34
35   int aType = SLVS_E_UNKNOWN; // type of created entity
36   Slvs_hEntity anEntityID = myGroup->getAttributeId(aStartPointAttr);
37   if (anEntityID == SLVS_E_UNKNOWN)
38     anEntityID = changeEntity(aStartPointAttr, aType);
39   theStartPoint = anEntityID;
40   anEntityID = myGroup->getAttributeId(aEndPointAttr);
41   if (anEntityID == SLVS_E_UNKNOWN)
42     anEntityID = changeEntity(aEndPointAttr, aType);
43   theEndPoint = anEntityID;
44
45   // Lists of objects and number of copies
46   AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
47       aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
48   myNumberOfObjects = anInitialRefList->size();
49   myNumberOfCopies = (size_t) aData->integer(SketchPlugin_MultiTranslation::NUMBER_OF_COPIES_ID())->value();
50   AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
51       myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
52   if (!aRefList) {
53     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
54     return;
55   }
56
57   // Obtain all points of initial features and store them into separate lists
58   // containing their translated copies.
59   // Also all circles and arc collected too, because they will be constrained by equal radii.
60   FeaturePtr aFeature;
61   ResultConstructionPtr aRC;
62   std::vector<Slvs_hEntity> aPoints[2]; // lists of points of features
63   std::vector<Slvs_hEntity> aCircs;     // list of circular objects
64   std::list<ObjectPtr> anObjectList = aRefList->list();
65   std::list<ObjectPtr>::iterator anObjectIter = anObjectList.begin();
66   while (anObjectIter != anObjectList.end()) {
67     aPoints[0].clear();
68     aPoints[1].clear();
69     aCircs.clear();
70
71     for (size_t i = 0; i <= myNumberOfCopies && anObjectIter != anObjectList.end(); i++, anObjectIter++) {
72       aFeature = ModelAPI_Feature::feature(*anObjectIter);
73       if (!aFeature)
74         continue;
75       anEntityID = changeEntity(aFeature, aType);
76       Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
77       switch (aType) {
78       case SLVS_E_POINT_IN_2D:
79       case SLVS_E_POINT_IN_3D:
80         aPoints[0].push_back(anEntityID);
81         break;
82       case SLVS_E_LINE_SEGMENT:
83         aPoints[0].push_back(anEntity.point[0]); // start point of line
84         aPoints[1].push_back(anEntity.point[1]); // end point of line
85         break;
86       case SLVS_E_CIRCLE:
87         aPoints[0].push_back(anEntity.point[0]); // center of circle
88         aCircs.push_back(anEntityID);
89         break;
90       case SLVS_E_ARC_OF_CIRCLE:
91         aPoints[0].push_back(anEntity.point[1]); // start point of arc
92         aPoints[1].push_back(anEntity.point[2]); // end point of arc
93         aCircs.push_back(anEntityID);
94         break;
95       default:
96         myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
97         return;
98       }
99     }
100
101     if (!aPoints[0].empty())
102       thePoints.push_back(aPoints[0]);
103     if (!aPoints[1].empty())
104       thePoints.push_back(aPoints[1]);
105     if (!aCircs.empty())
106       theCircular.push_back(aCircs);
107   }
108 }
109
110 void SketchSolver_ConstraintMultiTranslation::process()
111 {
112   cleanErrorMsg();
113   if (!myBaseConstraint || !myStorage || myGroup == 0) {
114     /// TODO: Put error message here
115     return;
116   }
117   if (!mySlvsConstraints.empty()) // some data is changed, update constraint
118     update(myBaseConstraint);
119
120   Slvs_hEntity aStartPoint, aEndPoint;
121   std::vector<std::vector<Slvs_hEntity> > aPointsAndCopies;
122   std::vector<std::vector<Slvs_hEntity> > aCircsAndCopies;
123   getAttributes(aStartPoint, aEndPoint, aPointsAndCopies, aCircsAndCopies);
124   if (!myErrorMsg.empty())
125     return;
126
127   // Create lines between neighbor translated points and make them parallel to the translation line.
128   // Also these lines should have equal lengths.
129   Slvs_Constraint aConstraint;
130   Slvs_Entity aTranslationLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
131       myGroup->getWorkplaneId(), aStartPoint, aEndPoint);
132   aTranslationLine.h = myStorage->addEntity(aTranslationLine);
133   myTranslationLine = aTranslationLine.h;
134   std::vector<std::vector<Slvs_hEntity> >::iterator aCopyIter = aPointsAndCopies.begin();
135   for (; aCopyIter != aPointsAndCopies.end(); aCopyIter++) {
136     size_t aSize = aCopyIter->size();
137     for (size_t i = 0; i < aSize - 1; i++) {
138       Slvs_Entity aLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
139           myGroup->getWorkplaneId(), (*aCopyIter)[i], (*aCopyIter)[i+1]);
140       aLine.h = myStorage->addEntity(aLine);
141       // Equal length constraint
142       aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
143           SLVS_C_EQUAL_LENGTH_LINES, myGroup->getWorkplaneId(), 0.0,
144           SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aTranslationLine.h, aLine.h);
145       aConstraint.h = myStorage->addConstraint(aConstraint);
146       mySlvsConstraints.push_back(aConstraint.h);
147       // Parallel constraint
148       aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
149           SLVS_C_PARALLEL, myGroup->getWorkplaneId(), 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
150           aTranslationLine.h, aLine.h);
151       aConstraint.h = myStorage->addConstraint(aConstraint);
152       mySlvsConstraints.push_back(aConstraint.h);
153     }
154   }
155   // Equal radii constraints
156   for (aCopyIter = aCircsAndCopies.begin(); aCopyIter != aCircsAndCopies.end(); aCopyIter++) {
157     size_t aSize = aCopyIter->size();
158     for (size_t i = 0; i < aSize - 1; i++) {
159       aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
160           SLVS_C_EQUAL_RADIUS, myGroup->getWorkplaneId(), 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
161           (*aCopyIter)[i], (*aCopyIter)[i+1]);
162       aConstraint.h = myStorage->addConstraint(aConstraint);
163       mySlvsConstraints.push_back(aConstraint.h);
164     }
165   }
166
167   // Set the translation line unchanged during constraint recalculation
168   for (int i = 0; i < 2; i++) {
169     if (myStorage->isPointFixed(aTranslationLine.point[i], aConstraint.h, true))
170       continue;
171     aConstraint = Slvs_MakeConstraint(
172         SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
173         aTranslationLine.point[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
174     aConstraint.h = myStorage->addConstraint(aConstraint);
175     mySlvsConstraints.push_back(aConstraint.h);
176   }
177
178   adjustConstraint();
179 }
180
181 void SketchSolver_ConstraintMultiTranslation::update(ConstraintPtr theConstraint)
182 {
183   cleanErrorMsg();
184   if (!theConstraint || theConstraint == myBaseConstraint) {
185     AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
186         myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
187     AttributeIntegerPtr aNbCopies = myBaseConstraint->integer(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 }