1 #include <SketchSolver_ConstraintRigid.h>
2 #include <SketchSolver_Error.h>
3 #include <SketchSolver_Group.h>
5 #include <SketchPlugin_Arc.h>
6 #include <SketchPlugin_Circle.h>
7 #include <SketchPlugin_ConstraintRigid.h>
8 #include <SketchPlugin_Line.h>
9 #include <SketchPlugin_Point.h>
11 #include <GeomAPI_Pnt2d.h>
12 #include <GeomAPI_XY.h>
13 #include <GeomDataAPI_Point2D.h>
14 #include <ModelAPI_AttributeDouble.h>
16 SketchSolver_ConstraintRigid::SketchSolver_ConstraintRigid(FeaturePtr theFeature)
17 : SketchSolver_Constraint(),
18 myBaseFeature(theFeature)
23 void SketchSolver_ConstraintRigid::process()
26 if ((!myBaseConstraint && !myBaseFeature) || !myStorage || myGroup == 0) {
27 /// TODO: Put error message here
30 if (!mySlvsConstraints.empty()) // some data is changed, update constraint
31 update(myBaseConstraint);
34 std::vector<Slvs_hEntity> anEntities;
35 getAttributes(aValue, anEntities);
36 if (!myErrorMsg.empty() || myFeatureMap.empty())
39 Slvs_hEntity anEntID = myFeatureMap.begin()->second;
40 if (myStorage->isEntityFixed(anEntID, true)) {
41 myErrorMsg = SketchSolver_Error::ALREADY_FIXED();
45 if (myFeatureMap.begin()->first->getKind() == SketchPlugin_Line::ID()) {
46 Slvs_Entity aLine = myStorage->getEntity(anEntID);
49 else if (myFeatureMap.begin()->first->getKind() == SketchPlugin_Arc::ID()) {
50 Slvs_Entity anArc = myStorage->getEntity(anEntID);
53 else if (myFeatureMap.begin()->first->getKind() == SketchPlugin_Circle::ID()) {
54 Slvs_Entity aCirc = myStorage->getEntity(anEntID);
57 else if (myFeatureMap.begin()->first->getKind() == SketchPlugin_Point::ID()) {
63 void SketchSolver_ConstraintRigid::getAttributes(
65 std::vector<Slvs_hEntity>& theAttributes)
68 int aType = SLVS_E_UNKNOWN; // type of created entity
69 Slvs_hEntity anEntityID = SLVS_E_UNKNOWN;
70 if (myBaseConstraint) {
71 // Get the attribute of constraint
72 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
73 myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
74 if (!aRefAttr || !aRefAttr->isInitialized()) {
75 myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
78 anEntityID = myGroup->getAttributeId(aRefAttr);
79 if (anEntityID == SLVS_E_UNKNOWN)
80 anEntityID = changeEntity(aRefAttr, aType);
82 anEntityID = myGroup->getFeatureId(myBaseFeature);
83 if (anEntityID == SLVS_E_UNKNOWN)
84 anEntityID = changeEntity(myBaseFeature, aType);
86 myFeatureMap[myBaseFeature] = anEntityID;
89 if (anEntityID == SLVS_E_UNKNOWN) {
90 myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
94 // Check the entity is complex
95 Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
96 if (anEntity.point[0] != SLVS_E_UNKNOWN) {
97 for (int i = 0; i < 4 && anEntity.point[i]; i++)
98 theAttributes.push_back(anEntity.point[i]);
99 } else // simple entity
100 theAttributes.push_back(anEntityID);
103 void SketchSolver_ConstraintRigid::adjustConstraint()
105 if (myFeatureMap.empty() || (
106 myFeatureMap.begin()->first->getKind() != SketchPlugin_Arc::ID() &&
107 myFeatureMap.begin()->first->getKind() != SketchPlugin_Circle::ID()))
109 FeaturePtr aFeature = myFeatureMap.begin()->first;
111 // Search radius constraints and update them
112 Slvs_Constraint aConstraint;
113 std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
114 for (; aCIter != mySlvsConstraints.end(); aCIter++) {
115 aConstraint = myStorage->getConstraint(*aCIter);
116 if (aConstraint.type != SLVS_C_DIAMETER)
118 double aRadius = 0.0;
119 if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
120 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
121 aFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
122 std::shared_ptr<GeomAPI_Pnt2d> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
123 aFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
124 aRadius = aCenter->distance(aStart);
126 aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
127 aFeature->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
130 aConstraint.valA = aRadius * 2.0;
131 *aCIter = myStorage->updateConstraint(aConstraint);
136 bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint)
139 if (theConstraint && theConstraint != myBaseConstraint)
141 bool isFullyRemoved = true;
142 std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
143 for (; aCIter != mySlvsConstraints.end(); aCIter++)
144 isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
146 if (isFullyRemoved) {
147 myFeatureMap.clear();
148 myAttributeMap.clear();
151 cleanRemovedEntities();
155 void SketchSolver_ConstraintRigid::fixPoint(const Slvs_hEntity& thePointID)
157 if (thePointID == SLVS_E_UNKNOWN)
160 Slvs_Constraint aConstraint;
161 Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN;
162 bool isFixed = myStorage->isPointFixed(thePointID, aConstrID, true);
163 bool isForceUpdate = (isFixed && !myBaseConstraint &&
164 myStorage->isTemporary(aConstrID));
165 if (!isForceUpdate) { // create new constraint
167 aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
168 0.0, thePointID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
169 aConstraint.h = myStorage->addConstraint(aConstraint);
170 mySlvsConstraints.push_back(aConstraint.h);
171 if (!myBaseConstraint)
172 myStorage->addConstraintWhereDragged(aConstraint.h);
173 } else { // update already existent constraint
174 if (!isFixed || aConstrID == SLVS_E_UNKNOWN || myBaseConstraint)
176 aConstraint = myStorage->getConstraint(aConstrID);
177 aConstraint.ptA = thePointID;
178 myStorage->addConstraint(aConstraint);
179 if (!myBaseConstraint)
180 myStorage->addConstraintWhereDragged(aConstraint.h);
184 void SketchSolver_ConstraintRigid::fixLine(const Slvs_Entity& theLine)
186 Slvs_Constraint anEqual;
187 if (isUsedInEqual(theLine, anEqual)) {
188 // Check another entity of Equal is already fixed
189 Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA;
190 if (myStorage->isEntityFixed(anOtherEntID, true)) {
191 // Fix start point of the line (if end point is not fixed yet) ...
192 Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN;
193 bool isFixed = myStorage->isPointFixed(theLine.point[1], anEndFixedID, true);
194 if (isFixed == SLVS_E_UNKNOWN)
195 fixPoint(theLine.point[0]);
196 // ... and create fixed point lying on this line
197 Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0];
198 // Firstly, search already fixed point on line
199 bool isPonLineFixed = false;
200 Slvs_hEntity aFixedPoint;
201 std::list<Slvs_Constraint> aPonLineList = myStorage->getConstraintsByType(SLVS_C_PT_ON_LINE);
202 std::list<Slvs_Constraint>::const_iterator aPLIter = aPonLineList.begin();
203 for (; aPLIter != aPonLineList.end() && !isPonLineFixed; aPLIter++)
204 if (aPLIter->entityA == theLine.h) {
205 isPonLineFixed = myStorage->isPointFixed(aPLIter->ptA, anEndFixedID);
206 aFixedPoint = aPLIter->ptA;
209 if (isPonLineFixed) { // update existent constraint
210 myStorage->copyEntity(aPointToCopy, aFixedPoint);
211 } else { // create new constraint
212 Slvs_hEntity aCopied = myStorage->copyEntity(aPointToCopy);
213 Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_LINE,
214 myGroup->getWorkplaneId(), 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN);
215 aPonLine.h = myStorage->addConstraint(aPonLine);
216 mySlvsConstraints.push_back(aPonLine.h);
223 for (int i = 0; i < 2; i++)
224 fixPoint(theLine.point[i]);
227 void SketchSolver_ConstraintRigid::fixCircle(const Slvs_Entity& theCircle)
229 bool isFixRadius = true;
230 // Verify the arc is under Equal constraint
231 Slvs_Constraint anEqual;
232 if (isUsedInEqual(theCircle, anEqual)) {
233 // Check another entity of Equal is already fixed
234 Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA;
235 if (myStorage->isEntityFixed(anOtherEntID, true))
239 fixPoint(theCircle.point[0]);
242 // Fix radius of a circle
243 AttributeDoublePtr aRadiusAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
244 myFeatureMap.begin()->first->attribute(SketchPlugin_Circle::RADIUS_ID()));
245 Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER,
246 myGroup->getWorkplaneId(), aRadiusAttr->value() * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
247 myFeatureMap.begin()->second, SLVS_E_UNKNOWN);
248 aFixedR.h = myStorage->addConstraint(aFixedR);
249 mySlvsConstraints.push_back(aFixedR.h);
253 void SketchSolver_ConstraintRigid::fixArc(const Slvs_Entity& theArc)
255 bool isFixRadius = true;
256 std::list<Slvs_hEntity> aPointsToFix;
257 aPointsToFix.push_back(theArc.point[1]);
258 aPointsToFix.push_back(theArc.point[2]);
260 // Verify the arc is under Equal constraint
261 Slvs_Constraint anEqual;
262 if (isUsedInEqual(theArc, anEqual)) {
263 // Check another entity of Equal is already fixed
264 Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA;
265 if (myStorage->isEntityFixed(anOtherEntID, true)) {
267 Slvs_Entity anOtherEntity = myStorage->getEntity(anOtherEntID);
268 if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) {
269 aPointsToFix.pop_back();
270 aPointsToFix.push_back(theArc.point[0]);
275 Slvs_hConstraint aConstrID;
276 int aNbPointsToFix = 2; // number of fixed points for the arc
277 if (myStorage->isPointFixed(theArc.point[0], aConstrID, true))
281 FeaturePtr aFeature = myFeatureMap.begin()->first;
282 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
283 aFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
284 std::shared_ptr<GeomAPI_Pnt2d> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
285 aFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
286 double aRadius = aCenter->distance(aStart);
288 // Update end point of the arc to be on a curve
289 std::shared_ptr<GeomAPI_Pnt2d> anEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
290 aFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
291 double aDistance = anEnd->distance(aCenter);
292 std::shared_ptr<GeomAPI_XY> aDir = anEnd->xy()->decreased(aCenter->xy());
293 if (aDistance < tolerance)
294 aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0);
296 aDir = aDir->multiplied(aRadius / aDistance);
297 double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()};
298 Slvs_Entity aEndPoint = myStorage->getEntity(theArc.point[2]);
299 for (int i = 0; i < 2; i++) {
300 Slvs_Param aParam = myStorage->getParameter(aEndPoint.param[i]);
302 myStorage->updateParameter(aParam);
305 std::list<Slvs_hEntity>::iterator aPtIt = aPointsToFix.begin();
306 for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--)
310 // Fix radius of the arc
311 bool isExists = false;
312 std::list<Slvs_Constraint> aDiamConstraints = myStorage->getConstraintsByType(SLVS_C_DIAMETER);
313 std::list<Slvs_Constraint>::iterator anIt = aDiamConstraints.begin();
314 for (; anIt != aDiamConstraints.end() && !isExists; anIt++)
315 if (anIt->entityA == myFeatureMap.begin()->second)
318 Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER,
319 myGroup->getWorkplaneId(), aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
320 myFeatureMap.begin()->second, SLVS_E_UNKNOWN);
321 aFixedR.h = myStorage->addConstraint(aFixedR);
322 mySlvsConstraints.push_back(aFixedR.h);
323 if (!myBaseConstraint)
324 myStorage->addConstraintWhereDragged(aFixedR.h);
329 bool SketchSolver_ConstraintRigid::isUsedInEqual(
330 const Slvs_Entity& theEntity, Slvs_Constraint& theEqual) const
332 // Check the entity is used in Equal constraint
333 std::list<Slvs_Constraint> anEqualConstr = myStorage->getConstraintsByType(SLVS_C_EQUAL_LENGTH_LINES);
334 std::list<Slvs_Constraint> anAddList = myStorage->getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN);
335 anEqualConstr.insert(anEqualConstr.end(), anAddList.begin(), anAddList.end());
336 anAddList = myStorage->getConstraintsByType(SLVS_C_EQUAL_RADIUS);
337 anEqualConstr.insert(anEqualConstr.end(), anAddList.begin(), anAddList.end());
339 std::list<Slvs_Constraint>::const_iterator anEqIter = anEqualConstr.begin();
340 for (; anEqIter != anEqualConstr.end(); anEqIter++)
341 if (anEqIter->entityA == theEntity.h || anEqIter->entityB == theEntity.h) {
342 theEqual = *anEqIter;