Salome HOME
Merge branch 'Dev_1.1.0' of newgeom:newgeom into Dev_1.1.0
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintMirror.cpp
1 #include <SketchSolver_ConstraintMirror.h>
2 #include <SketchSolver_Group.h>
3 #include <SketchSolver_Error.h>
4
5 #include <ModelAPI_AttributeDouble.h>
6 #include <ModelAPI_AttributeRefAttr.h>
7 #include <ModelAPI_AttributeRefList.h>
8 #include <ModelAPI_ResultConstruction.h>
9
10 #include <GeomAPI_Dir2d.h>
11 #include <GeomAPI_XY.h>
12
13
14 void SketchSolver_ConstraintMirror::getAttributes(
15     Slvs_Entity& theMirrorLine,
16     std::vector<Slvs_Entity>& theBaseEntities,
17     std::vector<Slvs_Entity>& theMirrorEntities)
18 {
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();
24     return;
25   }
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);
31
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();
40     return;
41   }
42
43   std::list<ObjectPtr> aBaseList = aBaseRefList->list();
44   std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
45
46   FeaturePtr aFeature;
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);
56       if (!aFeature)
57         continue;
58
59       anEntity = changeEntity(aFeature, aType);
60       aList->push_back(myStorage->getEntity(anEntity));
61     }
62   }
63
64   if (theBaseEntities.size() > theMirrorEntities.size())
65     myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
66 }
67
68 void SketchSolver_ConstraintMirror::process()
69 {
70   cleanErrorMsg();
71   if (!myBaseConstraint || !myStorage || myGroup == 0) {
72     /// TODO: Put error message here
73     return;
74   }
75   if (!mySlvsConstraints.empty()) // some data is changed, update constraint
76     update(myBaseConstraint);
77
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())
83     return;
84
85   if (aBaseList.size() != aMirrorList.size()) {
86     myErrorMsg = SketchSolver_Error::INCORRECT_MIRROR_ATTRIBUTE();
87     return;
88   }
89
90   Slvs_Constraint aConstraint;
91   // Get coordinates of mirror line points for speed up
92   double aStartEnd[4];
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;
97   }
98
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);
104
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);
118       }
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] = {
136           aBaseIter->point[1],
137           aBaseIter->point[2],
138           SLVS_E_UNKNOWN};
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],
142           SLVS_E_UNKNOWN};
143
144       Slvs_Entity aBothArcs[2] = {*aBaseIter, *aMirrorIter};
145       Slvs_hEntity aBothMiddlePoints[2];
146       for (int i = 0; i < 2; i++) {
147         double x, y;
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);
162         if (i == 0) {
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);
175         }
176       }
177
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);
186       }
187     }
188   }
189
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);
197   }
198 }
199
200
201 void SketchSolver_ConstraintMirror::update(ConstraintPtr theConstraint)
202 {
203   cleanErrorMsg();
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);
209       process();
210       return;
211     }
212   }
213   SketchSolver_Constraint::update();
214 }
215
216 bool SketchSolver_ConstraintMirror::remove(ConstraintPtr theConstraint)
217 {
218   cleanErrorMsg();
219   if (theConstraint && theConstraint != myBaseConstraint)
220     return false;
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();
226
227   if (isFullyRemoved) {
228     myFeatureMap.clear();
229     myAttributeMap.clear();
230     myValueMap.clear();
231   } else
232     cleanRemovedEntities();
233   return true;
234 }
235
236 void SketchSolver_ConstraintMirror::makeMirrorEntity(
237     const Slvs_Entity& theBase,
238     const Slvs_Entity& theMirror,
239     const double theMirrorLine[]) const
240 {
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];
246   }
247   if (theBase.type == SLVS_E_ARC_OF_CIRCLE) {
248     Slvs_hEntity aTmp = aMirrorPoint[2];
249     aMirrorPoint[2] = aMirrorPoint[1];
250     aMirrorPoint[1] = aTmp;
251   }
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;
255   }
256
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()));
267
268   for (int i = 0; i < 4; i++) {
269     if (aBasePoint[i] == SLVS_E_UNKNOWN || aMirrorPoint[i] == SLVS_E_UNKNOWN)
270       continue;
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));
275
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));
280
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);
286   }
287 }
288
289 void SketchSolver_ConstraintMirror::adjustConstraint()
290 {
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())
294     return;
295
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();
300     return;
301   }
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())
308     return;
309   Slvs_Entity aMirrorLine = myStorage->getEntity(aMirLineIter->second);
310
311   double aStartEnd[4];
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;
316   }
317
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)
323       continue;
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;
333     }
334     if (aPonCircA.h == SLVS_E_UNKNOWN || aPonCircB.h == SLVS_E_UNKNOWN)
335       continue;
336
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);
355   }
356 }