1 #include <SketchSolver_ConstraintCoincidence.h>
2 #include <SketchSolver_Error.h>
3 #include <SketchSolver_Group.h>
5 #include <SketchPlugin_Point.h>
9 void SketchSolver_ConstraintCoincidence::getAttributes(
11 std::vector<Slvs_hEntity>& theAttributes)
13 SketchSolver_Constraint::getAttributes(theValue, theAttributes);
14 if (!myErrorMsg.empty() || theAttributes[0] == SLVS_E_UNKNOWN)
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;
27 myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
29 myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
33 bool SketchSolver_ConstraintCoincidence::hasConstraint(ConstraintPtr theConstraint) const
35 if (myBaseConstraint == theConstraint)
37 return myExtraCoincidence.find(theConstraint) != myExtraCoincidence.end();
40 std::list<ConstraintPtr> SketchSolver_ConstraintCoincidence::constraints() const
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);
50 bool SketchSolver_ConstraintCoincidence::isCoincide(
51 std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const
53 std::set<AttributePtr>::const_iterator anAttrIter = theConstraint->myCoincidentPoints.begin();
54 for (; anAttrIter != theConstraint->myCoincidentPoints.end(); anAttrIter++)
55 if (myCoincidentPoints.find(*anAttrIter) != myCoincidentPoints.end())
60 void SketchSolver_ConstraintCoincidence::attach(
61 std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint)
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);
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);
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()) {
81 std::map<FeaturePtr, Slvs_hEntity>::iterator aRemoveIt = aFeatIt++;
82 theConstraint->myFeatureMap.erase(aRemoveIt);
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()) {
90 std::map<AttributePtr, Slvs_hEntity>::iterator aRemoveIt = anAttrIt++;
91 theConstraint->myAttributeMap.erase(aRemoveIt);
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();
110 Slvs_hConstraint SketchSolver_ConstraintCoincidence::addConstraint(
111 Slvs_hEntity thePoint1, Slvs_hEntity thePoint2)
113 if (thePoint1 == thePoint2)
114 return SLVS_E_UNKNOWN;
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;
126 mySlvsConstraints.push_back(aNewID);
130 Slvs_hConstraint SketchSolver_ConstraintCoincidence::addPointOnEntity(
131 Slvs_hEntity thePoint, Slvs_hEntity theEntity)
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;
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;
154 mySlvsConstraints.push_back(aNewID);
158 void SketchSolver_ConstraintCoincidence::addConstraint(ConstraintPtr theConstraint)
160 if (mySlvsConstraints.empty()) {
161 // This constraint is empty, rebuild it from scratch
162 myBaseConstraint = theConstraint;
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;
173 for (; anIter != anAttrList.end(); anIter++) {
174 Slvs_hEntity aPointID = SLVS_E_UNKNOWN;
175 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
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;
187 anEntity = myGroup->getFeatureId(aFeature);
188 if (anEntity == SLVS_E_UNKNOWN)
189 anEntity = changeEntity(aFeature, anEntType);
191 myFeatureMap[aFeature] = anEntity;
193 // If the feature is a point, add it to the list of coincident points
194 if (aFeature->getKind() == SketchPlugin_Point::ID()) {
196 anEntity = SLVS_E_UNKNOWN;
197 aPointAttr = aFeature->attribute(SketchPlugin_Point::COORD_ID());
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;
206 aPointID = myGroup->getAttributeId(aPointAttr);
207 if (aPointID == SLVS_E_UNKNOWN)
208 aPointID = changeEntity(aPointAttr, anEntType);
212 if (aPointAttr) { // the point is found
213 aPoints.push_back(aPointID);
214 myCoincidentPoints.insert(aPointAttr);
215 myAttributeMap[aPointAttr] = aPointID;
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)
231 myExtraCoincidence[theConstraint] = aNewConstr;
234 void SketchSolver_ConstraintCoincidence::process()
236 SketchSolver_Constraint::process();
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())
246 myCoincidentPoints.insert(aRefAttr->attr());
250 bool SketchSolver_ConstraintCoincidence::remove(ConstraintPtr theConstraint)
253 if (mySlvsConstraints.empty())
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
263 bool isEmpty = anExtraIt->second == SLVS_E_UNKNOWN;
266 for (aPos = 0; aPos < (int)mySlvsConstraints.size(); aPos++)
267 if (mySlvsConstraints[aPos] == anExtraIt->second) {
273 myExtraCoincidence.erase(anExtraIt);
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);
296 myExtraCoincidence.erase(aTempIt);
301 // Find first non-extra conststraint
302 anExtraIt = myExtraCoincidence.begin();
303 while (anExtraIt != myExtraCoincidence.end() && anExtraIt->second == SLVS_E_UNKNOWN)
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);
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);
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);
345 if (mySlvsConstraints.empty()) {
346 myBaseConstraint = anExtraIt->first;
347 std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
348 myExtraCoincidence.erase(aTempIt);
352 addConstraint(anExtraIt->first);
356 return mySlvsConstraints.empty();