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;
21 // set coordinates of slave (second) point equal to the master (first) point
22 Slvs_Entity aFirst = myStorage->getEntity(theAttributes[0]);
23 Slvs_Entity aSecond = myStorage->getEntity(theAttributes[1]);
24 for (int i = 0; i < 4; i++)
25 if (aFirst.param[i] != SLVS_E_UNKNOWN && aSecond.param[i] != SLVS_E_UNKNOWN) {
26 Slvs_Param aPar1 = myStorage->getParameter(aFirst.param[i]);
27 Slvs_Param aPar2 = myStorage->getParameter(aSecond.param[i]);
28 aPar2.val = aPar1.val;
29 myStorage->updateParameter(aPar2);
32 else if (theAttributes[2] != SLVS_E_UNKNOWN) {
33 // check the type of entity (line or circle)
34 Slvs_Entity anEnt = myStorage->getEntity(theAttributes[2]);
35 if (anEnt.type == SLVS_E_LINE_SEGMENT)
36 myType = SLVS_C_PT_ON_LINE;
37 else if (anEnt.type == SLVS_E_CIRCLE || anEnt.type == SLVS_E_ARC_OF_CIRCLE)
38 myType = SLVS_C_PT_ON_CIRCLE;
40 myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
42 myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
46 bool SketchSolver_ConstraintCoincidence::hasConstraint(ConstraintPtr theConstraint) const
48 if (myBaseConstraint == theConstraint)
50 return myExtraCoincidence.find(theConstraint) != myExtraCoincidence.end();
53 std::list<ConstraintPtr> SketchSolver_ConstraintCoincidence::constraints() const
55 std::list<ConstraintPtr> aConstraints;
56 aConstraints.push_back(myBaseConstraint);
57 std::map<ConstraintPtr, Slvs_hConstraint>::const_iterator anIt = myExtraCoincidence.begin();
58 for (; anIt != myExtraCoincidence.end(); anIt++)
59 aConstraints.push_back(anIt->first);
63 bool SketchSolver_ConstraintCoincidence::isCoincide(
64 std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const
66 std::set<AttributePtr>::const_iterator anAttrIter = theConstraint->myCoincidentPoints.begin();
67 for (; anAttrIter != theConstraint->myCoincidentPoints.end(); anAttrIter++)
68 if (myCoincidentPoints.find(*anAttrIter) != myCoincidentPoints.end())
73 void SketchSolver_ConstraintCoincidence::attach(
74 std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint)
77 // Remove constraints from theConstraint
78 std::vector<Slvs_hConstraint>::iterator aCIter = theConstraint->mySlvsConstraints.begin();
79 for (; aCIter != theConstraint->mySlvsConstraints.end(); aCIter++)
80 theConstraint->myStorage->removeConstraint(*aCIter);
82 if (myStorage == theConstraint->myStorage) {
83 // Clean removed items
84 std::set<Slvs_hParam> aRemParams;
85 std::set<Slvs_hEntity> aRemEnts;
86 std::set<Slvs_hConstraint> aRemConstr;
87 theConstraint->myStorage->getRemoved(aRemParams, aRemEnts, aRemConstr);
89 if (!aRemEnts.empty()) {
90 std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = theConstraint->myFeatureMap.begin();
91 while (aFeatIt != theConstraint->myFeatureMap.end()) {
92 if (aRemEnts.find(aFeatIt->second) != aRemEnts.end()) {
94 std::map<FeaturePtr, Slvs_hEntity>::iterator aRemoveIt = aFeatIt++;
95 theConstraint->myFeatureMap.erase(aRemoveIt);
99 std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIt = theConstraint->myAttributeMap.begin();
100 while (anAttrIt != theConstraint->myAttributeMap.end()) {
101 if (aRemEnts.find(anAttrIt->second) != aRemEnts.end()) {
103 std::map<AttributePtr, Slvs_hEntity>::iterator aRemoveIt = anAttrIt++;
104 theConstraint->myAttributeMap.erase(aRemoveIt);
112 addConstraint(theConstraint->myBaseConstraint);
113 std::map<ConstraintPtr, Slvs_hConstraint>::iterator aConstrIter =
114 theConstraint->myExtraCoincidence.begin();
115 for (; aConstrIter != theConstraint->myExtraCoincidence.end(); aConstrIter++)
116 addConstraint(aConstrIter->first);
117 // Clear the lists to not remove the entities on destruction
118 theConstraint->mySlvsConstraints.clear();
119 theConstraint->myFeatureMap.clear();
120 theConstraint->myAttributeMap.clear();
123 Slvs_hConstraint SketchSolver_ConstraintCoincidence::addConstraint(
124 Slvs_hEntity thePoint1, Slvs_hEntity thePoint2)
126 if (thePoint1 == thePoint2)
127 return SLVS_E_UNKNOWN;
129 bool hasDuplicated = myStorage->hasDuplicatedConstraint();
130 Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
131 SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(), 0.0, thePoint1, thePoint2,
132 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
133 Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
134 if (!hasDuplicated && myStorage->hasDuplicatedConstraint()) {
135 // the duplicated constraint appears
136 myStorage->removeConstraint(aNewID);
137 return SLVS_E_UNKNOWN;
139 mySlvsConstraints.push_back(aNewID);
143 Slvs_hConstraint SketchSolver_ConstraintCoincidence::addPointOnEntity(
144 Slvs_hEntity thePoint, Slvs_hEntity theEntity)
146 // Check the point is not coincident with boundaries of the entity
147 Slvs_Entity anEnt = myStorage->getEntity(theEntity);
148 int aPos = anEnt.type == SLVS_E_LINE_SEGMENT ? 0 : 1;
149 for (; anEnt.point[aPos] != SLVS_E_UNKNOWN; aPos++)
150 if (anEnt.point[aPos] == thePoint ||
151 myStorage->isCoincident(anEnt.point[aPos], thePoint))
152 return SLVS_E_UNKNOWN;
154 bool hasDuplicated = myStorage->hasDuplicatedConstraint();
155 Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
156 Slvs_hConstraint aType = anEnt.type == SLVS_E_LINE_SEGMENT ?
157 SLVS_C_PT_ON_LINE : SLVS_C_PT_ON_CIRCLE;
158 Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
159 aType, myGroup->getWorkplaneId(), 0.0, aBaseCoincidence.ptA, SLVS_E_UNKNOWN,
160 theEntity, SLVS_E_UNKNOWN);
161 Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
162 if (!hasDuplicated && myStorage->hasDuplicatedConstraint()) {
163 // the duplicated constraint appears
164 myStorage->removeConstraint(aNewID);
165 return SLVS_E_UNKNOWN;
167 mySlvsConstraints.push_back(aNewID);
171 void SketchSolver_ConstraintCoincidence::addConstraint(ConstraintPtr theConstraint)
173 if (mySlvsConstraints.empty()) {
174 // This constraint is empty, rebuild it from scratch
175 myBaseConstraint = theConstraint;
180 std::list<AttributePtr> anAttrList =
181 theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
182 std::list<AttributePtr>::iterator anIter = anAttrList.begin();
183 std::vector<Slvs_hEntity> aPoints;
184 Slvs_hEntity anEntity = SLVS_E_UNKNOWN;
186 for (; anIter != anAttrList.end(); anIter++) {
187 Slvs_hEntity aPointID = SLVS_E_UNKNOWN;
188 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
192 AttributePtr aPointAttr;
193 if (aRefAttr->isObject()) {
194 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
195 std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFeatFound =
196 myFeatureMap.find(aFeature);
197 if (aFeatFound != myFeatureMap.end())
198 anEntity = aFeatFound->second;
200 anEntity = myGroup->getFeatureId(aFeature);
201 if (anEntity == SLVS_E_UNKNOWN)
202 anEntity = changeEntity(aFeature, anEntType);
204 myFeatureMap[aFeature] = anEntity;
205 // Obtain relations between attributes of the feature and SolveSpace entities
206 std::list<AttributePtr> anAttrList =
207 aFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
208 std::list<AttributePtr>::iterator anIt = anAttrList.begin();
209 for (; anIt != anAttrList.end(); ++anIt) {
210 Slvs_hEntity anAttrID = myGroup->getAttributeId(*anIt);
211 if (anAttrID != SLVS_E_UNKNOWN)
212 myAttributeMap[*anIt] = anAttrID;
216 // If the feature is a point, add it to the list of coincident points
217 if (aFeature->getKind() == SketchPlugin_Point::ID()) {
219 anEntity = SLVS_E_UNKNOWN;
220 aPointAttr = aFeature->attribute(SketchPlugin_Point::COORD_ID());
223 aPointAttr = aRefAttr->attr();
224 std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrFound =
225 myAttributeMap.find(aPointAttr);
226 if (anAttrFound != myAttributeMap.end())
227 aPointID = anAttrFound->second;
229 aPointID = myGroup->getAttributeId(aPointAttr);
230 if (aPointID == SLVS_E_UNKNOWN)
231 aPointID = changeEntity(aPointAttr, anEntType);
235 if (aPointAttr) { // the point is found
236 aPoints.push_back(aPointID);
237 myCoincidentPoints.insert(aPointAttr);
238 myAttributeMap[aPointAttr] = aPointID;
242 Slvs_hConstraint aNewConstr = SLVS_E_UNKNOWN;
243 if (anEntity != SLVS_E_UNKNOWN)
244 aNewConstr = addPointOnEntity(aPoints.front(), anEntity);
245 else { // coincidence between two points
246 Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
247 std::vector<Slvs_hEntity>::const_iterator aPtIter = aPoints.begin();
248 for (; aPtIter != aPoints.end(); aPtIter++) {
249 Slvs_hConstraint aC = addConstraint(aBaseCoincidence.ptA, *aPtIter);
250 if (aC != SLVS_E_UNKNOWN)
254 myExtraCoincidence[theConstraint] = aNewConstr;
257 void SketchSolver_ConstraintCoincidence::process()
259 SketchSolver_Constraint::process();
261 // Fill the list of coincident points
262 std::list<AttributePtr> anAttrList =
263 myBaseConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
264 std::list<AttributePtr>::iterator anIt = anAttrList.begin();
265 for (; anIt != anAttrList.end(); anIt++) {
266 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
267 if (!aRefAttr || aRefAttr->isObject())
269 myCoincidentPoints.insert(aRefAttr->attr());
273 bool SketchSolver_ConstraintCoincidence::remove(ConstraintPtr theConstraint)
276 if (mySlvsConstraints.empty())
278 ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
279 int aPos = -1; // position of constraint in the list (-1 for base constraint)
280 std::map<ConstraintPtr, Slvs_hConstraint>::iterator anExtraIt;
281 if (aConstraint != myBaseConstraint) {
282 anExtraIt = myExtraCoincidence.find(aConstraint);
283 if (anExtraIt == myExtraCoincidence.end())
284 return false; // there is no constraint, which is specified to remove
286 bool isEmpty = anExtraIt->second == SLVS_E_UNKNOWN;
289 for (aPos = 0; aPos < (int)mySlvsConstraints.size(); aPos++)
290 if (mySlvsConstraints[aPos] == anExtraIt->second) {
296 myExtraCoincidence.erase(anExtraIt);
302 bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints[aPos+1]);
303 mySlvsConstraints.erase(mySlvsConstraints.begin() + (1+aPos));
304 if (aPos < 0 && !myExtraCoincidence.empty()) {
305 anExtraIt = myExtraCoincidence.begin();
306 // Remove invalid constraints
307 while (anExtraIt != myExtraCoincidence.end()) {
308 if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) {
309 std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
310 if (aTempIt->first != SLVS_E_UNKNOWN) {
311 myStorage->removeConstraint(aTempIt->second);
312 std::vector<Slvs_hConstraint>::iterator anIt = mySlvsConstraints.begin();
313 for (; anIt != mySlvsConstraints.end(); anIt++)
314 if (*anIt == aTempIt->second) {
315 mySlvsConstraints.erase(anIt);
319 myExtraCoincidence.erase(aTempIt);
324 // Find first non-extra conststraint
325 anExtraIt = myExtraCoincidence.begin();
326 while (anExtraIt != myExtraCoincidence.end() && anExtraIt->second == SLVS_E_UNKNOWN)
328 if (anExtraIt != myExtraCoincidence.end()) {
329 // Need to specify another base coincidence constraint
330 myBaseConstraint = anExtraIt->first;
331 myExtraCoincidence.erase(anExtraIt);
332 if (mySlvsConstraints.empty()) {
333 std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
334 Slvs_Constraint aBase = myStorage->getConstraint(*aCIter);
335 for (++aCIter; aCIter != mySlvsConstraints.end(); aCIter++) {
336 Slvs_Constraint aConstr = myStorage->getConstraint(*aCIter);
337 aConstr.ptA = aBase.ptA;
338 myStorage->updateConstraint(aConstr);
343 // Clear removed attributes
344 std::set<Slvs_hParam> aParamRemoved;
345 std::set<Slvs_hEntity> anEntRemoved;
346 std::set<Slvs_hConstraint> aConstrRemoved;
347 myStorage->getRemoved(aParamRemoved, anEntRemoved, aConstrRemoved);
348 std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
349 while (anAttrIter != myAttributeMap.end()) {
350 if (anEntRemoved.find(anAttrIter->second) != anEntRemoved.end()) {
351 std::map<AttributePtr, Slvs_hEntity>::iterator aTempIt = anAttrIter++;
352 myCoincidentPoints.erase(aTempIt->first);
353 myAttributeMap.erase(aTempIt);
359 // Go through remaining extra coincidence and try to add or remove them
360 anExtraIt = myExtraCoincidence.begin();
361 while (anExtraIt != myExtraCoincidence.end()) {
362 if (anExtraIt->first == SLVS_E_UNKNOWN) {
363 if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) {
364 std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
365 myExtraCoincidence.erase(aTempIt);
368 if (mySlvsConstraints.empty()) {
369 myBaseConstraint = anExtraIt->first;
370 std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
371 myExtraCoincidence.erase(aTempIt);
375 addConstraint(anExtraIt->first);
379 return mySlvsConstraints.empty();