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