1 #include <SketchSolver_ConstraintCoincidence.h>
2 #include <SketchSolver_Error.h>
3 #include <SketchSolver_Group.h>
5 #include <SketchPlugin_Point.h>
6 #include <GeomDataAPI_Point2D.h>
10 void SketchSolver_ConstraintCoincidence::getAttributes(
12 std::vector<Slvs_hEntity>& theAttributes)
14 SketchSolver_Constraint::getAttributes(theValue, theAttributes);
15 if (!myErrorMsg.empty() || theAttributes[0] == SLVS_E_UNKNOWN)
18 if (theAttributes[1] != SLVS_E_UNKNOWN)
19 myType = SLVS_C_POINTS_COINCIDENT;
20 else if (theAttributes[2] != SLVS_E_UNKNOWN) {
21 // check the type of entity (line or circle)
22 Slvs_Entity anEnt = myStorage->getEntity(theAttributes[2]);
23 if (anEnt.type == SLVS_E_LINE_SEGMENT)
24 myType = SLVS_C_PT_ON_LINE;
25 else if (anEnt.type == SLVS_E_CIRCLE || anEnt.type == SLVS_E_ARC_OF_CIRCLE)
26 myType = SLVS_C_PT_ON_CIRCLE;
28 myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
30 myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
34 bool SketchSolver_ConstraintCoincidence::hasConstraint(ConstraintPtr theConstraint) const
36 if (myBaseConstraint == theConstraint)
38 return myExtraCoincidence.find(theConstraint) != myExtraCoincidence.end();
41 std::list<ConstraintPtr> SketchSolver_ConstraintCoincidence::constraints() const
43 std::list<ConstraintPtr> aConstraints;
44 aConstraints.push_back(myBaseConstraint);
45 std::map<ConstraintPtr, Slvs_hConstraint>::const_iterator anIt = myExtraCoincidence.begin();
46 for (; anIt != myExtraCoincidence.end(); anIt++)
47 aConstraints.push_back(anIt->first);
51 bool SketchSolver_ConstraintCoincidence::isCoincide(
52 std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const
54 std::set<AttributePtr>::const_iterator anAttrIter = theConstraint->myCoincidentPoints.begin();
55 for (; anAttrIter != theConstraint->myCoincidentPoints.end(); anAttrIter++)
56 if (myCoincidentPoints.find(*anAttrIter) != myCoincidentPoints.end())
61 void SketchSolver_ConstraintCoincidence::attach(
62 std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint)
65 // Remove constraints from theConstraint
66 std::vector<Slvs_hConstraint>::iterator aCIter = theConstraint->mySlvsConstraints.begin();
67 for (; aCIter != theConstraint->mySlvsConstraints.end(); aCIter++)
68 theConstraint->myStorage->removeConstraint(*aCIter);
70 if (myStorage == theConstraint->myStorage) {
71 // Clean removed items
72 std::set<Slvs_hParam> aRemParams;
73 std::set<Slvs_hEntity> aRemEnts;
74 std::set<Slvs_hConstraint> aRemConstr;
75 theConstraint->myStorage->getRemoved(aRemParams, aRemEnts, aRemConstr);
77 if (!aRemEnts.empty()) {
78 std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = theConstraint->myFeatureMap.begin();
79 while (aFeatIt != theConstraint->myFeatureMap.end()) {
80 if (aRemEnts.find(aFeatIt->second) != aRemEnts.end()) {
82 std::map<FeaturePtr, Slvs_hEntity>::iterator aRemoveIt = aFeatIt++;
83 theConstraint->myFeatureMap.erase(aRemoveIt);
87 std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIt = theConstraint->myAttributeMap.begin();
88 while (anAttrIt != theConstraint->myAttributeMap.end()) {
89 if (aRemEnts.find(anAttrIt->second) != aRemEnts.end()) {
91 std::map<AttributePtr, Slvs_hEntity>::iterator aRemoveIt = anAttrIt++;
92 theConstraint->myAttributeMap.erase(aRemoveIt);
100 addConstraint(theConstraint->myBaseConstraint);
101 std::map<ConstraintPtr, Slvs_hConstraint>::iterator aConstrIter =
102 theConstraint->myExtraCoincidence.begin();
103 for (; aConstrIter != theConstraint->myExtraCoincidence.end(); aConstrIter++)
104 addConstraint(aConstrIter->first);
105 // Clear the lists to not remove the entities on destruction
106 theConstraint->mySlvsConstraints.clear();
107 theConstraint->myFeatureMap.clear();
108 theConstraint->myAttributeMap.clear();
111 Slvs_hConstraint SketchSolver_ConstraintCoincidence::addConstraint(
112 Slvs_hEntity thePoint1, Slvs_hEntity thePoint2)
114 if (thePoint1 == thePoint2)
115 return SLVS_E_UNKNOWN;
117 bool hasDuplicated = myStorage->hasDuplicatedConstraint();
118 Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
119 SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(), 0.0, thePoint1, thePoint2,
120 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
121 Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
122 if (!hasDuplicated && myStorage->hasDuplicatedConstraint()) {
123 // the duplicated constraint appears
124 myStorage->removeConstraint(aNewID);
125 return SLVS_E_UNKNOWN;
127 mySlvsConstraints.push_back(aNewID);
131 Slvs_hConstraint SketchSolver_ConstraintCoincidence::addPointOnEntity(
132 Slvs_hEntity thePoint, Slvs_hEntity theEntity)
134 // Check the point is not coincident with boundaries of the entity
135 Slvs_Entity anEnt = myStorage->getEntity(theEntity);
136 int aPos = anEnt.type == SLVS_E_LINE_SEGMENT ? 0 : 1;
137 for (; anEnt.point[aPos] != SLVS_E_UNKNOWN; aPos++)
138 if (anEnt.point[aPos] == thePoint ||
139 myStorage->isCoincident(anEnt.point[aPos], thePoint))
140 return SLVS_E_UNKNOWN;
142 bool hasDuplicated = myStorage->hasDuplicatedConstraint();
143 Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
144 Slvs_hConstraint aType = anEnt.type == SLVS_E_LINE_SEGMENT ?
145 SLVS_C_PT_ON_LINE : SLVS_C_PT_ON_CIRCLE;
146 Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
147 aType, myGroup->getWorkplaneId(), 0.0, aBaseCoincidence.ptA, SLVS_E_UNKNOWN,
148 theEntity, SLVS_E_UNKNOWN);
149 Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
150 if (!hasDuplicated && myStorage->hasDuplicatedConstraint()) {
151 // the duplicated constraint appears
152 myStorage->removeConstraint(aNewID);
153 return SLVS_E_UNKNOWN;
155 mySlvsConstraints.push_back(aNewID);
159 void SketchSolver_ConstraintCoincidence::addConstraint(ConstraintPtr theConstraint)
161 if (mySlvsConstraints.empty()) {
162 // This constraint is empty, rebuild it from scratch
163 myBaseConstraint = theConstraint;
168 std::list<AttributePtr> anAttrList =
169 theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
170 std::list<AttributePtr>::iterator anIter = anAttrList.begin();
171 std::vector<Slvs_hEntity> aPoints;
172 Slvs_hEntity anEntity = SLVS_E_UNKNOWN;
174 for (; anIter != anAttrList.end(); anIter++) {
175 Slvs_hEntity aPointID = SLVS_E_UNKNOWN;
176 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
180 AttributePtr aPointAttr;
181 if (aRefAttr->isObject()) {
182 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
183 std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFeatFound =
184 myFeatureMap.find(aFeature);
185 if (aFeatFound != myFeatureMap.end())
186 anEntity = aFeatFound->second;
188 anEntity = myGroup->getFeatureId(aFeature);
189 if (anEntity == SLVS_E_UNKNOWN)
190 anEntity = changeEntity(aFeature, anEntType);
192 myFeatureMap[aFeature] = anEntity;
193 // Obtain relations between attributes of the feature and SolveSpace entities
194 std::list<AttributePtr> anAttrList =
195 aFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
196 std::list<AttributePtr>::iterator anIt = anAttrList.begin();
197 for (; anIt != anAttrList.end(); ++anIt) {
198 Slvs_hEntity anAttrID = myGroup->getAttributeId(*anIt);
199 if (anAttrID != SLVS_E_UNKNOWN)
200 myAttributeMap[*anIt] = anAttrID;
204 // If the feature is a point, add it to the list of coincident points
205 if (aFeature->getKind() == SketchPlugin_Point::ID()) {
207 anEntity = SLVS_E_UNKNOWN;
208 aPointAttr = aFeature->attribute(SketchPlugin_Point::COORD_ID());
211 aPointAttr = aRefAttr->attr();
212 std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrFound =
213 myAttributeMap.find(aPointAttr);
214 if (anAttrFound != myAttributeMap.end())
215 aPointID = anAttrFound->second;
217 aPointID = myGroup->getAttributeId(aPointAttr);
218 if (aPointID == SLVS_E_UNKNOWN)
219 aPointID = changeEntity(aPointAttr, anEntType);
223 if (aPointAttr) { // the point is found
224 aPoints.push_back(aPointID);
225 myCoincidentPoints.insert(aPointAttr);
226 myAttributeMap[aPointAttr] = aPointID;
230 Slvs_hConstraint aNewConstr = SLVS_E_UNKNOWN;
231 if (anEntity != SLVS_E_UNKNOWN)
232 aNewConstr = addPointOnEntity(aPoints.front(), anEntity);
233 else { // coincidence between two points
234 Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
235 std::vector<Slvs_hEntity>::const_iterator aPtIter = aPoints.begin();
236 for (; aPtIter != aPoints.end(); aPtIter++) {
237 Slvs_hConstraint aC = addConstraint(aBaseCoincidence.ptA, *aPtIter);
238 if (aC != SLVS_E_UNKNOWN)
242 myExtraCoincidence[theConstraint] = aNewConstr;
245 void SketchSolver_ConstraintCoincidence::process()
247 SketchSolver_Constraint::process();
249 // Fill the list of coincident points
250 std::list<AttributePtr> anAttrList =
251 myBaseConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
252 std::list<AttributePtr>::iterator anIt = anAttrList.begin();
253 for (; anIt != anAttrList.end(); anIt++) {
254 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
255 if (!aRefAttr || aRefAttr->isObject())
257 myCoincidentPoints.insert(aRefAttr->attr());
261 bool SketchSolver_ConstraintCoincidence::remove(ConstraintPtr theConstraint)
264 if (mySlvsConstraints.empty())
266 ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
267 int aPos = -1; // position of constraint in the list (-1 for base constraint)
268 std::map<ConstraintPtr, Slvs_hConstraint>::iterator anExtraIt;
269 if (aConstraint != myBaseConstraint) {
270 anExtraIt = myExtraCoincidence.find(aConstraint);
271 if (anExtraIt == myExtraCoincidence.end())
272 return false; // there is no constraint, which is specified to remove
274 bool isEmpty = anExtraIt->second == SLVS_E_UNKNOWN;
277 for (aPos = 0; aPos < (int)mySlvsConstraints.size(); aPos++)
278 if (mySlvsConstraints[aPos] == anExtraIt->second) {
284 myExtraCoincidence.erase(anExtraIt);
290 bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints[aPos+1]);
291 mySlvsConstraints.erase(mySlvsConstraints.begin() + (1+aPos));
292 if (aPos < 0 && !myExtraCoincidence.empty()) {
293 anExtraIt = myExtraCoincidence.begin();
294 // Remove invalid constraints
295 while (anExtraIt != myExtraCoincidence.end()) {
296 if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) {
297 std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
298 if (aTempIt->first != SLVS_E_UNKNOWN) {
299 myStorage->removeConstraint(aTempIt->second);
300 std::vector<Slvs_hConstraint>::iterator anIt = mySlvsConstraints.begin();
301 for (; anIt != mySlvsConstraints.end(); anIt++)
302 if (*anIt == aTempIt->second) {
303 mySlvsConstraints.erase(anIt);
307 myExtraCoincidence.erase(aTempIt);
312 // Find first non-extra conststraint
313 anExtraIt = myExtraCoincidence.begin();
314 while (anExtraIt != myExtraCoincidence.end() && anExtraIt->second == SLVS_E_UNKNOWN)
316 if (anExtraIt != myExtraCoincidence.end()) {
317 // Need to specify another base coincidence constraint
318 myBaseConstraint = anExtraIt->first;
319 myExtraCoincidence.erase(anExtraIt);
320 if (mySlvsConstraints.empty()) {
321 std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
322 Slvs_Constraint aBase = myStorage->getConstraint(*aCIter);
323 for (++aCIter; aCIter != mySlvsConstraints.end(); aCIter++) {
324 Slvs_Constraint aConstr = myStorage->getConstraint(*aCIter);
325 aConstr.ptA = aBase.ptA;
326 myStorage->updateConstraint(aConstr);
331 // Clear removed attributes
332 std::set<Slvs_hParam> aParamRemoved;
333 std::set<Slvs_hEntity> anEntRemoved;
334 std::set<Slvs_hConstraint> aConstrRemoved;
335 myStorage->getRemoved(aParamRemoved, anEntRemoved, aConstrRemoved);
336 std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
337 while (anAttrIter != myAttributeMap.end()) {
338 if (anEntRemoved.find(anAttrIter->second) != anEntRemoved.end()) {
339 std::map<AttributePtr, Slvs_hEntity>::iterator aTempIt = anAttrIter++;
340 myCoincidentPoints.erase(aTempIt->first);
341 myAttributeMap.erase(aTempIt);
347 // Go through remaining extra coincidence and try to add or remove them
348 anExtraIt = myExtraCoincidence.begin();
349 while (anExtraIt != myExtraCoincidence.end()) {
350 if (anExtraIt->first == SLVS_E_UNKNOWN) {
351 if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) {
352 std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
353 myExtraCoincidence.erase(aTempIt);
356 if (mySlvsConstraints.empty()) {
357 myBaseConstraint = anExtraIt->first;
358 std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
359 myExtraCoincidence.erase(aTempIt);
363 addConstraint(anExtraIt->first);
367 return mySlvsConstraints.empty();