Salome HOME
Fix for crash in Object Browser when object was deleted but message not sent
[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   adjustConstraint();
168 }
169
170 void SketchSolver_ConstraintMultiTranslation::update(ConstraintPtr theConstraint)
171 {
172   cleanErrorMsg();
173   if (!theConstraint || theConstraint == myBaseConstraint) {
174     AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
175         myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
176     AttributeIntegerPtr aNbCopies = myBaseConstraint->integer(SketchPlugin_MultiTranslation::NUMBER_OF_COPIES_ID());
177     if (anInitialRefList->size() != myNumberOfObjects ||
178         (size_t)aNbCopies->value() != myNumberOfCopies) {
179       remove(myBaseConstraint);
180       process();
181       return;
182     }
183   }
184   SketchSolver_Constraint::update();
185 }
186
187 bool SketchSolver_ConstraintMultiTranslation::remove(ConstraintPtr theConstraint)
188 {
189   cleanErrorMsg();
190   if (theConstraint && theConstraint != myBaseConstraint)
191     return false;
192   bool isFullyRemoved = true;
193   std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
194   for (; aCIter != mySlvsConstraints.end(); aCIter++)
195    isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
196   mySlvsConstraints.clear();
197
198   std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
199   for (; aFeatIt != myFeatureMap.end(); aFeatIt++)
200     myStorage->removeEntity(aFeatIt->second);
201
202   if (isFullyRemoved) {
203     myFeatureMap.clear();
204     myAttributeMap.clear();
205     myValueMap.clear();
206   } else
207     cleanRemovedEntities();
208   return true;
209 }
210
211 void SketchSolver_ConstraintMultiTranslation::adjustConstraint()
212 {
213   Slvs_Entity aTranslationLine = myStorage->getEntity(myTranslationLine);
214   Slvs_hConstraint aFixed; // temporary variable
215   // Set the translation line unchanged during constraint recalculation
216   for (int i = 0; i < 2; i++) {
217     if (myStorage->isPointFixed(aTranslationLine.point[i], aFixed, true))
218       continue;
219     Slvs_Constraint aConstraint = Slvs_MakeConstraint(
220         SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
221         aTranslationLine.point[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
222     aConstraint.h = myStorage->addConstraint(aConstraint);
223     myStorage->addTemporaryConstraint(aConstraint.h);
224   }
225
226   // Check if the distance between point is 0, no need to resolve constraints (just wait another values)
227   double aXY[4];
228   for (int i = 0; i < 2; i++) {
229     Slvs_Entity aPnt = myStorage->getEntity(aTranslationLine.point[i]);
230     aXY[2*i] = myStorage->getParameter(aPnt.param[0]).val;
231     aXY[2*i+1] = myStorage->getParameter(aPnt.param[1]).val;
232   }
233   double aDelta[2] = {aXY[2] - aXY[0], aXY[3] - aXY[1]};
234   if (fabs(aDelta[0]) + fabs(aDelta[1]) < tolerance) {
235     myStorage->setNeedToResolve(false);
236     return;
237   }
238
239   // Update positions of all points to satisfy distances
240   std::list<Slvs_Constraint> aParallel = myStorage->getConstraintsByType(SLVS_C_PARALLEL);
241   std::list<Slvs_Constraint>::iterator aParIt = aParallel.begin();
242   std::vector<Slvs_hConstraint>::iterator aCIt;
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 }