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