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