1 #include <SketchSolver_ConstraintMultiRotation.h>
2 #include <SketchSolver_Group.h>
3 #include <SketchSolver_Error.h>
5 #include <SketchPlugin_Arc.h>
6 #include <SketchPlugin_MultiRotation.h>
8 #include <ModelAPI_AttributeDouble.h>
9 #include <ModelAPI_AttributeRefAttr.h>
10 #include <ModelAPI_AttributeRefList.h>
11 #include <ModelAPI_ResultConstruction.h>
13 #include <GeomAPI_Dir2d.h>
14 #include <GeomAPI_XY.h>
18 void SketchSolver_ConstraintMultiRotation::getAttributes(
19 Slvs_hEntity& theCenter, double& theAngle,
20 std::vector<std::vector<Slvs_hEntity> >& thePoints,
21 std::vector<std::vector<Slvs_hEntity> >& theCircular)
23 DataPtr aData = myBaseConstraint->data();
24 theAngle = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
25 aData->attribute(SketchPlugin_MultiRotation::ANGLE_ID()))->value();
27 AttributePtr aCenterAttr = aData->attribute(SketchPlugin_MultiRotation::CENTER_ID());
28 if (!aCenterAttr || !aCenterAttr->isInitialized()) {
29 myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
32 int aType = SLVS_E_UNKNOWN; // type of created entity
33 Slvs_hEntity anEntityID = myGroup->getAttributeId(aCenterAttr);
34 if (anEntityID == SLVS_E_UNKNOWN)
35 anEntityID = changeEntity(aCenterAttr, aType);
36 theCenter = anEntityID;
38 // Lists of objects and number of copies
39 AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
40 aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
41 myNumberOfObjects = anInitialRefList->size();
42 myNumberOfCopies = (size_t)std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
43 aData->attribute(SketchPlugin_MultiRotation::NUMBER_OF_COPIES_ID()))->value();
44 AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
45 myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
47 myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
51 // Obtain all points of initial features and store them into separate lists
52 // containing their translated copies.
53 // Also all circles and arc collected too, because they will be constrained by equal radii.
55 ResultConstructionPtr aRC;
56 std::vector<Slvs_hEntity> aPoints[2]; // lists of points of features
57 std::vector<Slvs_hEntity> aCircs; // list of circular objects
58 std::list<ObjectPtr> anObjectList = aRefList->list();
59 std::list<ObjectPtr>::iterator anObjectIter = anObjectList.begin();
60 while (anObjectIter != anObjectList.end()) {
65 for (size_t i = 0; i <= myNumberOfCopies && anObjectIter != anObjectList.end(); i++, anObjectIter++) {
66 aFeature = ModelAPI_Feature::feature(*anObjectIter);
69 anEntityID = changeEntity(aFeature, aType);
70 Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
72 case SLVS_E_POINT_IN_2D:
73 case SLVS_E_POINT_IN_3D:
74 aPoints[0].push_back(anEntityID);
76 case SLVS_E_LINE_SEGMENT:
77 aPoints[0].push_back(anEntity.point[0]); // start point of line
78 aPoints[1].push_back(anEntity.point[1]); // end point of line
81 aPoints[0].push_back(anEntity.point[0]); // center of circle
82 aCircs.push_back(anEntityID);
84 case SLVS_E_ARC_OF_CIRCLE:
85 aPoints[0].push_back(anEntity.point[1]); // start point of arc
86 aPoints[1].push_back(anEntity.point[2]); // end point of arc
87 aCircs.push_back(anEntityID);
90 myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
95 if (!aPoints[0].empty())
96 thePoints.push_back(aPoints[0]);
97 if (!aPoints[1].empty())
98 thePoints.push_back(aPoints[1]);
100 theCircular.push_back(aCircs);
104 void SketchSolver_ConstraintMultiRotation::process()
107 if (!myBaseConstraint || !myStorage || myGroup == 0) {
108 /// TODO: Put error message here
111 if (!mySlvsConstraints.empty()) // some data is changed, update constraint
112 update(myBaseConstraint);
114 Slvs_hEntity aCenter;
115 std::vector<std::vector<Slvs_hEntity> > aPointsAndCopies;
116 std::vector<std::vector<Slvs_hEntity> > aCircsAndCopies;
117 getAttributes(aCenter, myAngle, aPointsAndCopies, aCircsAndCopies);
118 if (!myErrorMsg.empty())
121 // Create lines between neighbor rotated points and make angle between them equal to anAngle.
122 // Also these lines should have equal lengths.
123 Slvs_Constraint aConstraint;
124 myRotationCenter = aCenter;
125 Slvs_Entity aPrevLine;
126 std::vector<std::vector<Slvs_hEntity> >::iterator aCopyIter = aPointsAndCopies.begin();
127 for (; aCopyIter != aPointsAndCopies.end(); aCopyIter++) {
128 size_t aSize = aCopyIter->size();
129 if (aSize <= 1) continue;
131 aPrevLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
132 myGroup->getWorkplaneId(), aCenter, (*aCopyIter)[0]);
133 aPrevLine.h = myStorage->addEntity(aPrevLine);
134 for (size_t i = 1; i < aSize; i++) {
135 Slvs_Entity aLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
136 myGroup->getWorkplaneId(), aCenter, (*aCopyIter)[i]);
137 aLine.h = myStorage->addEntity(aLine);
138 // Equal length constraint
139 aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
140 SLVS_C_EQUAL_LENGTH_LINES, myGroup->getWorkplaneId(), 0.0,
141 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aPrevLine.h, aLine.h);
142 aConstraint.h = myStorage->addConstraint(aConstraint);
143 mySlvsConstraints.push_back(aConstraint.h);
145 aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
146 SLVS_C_ANGLE, myGroup->getWorkplaneId(), fabs(myAngle), SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
147 aPrevLine.h, aLine.h);
148 if (myAngle < 0.0) // clockwise rotation
149 aConstraint.other = true;
150 aConstraint.h = myStorage->addConstraint(aConstraint);
151 mySlvsConstraints.push_back(aConstraint.h);
156 // Equal radii constraints
157 for (aCopyIter = aCircsAndCopies.begin(); aCopyIter != aCircsAndCopies.end(); aCopyIter++) {
158 size_t aSize = aCopyIter->size();
159 for (size_t i = 0; i < aSize - 1; i++) {
160 aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
161 SLVS_C_EQUAL_RADIUS, myGroup->getWorkplaneId(), 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
162 (*aCopyIter)[i], (*aCopyIter)[i+1]);
163 aConstraint.h = myStorage->addConstraint(aConstraint);
164 mySlvsConstraints.push_back(aConstraint.h);
168 // Set the rotation center unchanged during constraint recalculation
169 if (!myStorage->isPointFixed(myRotationCenter, aConstraint.h, true)) {
170 aConstraint = Slvs_MakeConstraint(
171 SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
172 myRotationCenter, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
173 aConstraint.h = myStorage->addConstraint(aConstraint);
174 mySlvsConstraints.push_back(aConstraint.h);
180 void SketchSolver_ConstraintMultiRotation::update(ConstraintPtr theConstraint)
183 if (!theConstraint || theConstraint == myBaseConstraint) {
184 AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
185 myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
186 AttributeDoublePtr aNbCopies = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
187 myBaseConstraint->attribute(SketchPlugin_MultiRotation::NUMBER_OF_COPIES_ID()));
188 if (anInitialRefList->size() != myNumberOfObjects ||
189 (size_t)aNbCopies->value() != myNumberOfCopies) {
190 remove(myBaseConstraint);
196 // update angle value
197 myAngle = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
198 myBaseConstraint->attribute(SketchPlugin_MultiRotation::ANGLE_ID()))->value();
200 SketchSolver_Constraint::update();
203 bool SketchSolver_ConstraintMultiRotation::remove(ConstraintPtr theConstraint)
206 if (theConstraint && theConstraint != myBaseConstraint)
208 bool isFullyRemoved = true;
209 std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
210 for (; aCIter != mySlvsConstraints.end(); aCIter++)
211 isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
212 mySlvsConstraints.clear();
214 std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
215 for (; aFeatIt != myFeatureMap.end(); aFeatIt++)
216 myStorage->removeEntity(aFeatIt->second);
218 if (isFullyRemoved) {
219 myFeatureMap.clear();
220 myAttributeMap.clear();
223 cleanRemovedEntities();
227 void SketchSolver_ConstraintMultiRotation::adjustConstraint()
229 if (abs(myAngle) < tolerance) {
230 myStorage->setNeedToResolve(false);
234 // Obtain coordinates of rotation center
235 Slvs_Entity aRotCenter = myStorage->getEntity(myRotationCenter);
237 for (int i = 0; i < 2; i++)
238 aCenterXY[i] = myStorage->getParameter(aRotCenter.param[i]).val;
240 double cosA = cos(myAngle * PI / 180.0);
241 double sinA = sin(myAngle * PI / 180.0);
243 // Update positions of all points to satisfy angles
244 std::list<Slvs_Constraint> aConstrAngle = myStorage->getConstraintsByType(SLVS_C_ANGLE);
245 std::list<Slvs_Constraint>::iterator anAngIt = aConstrAngle.begin();
246 std::vector<Slvs_hConstraint>::iterator aCIt;
247 Slvs_hConstraint aFixed; // temporary variable
248 double aVec[2]; // coordinates of vector defining a line
249 Slvs_Param aTarget[2]; // parameter to be changed
250 for (; anAngIt != aConstrAngle.end(); anAngIt++) {
251 for (aCIt = mySlvsConstraints.begin(); aCIt != mySlvsConstraints.end(); aCIt++)
252 if (anAngIt->h == *aCIt)
254 if (aCIt == mySlvsConstraints.end())
256 Slvs_Entity aLineA = myStorage->getEntity(anAngIt->entityA);
257 Slvs_Entity aLineB = myStorage->getEntity(anAngIt->entityB);
258 if (myStorage->isPointFixed(aLineB.point[1], aFixed))
260 Slvs_Entity aPointA = myStorage->getEntity(aLineA.point[1]);
261 Slvs_Entity aPointB = myStorage->getEntity(aLineB.point[1]);
262 for (int i = 0; i < 2; i++) {
263 aVec[i] = myStorage->getParameter(aPointA.param[i]).val - aCenterXY[i];
264 aTarget[i] = myStorage->getParameter(aPointB.param[i]);
266 aTarget[0].val = aCenterXY[0] + aVec[0] * cosA - aVec[1] * sinA;
267 aTarget[1].val = aCenterXY[1] + aVec[0] * sinA + aVec[1] * cosA;
268 myStorage->updateParameter(aTarget[0]);
269 myStorage->updateParameter(aTarget[1]);
271 anAngIt->valA = myAngle;
272 myStorage->updateConstraint(*anAngIt);
275 // update positions of centers of arcs for correct radius calculation
276 std::list<Slvs_Constraint> aRadii = myStorage->getConstraintsByType(SLVS_C_EQUAL_RADIUS);
277 std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt;
278 for (anAngIt = aRadii.begin(); anAngIt != aRadii.end(); anAngIt++) {
279 int aNbFound = 0; // number of arcs used in translation
280 for (aFeatIt = myFeatureMap.begin(); aFeatIt != myFeatureMap.end(); aFeatIt++)
281 if (aFeatIt->second == anAngIt->entityA || aFeatIt->second == anAngIt->entityB) {
282 if (aFeatIt->first->getKind() == SketchPlugin_Arc::ID())
289 // two arcs were found, update their centers
290 Slvs_Entity anArcA = myStorage->getEntity(anAngIt->entityA);
291 Slvs_Entity anArcB = myStorage->getEntity(anAngIt->entityB);
292 if (myStorage->isPointFixed(anArcB.point[0], aFixed))
294 Slvs_Entity aCenterA = myStorage->getEntity(anArcA.point[0]);
295 Slvs_Entity aCenterB = myStorage->getEntity(anArcB.point[0]);
296 for (int i = 0; i < 2; i++) {
297 aVec[i] = myStorage->getParameter(aCenterA.param[i]).val - aCenterXY[i];
298 aTarget[i] = myStorage->getParameter(aCenterB.param[i]);
300 aTarget[0].val = aCenterXY[0] + aVec[0] * cosA - aVec[1] * sinA;
301 aTarget[1].val = aCenterXY[1] + aVec[0] * sinA + aVec[1] * cosA;
302 myStorage->updateParameter(aTarget[0]);
303 myStorage->updateParameter(aTarget[1]);