Salome HOME
e304a7e04f1fd0194c07d2bbcd5788bd51246326
[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     if (anInitialRefList->size() != myNumberOfObjects) {
187       remove(myBaseConstraint);
188       process();
189       return;
190     }
191   }
192   SketchSolver_Constraint::update();
193 }
194
195 bool SketchSolver_ConstraintMultiTranslation::remove(ConstraintPtr theConstraint)
196 {
197   cleanErrorMsg();
198   if (theConstraint && theConstraint != myBaseConstraint)
199     return false;
200   bool isFullyRemoved = true;
201   std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
202   for (; aCIter != mySlvsConstraints.end(); aCIter++)
203    isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
204   mySlvsConstraints.clear();
205
206   std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
207   for (; aFeatIt != myFeatureMap.end(); aFeatIt++)
208     myStorage->removeEntity(aFeatIt->second);
209
210   if (isFullyRemoved) {
211     myFeatureMap.clear();
212     myAttributeMap.clear();
213     myValueMap.clear();
214   } else
215     cleanRemovedEntities();
216   return true;
217 }
218
219 void SketchSolver_ConstraintMultiTranslation::adjustConstraint()
220 {
221   Slvs_Entity aTranslationLine = myStorage->getEntity(myTranslationLine);
222   // Check if the distance between point is 0, no need to resolve constraints (just wait another values)
223   double aXY[4];
224   for (int i = 0; i < 2; i++) {
225     Slvs_Entity aPnt = myStorage->getEntity(aTranslationLine.point[i]);
226     aXY[2*i] = myStorage->getParameter(aPnt.param[0]).val;
227     aXY[2*i+1] = myStorage->getParameter(aPnt.param[1]).val;
228   }
229   double aDelta[2] = {aXY[2] - aXY[0], aXY[3] - aXY[1]};
230   if (fabs(aDelta[0]) + fabs(aDelta[1]) < tolerance) {
231     myStorage->setNeedToResolve(false);
232     return;
233   }
234
235   // Update positions of all points to satisfy distances
236   std::list<Slvs_Constraint> aParallel = myStorage->getConstraintsByType(SLVS_C_PARALLEL);
237   std::list<Slvs_Constraint>::iterator aParIt = aParallel.begin();
238   std::vector<Slvs_hConstraint>::iterator aCIt;
239   Slvs_hConstraint aFixed; // temporary variable
240   for (; aParIt != aParallel.end(); aParIt++) {
241     for (aCIt = mySlvsConstraints.begin(); aCIt != mySlvsConstraints.end(); aCIt++)
242       if (aParIt->h == *aCIt)
243         break;
244     if (aCIt == mySlvsConstraints.end())
245       continue;
246     Slvs_Entity aLine = myStorage->getEntity(aParIt->entityB);
247     if (myStorage->isPointFixed(aLine.point[1], aFixed))
248       continue;
249     Slvs_Entity aStart = myStorage->getEntity(aLine.point[0]);
250     Slvs_Entity aEnd = myStorage->getEntity(aLine.point[1]);
251     for (int i = 0; i < 2; i++) {
252       Slvs_Param aFrom = myStorage->getParameter(aStart.param[i]);
253       Slvs_Param aTo = myStorage->getParameter(aEnd.param[i]);
254       aTo.val = aFrom.val + aDelta[i];
255       myStorage->updateParameter(aTo);
256     }
257   }
258
259   // update positions of centers of arcs for correct radius calculation
260   std::list<Slvs_Constraint> aRadii = myStorage->getConstraintsByType(SLVS_C_EQUAL_RADIUS);
261   std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt;
262   for (aParIt = aRadii.begin(); aParIt != aRadii.end(); aParIt++) {
263     int aNbFound = 0; // number of arcs used in translation
264     for (aFeatIt = myFeatureMap.begin(); aFeatIt != myFeatureMap.end(); aFeatIt++)
265       if (aFeatIt->second == aParIt->entityA || aFeatIt->second == aParIt->entityB) {
266         if (aFeatIt->first->getKind() == SketchPlugin_Arc::ID())
267           aNbFound++;
268         else
269           break;
270       }
271     if (aNbFound != 2)
272       continue;
273     // two arcs were found, update their centers
274     Slvs_Entity anArcA = myStorage->getEntity(aParIt->entityA);
275     Slvs_Entity anArcB = myStorage->getEntity(aParIt->entityB);
276     if (myStorage->isPointFixed(anArcB.point[0], aFixed))
277       continue;
278     Slvs_Entity aCenterA = myStorage->getEntity(anArcA.point[0]);
279     Slvs_Entity aCenterB = myStorage->getEntity(anArcB.point[0]);
280     for (int i = 0; i < 2; i++) {
281       Slvs_Param aFrom = myStorage->getParameter(aCenterA.param[i]);
282       Slvs_Param aTo = myStorage->getParameter(aCenterB.param[i]);
283       aTo.val = aFrom.val + aDelta[i];
284       myStorage->updateParameter(aTo);
285     }
286   }
287 }