Salome HOME
Add tools
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintCoincidence.cpp
1 #include <SketchSolver_ConstraintCoincidence.h>
2 #include <SketchSolver_Error.h>
3 #include <SketchSolver_Group.h>
4
5 #include <SketchPlugin_Point.h>
6 #include <GeomDataAPI_Point2D.h>
7
8 #include <map>
9
10 void SketchSolver_ConstraintCoincidence::getAttributes(
11     double& theValue,
12     std::vector<Slvs_hEntity>& theAttributes)
13 {
14   SketchSolver_Constraint::getAttributes(theValue, theAttributes);
15   if (!myErrorMsg.empty() || theAttributes[0] == SLVS_E_UNKNOWN)
16     return;
17
18   if (theAttributes[1] != SLVS_E_UNKNOWN) {
19     myType = SLVS_C_POINTS_COINCIDENT;
20
21     // set coordinates of slave (second) point equal to the master (first) point
22     Slvs_Entity aFirst  = myStorage->getEntity(theAttributes[0]);
23     Slvs_Entity aSecond = myStorage->getEntity(theAttributes[1]);
24     for (int i = 0; i < 4; i++)
25       if (aFirst.param[i] != SLVS_E_UNKNOWN && aSecond.param[i] != SLVS_E_UNKNOWN) {
26         Slvs_Param aPar1 = myStorage->getParameter(aFirst.param[i]);
27         Slvs_Param aPar2 = myStorage->getParameter(aSecond.param[i]);
28         aPar2.val = aPar1.val;
29         myStorage->updateParameter(aPar2);
30       }
31   }
32   else if (theAttributes[2] != SLVS_E_UNKNOWN) {
33     // check the type of entity (line or circle)
34     Slvs_Entity anEnt = myStorage->getEntity(theAttributes[2]);
35     if (anEnt.type == SLVS_E_LINE_SEGMENT)
36       myType = SLVS_C_PT_ON_LINE;
37     else if (anEnt.type == SLVS_E_CIRCLE || anEnt.type == SLVS_E_ARC_OF_CIRCLE)
38       myType = SLVS_C_PT_ON_CIRCLE;
39     else
40       myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
41   } else
42     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
43 }
44
45
46 bool SketchSolver_ConstraintCoincidence::hasConstraint(ConstraintPtr theConstraint) const
47 {
48   if (myBaseConstraint == theConstraint)
49     return true;
50   return myExtraCoincidence.find(theConstraint) != myExtraCoincidence.end();
51 }
52
53 std::list<ConstraintPtr> SketchSolver_ConstraintCoincidence::constraints() const
54 {
55   std::list<ConstraintPtr> aConstraints;
56   aConstraints.push_back(myBaseConstraint);
57   std::map<ConstraintPtr, Slvs_hConstraint>::const_iterator anIt = myExtraCoincidence.begin();
58   for (; anIt != myExtraCoincidence.end(); anIt++)
59     aConstraints.push_back(anIt->first);
60   return aConstraints;
61 }
62
63 bool SketchSolver_ConstraintCoincidence::isCoincide(
64     std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const
65 {
66   std::set<AttributePtr>::const_iterator anAttrIter = theConstraint->myCoincidentPoints.begin();
67   for (; anAttrIter != theConstraint->myCoincidentPoints.end(); anAttrIter++)
68     if (myCoincidentPoints.find(*anAttrIter) != myCoincidentPoints.end())
69       return true;
70   return false;
71 }
72
73 void SketchSolver_ConstraintCoincidence::attach(
74     std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint)
75 {
76   cleanErrorMsg();
77   // Remove constraints from theConstraint
78   std::vector<Slvs_hConstraint>::iterator aCIter = theConstraint->mySlvsConstraints.begin();
79   for (; aCIter != theConstraint->mySlvsConstraints.end(); aCIter++)
80     theConstraint->myStorage->removeConstraint(*aCIter);
81
82   if (myStorage == theConstraint->myStorage) {
83     // Clean removed items
84     std::set<Slvs_hParam> aRemParams;
85     std::set<Slvs_hEntity> aRemEnts;
86     std::set<Slvs_hConstraint> aRemConstr;
87     theConstraint->myStorage->getRemoved(aRemParams, aRemEnts, aRemConstr);
88
89     if (!aRemEnts.empty()) {
90       std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = theConstraint->myFeatureMap.begin();
91       while (aFeatIt != theConstraint->myFeatureMap.end()) {
92         if (aRemEnts.find(aFeatIt->second) != aRemEnts.end()) {
93           // remove feature
94           std::map<FeaturePtr, Slvs_hEntity>::iterator aRemoveIt = aFeatIt++;
95           theConstraint->myFeatureMap.erase(aRemoveIt);
96         } else
97           ++aFeatIt;
98       }
99       std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIt = theConstraint->myAttributeMap.begin();
100       while (anAttrIt != theConstraint->myAttributeMap.end()) {
101         if (aRemEnts.find(anAttrIt->second) != aRemEnts.end()) {
102           // remove attribute
103           std::map<AttributePtr, Slvs_hEntity>::iterator aRemoveIt = anAttrIt++;
104           theConstraint->myAttributeMap.erase(aRemoveIt);
105         } else
106           ++anAttrIt;
107       }
108     }
109   }
110
111   // Copy data.
112   addConstraint(theConstraint->myBaseConstraint);
113   std::map<ConstraintPtr, Slvs_hConstraint>::iterator aConstrIter =
114       theConstraint->myExtraCoincidence.begin();
115   for (; aConstrIter != theConstraint->myExtraCoincidence.end(); aConstrIter++)
116     addConstraint(aConstrIter->first);
117   // Clear the lists to not remove the entities on destruction
118   theConstraint->mySlvsConstraints.clear();
119   theConstraint->myFeatureMap.clear();
120   theConstraint->myAttributeMap.clear();
121 }
122
123 Slvs_hConstraint SketchSolver_ConstraintCoincidence::addConstraint(
124     Slvs_hEntity thePoint1, Slvs_hEntity thePoint2)
125 {
126   if (thePoint1 == thePoint2)
127     return SLVS_E_UNKNOWN;
128
129   bool hasDuplicated = myStorage->hasDuplicatedConstraint();
130   Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
131       SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(), 0.0, thePoint1, thePoint2, 
132       SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
133   Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
134   if (!hasDuplicated && myStorage->hasDuplicatedConstraint()) {
135     // the duplicated constraint appears
136     myStorage->removeConstraint(aNewID);
137     return SLVS_E_UNKNOWN;
138   }
139   mySlvsConstraints.push_back(aNewID);
140   return aNewID;
141 }
142
143 Slvs_hConstraint SketchSolver_ConstraintCoincidence::addPointOnEntity(
144     Slvs_hEntity thePoint, Slvs_hEntity theEntity)
145 {
146   // Check the point is not coincident with boundaries of the entity
147   Slvs_Entity anEnt = myStorage->getEntity(theEntity);
148   int aPos = anEnt.type == SLVS_E_LINE_SEGMENT ? 0 : 1;
149   for (; anEnt.point[aPos] != SLVS_E_UNKNOWN; aPos++)
150     if (anEnt.point[aPos] == thePoint ||
151         myStorage->isCoincident(anEnt.point[aPos], thePoint))
152       return SLVS_E_UNKNOWN;
153
154   bool hasDuplicated = myStorage->hasDuplicatedConstraint();
155   Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
156   Slvs_hConstraint aType = anEnt.type == SLVS_E_LINE_SEGMENT ?
157       SLVS_C_PT_ON_LINE : SLVS_C_PT_ON_CIRCLE;
158   Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
159       aType, myGroup->getWorkplaneId(), 0.0, aBaseCoincidence.ptA, SLVS_E_UNKNOWN,
160       theEntity, SLVS_E_UNKNOWN);
161   Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
162   if (!hasDuplicated && myStorage->hasDuplicatedConstraint()) {
163     // the duplicated constraint appears
164     myStorage->removeConstraint(aNewID);
165     return SLVS_E_UNKNOWN;
166   }
167   mySlvsConstraints.push_back(aNewID);
168   return aNewID;
169 }
170
171 void SketchSolver_ConstraintCoincidence::addConstraint(ConstraintPtr theConstraint)
172 {
173   if (mySlvsConstraints.empty()) {
174     // This constraint is empty, rebuild it from scratch
175     myBaseConstraint = theConstraint;
176     process();
177     return;
178   }
179
180   std::list<AttributePtr> anAttrList =
181       theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
182   std::list<AttributePtr>::iterator anIter = anAttrList.begin();
183   std::vector<Slvs_hEntity> aPoints;
184   Slvs_hEntity anEntity = SLVS_E_UNKNOWN;
185   int anEntType;
186   for (; anIter != anAttrList.end(); anIter++) {
187     Slvs_hEntity aPointID = SLVS_E_UNKNOWN;
188     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
189     if (!aRefAttr)
190       continue;
191
192     AttributePtr aPointAttr;
193     if (aRefAttr->isObject()) {
194       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
195       std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFeatFound = 
196           myFeatureMap.find(aFeature);
197       if (aFeatFound != myFeatureMap.end())
198         anEntity = aFeatFound->second;
199       else {
200         anEntity = myGroup->getFeatureId(aFeature);
201         if (anEntity == SLVS_E_UNKNOWN)
202           anEntity = changeEntity(aFeature, anEntType);
203         else {
204           myFeatureMap[aFeature] = anEntity;
205           // Obtain relations between attributes of the feature and SolveSpace entities
206           std::list<AttributePtr> anAttrList =
207               aFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
208           std::list<AttributePtr>::iterator anIt = anAttrList.begin();
209           for (; anIt != anAttrList.end(); ++anIt) {
210             Slvs_hEntity anAttrID = myGroup->getAttributeId(*anIt);
211             if (anAttrID != SLVS_E_UNKNOWN)
212               myAttributeMap[*anIt] = anAttrID;
213           }
214         }
215       }
216       // If the feature is a point, add it to the list of coincident points
217       if (aFeature->getKind() == SketchPlugin_Point::ID()) {
218         aPointID = anEntity;
219         anEntity = SLVS_E_UNKNOWN;
220         aPointAttr = aFeature->attribute(SketchPlugin_Point::COORD_ID());
221       }
222     } else {
223       aPointAttr = aRefAttr->attr();
224       std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrFound =
225           myAttributeMap.find(aPointAttr);
226       if (anAttrFound != myAttributeMap.end())
227         aPointID = anAttrFound->second;
228       else {
229         aPointID = myGroup->getAttributeId(aPointAttr);
230         if (aPointID == SLVS_E_UNKNOWN)
231           aPointID = changeEntity(aPointAttr, anEntType);
232       }
233     }
234
235     if (aPointAttr) { // the point is found
236       aPoints.push_back(aPointID);
237       myCoincidentPoints.insert(aPointAttr);
238       myAttributeMap[aPointAttr] = aPointID;
239     }
240   }
241
242   Slvs_hConstraint aNewConstr = SLVS_E_UNKNOWN;
243   if (anEntity != SLVS_E_UNKNOWN)
244     aNewConstr = addPointOnEntity(aPoints.front(), anEntity);
245   else { // coincidence between two points
246     Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
247     std::vector<Slvs_hEntity>::const_iterator aPtIter = aPoints.begin();
248     for (; aPtIter != aPoints.end(); aPtIter++) {
249       Slvs_hConstraint aC = addConstraint(aBaseCoincidence.ptA, *aPtIter);
250       if (aC != SLVS_E_UNKNOWN)
251         aNewConstr = aC;
252     }
253   }
254   myExtraCoincidence[theConstraint] = aNewConstr;
255 }
256
257 void SketchSolver_ConstraintCoincidence::process()
258 {
259   SketchSolver_Constraint::process();
260
261   // Fill the list of coincident points
262   std::list<AttributePtr> anAttrList =
263       myBaseConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
264   std::list<AttributePtr>::iterator anIt = anAttrList.begin();
265   for (; anIt != anAttrList.end(); anIt++) {
266     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
267     if (!aRefAttr || aRefAttr->isObject())
268       continue;
269     myCoincidentPoints.insert(aRefAttr->attr());
270   }
271 }
272
273 bool SketchSolver_ConstraintCoincidence::remove(ConstraintPtr theConstraint)
274 {
275   cleanErrorMsg();
276   if (mySlvsConstraints.empty())
277     return true;
278   ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
279   int aPos = -1; // position of constraint in the list (-1 for base constraint)
280   std::map<ConstraintPtr, Slvs_hConstraint>::iterator anExtraIt;
281   if (aConstraint != myBaseConstraint) {
282     anExtraIt = myExtraCoincidence.find(aConstraint);
283     if (anExtraIt == myExtraCoincidence.end())
284       return false; // there is no constraint, which is specified to remove
285     else {
286       bool isEmpty = anExtraIt->second == SLVS_E_UNKNOWN;
287       if (!isEmpty) {
288         isEmpty = true;
289         for (aPos = 0; aPos < (int)mySlvsConstraints.size(); aPos++)
290           if (mySlvsConstraints[aPos] == anExtraIt->second) {
291             isEmpty = false;
292             break;
293           }
294         aPos -= 1;
295       }
296       myExtraCoincidence.erase(anExtraIt);
297       if (isEmpty)
298         return false;
299     }
300   }
301
302   bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints[aPos+1]);
303   mySlvsConstraints.erase(mySlvsConstraints.begin() + (1+aPos));
304   if (aPos < 0 && !myExtraCoincidence.empty()) {
305     anExtraIt = myExtraCoincidence.begin();
306     // Remove invalid constraints
307     while (anExtraIt != myExtraCoincidence.end()) {
308       if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) {
309         std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
310         if (aTempIt->first != SLVS_E_UNKNOWN) {
311           myStorage->removeConstraint(aTempIt->second);
312           std::vector<Slvs_hConstraint>::iterator anIt = mySlvsConstraints.begin();
313           for (; anIt != mySlvsConstraints.end(); anIt++)
314             if (*anIt == aTempIt->second) {
315               mySlvsConstraints.erase(anIt);
316               break;
317             }
318         }
319         myExtraCoincidence.erase(aTempIt);
320         continue;
321       }
322       anExtraIt++;
323     }
324     // Find first non-extra conststraint
325     anExtraIt = myExtraCoincidence.begin();
326     while (anExtraIt != myExtraCoincidence.end() && anExtraIt->second == SLVS_E_UNKNOWN)
327       anExtraIt++;
328     if (anExtraIt != myExtraCoincidence.end()) {
329       // Need to specify another base coincidence constraint
330       myBaseConstraint = anExtraIt->first;
331       myExtraCoincidence.erase(anExtraIt);
332       if (mySlvsConstraints.empty()) {
333         std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
334         Slvs_Constraint aBase = myStorage->getConstraint(*aCIter);
335         for (++aCIter; aCIter != mySlvsConstraints.end(); aCIter++) {
336           Slvs_Constraint aConstr = myStorage->getConstraint(*aCIter);
337           aConstr.ptA = aBase.ptA;
338           myStorage->updateConstraint(aConstr);
339         }
340       }
341     }
342   }
343   // Clear removed attributes
344   std::set<Slvs_hParam> aParamRemoved;
345   std::set<Slvs_hEntity> anEntRemoved;
346   std::set<Slvs_hConstraint> aConstrRemoved;
347   myStorage->getRemoved(aParamRemoved, anEntRemoved, aConstrRemoved);
348   std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
349   while (anAttrIter != myAttributeMap.end()) {
350     if (anEntRemoved.find(anAttrIter->second) != anEntRemoved.end()) {
351       std::map<AttributePtr, Slvs_hEntity>::iterator aTempIt = anAttrIter++;
352       myCoincidentPoints.erase(aTempIt->first);
353       myAttributeMap.erase(aTempIt);
354       continue;
355     }
356     anAttrIter++;
357   }
358
359   // Go through remaining extra coincidence and try to add or remove them
360   anExtraIt = myExtraCoincidence.begin();
361   while (anExtraIt != myExtraCoincidence.end()) {
362     if (anExtraIt->first == SLVS_E_UNKNOWN) {
363       if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) {
364         std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
365         myExtraCoincidence.erase(aTempIt);
366         continue;
367       }
368       if (mySlvsConstraints.empty()) {
369         myBaseConstraint = anExtraIt->first;
370         std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
371         myExtraCoincidence.erase(aTempIt);
372         process();
373         continue;
374       } else
375         addConstraint(anExtraIt->first);
376     }
377     anExtraIt++;
378   }
379   return mySlvsConstraints.empty();
380 }
381