1 #include <SketchSolver_ConstraintMirror.h>
2 #include <SketchSolver_Group.h>
3 #include <SketchSolver_Error.h>
5 #include <ModelAPI_AttributeDouble.h>
6 #include <ModelAPI_AttributeRefAttr.h>
7 #include <ModelAPI_AttributeRefList.h>
8 #include <ModelAPI_ResultConstruction.h>
10 #include <GeomAPI_Dir2d.h>
11 #include <GeomAPI_XY.h>
14 void SketchSolver_ConstraintMirror::getAttributes(
15 Slvs_Entity& theMirrorLine,
16 std::vector<Slvs_Entity>& theBaseEntities,
17 std::vector<Slvs_Entity>& theMirrorEntities)
19 DataPtr aData = myBaseConstraint->data();
20 AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
21 myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
22 if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) {
23 myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
26 int aType = SLVS_E_UNKNOWN; // type of created entity
27 Slvs_hEntity anEntity = myGroup->getAttributeId(aMirLineAttr);
28 if (anEntity == SLVS_E_UNKNOWN)
29 anEntity = changeEntity(aMirLineAttr, aType);
30 theMirrorLine = myStorage->getEntity(anEntity);
32 // Create SolveSpace entity for all features
33 AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
34 myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
35 AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
36 myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C()));
37 myNumberOfObjects = aMirroredRefList->size();
38 if (!aBaseRefList || !aMirroredRefList) {
39 myErrorMsg = SketchSolver_Error::INCORRECT_MIRROR_ATTRIBUTE();
43 std::list<ObjectPtr> aBaseList = aBaseRefList->list();
44 std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
47 ResultConstructionPtr aRC;
48 for (int i = 0; i < 2; i++) {
49 std::list<ObjectPtr>::iterator anIter = i == 0 ? aBaseList.begin() : aMirroredList.begin();
50 std::list<ObjectPtr>::iterator aEndIter = i == 0 ? aBaseList.end() : aMirroredList.end();
51 std::vector<Slvs_Entity>* aList = i == 0 ? &theBaseEntities : & theMirrorEntities;
52 for ( ; anIter != aEndIter; anIter++) {
53 aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anIter);
54 aFeature = aRC ? aRC->document()->feature(aRC) :
55 std::dynamic_pointer_cast<ModelAPI_Feature>(*anIter);
59 anEntity = changeEntity(aFeature, aType);
60 aList->push_back(myStorage->getEntity(anEntity));
64 if (theBaseEntities.size() > theMirrorEntities.size())
65 myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
68 void SketchSolver_ConstraintMirror::process()
71 if (!myBaseConstraint || !myStorage || myGroup == 0) {
72 /// TODO: Put error message here
75 if (!mySlvsConstraints.empty()) // some data is changed, update constraint
76 update(myBaseConstraint);
78 Slvs_Entity aMirrorLine;
79 std::vector<Slvs_Entity> aBaseList;
80 std::vector<Slvs_Entity> aMirrorList;
81 getAttributes(aMirrorLine, aBaseList, aMirrorList);
82 if (!myErrorMsg.empty())
85 if (aBaseList.size() != aMirrorList.size()) {
86 myErrorMsg = SketchSolver_Error::INCORRECT_MIRROR_ATTRIBUTE();
90 Slvs_Constraint aConstraint;
91 // Get coordinates of mirror line points for speed up
93 for (int i = 0; i < 2; i++) {
94 Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]);
95 for (int j = 0; j < 2; j++)
96 aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val;
99 std::vector<Slvs_Entity>::iterator aBaseIter = aBaseList.begin();
100 std::vector<Slvs_Entity>::iterator aMirrorIter = aMirrorList.begin();
101 for (; aBaseIter != aBaseList.end(); aBaseIter++, aMirrorIter++) {
102 // Make aMirrorEnt parameters to be symmetric with aBaseEnt
103 makeMirrorEntity(*aBaseIter, *aMirrorIter, aStartEnd);
105 if (aBaseIter->type == SLVS_E_POINT_IN_2D) {
106 aConstraint = Slvs_MakeConstraint(
107 SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
108 0.0, aBaseIter->h, aMirrorIter->h, aMirrorLine.h, SLVS_E_UNKNOWN);
109 aConstraint.h = myStorage->addConstraint(aConstraint);
110 mySlvsConstraints.push_back(aConstraint.h);
111 } else if (aBaseIter->type == SLVS_E_LINE_SEGMENT) {
112 for (int i = 0; i < 2; i++) {
113 aConstraint = Slvs_MakeConstraint(
114 SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
115 aBaseIter->point[i], aMirrorIter->point[i], aMirrorLine.h, SLVS_E_UNKNOWN);
116 aConstraint.h = myStorage->addConstraint(aConstraint);
117 mySlvsConstraints.push_back(aConstraint.h);
119 } else if (aBaseIter->type == SLVS_E_CIRCLE) {
120 aConstraint = Slvs_MakeConstraint(
121 SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
122 aBaseIter->point[0], aMirrorIter->point[0], aMirrorLine.h, SLVS_E_UNKNOWN);
123 aConstraint.h = myStorage->addConstraint(aConstraint);
124 mySlvsConstraints.push_back(aConstraint.h);
125 // Additional constraint for equal radii
126 Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
127 SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_EQUAL_RADIUS, myGroup->getWorkplaneId(),
128 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseIter->h, aMirrorIter->h);
129 anEqRadConstr.h = myStorage->addConstraint(anEqRadConstr);
130 mySlvsConstraints.push_back(anEqRadConstr.h);
131 } else if (aBaseIter->type == SLVS_E_ARC_OF_CIRCLE) {
132 // Workaround to avoid problems in SolveSpace.
133 // The symmetry of two arcs will be done using symmetry of three points on these arcs:
134 // start point, end point, and any other point on the arc
135 Slvs_hEntity aBaseArcPoints[3] = {
139 Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
140 aMirrorIter->point[2],
141 aMirrorIter->point[1],
144 Slvs_Entity aBothArcs[2] = {*aBaseIter, *aMirrorIter};
145 Slvs_hEntity aBothMiddlePoints[2];
146 for (int i = 0; i < 2; i++) {
148 calculateMiddlePoint(aBothArcs[i], 0.5, x, y);
149 Slvs_Param aParamX = Slvs_MakeParam(SLVS_E_UNKNOWN, myGroup->getId(), x);
150 Slvs_Param aParamY = Slvs_MakeParam(SLVS_E_UNKNOWN, myGroup->getId(), y);
151 aParamX.h = myStorage->addParameter(aParamX);
152 aParamY.h = myStorage->addParameter(aParamY);
153 Slvs_Entity aPoint = Slvs_MakePoint2d(SLVS_E_UNKNOWN, myGroup->getId(),
154 myGroup->getWorkplaneId(), aParamX.h, aParamY.h);
155 aBothMiddlePoints[i] = myStorage->addEntity(aPoint);
156 // additional constraint point-on-curve
157 Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
158 SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_CIRCLE, myGroup->getWorkplaneId(),
159 0.0, aBothMiddlePoints[i], SLVS_E_UNKNOWN, aBothArcs[i].h, SLVS_E_UNKNOWN);
160 aPonCircConstr.h = myStorage->addConstraint(aPonCircConstr);
161 mySlvsConstraints.push_back(aPonCircConstr.h);
163 // additional constraint for the point to be in the middle of a base arc
164 Slvs_Entity aLine1 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
165 myGroup->getWorkplaneId(), aBothArcs[i].point[1], aBothMiddlePoints[i]);
166 aLine1.h = myStorage->addEntity(aLine1);
167 Slvs_Entity aLine2 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
168 myGroup->getWorkplaneId(), aBothArcs[i].point[2], aBothMiddlePoints[i]);
169 aLine2.h = myStorage->addEntity(aLine2);
170 Slvs_Constraint aMiddleConstr = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
171 SLVS_C_EQUAL_LENGTH_LINES, myGroup->getWorkplaneId(),
172 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aLine1.h, aLine2.h);
173 aMiddleConstr.h = myStorage->addConstraint(aMiddleConstr);
174 mySlvsConstraints.push_back(aMiddleConstr.h);
178 aBaseArcPoints[2] = aBothMiddlePoints[0];
179 aMirrorArcPoints[2] = aBothMiddlePoints[1];
180 for (int ind = 0; ind < 3; ind++) {
181 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
182 SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
183 aBaseArcPoints[ind], aMirrorArcPoints[ind], aMirrorLine.h, SLVS_E_UNKNOWN);
184 aConstraint.h = myStorage->addConstraint(aConstraint);
185 mySlvsConstraints.push_back(aConstraint.h);
190 // Set the mirror line unchanged during constraint recalculation
191 for (int i = 0; i < 2; i++) {
192 aConstraint = Slvs_MakeConstraint(
193 SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
194 aMirrorLine.point[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
195 aConstraint.h = myStorage->addConstraint(aConstraint);
196 mySlvsConstraints.push_back(aConstraint.h);
201 void SketchSolver_ConstraintMirror::update(ConstraintPtr theConstraint)
204 if (!theConstraint || theConstraint == myBaseConstraint) {
205 AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
206 myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C()));
207 if (aMirroredRefList->size() != myNumberOfObjects) {
208 remove(myBaseConstraint);
213 SketchSolver_Constraint::update();
216 bool SketchSolver_ConstraintMirror::remove(ConstraintPtr theConstraint)
219 if (theConstraint && theConstraint != myBaseConstraint)
221 bool isFullyRemoved = true;
222 std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
223 for (; aCIter != mySlvsConstraints.end(); aCIter++)
224 isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
225 mySlvsConstraints.clear();
227 if (isFullyRemoved) {
228 myFeatureMap.clear();
229 myAttributeMap.clear();
232 cleanRemovedEntities();
236 void SketchSolver_ConstraintMirror::makeMirrorEntity(
237 const Slvs_Entity& theBase,
238 const Slvs_Entity& theMirror,
239 const double theMirrorLine[]) const
241 Slvs_hEntity aBasePoint[4];
242 Slvs_hEntity aMirrorPoint[4];
243 for (int i = 0; i < 4; i++) {
244 aBasePoint[i] = theBase.point[i];
245 aMirrorPoint[i] = theMirror.point[i];
247 if (theBase.type == SLVS_E_ARC_OF_CIRCLE) {
248 Slvs_hEntity aTmp = aMirrorPoint[2];
249 aMirrorPoint[2] = aMirrorPoint[1];
250 aMirrorPoint[1] = aTmp;
252 if (theBase.type == SLVS_E_POINT_IN_2D || theBase.type == SLVS_E_POINT_IN_3D) {
253 aBasePoint[0] = theBase.h;
254 aMirrorPoint[0] = theMirror.h;
257 // Mirror line parameters
258 std::shared_ptr<GeomAPI_XY> aLinePoints[2];
259 for (int i = 0; i < 2; i++)
260 aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
261 new GeomAPI_XY(theMirrorLine[2*i], theMirrorLine[2*i+1]));
262 // direction of a mirror line
263 std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
264 new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
265 // orthogonal direction
266 aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
268 for (int i = 0; i < 4; i++) {
269 if (aBasePoint[i] == SLVS_E_UNKNOWN || aMirrorPoint[i] == SLVS_E_UNKNOWN)
271 Slvs_Entity aPointEnt = myStorage->getEntity(aBasePoint[i]);
272 double aBaseX = myStorage->getParameter(aPointEnt.param[0]).val;
273 double aBaseY = myStorage->getParameter(aPointEnt.param[1]).val;
274 std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(aBaseX, aBaseY));
276 std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
277 new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
278 double aDist = aVec->dot(aDir->xy());
279 aPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
281 Slvs_Entity aMirrorEnt = myStorage->getEntity(aMirrorPoint[i]);
282 Slvs_Param aParam = Slvs_MakeParam(aMirrorEnt.param[0], myGroup->getId(), aPoint->x());
283 myStorage->updateParameter(aParam);
284 aParam = Slvs_MakeParam(aMirrorEnt.param[1], myGroup->getId(), aPoint->y());
285 myStorage->updateParameter(aParam);
289 void SketchSolver_ConstraintMirror::adjustConstraint()
291 // Search mirror between middle points on the arcs and recompute their coordinates
292 std::list<Slvs_Constraint> aPonCirc = myStorage->getConstraintsByType(SLVS_C_PT_ON_CIRCLE);
293 if (aPonCirc.empty())
296 AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
297 myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
298 if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) {
299 myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
302 ResultConstructionPtr aRC =
303 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aMirLineAttr->object());
304 FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
305 std::dynamic_pointer_cast<ModelAPI_Feature>(aMirLineAttr->object());
306 std::map<FeaturePtr, Slvs_hEntity>::iterator aMirLineIter = myFeatureMap.find(aFeature);
307 if (aMirLineIter == myFeatureMap.end())
309 Slvs_Entity aMirrorLine = myStorage->getEntity(aMirLineIter->second);
312 for (int i = 0; i < 2; i++) {
313 Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]);
314 for (int j = 0; j < 2; j++)
315 aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val;
318 Slvs_Constraint aMirror;
319 std::vector<Slvs_hConstraint>::iterator aConstrIter = mySlvsConstraints.begin();
320 for (; aConstrIter != mySlvsConstraints.end(); aConstrIter++) {
321 aMirror = myStorage->getConstraint(*aConstrIter);
322 if (aMirror.type != SLVS_C_SYMMETRIC_LINE)
324 Slvs_Constraint aPonCircA, aPonCircB;
325 aPonCircA.h = SLVS_E_UNKNOWN;
326 aPonCircB.h = SLVS_E_UNKNOWN;
327 std::list<Slvs_Constraint>::iterator aPtIter = aPonCirc.begin();
328 for (; aPtIter != aPonCirc.end(); aPtIter++) {
329 if (aMirror.ptA == aPtIter->ptA)
330 aPonCircA = *aPtIter;
331 if (aMirror.ptB == aPtIter->ptA)
332 aPonCircB = *aPtIter;
334 if (aPonCircA.h == SLVS_E_UNKNOWN || aPonCircB.h == SLVS_E_UNKNOWN)
337 bool aNeedToResolve = myStorage->isNeedToResolve();
338 // Calculate middle point for base arc and mirrored point on mirror arc
339 Slvs_Entity aBaseArc = myStorage->getEntity(aPonCircA.entityA);
340 Slvs_Entity aBasePoint = myStorage->getEntity(aPonCircA.ptA);
341 Slvs_Param aParamX = myStorage->getParameter(aBasePoint.param[0]);
342 Slvs_Param aParamY = myStorage->getParameter(aBasePoint.param[1]);
343 calculateMiddlePoint(aBaseArc, 0.5, aParamX.val, aParamY.val);
344 myStorage->updateParameter(aParamX);
345 myStorage->updateParameter(aParamY);
346 Slvs_Entity aMirrorArc = myStorage->getEntity(aPonCircB.entityA);
347 Slvs_Entity aMirrorPoint = myStorage->getEntity(aPonCircB.ptA);
348 aParamX = myStorage->getParameter(aMirrorPoint.param[0]);
349 aParamY = myStorage->getParameter(aMirrorPoint.param[1]);
350 calculateMiddlePoint(aMirrorArc, 0.5, aParamX.val, aParamY.val);
351 myStorage->updateParameter(aParamX);
352 myStorage->updateParameter(aParamY);
353 // To avoid looped recalculations of sketch
354 myStorage->setNeedToResolve(aNeedToResolve);