]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SketchSolver_ConstraintRigid.cpp
Salome HOME
49fded0732536720edf771eb86dbf4f7dd9393df
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintRigid.cpp
1 #include <SketchSolver_ConstraintRigid.h>
2 #include <SketchSolver_Error.h>
3 #include <SketchSolver_Group.h>
4
5 #include <SketchPlugin_Arc.h>
6 #include <SketchPlugin_Circle.h>
7 #include <SketchPlugin_ConstraintRigid.h>
8 #include <SketchPlugin_Line.h>
9
10 #include <GeomAPI_Pnt2d.h>
11 #include <GeomAPI_XY.h>
12 #include <GeomDataAPI_Point2D.h>
13 #include <ModelAPI_AttributeDouble.h>
14
15 SketchSolver_ConstraintRigid::SketchSolver_ConstraintRigid(FeaturePtr theFeature)
16   : SketchSolver_Constraint(),
17     myBaseFeature(theFeature)
18 {
19   process();
20 }
21
22 void SketchSolver_ConstraintRigid::process()
23 {
24   cleanErrorMsg();
25   if ((!myBaseConstraint && !myBaseFeature) || !myStorage || myGroup == 0) {
26     /// TODO: Put error message here
27     return;
28   }
29   if (!mySlvsConstraints.empty()) // some data is changed, update constraint
30     update(myBaseConstraint);
31
32   double aValue;
33   std::vector<Slvs_hEntity> anEntities;
34   getAttributes(aValue, anEntities);
35   if (!myErrorMsg.empty() || myFeatureMap.empty())
36     return;
37
38   Slvs_hEntity anEntID = myFeatureMap.begin()->second;
39   if (myStorage->isEntityFixed(anEntID, true)) {
40     myErrorMsg = SketchSolver_Error::ALREADY_FIXED();
41     return;
42   }
43
44   if (myFeatureMap.begin()->first->getKind() == SketchPlugin_Line::ID()) {
45     Slvs_Entity aLine = myStorage->getEntity(anEntID);
46     fixLine(aLine);
47   }
48   else if (myFeatureMap.begin()->first->getKind() == SketchPlugin_Arc::ID()) {
49     Slvs_Entity anArc = myStorage->getEntity(anEntID);
50     fixArc(anArc);
51   }
52   else if (myFeatureMap.begin()->first->getKind() == SketchPlugin_Circle::ID()) {
53     Slvs_Entity aCirc = myStorage->getEntity(anEntID);
54     fixCircle(aCirc);
55   }
56 }
57
58
59 void SketchSolver_ConstraintRigid::getAttributes(
60     double& theValue,
61     std::vector<Slvs_hEntity>& theAttributes)
62 {
63   theValue = 0.0;
64   int aType = SLVS_E_UNKNOWN; // type of created entity
65   Slvs_hEntity anEntityID = SLVS_E_UNKNOWN;
66   if (myBaseConstraint) {
67     // Get the attribute of constraint
68     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
69         myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
70     if (!aRefAttr || !aRefAttr->isInitialized()) {
71       myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
72       return;
73     }
74     anEntityID = myGroup->getAttributeId(aRefAttr);
75     if (anEntityID == SLVS_E_UNKNOWN)
76       anEntityID = changeEntity(aRefAttr, aType);
77   } else {
78     anEntityID = myGroup->getFeatureId(myBaseFeature);
79     if (anEntityID == SLVS_E_UNKNOWN)
80       anEntityID = changeEntity(myBaseFeature, aType);
81     else
82       myFeatureMap[myBaseFeature] = anEntityID;
83   }
84
85   if (anEntityID == SLVS_E_UNKNOWN) {
86     myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
87     return;
88   }
89
90   // Check the entity is complex
91   Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
92   if (anEntity.point[0] != SLVS_E_UNKNOWN) {
93     for (int i = 0; i < 4 && anEntity.point[i]; i++)
94       theAttributes.push_back(anEntity.point[i]);
95   } else // simple entity
96     theAttributes.push_back(anEntityID);
97 }
98
99 void SketchSolver_ConstraintRigid::adjustConstraint()
100 {
101   if (myFeatureMap.empty() || (
102       myFeatureMap.begin()->first->getKind() != SketchPlugin_Arc::ID() && 
103       myFeatureMap.begin()->first->getKind() != SketchPlugin_Circle::ID()))
104     return;
105   FeaturePtr aFeature = myFeatureMap.begin()->first;
106
107   // Search radius constraints and update them
108   Slvs_Constraint aConstraint;
109   std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
110   for (; aCIter != mySlvsConstraints.end(); aCIter++) {
111     aConstraint = myStorage->getConstraint(*aCIter);
112     if (aConstraint.type != SLVS_C_DIAMETER)
113       continue;
114     double aRadius = 0.0;
115     if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
116       std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
117         aFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
118       std::shared_ptr<GeomAPI_Pnt2d> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
119         aFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
120       aRadius = aCenter->distance(aStart);
121     } else {
122       aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
123           aFeature->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
124     }
125
126     aConstraint.valA = aRadius * 2.0;
127     *aCIter = myStorage->updateConstraint(aConstraint);
128   }
129 }
130
131
132 bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint)
133 {
134   cleanErrorMsg();
135   if (theConstraint && theConstraint != myBaseConstraint)
136     return false;
137   bool isFullyRemoved = true;
138   std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
139   for (; aCIter != mySlvsConstraints.end(); aCIter++)
140     isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
141
142   if (isFullyRemoved) {
143     myFeatureMap.clear();
144     myAttributeMap.clear();
145     myValueMap.clear();
146   } else
147     cleanRemovedEntities();
148   return true;
149 }
150
151 void SketchSolver_ConstraintRigid::fixPoint(const Slvs_hEntity& thePointID)
152 {
153   if (thePointID == SLVS_E_UNKNOWN)
154     return;
155
156   Slvs_Constraint aConstraint;
157   Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN;
158   bool isFixed = myStorage->isPointFixed(thePointID, aConstrID, true);
159   bool isForceUpdate = (isFixed && !myBaseConstraint &&
160                         myStorage->isTemporary(aConstrID));
161   if (!isForceUpdate) { // create new constraint
162     if (isFixed) return;
163     aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
164         0.0, thePointID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
165     aConstraint.h = myStorage->addConstraint(aConstraint);
166     mySlvsConstraints.push_back(aConstraint.h);
167     if (!myBaseConstraint)
168       myStorage->addConstraintWhereDragged(aConstraint.h);
169   } else { // update already existent constraint
170     if (!isFixed || aConstrID == SLVS_E_UNKNOWN || myBaseConstraint)
171       return;
172     aConstraint = myStorage->getConstraint(aConstrID);
173     aConstraint.ptA = thePointID;
174     myStorage->addConstraint(aConstraint);
175     if (!myBaseConstraint)
176       myStorage->addConstraintWhereDragged(aConstraint.h);
177   }
178 }
179
180 void SketchSolver_ConstraintRigid::fixLine(const Slvs_Entity& theLine)
181 {
182   Slvs_Constraint anEqual;
183   if (isUsedInEqual(theLine, anEqual)) {
184     // Check another entity of Equal is already fixed
185     Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA;
186     if (myStorage->isEntityFixed(anOtherEntID, true)) {
187       // Fix start point of the line (if end point is not fixed yet) ...
188       Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN;
189       bool isFixed = myStorage->isPointFixed(theLine.point[1], anEndFixedID, true);
190       if (isFixed == SLVS_E_UNKNOWN)
191         fixPoint(theLine.point[0]);
192       // ...  and create fixed point lying on this line
193       Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0];
194       // Firstly, search already fixed point on line
195       bool isPonLineFixed = false;
196       Slvs_hEntity aFixedPoint;
197       std::list<Slvs_Constraint> aPonLineList = myStorage->getConstraintsByType(SLVS_C_PT_ON_LINE);
198       std::list<Slvs_Constraint>::const_iterator aPLIter = aPonLineList.begin();
199       for (; aPLIter != aPonLineList.end() && !isPonLineFixed; aPLIter++)
200         if (aPLIter->entityA == theLine.h) {
201           isPonLineFixed = myStorage->isPointFixed(aPLIter->ptA, anEndFixedID);
202           aFixedPoint = aPLIter->ptA;
203         }
204
205       if (isPonLineFixed) { // update existent constraint
206         myStorage->copyEntity(aPointToCopy, aFixedPoint);
207       } else { // create new constraint
208         Slvs_hEntity aCopied = myStorage->copyEntity(aPointToCopy);
209         Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_LINE,
210             myGroup->getWorkplaneId(), 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN);
211         aPonLine.h = myStorage->addConstraint(aPonLine);
212         mySlvsConstraints.push_back(aPonLine.h);
213         fixPoint(aCopied);
214       }
215       return;
216     }
217   }
218
219   for (int i = 0; i < 2; i++)
220     fixPoint(theLine.point[i]);
221 }
222
223 void SketchSolver_ConstraintRigid::fixCircle(const Slvs_Entity& theCircle)
224 {
225   bool isFixRadius = true;
226   // Verify the arc is under Equal constraint
227   Slvs_Constraint anEqual;
228   if (isUsedInEqual(theCircle, anEqual)) {
229     // Check another entity of Equal is already fixed
230     Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA;
231     if (myStorage->isEntityFixed(anOtherEntID, true))
232       isFixRadius = false;
233   }
234
235   fixPoint(theCircle.point[0]);
236
237   if (isFixRadius) {
238     // Fix radius of a circle
239     AttributeDoublePtr aRadiusAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
240         myFeatureMap.begin()->first->attribute(SketchPlugin_Circle::RADIUS_ID()));
241     Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER,
242         myGroup->getWorkplaneId(), aRadiusAttr->value() * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
243         myFeatureMap.begin()->second, SLVS_E_UNKNOWN);
244     aFixedR.h = myStorage->addConstraint(aFixedR);
245     mySlvsConstraints.push_back(aFixedR.h);
246   }
247 }
248
249 void SketchSolver_ConstraintRigid::fixArc(const Slvs_Entity& theArc)
250 {
251   bool isFixRadius = true;
252   std::list<Slvs_hEntity> aPointsToFix;
253   aPointsToFix.push_back(theArc.point[1]);
254   aPointsToFix.push_back(theArc.point[2]);
255
256   // Verify the arc is under Equal constraint
257   Slvs_Constraint anEqual;
258   if (isUsedInEqual(theArc, anEqual)) {
259     // Check another entity of Equal is already fixed
260     Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA;
261     if (myStorage->isEntityFixed(anOtherEntID, true)) {
262       isFixRadius = false;
263       Slvs_Entity anOtherEntity = myStorage->getEntity(anOtherEntID);
264       if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) {
265         aPointsToFix.pop_back();
266         aPointsToFix.push_back(theArc.point[0]);
267       }
268     }
269   }
270
271   Slvs_hConstraint aConstrID;
272   int aNbPointsToFix = 2; // number of fixed points for the arc
273   if (myStorage->isPointFixed(theArc.point[0], aConstrID, true))
274     aNbPointsToFix--;
275
276   // Radius of the arc
277   FeaturePtr aFeature = myFeatureMap.begin()->first;
278   std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
279     aFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
280   std::shared_ptr<GeomAPI_Pnt2d> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
281     aFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
282   double aRadius = aCenter->distance(aStart);
283
284   // Update end point of the arc to be on a curve
285   std::shared_ptr<GeomAPI_Pnt2d> anEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
286     aFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
287   double aDistance = anEnd->distance(aCenter);
288   std::shared_ptr<GeomAPI_XY> aDir = anEnd->xy()->decreased(aCenter->xy());
289   if (aDistance < tolerance)
290     aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0);
291   else
292     aDir = aDir->multiplied(aRadius / aDistance);
293   double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()};
294   Slvs_Entity aEndPoint = myStorage->getEntity(theArc.point[2]);
295   for (int i = 0; i < 2; i++) {
296     Slvs_Param aParam = myStorage->getParameter(aEndPoint.param[i]);
297     aParam.val = xy[i];
298     myStorage->updateParameter(aParam);
299   }
300
301   std::list<Slvs_hEntity>::iterator aPtIt = aPointsToFix.begin();
302   for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--)
303     fixPoint(*aPtIt);
304
305   if (isFixRadius) {
306     // Fix radius of the arc
307     bool isExists = false;
308     std::list<Slvs_Constraint> aDiamConstraints = myStorage->getConstraintsByType(SLVS_C_DIAMETER);
309     std::list<Slvs_Constraint>::iterator anIt = aDiamConstraints.begin();
310     for (; anIt != aDiamConstraints.end() && !isExists; anIt++)
311       if (anIt->entityA == myFeatureMap.begin()->second)
312         isExists = true;
313     if (!isExists) {
314       Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER,
315           myGroup->getWorkplaneId(), aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
316           myFeatureMap.begin()->second, SLVS_E_UNKNOWN);
317       aFixedR.h = myStorage->addConstraint(aFixedR);
318       mySlvsConstraints.push_back(aFixedR.h);
319       if (!myBaseConstraint)
320         myStorage->addConstraintWhereDragged(aFixedR.h);
321     }
322   }
323 }
324
325 bool SketchSolver_ConstraintRigid::isUsedInEqual(
326     const Slvs_Entity& theEntity, Slvs_Constraint& theEqual) const
327 {
328   // Check the entity is used in Equal constraint
329   std::list<Slvs_Constraint> anEqualConstr = myStorage->getConstraintsByType(SLVS_C_EQUAL_LENGTH_LINES);
330   std::list<Slvs_Constraint> anAddList = myStorage->getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN);
331   anEqualConstr.insert(anEqualConstr.end(), anAddList.begin(), anAddList.end());
332   anAddList = myStorage->getConstraintsByType(SLVS_C_EQUAL_RADIUS);
333   anEqualConstr.insert(anEqualConstr.end(), anAddList.begin(), anAddList.end());
334
335   std::list<Slvs_Constraint>::const_iterator anEqIter = anEqualConstr.begin();
336   for (; anEqIter != anEqualConstr.end(); anEqIter++)
337     if (anEqIter->entityA == theEntity.h || anEqIter->entityB == theEntity.h) {
338       theEqual = *anEqIter;
339       return true;
340     }
341   return false;
342 }
343