Salome HOME
Update coincidence constraints
[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   // Multi-coincidence allowed for two points only
52   if (getType() != theConstraint->getType() || getType() != SLVS_C_POINTS_COINCIDENT)
53     return false;
54
55   std::set<AttributePtr>::const_iterator anAttrIter = theConstraint->myCoincidentPoints.begin();
56   for (; anAttrIter != theConstraint->myCoincidentPoints.end(); anAttrIter++)
57     if (myCoincidentPoints.find(*anAttrIter) != myCoincidentPoints.end())
58       return true;
59   return false;
60 }
61
62 void SketchSolver_ConstraintCoincidence::attach(
63     std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint)
64 {
65   cleanErrorMsg();
66   // Remove constraints from theConstraint
67   std::vector<Slvs_hConstraint>::iterator aCIter = theConstraint->mySlvsConstraints.begin();
68   for (; aCIter != theConstraint->mySlvsConstraints.end(); aCIter++)
69     theConstraint->myStorage->removeConstraint(*aCIter);
70
71   if (myStorage == theConstraint->myStorage) {
72     // Clean removed items
73     std::set<Slvs_hParam> aRemParams;
74     std::set<Slvs_hEntity> aRemEnts;
75     std::set<Slvs_hConstraint> aRemConstr;
76     theConstraint->myStorage->getRemoved(aRemParams, aRemEnts, aRemConstr);
77
78     if (!aRemEnts.empty()) {
79       std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = theConstraint->myFeatureMap.begin();
80       while (aFeatIt != theConstraint->myFeatureMap.end()) {
81         if (aRemEnts.find(aFeatIt->second) != aRemEnts.end()) {
82           // remove feature
83           std::map<FeaturePtr, Slvs_hEntity>::iterator aRemoveIt = aFeatIt++;
84           theConstraint->myFeatureMap.erase(aRemoveIt);
85         } else
86           ++aFeatIt;
87       }
88       std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIt = theConstraint->myAttributeMap.begin();
89       while (anAttrIt != theConstraint->myAttributeMap.end()) {
90         if (aRemEnts.find(anAttrIt->second) != aRemEnts.end()) {
91           // remove attribute
92           std::map<AttributePtr, Slvs_hEntity>::iterator aRemoveIt = anAttrIt++;
93           theConstraint->myAttributeMap.erase(aRemoveIt);
94         } else
95           ++anAttrIt;
96       }
97     }
98   }
99
100   // Copy data.
101   addConstraint(theConstraint->myBaseConstraint);
102   std::map<ConstraintPtr, Slvs_hConstraint>::iterator aConstrIter =
103       theConstraint->myExtraCoincidence.begin();
104   for (; aConstrIter != theConstraint->myExtraCoincidence.end(); aConstrIter++)
105     addConstraint(aConstrIter->first);
106   // Clear the lists to not remove the entities on destruction
107   theConstraint->mySlvsConstraints.clear();
108   theConstraint->myFeatureMap.clear();
109   theConstraint->myAttributeMap.clear();
110 }
111
112 Slvs_hConstraint SketchSolver_ConstraintCoincidence::addConstraint(
113     Slvs_hEntity thePoint1, Slvs_hEntity thePoint2)
114 {
115   bool hasDuplicated = myStorage->hasDuplicatedConstraint();
116   Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
117       SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(), 0.0, thePoint1, thePoint2, 
118       SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
119   Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
120   if (!hasDuplicated && myStorage->hasDuplicatedConstraint()) {
121     // the duplicated constraint appears
122     myStorage->removeConstraint(aNewID);
123     return SLVS_E_UNKNOWN;
124   }
125   mySlvsConstraints.push_back(aNewID);
126   return aNewID;
127 }
128
129 void SketchSolver_ConstraintCoincidence::addConstraint(ConstraintPtr theConstraint)
130 {
131   std::list<AttributePtr> anAttrList =
132       theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
133   std::list<AttributePtr>::iterator anIter = anAttrList.begin();
134   std::vector<Slvs_hEntity> anEntities;
135   for (; anIter != anAttrList.end(); anIter++) {
136     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
137     if (!aRefAttr || aRefAttr->isObject() ||
138         myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end())
139       continue;
140     int aType;
141     Slvs_hEntity anEntityID = myGroup->getAttributeId(aRefAttr->attr());
142     if (anEntityID == SLVS_E_UNKNOWN)
143       anEntityID = changeEntity(aRefAttr->attr(), aType);
144     anEntities.push_back(anEntityID);
145     myCoincidentPoints.insert(aRefAttr->attr());
146   }
147
148   Slvs_hConstraint aNewConstr = SLVS_E_UNKNOWN;
149   std::vector<Slvs_hEntity>::iterator anEntIter = anEntities.begin();
150   if (mySlvsConstraints.empty()) {
151     aNewConstr = addConstraint(*anEntIter, *(anEntIter + 1));
152     anEntIter += 2;
153   }
154   Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
155   for (; anEntIter != anEntities.end(); anEntIter++)
156     aNewConstr = addConstraint(aBaseCoincidence.ptA, *anEntIter);
157   myExtraCoincidence[theConstraint] = aNewConstr;
158 }
159
160 void SketchSolver_ConstraintCoincidence::process()
161 {
162   SketchSolver_Constraint::process();
163
164   // Fill the list of coincident points
165   std::list<AttributePtr> anAttrList =
166       myBaseConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
167   std::list<AttributePtr>::iterator anIt = anAttrList.begin();
168   for (; anIt != anAttrList.end(); anIt++) {
169     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
170     if (!aRefAttr || aRefAttr->isObject())
171       continue;
172     myCoincidentPoints.insert(aRefAttr->attr());
173   }
174 }
175
176 bool SketchSolver_ConstraintCoincidence::remove(ConstraintPtr theConstraint)
177 {
178   cleanErrorMsg();
179   if (mySlvsConstraints.empty())
180     return true;
181   ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
182   int aPos = -1; // position of constraint in the list (-1 for base constraint)
183   std::map<ConstraintPtr, Slvs_hConstraint>::iterator anExtraIt;
184   if (aConstraint != myBaseConstraint) {
185     anExtraIt = myExtraCoincidence.find(aConstraint);
186     if (anExtraIt == myExtraCoincidence.end())
187       return false; // there is no constraint, which is specified to remove
188     else {
189       bool isEmpty = anExtraIt->second == SLVS_E_UNKNOWN;
190       if (!isEmpty) {
191         isEmpty = true;
192         for (aPos = 0; aPos < (int)mySlvsConstraints.size(); aPos++)
193           if (mySlvsConstraints[aPos] == anExtraIt->second) {
194             isEmpty = false;
195             break;
196           }
197         aPos -= 1;
198       }
199       myExtraCoincidence.erase(anExtraIt);
200       if (isEmpty)
201         return false;
202     }
203   }
204
205   bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints[aPos+1]);
206   mySlvsConstraints.erase(mySlvsConstraints.begin() + (1+aPos));
207   if (aPos < 0 && !myExtraCoincidence.empty()) {
208     anExtraIt = myExtraCoincidence.begin();
209     // Remove invalid constraints
210     while (anExtraIt != myExtraCoincidence.end()) {
211       if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) {
212         std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
213         if (aTempIt->first != SLVS_E_UNKNOWN) {
214           myStorage->removeConstraint(aTempIt->second);
215           std::vector<Slvs_hConstraint>::iterator anIt = mySlvsConstraints.begin();
216           for (; anIt != mySlvsConstraints.end(); anIt++)
217             if (*anIt == aTempIt->second) {
218               mySlvsConstraints.erase(anIt);
219               break;
220             }
221         }
222         myExtraCoincidence.erase(aTempIt);
223         continue;
224       }
225       anExtraIt++;
226     }
227     // Find first non-extra conststraint
228     anExtraIt = myExtraCoincidence.begin();
229     while (anExtraIt != myExtraCoincidence.end() && anExtraIt->second == SLVS_E_UNKNOWN)
230       anExtraIt++;
231     if (anExtraIt != myExtraCoincidence.end()) {
232       // Need to specify another base coincidence constraint
233       myBaseConstraint = anExtraIt->first;
234       myExtraCoincidence.erase(anExtraIt);
235       if (mySlvsConstraints.empty()) {
236         std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
237         Slvs_Constraint aBase = myStorage->getConstraint(*aCIter);
238         for (++aCIter; aCIter != mySlvsConstraints.end(); aCIter++) {
239           Slvs_Constraint aConstr = myStorage->getConstraint(*aCIter);
240           aConstr.ptA = aBase.ptA;
241           myStorage->updateConstraint(aConstr);
242         }
243       }
244     }
245   }
246   // Clear removed attributes
247   std::set<Slvs_hParam> aParamRemoved;
248   std::set<Slvs_hEntity> anEntRemoved;
249   std::set<Slvs_hConstraint> aConstrRemoved;
250   myStorage->getRemoved(aParamRemoved, anEntRemoved, aConstrRemoved);
251   std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
252   while (anAttrIter != myAttributeMap.end()) {
253     if (anEntRemoved.find(anAttrIter->second) != anEntRemoved.end()) {
254       std::map<AttributePtr, Slvs_hEntity>::iterator aTempIt = anAttrIter++;
255       myCoincidentPoints.erase(aTempIt->first);
256       myAttributeMap.erase(aTempIt);
257       continue;
258     }
259     anAttrIter++;
260   }
261
262   // Go through remaining extra coincidence and try to add or remove them
263   anExtraIt = myExtraCoincidence.begin();
264   while (anExtraIt != myExtraCoincidence.end()) {
265     if (anExtraIt->first == SLVS_E_UNKNOWN) {
266       if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) {
267         std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
268         myExtraCoincidence.erase(aTempIt);
269         continue;
270       }
271       if (mySlvsConstraints.empty()) {
272         myBaseConstraint = anExtraIt->first;
273         std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
274         myExtraCoincidence.erase(aTempIt);
275         process();
276         continue;
277       } else
278         addConstraint(anExtraIt->first);
279     }
280     anExtraIt++;
281   }
282   return mySlvsConstraints.empty();
283 }
284