1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: SketchSolver_ConstraintGroup.cpp
4 // Created: 27 May 2014
5 // Author: Artem ZHIDKOV
7 #include "SketchSolver_ConstraintGroup.h"
9 #include <SketchSolver_Constraint.h>
11 #include <Events_Error.h>
12 #include <Events_Loop.h>
13 #include <GeomAPI_XY.h>
14 #include <GeomAPI_Dir2d.h>
15 #include <GeomAPI_Pnt2d.h>
16 #include <GeomDataAPI_Dir.h>
17 #include <GeomDataAPI_Point.h>
18 #include <GeomDataAPI_Point2D.h>
19 #include <ModelAPI_AttributeDouble.h>
20 #include <ModelAPI_AttributeRefList.h>
21 #include <ModelAPI_Document.h>
22 #include <ModelAPI_Events.h>
23 #include <ModelAPI_ResultConstruction.h>
25 #include <SketchPlugin_Constraint.h>
26 #include <SketchPlugin_ConstraintFillet.h>
27 #include <SketchPlugin_ConstraintLength.h>
28 #include <SketchPlugin_ConstraintCoincidence.h>
29 #include <SketchPlugin_ConstraintMirror.h>
30 #include <SketchPlugin_ConstraintRigid.h>
32 #include <SketchPlugin_Arc.h>
33 #include <SketchPlugin_Circle.h>
34 #include <SketchPlugin_Line.h>
35 #include <SketchPlugin_Point.h>
36 #include <SketchPlugin_Sketch.h>
41 /// Tolerance for value of parameters
42 const double tolerance = 1.e-10;
45 * Collects all sketch solver error' codes
46 * as inline static functions
48 // TODO: Move this class into a separate file
49 class SketchSolver_Error
52 /// The value parameter for the constraint
53 inline static const std::string& CONSTRAINTS()
55 static const std::string MY_ERROR_VALUE("Conflicting constraints");
56 return MY_ERROR_VALUE;
58 /// The entities need to have shared point, but they have not
59 inline static const std::string& NO_COINCIDENT_POINTS()
61 static const std::string MY_ERROR_VALUE("Objects should have coincident point");
62 return MY_ERROR_VALUE;
66 /// This value is used to give unique index to the groups
67 static Slvs_hGroup myGroupIndexer = 0;
69 /** \brief Search the entity/parameter with specified ID in the list of elements
70 * \param[in] theEntityID unique ID of the element
71 * \param[in] theEntities list of elements
72 * \return position of the found element or -1 if the element is not found
75 static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
77 // ========================================================
78 // ========= SketchSolver_ConstraintGroup ===============
79 // ========================================================
81 SketchSolver_ConstraintGroup::SketchSolver_ConstraintGroup(
82 std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
83 : myID(++myGroupIndexer),
93 myEntOfConstr.clear();
94 myConstraints.clear();
96 myTempConstraints.clear();
97 myTempPointWhereDragged.clear();
98 myTempPointWDrgdID = 0;
100 // Initialize workplane
101 myWorkplane.h = SLVS_E_UNKNOWN;
103 assert(addWorkplane(theWorkplane));
105 addWorkplane(theWorkplane);
109 SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
113 myEntOfConstr.clear();
114 myConstraints.clear();
115 myConstraintMap.clear();
116 myTempConstraints.clear();
117 myTempPointWhereDragged.clear();
119 // If the group with maximal identifier is deleted, decrease the indexer
120 if (myID == myGroupIndexer)
124 // ============================================================================
125 // Function: isBaseWorkplane
126 // Class: SketchSolver_ConstraintGroup
127 // Purpose: verify the group is based on the given workplane
128 // ============================================================================
129 bool SketchSolver_ConstraintGroup::isBaseWorkplane(
130 std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane) const
132 return theWorkplane == mySketch;
135 // ============================================================================
136 // Function: isInteract
137 // Class: SketchSolver_ConstraintGroup
138 // Purpose: verify are there any entities in the group used by given constraint
139 // ============================================================================
140 bool SketchSolver_ConstraintGroup::isInteract(
141 std::shared_ptr<SketchPlugin_Feature> theFeature) const
143 // Check the group is empty
147 // Check if the feature is already in the group
148 if (myEntityFeatMap.find(theFeature) != myEntityFeatMap.end())
150 std::shared_ptr<SketchPlugin_Constraint> aConstr =
151 std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
152 if (aConstr && myConstraintMap.find(aConstr) != myConstraintMap.end())
155 // Go through the attributes and verify if some of them already in the group
156 std::list<std::shared_ptr<ModelAPI_Attribute>>
157 anAttrList = theFeature->data()->attributes(std::string());
158 std::list<std::shared_ptr<ModelAPI_Attribute>>::const_iterator
159 anAttrIter = anAttrList.begin();
160 for ( ; anAttrIter != anAttrList.end(); anAttrIter++) {
161 AttributeRefListPtr aCAttrRefList =
162 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrIter);
164 std::list<ObjectPtr> anObjList = aCAttrRefList->list();
165 std::list<ObjectPtr>::iterator anIt = anObjList.begin();
166 for ( ; anIt != anObjList.end(); anIt++) {
167 FeaturePtr aFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(*anIt);
168 if (aFeature && myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
173 AttributeRefAttrPtr aCAttrRef =
174 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
175 if (!aCAttrRef || !aCAttrRef->isObject()) {
176 std::shared_ptr<ModelAPI_Attribute> anAttr =
177 aCAttrRef ? aCAttrRef->attr() : *anAttrIter;
178 if (myEntityAttrMap.find(anAttr) != myEntityAttrMap.end())
181 ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
182 aCAttrRef->object());
185 std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
186 FeaturePtr aFeature = aDoc->feature(aRC);
187 if (myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
189 // search attributes of a feature to be parameters of constraint
190 std::list<std::shared_ptr<ModelAPI_Attribute> > aFeatAttrList =
191 aFeature->data()->attributes(std::string());
192 std::list<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aFAIter = aFeatAttrList
194 for (; aFAIter != aFeatAttrList.end(); aFAIter++)
195 if (myEntityAttrMap.find(*aFAIter) != myEntityAttrMap.end())
200 // Entities did not found
204 // ============================================================================
205 // Function: checkConstraintConsistence
206 // Class: SketchSolver_ConstraintGroup
207 // Purpose: verifies and changes parameters of the constraint
208 // ============================================================================
209 void SketchSolver_ConstraintGroup::checkConstraintConsistence(Slvs_Constraint& theConstraint)
211 if (theConstraint.type == SLVS_C_PT_LINE_DISTANCE) {
212 // Get constraint parameters and check the sign of constraint value
215 int aPtPos = Search(theConstraint.ptA, myEntities);
216 int aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
217 std::shared_ptr<GeomAPI_XY> aPoint(
218 new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
221 int aLnPos = Search(theConstraint.entityA, myEntities);
222 aPtPos = Search(myEntities[aLnPos].point[0], myEntities);
223 aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
224 std::shared_ptr<GeomAPI_XY> aStart(
225 new GeomAPI_XY(-myParams[aPtParamPos].val, -myParams[aPtParamPos + 1].val));
226 aPtPos = Search(myEntities[aLnPos].point[1], myEntities);
227 aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
228 std::shared_ptr<GeomAPI_XY> aEnd(
229 new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
231 aEnd = aEnd->added(aStart);
232 aPoint = aPoint->added(aStart);
233 if (aPoint->cross(aEnd) * theConstraint.valA < 0.0)
234 theConstraint.valA *= -1.0;
238 // ============================================================================
239 // Function: changeConstraint
240 // Class: SketchSolver_ConstraintGroup
241 // Purpose: create/update the constraint in the group
242 // ============================================================================
243 bool SketchSolver_ConstraintGroup::changeConstraint(
244 std::shared_ptr<SketchPlugin_Constraint> theConstraint)
246 // There is no workplane yet, something wrong
247 if (myWorkplane.h == SLVS_E_UNKNOWN)
251 if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID())
252 return changeRigidConstraint(theConstraint);
253 if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID())
254 return changeMirrorConstraint(theConstraint);
255 if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID())
256 return changeFilletConstraint(theConstraint);
259 // Search this constraint in the current group to update it
260 ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
261 std::vector<Slvs_Constraint>::iterator aConstrIter;
262 if (aConstrMapIter != myConstraintMap.end()) {
263 int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
264 aConstrIter = myConstraints.begin() + aConstrPos;
267 // Get constraint type and verify the constraint parameters are correct
268 SketchSolver_Constraint aConstraint(theConstraint);
269 int aConstrType = aConstraint.getType();
270 if (aConstrType == SLVS_C_UNKNOWN
271 || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
273 const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
275 // Create constraint parameters
276 double aDistance = 0.0; // scalar value of the constraint
277 AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
278 theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE()));
280 aDistance = aDistAttr->value();
281 // Issue #196: checking the positivity of the distance constraint
282 if (aDistance < tolerance &&
283 (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE))
285 // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
286 if (aConstrType == SLVS_C_DIAMETER)
288 if (aConstrMapIter != myConstraintMap.end()
289 && fabs(aConstrIter->valA - aDistance) > tolerance) {
290 myNeedToSolve = true;
291 aConstrIter->valA = aDistance;
295 size_t aNbTmpConstraints = myTempConstraints.size();
296 Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
297 for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
298 aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
299 std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
300 ModelAPI_AttributeRefAttr>(
301 theConstraint->data()->attribute(aConstraintAttributes[indAttr]));
305 // Convert the object of the attribute to the feature
307 if (aConstrAttr->isObject() && aConstrAttr->object()) {
308 ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
309 aConstrAttr->object());
312 std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
313 aFeature = aDoc->feature(aRC);
316 // For the length constraint the start and end points of the line should be added to the entities list instead of line
317 if (aConstrType == SLVS_C_PT_PT_DISTANCE
318 && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0) {
319 Slvs_hEntity aLineEnt = changeEntityFeature(aFeature);
320 int aEntPos = Search(aLineEnt, myEntities);
321 aConstrEnt[indAttr++] = myEntities[aEntPos].point[0];
322 aConstrEnt[indAttr++] = myEntities[aEntPos].point[1];
323 while (indAttr < CONSTRAINT_ATTR_SIZE)
324 aConstrEnt[indAttr++] = 0;
325 break; // there should be no other entities
326 } else if (aConstrAttr->isObject())
327 aConstrEnt[indAttr] = changeEntityFeature(aFeature);
329 aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
332 if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
333 // Several points may be coincident, it is not necessary to store all constraints between them.
334 // Try to find sequence of coincident points which connects the points of new constraint
335 if (aConstrType == SLVS_C_POINTS_COINCIDENT) {
336 if (aConstrEnt[0] == aConstrEnt[1]) // no need to add self coincidence
338 if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) {
339 myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes
342 if (aNbTmpConstraints < myTempConstraints.size()) {
343 // There was added temporary constraint. Check that there is no coincident points which already rigid.
345 // Get list of already fixed points
346 std::set<Slvs_hEntity> anAlreadyFixed;
347 std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
348 for (; aCIter != myConstraints.end(); aCIter++)
349 if (aCIter->type == SLVS_C_WHERE_DRAGGED) {
350 std::list<Slvs_hConstraint>::const_iterator aTmpIt = myTempConstraints.begin();
351 for (; aTmpIt != myTempConstraints.end(); aTmpIt++)
352 if (*aTmpIt == aCIter->h)
354 if (aTmpIt == myTempConstraints.end())
355 anAlreadyFixed.insert(aCIter->ptA);
358 std::set<Slvs_hConstraint> aTmpConstrToDelete;
359 std::list<Slvs_hConstraint>::reverse_iterator aTmpIter = myTempConstraints.rbegin();
360 size_t aCurSize = myTempConstraints.size();
361 for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend();
362 aTmpIter++, aCurSize--) {
363 int aConstrPos = Search(*aTmpIter, myConstraints);
364 std::vector<std::set<Slvs_hEntity> >::const_iterator
365 aCoincIter = myCoincidentPoints.begin();
366 for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
367 if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) {
368 std::set<Slvs_hEntity>::const_iterator anIt;
369 for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++)
370 if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) {
371 aTmpConstrToDelete.insert(*aTmpIter);
377 if (!aTmpConstrToDelete.empty())
378 removeTemporaryConstraints(aTmpConstrToDelete);
381 // For the tangency constraints it is necessary to identify which points of entities are coincident
382 int aSlvsOtherFlag = 0;
383 int aSlvsOther2Flag = 0;
384 if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) {
385 // Search entities used by constraint
386 int anEnt1Pos = Search(aConstrEnt[2], myEntities);
387 int anEnt2Pos = Search(aConstrEnt[3], myEntities);
388 // Obtain start and end points of entities
389 Slvs_hEntity aPointsToFind[4];
390 aPointsToFind[0] = myEntities[anEnt1Pos].point[1];
391 aPointsToFind[1]= myEntities[anEnt1Pos].point[2];
392 bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT);
393 aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1];
394 aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2];
395 // Search coincident points
396 bool isPointFound[4];
397 std::vector<std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
398 for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) {
399 for (int i = 0; i < 4; i++)
400 isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end());
401 if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) {
402 // the arc is tangent by end point
403 if (isPointFound[1]) aSlvsOtherFlag = 1;
404 // the second item is an arc and it is tangent by end point too
405 if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1;
409 if (aCPIter == myCoincidentPoints.end()) {
410 // There is no coincident points between tangential objects. Generate error message
411 Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
416 // Create SolveSpace constraint structure
417 Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
418 myWorkplane.h, aDistance, aConstrEnt[0],
419 aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
420 if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag;
421 if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag;
422 myConstraints.push_back(aSlvsConstr);
423 myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aSlvsConstr.h);
424 int aConstrPos = Search(aSlvsConstr.h, myConstraints);
425 aConstrIter = myConstraints.begin() + aConstrPos;
426 myNeedToSolve = true;
427 } else { // Attributes of constraint may be changed => update constraint
428 Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB,
429 &aConstrIter->entityA, &aConstrIter->entityB,
430 &aConstrIter->entityC, &aConstrIter->entityD};
431 for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
432 if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr])
434 *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr];
435 myNeedToSolve = true;
440 // Update flags of entities to be used by constraints
441 for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
442 if (aConstrEnt[indAttr] != 0) {
443 int aPos = Search(aConstrEnt[indAttr], myEntities);
444 myEntOfConstr[aPos] = true;
445 // Sub-entities should be used implcitly
446 Slvs_hEntity* aEntPtr = myEntities[aPos].point;
447 while (*aEntPtr != 0) {
448 aPos = Search(*aEntPtr, myEntities);
449 myEntOfConstr[aPos] = true;
454 checkConstraintConsistence(*aConstrIter);
458 // ============================================================================
459 // Function: changeRigidConstraint
460 // Class: SketchSolver_ConstraintGroup
461 // Purpose: create/update the "Rigid" constraint in the group
462 // ============================================================================
463 bool SketchSolver_ConstraintGroup::changeRigidConstraint(
464 std::shared_ptr<SketchPlugin_Constraint> theConstraint)
466 // Search this constraint in the current group to update it
467 ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
468 std::vector<Slvs_Constraint>::iterator aConstrIter;
469 if (aConstrMapIter != myConstraintMap.end()) {
470 int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
471 aConstrIter = myConstraints.begin() + aConstrPos;
474 // Get constraint type and verify the constraint parameters are correct
475 SketchSolver_Constraint aConstraint(theConstraint);
476 int aConstrType = aConstraint.getType();
477 if (aConstrType == SLVS_C_UNKNOWN
478 || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
480 const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
482 Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN;
483 std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
484 ModelAPI_AttributeRefAttr>(
485 theConstraint->data()->attribute(aConstraintAttributes[0]));
489 // Convert the object of the attribute to the feature
491 if (aConstrAttr->isObject() && aConstrAttr->object()) {
492 ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
493 aConstrAttr->object());
496 std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
497 aFeature = aDoc->feature(aRC);
500 aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr());
502 if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
503 // Check the fixed entity is not a point.
504 std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
505 ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0]));
506 std::shared_ptr<GeomDataAPI_Point> aPoint =
507 std::dynamic_pointer_cast<GeomDataAPI_Point>(aConstrAttr->attr());
508 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
509 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aConstrAttr->attr());
510 if (aPoint || aPoint2D || aFeature->getKind() == SketchPlugin_Point::ID()) {
511 // Create SolveSpace constraint structure
512 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
513 ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
514 aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
515 myConstraints.push_back(aConstraint);
516 myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aConstraint.h);
517 int aConstrPos = Search(aConstraint.h, myConstraints);
518 aConstrIter = myConstraints.begin() + aConstrPos;
519 myNeedToSolve = true;
521 myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
523 // To avoid SolveSpace problems:
524 // * if the circle is rigid, we will fix its center and radius;
525 // * if the arc is rigid, we will fix its start and end points and radius.
526 double aRadius = 0.0;
528 bool isCircle = false;
530 if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
531 std::shared_ptr<GeomDataAPI_Point2D> aCenter =
532 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
533 aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
534 std::shared_ptr<GeomDataAPI_Point2D> aStart =
535 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
536 aFeature->data()->attribute(SketchPlugin_Arc::START_ID()));
537 aRadius = aStart->pnt()->distance(aCenter->pnt());
539 } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
540 aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
541 aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
546 // Get list of already fixed points
547 std::set<Slvs_hEntity> anAlreadyFixed;
548 std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
549 for (; aCIter != myConstraints.end(); aCIter++)
550 if (aCIter->type == SLVS_C_WHERE_DRAGGED)
551 anAlreadyFixed.insert(aCIter->ptA);
553 // Create constraints to fix the parameters of the entity
554 int aEntPos = Search(aConstrEnt, myEntities);
555 Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point;
556 if (isArc) aPointsPtr++; // avoid to fix center of arc
557 while (*aPointsPtr != 0) {
558 // Avoid to create additional "Rigid" constraints for coincident points
559 bool isCoincAlreadyFixed = false;
560 if (!anAlreadyFixed.empty()) {
561 if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end())
562 isCoincAlreadyFixed = true;
564 std::vector<std::set<Slvs_hEntity> >::const_iterator aCoincIter =
565 myCoincidentPoints.begin();
566 for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) {
567 if (aCoincIter->find(*aPointsPtr) == aCoincIter->end())
569 std::set<Slvs_hEntity>::const_iterator anIter = anAlreadyFixed.begin();
570 for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++)
571 if (aCoincIter->find(*anIter) != aCoincIter->end())
572 isCoincAlreadyFixed = true;
576 if (!isCoincAlreadyFixed) {
577 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
578 ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
579 *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
580 myConstraints.push_back(aConstraint);
581 myConstraintMap[theConstraint].push_back(aConstraint.h);
586 if (isArc || isCircle) { // add radius constraint
587 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
588 ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius,
589 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN);
590 myConstraints.push_back(aConstraint);
591 myConstraintMap[theConstraint].push_back(aConstraint.h);
594 // The object is already rigid, so there is no constraints added
595 if (myConstraintMap[theConstraint].empty()) {
596 myConstraintMap.erase(theConstraint);
597 myNeedToSolve = false;
600 myNeedToSolve = true;
606 // ============================================================================
607 // Function: changeMirrorConstraint
608 // Class: SketchSolver_ConstraintGroup
609 // Purpose: create/update the "Mirror" constraint in the group
610 // ============================================================================
611 bool SketchSolver_ConstraintGroup::changeMirrorConstraint(
612 std::shared_ptr<SketchPlugin_Constraint> theConstraint)
614 DataPtr aConstrData = theConstraint->data();
616 // Search this constraint in the current group to update it
617 ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
618 std::vector<Slvs_Constraint>::iterator aConstrIter;
619 bool isExists = false;
620 if (aConstrMapIter != myConstraintMap.end()) {
621 int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
622 aConstrIter = myConstraints.begin() + aConstrPos;
626 // Get constraint type and verify the constraint parameters are correct
627 SketchSolver_Constraint aConstraint(theConstraint);
628 int aConstrType = aConstraint.getType();
629 if (aConstrType == SLVS_C_UNKNOWN
630 || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
632 const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
634 Slvs_hEntity aMirrorLineEnt = SLVS_E_UNKNOWN;
635 AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
636 aConstrData->attribute(aConstraintAttributes[0]));
640 // Convert the object of the attribute to the feature
641 FeaturePtr aMirrorLineFeat;
642 if (aConstrAttr->isObject() && aConstrAttr->object()) {
643 ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
644 aConstrAttr->object());
647 std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
648 aMirrorLineFeat = aDoc->feature(aRC);
650 aMirrorLineEnt = aConstrAttr->isObject() ?
651 changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr());
653 // Append symmetric constraint for each point of mirroring features
654 AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
655 aConstrData->attribute(aConstraintAttributes[1]));
656 AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
657 aConstrData->attribute(aConstraintAttributes[2]));
658 if (!aBaseRefList || !aMirroredRefList)
661 std::list<ObjectPtr> aBaseList = aBaseRefList->list();
662 std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
663 // remove all empty items
664 std::list<ObjectPtr>::iterator anIt = aBaseList.begin();
665 std::list<ObjectPtr>::iterator aTmpIt;
666 while (anIt != aBaseList.end()) {
670 aBaseList.erase(aTmpIt);
672 anIt = aMirroredList.begin();
673 while (anIt != aMirroredList.end()) {
677 aMirroredList.erase(aTmpIt);
679 if (aBaseList.empty() || aBaseList.size() != aMirroredList.size())
682 std::vector<Slvs_hConstraint> aNewConstraints;
683 // Fill the list of already mirrored points
684 std::vector<Slvs_Constraint> anOldConstraints;
685 std::map<Slvs_hEntity, Slvs_hEntity> aMirroredPoints;
687 std::vector<Slvs_hConstraint>::const_iterator aCIter = aConstrMapIter->second.begin();
688 for (; aCIter != aConstrMapIter->second.end(); aCIter++) {
689 int anInd = Search(*aCIter, myConstraints);
690 if (myConstraints[anInd].type != aConstrType)
692 aMirroredPoints[myConstraints[anInd].ptA] = myConstraints[anInd].ptB;
693 anOldConstraints.push_back(myConstraints[anInd]);
697 FeaturePtr aBaseFeature, aMirrorFeature;
698 ResultConstructionPtr aRC;
699 std::list<ObjectPtr>::iterator aBaseIter = aBaseList.begin();
700 std::list<ObjectPtr>::iterator aMirIter = aMirroredList.begin();
701 for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) {
702 aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
703 aBaseFeature = aRC ? aRC->document()->feature(aRC) :
704 std::dynamic_pointer_cast<ModelAPI_Feature>(*aBaseIter);
705 aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirIter);
706 aMirrorFeature = aRC ? aRC->document()->feature(aRC) :
707 std::dynamic_pointer_cast<ModelAPI_Feature>(*aMirIter);
709 if (!aBaseFeature || !aMirrorFeature ||
710 aBaseFeature->getKind() != aMirrorFeature->getKind())
712 Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature);
713 Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature);
714 // Make aMirrorEnt parameters to be symmetric with aBaseEnt
715 makeMirrorEntity(aBaseEnt, aMirrorEnt, aMirrorLineEnt);
717 if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) {
718 Slvs_hConstraint anID = changeMirrorPoints(aBaseEnt, aMirrorEnt,
719 aMirrorLineEnt, anOldConstraints, aMirroredPoints);
720 aNewConstraints.push_back(anID);
722 int aBasePos = Search(aBaseEnt, myEntities);
723 int aMirrorPos = Search(aMirrorEnt, myEntities);
724 if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) {
725 for (int ind = 0; ind < 2; ind++) {
726 Slvs_hConstraint anID = changeMirrorPoints(myEntities[aBasePos].point[ind],
727 myEntities[aMirrorPos].point[ind], aMirrorLineEnt, anOldConstraints, aMirroredPoints);
728 aNewConstraints.push_back(anID);
730 } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
731 Slvs_hConstraint anID = changeMirrorPoints(myEntities[aBasePos].point[0],
732 myEntities[aMirrorPos].point[0], aMirrorLineEnt, anOldConstraints, aMirroredPoints);
733 aNewConstraints.push_back(anID);
734 // Additional constraint for equal radii
735 Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
736 ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0,
737 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt);
738 myConstraints.push_back(anEqRadConstr);
739 myConstraintMap[theConstraint].push_back(anEqRadConstr.h);
740 } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
741 // Workaround to avoid problems in SolveSpace.
742 // The symmetry of two arcs will be done using symmetry of three points on these arcs:
743 // start point, end point, and any other point on the arc
744 Slvs_hEntity aBaseArcPoints[3] = {
745 myEntities[aBasePos].point[1],
746 myEntities[aBasePos].point[2],
748 Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
749 myEntities[aMirrorPos].point[2],
750 myEntities[aMirrorPos].point[1],
752 Slvs_hEntity aBothArcs[2] = {aBaseEnt, aMirrorEnt};
753 Slvs_hEntity aBothMiddlePoints[2];
754 for (int i = 0; i < 2; i++) {
756 calculateMiddlePoint(aBothArcs[i], x, y);
757 std::vector<Slvs_Param>::iterator aParamIter = myParams.end();
758 Slvs_hParam u = changeParameter(x, aParamIter);
759 Slvs_hParam v = changeParameter(y, aParamIter);
760 Slvs_Entity aPoint = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, u, v);
761 myEntities.push_back(aPoint);
762 myEntOfConstr.push_back(true);
763 aBothMiddlePoints[i] = aPoint.h;
764 // additional constraint point-on-curve
765 Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
766 ++myConstrMaxID, myID, SLVS_C_PT_ON_CIRCLE, myWorkplane.h, 0.0,
767 aPoint.h, SLVS_E_UNKNOWN, aBothArcs[i], SLVS_E_UNKNOWN);
768 myConstraints.push_back(aPonCircConstr);
769 myConstraintMap[theConstraint].push_back(aPonCircConstr.h);
770 aNewConstraints.push_back(aPonCircConstr.h);
773 aBaseArcPoints[2] = aBothMiddlePoints[0];
774 aMirrorArcPoints[2] = aBothMiddlePoints[1];
775 for (int ind = 0; ind < 3; ind++) {
776 Slvs_hConstraint anID = changeMirrorPoints(aBaseArcPoints[ind], aMirrorArcPoints[ind],
777 aMirrorLineEnt, anOldConstraints, aMirroredPoints);
778 aNewConstraints.push_back(anID);
784 // Remove unused constraints
785 std::vector<Slvs_Constraint>::const_iterator anOldCIter = anOldConstraints.begin();
786 for (; anOldCIter != anOldConstraints.end(); anOldCIter++) {
787 int anInd = Search(anOldCIter->h, myConstraints);
788 myConstraints.erase(myConstraints.begin() + anInd);
790 myConstraintMap[theConstraint] = aNewConstraints;
793 // Set the mirror line unchanged during constraint recalculation
794 int aMirrorLinePos = Search(aMirrorLineEnt, myEntities);
795 // firstly check the line is not fixed yet
796 bool isFixed[2] = {false, false};
797 std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
798 for (; aConstrIter != myConstraints.end() && !(isFixed[0] && isFixed[1]); aConstrIter++)
799 if (aConstrIter->type == SLVS_C_WHERE_DRAGGED) {
800 if (aConstrIter->ptA == myEntities[aMirrorLinePos].point[0])
802 else if (aConstrIter->ptA == myEntities[aMirrorLinePos].point[1])
805 // add new rigid constraints
807 Slvs_Constraint aRigidStart = Slvs_MakeConstraint(
808 ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
809 myEntities[aMirrorLinePos].point[0], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
810 myConstraints.push_back(aRigidStart);
811 myConstraintMap[theConstraint].push_back(aRigidStart.h);
814 Slvs_Constraint aRigidEnd = Slvs_MakeConstraint(
815 ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
816 myEntities[aMirrorLinePos].point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
817 myConstraints.push_back(aRigidEnd);
818 myConstraintMap[theConstraint].push_back(aRigidEnd.h);
821 // Add temporary constraints for initial objects to be unchanged
822 for (aBaseIter = aBaseList.begin(); aBaseIter != aBaseList.end(); aBaseIter++) {
823 aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
824 aBaseFeature = aRC ? aRC->document()->feature(aRC) :
825 std::dynamic_pointer_cast<ModelAPI_Feature>(*aBaseIter);
826 if (!aBaseFeature) continue;
827 std::list<AttributePtr> aPoints = aBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
828 if (aBaseFeature->getKind() != SketchPlugin_Arc::ID()) {
829 std::list<AttributePtr>::iterator anIt = aPoints.begin();
830 for ( ; anIt != aPoints.end(); anIt++) {
831 addTemporaryConstraintWhereDragged(*anIt);
834 // Arcs are fixed by center and start points only (to avoid solving errors in SolveSpace)
835 AttributePtr aCenterAttr = aBaseFeature->attribute(SketchPlugin_Arc::CENTER_ID());
836 std::map<AttributePtr, Slvs_hEntity>::iterator aFound = myEntityAttrMap.find(aCenterAttr);
837 Slvs_hEntity anArcPoints[3] = {aFound->second, 0, 0};
838 AttributePtr aStartAttr = aBaseFeature->attribute(SketchPlugin_Arc::START_ID());
839 aFound = myEntityAttrMap.find(aStartAttr);
840 anArcPoints[1] = aFound->second;
841 AttributePtr aEndAttr = aBaseFeature->attribute(SketchPlugin_Arc::END_ID());
842 aFound = myEntityAttrMap.find(aEndAttr);
843 anArcPoints[2] = aFound->second;
845 bool isFixed[3] = {false, false, false};
846 int aNbFixed = 0; // number of already fixed points on the arc
847 for (int i = 0; i < 3; i++) {
848 std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
849 for (; aCoPtIter != myCoincidentPoints.end() && !isFixed[i]; aCoPtIter++) {
850 if (aCoPtIter->find(anArcPoints[i]) == aCoPtIter->end())
851 continue; // the entity was not found in current set
853 // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
854 std::vector<Slvs_Constraint>::iterator aConstrIter = myConstraints.begin();
855 for (; aConstrIter != myConstraints.end(); aConstrIter++)
856 if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
857 aCoPtIter->find(aConstrIter->ptA) != aCoPtIter->end()) {
860 break; // the SLVS_C_WHERE_DRAGGED constraint already exists
864 if (aNbFixed < 2) { // append constraints
866 addTemporaryConstraintWhereDragged(aCenterAttr);
867 if (!isFixed[1] && (isFixed[0] || aNbFixed == 0))
868 addTemporaryConstraintWhereDragged(aStartAttr);
876 // ============================================================================
877 // Function: changeFilletConstraint
878 // Class: SketchSolver_ConstraintGroup
879 // Purpose: create/update the "Fillet" constraint in the group
880 // ============================================================================
881 bool SketchSolver_ConstraintGroup::changeFilletConstraint(
882 std::shared_ptr<SketchPlugin_Constraint> theConstraint)
884 DataPtr aConstrData = theConstraint->data();
886 // Search this constraint in the current group to update it
887 ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
888 std::vector<Slvs_Constraint>::iterator aConstrIter;
889 if (aConstrMapIter != myConstraintMap.end()) {
890 int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
891 aConstrIter = myConstraints.begin() + aConstrPos;
894 // Get constraint type and verify the constraint parameters are correct
895 SketchSolver_Constraint aConstraint(theConstraint);
896 int aConstrType = aConstraint.getType();
897 if (aConstrType == SLVS_C_UNKNOWN)
899 const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
901 // Obtain hEntity for basic objects of fillet
902 Slvs_hEntity aBaseObject[2];
903 FeaturePtr aBaseFeature[2];
904 for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
905 AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
906 aConstrData->attribute(aConstraintAttributes[indAttr]));
909 if (aConstrAttr->isObject() && aConstrAttr->object()) {
910 ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
911 aConstrAttr->object());
914 std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
915 aBaseFeature[indAttr] = aDoc->feature(aRC);
917 aBaseObject[indAttr] = aConstrAttr->isObject() ?
918 changeEntityFeature(aBaseFeature[indAttr]) : changeEntity(aConstrAttr->attr());
920 // Check the base entities have a coincident point
921 int aBaseObjInd[2] = {
922 Search(aBaseObject[0], myEntities),
923 Search(aBaseObject[1], myEntities)
925 int aShift[2] = { // shift for calculating correct start and end points for different types of objects
926 myEntities[aBaseObjInd[0]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
927 myEntities[aBaseObjInd[1]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
929 Slvs_hEntity aFirstObjPoints[2] = { // indices of start and end point of first object
930 myEntities[aBaseObjInd[0]].point[aShift[0]],
931 myEntities[aBaseObjInd[0]].point[1+aShift[0]]
933 Slvs_hEntity aSecondObjPoints[2] = { // indices of start and end point of second object
934 myEntities[aBaseObjInd[1]].point[aShift[1]],
935 myEntities[aBaseObjInd[1]].point[1+aShift[1]]
937 bool isCoincidentFound = false;
938 int aBaseCoincInd[2] = {0, 0}; // indices in aFirstObjPoint and aSecondObjPoint identifying coincident points
939 std::vector<std::set<Slvs_hEntity> >::iterator aCPIter = myCoincidentPoints.begin();
940 for ( ; aCPIter != myCoincidentPoints.end() && !isCoincidentFound; aCPIter++)
941 for (int ind1 = 0; ind1 < 2 && !isCoincidentFound; ind1++)
942 for (int ind2 = 0; ind2 < 2 && !isCoincidentFound; ind2++)
943 if (aCPIter->find(aFirstObjPoints[ind1]) != aCPIter->end() &&
944 aCPIter->find(aSecondObjPoints[ind2]) != aCPIter->end()) {
945 aBaseCoincInd[0] = ind1;
946 aBaseCoincInd[1] = ind2;
947 isCoincidentFound = true;
949 if (!isCoincidentFound) {
950 // There is no coincident points between objects. Generate error message
951 Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
955 // Create fillet entities
956 // - first object is placed on the first base
957 // - second object is on the second base
958 // - third object is a filleting arc
959 static const int aNbFilletEnt = 3;
960 Slvs_hEntity aFilletEnt[aNbFilletEnt];
961 int aFilletObjInd[aNbFilletEnt];
962 AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
963 aConstrData->attribute(aConstraintAttributes[2]));
966 std::list<ObjectPtr> aFilletList = aFilletRefList->list();
967 if (aFilletList.size() < aNbFilletEnt)
969 FeaturePtr aFilletFeature;
970 ResultConstructionPtr aRC;
971 std::list<ObjectPtr>::iterator aFilIter = aFilletList.begin();
972 for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) {
973 aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aFilIter);
974 aFilletFeature = aRC ? aRC->document()->feature(aRC) :
975 std::dynamic_pointer_cast<ModelAPI_Feature>(*aFilIter);
978 aFilletEnt[indEnt] = changeEntityFeature(aFilletFeature);
979 if (aFilletEnt[indEnt] == SLVS_E_UNKNOWN)
980 return false; // not all attributes are initialized yet
981 aFilletObjInd[indEnt] = Search(aFilletEnt[indEnt], myEntities);
983 // At first time, for correct result, move floating points of fillet on the middle points of base objects
984 if (myConstraintMap.find(theConstraint) == myConstraintMap.end()) {
985 double anArcPoints[6];
986 for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
987 int anIndShift = myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
988 int aPointsPos[2] = {
989 Search(myEntities[aFilletObjInd[indEnt]].point[anIndShift], myEntities),
990 Search(myEntities[aFilletObjInd[indEnt]].point[1+anIndShift], myEntities)
993 Search(myEntities[aPointsPos[0]].param[0], myParams),
994 Search(myEntities[aPointsPos[1]].param[0], myParams)
996 int anIndex = aParamPos[aBaseCoincInd[indEnt]];
997 if (anIndShift == 0) {
998 myParams[anIndex].val =
999 0.5 * (myParams[aParamPos[0]].val + myParams[aParamPos[1]].val);
1000 myParams[1 + anIndex].val =
1001 0.5 * (myParams[1 + aParamPos[0]].val + myParams[1 + aParamPos[1]].val);
1002 } else { // place the changed point on the arc
1003 double x = 0, y = 0;
1004 calculateMiddlePoint(aFilletEnt[indEnt], x, y);
1005 myParams[anIndex].val = x;
1006 myParams[1 + anIndex].val = y;
1008 anArcPoints[indEnt*2+2] = myParams[anIndex].val;
1009 anArcPoints[indEnt*2+3] = myParams[1 + anIndex].val;
1011 anArcPoints[0] = 0.5 * (anArcPoints[2] + anArcPoints[4]);
1012 anArcPoints[1] = 0.5 * (anArcPoints[3] + anArcPoints[5]);
1013 for (int indArcPt = 0; indArcPt < 3; indArcPt++) {
1014 int aPtPos = Search(myEntities[aFilletObjInd[2]].point[indArcPt], myEntities);
1015 int aParamPos = Search(myEntities[aPtPos].param[0], myParams);
1016 myParams[aParamPos].val = anArcPoints[indArcPt * 2];
1017 myParams[aParamPos + 1].val = anArcPoints[indArcPt * 2 + 1];
1021 // Create list of constraints to generate fillet
1023 std::vector<Slvs_hConstraint> aConstrList;
1024 bool isExists = myConstraintMap.find(theConstraint) != myConstraintMap.end(); // constraint already exists
1025 std::vector<Slvs_hConstraint>::iterator aCMapIter =
1026 isExists ? myConstraintMap[theConstraint].begin() : aConstrList.begin();
1027 std::vector<Slvs_hConstraint>::iterator aCMapEnd =
1028 isExists ? myConstraintMap[theConstraint].end() : aConstrList.end();
1029 int aCurConstrPos = isExists ? Search(*aCMapIter, myConstraints) : 0;
1030 for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
1031 // one point of fillet object should be coincident with the point on base, non-coincident with another base object
1032 aPtInd = 1-aBaseCoincInd[indEnt]+aShift[indEnt]; // (1-aBaseCoincInd[indEnt]) = index of non-coincident point, aShift is used to process all types of shapes
1033 Slvs_hEntity aPtBase = myEntities[aBaseObjInd[indEnt]].point[aPtInd];
1034 Slvs_hEntity aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
1036 myConstraints[aCurConstrPos].ptA = aPtBase;
1037 myConstraints[aCurConstrPos].ptB = aPtFillet;
1039 aCurConstrPos = Search(*aCMapIter, myConstraints);
1040 } else if (addCoincidentPoints(aPtBase, aPtFillet)) { // the points are not connected by coincidence yet
1041 Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
1042 ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
1043 0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
1044 myConstraints.push_back(aCoincConstr);
1045 aConstrList.push_back(aCoincConstr.h);
1048 // another point of fillet object should be placed on the base object
1049 Slvs_Constraint aPonCurveConstr;
1051 if (myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE) {
1052 // centers of arcs should be coincident
1053 aPtBase = myEntities[aBaseObjInd[indEnt]].point[0];
1054 aPtFillet = myEntities[aFilletObjInd[indEnt]].point[0];
1056 myConstraints[aCurConstrPos].ptA = aPtBase;
1057 myConstraints[aCurConstrPos].ptB = aPtFillet;
1059 if (aCMapIter != aCMapEnd)
1060 aCurConstrPos = Search(*aCMapIter, myConstraints);
1061 } else if (addCoincidentPoints(aPtBase, aPtFillet)) { // the points are not connected by coincidence yet
1062 aPonCurveConstr = Slvs_MakeConstraint(
1063 ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
1064 0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
1066 aPtFillet = myEntities[aFilletObjInd[indEnt]].point[1+aBaseCoincInd[indEnt]]; // !!! will be used below
1067 aTangentType = SLVS_C_CURVE_CURVE_TANGENT;
1069 aPtInd = aBaseCoincInd[indEnt];
1070 aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
1072 myConstraints[aCurConstrPos].ptA = aPtFillet;
1074 if (aCMapIter != aCMapEnd)
1075 aCurConstrPos = Search(*aCMapIter, myConstraints);
1077 aPonCurveConstr = Slvs_MakeConstraint(
1078 ++myConstrMaxID, myID, SLVS_C_PT_ON_LINE, myWorkplane.h,
1079 0, aPtFillet, SLVS_E_UNKNOWN, aBaseObject[indEnt], SLVS_E_UNKNOWN);
1081 aTangentType = SLVS_C_ARC_LINE_TANGENT;
1084 myConstraints.push_back(aPonCurveConstr);
1085 aConstrList.push_back(aPonCurveConstr.h);
1090 myConstraintMap[theConstraint] = aConstrList;
1092 // Additional temporary constraints for base objects to be fixed
1094 for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
1095 if (!aBaseFeature[indAttr]) {
1096 AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1097 aConstrData->attribute(aConstraintAttributes[indAttr]));
1098 addTemporaryConstraintWhereDragged(aConstrAttr->attr());
1101 if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Line::ID()) {
1102 addTemporaryConstraintWhereDragged(
1103 aBaseFeature[indAttr]->attribute(SketchPlugin_Line::START_ID()));
1104 addTemporaryConstraintWhereDragged(
1105 aBaseFeature[indAttr]->attribute(SketchPlugin_Line::END_ID()));
1106 } else if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Arc::ID()) {
1107 // Arc should be fixed by its center only (to avoid "conflicting constraints" message)
1108 // If the fillet is made on two arc, the shared point should be fixed too
1110 addTemporaryConstraintWhereDragged(
1111 aBaseFeature[indAttr]->attribute(SketchPlugin_Arc::CENTER_ID()));
1115 addTemporaryConstraintWhereDragged(aBaseCoincInd[0] == 0 ?
1116 aBaseFeature[0]->attribute(SketchPlugin_Arc::START_ID()) :
1117 aBaseFeature[0]->attribute(SketchPlugin_Arc::END_ID()));
1122 // ============================================================================
1123 // Function: changeEntity
1124 // Class: SketchSolver_ConstraintGroup
1125 // Purpose: create/update the element affected by any constraint
1126 // ============================================================================
1127 Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
1128 std::shared_ptr<ModelAPI_Attribute> theEntity)
1130 // If the entity is already in the group, try to find it
1131 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
1132 myEntityAttrMap.find(theEntity);
1134 std::vector<Slvs_Param>::iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise
1135 if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
1136 aParamIter = myParams.end();
1137 else { // the entity already exists
1138 aEntPos = Search(aEntIter->second, myEntities);
1139 int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
1140 aParamIter = myParams.begin() + aParamPos;
1142 const bool isEntExists = (aEntIter != myEntityAttrMap.end()); // defines that the entity already exists
1143 const bool isNeedToSolve = myNeedToSolve;
1144 myNeedToSolve = false;
1147 // Verify that the entity is not used by "Rigid" constraint.
1148 // If it is used, the object should not move.
1149 std::vector<std::set<Slvs_hEntity> >::iterator aCoincIter = myCoincidentPoints.begin();
1150 for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
1151 if (aCoincIter->find(aEntIter->second) != aCoincIter->end())
1153 std::set<Slvs_hEntity> aCoincident;
1154 if (aCoincIter != myCoincidentPoints.end()) {
1155 aCoincident = *aCoincIter;
1156 aCoincident.erase(aEntIter->second);
1158 std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1159 for (; aConstrIter != myConstraints.end(); aConstrIter++)
1160 if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
1161 aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
1162 myNeedToSolve = true;
1163 return aEntIter->second;
1168 // Look over supported types of entities
1169 Slvs_Entity aNewEntity;
1170 aNewEntity.h = SLVS_E_UNKNOWN;
1173 std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1176 Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
1177 Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
1178 Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
1179 if (!isEntExists) // New entity
1180 aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
1182 // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
1183 if (myWorkplane.h == SLVS_E_UNKNOWN)
1184 return SLVS_E_UNKNOWN;
1187 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
1188 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
1190 Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
1191 Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
1192 if (!isEntExists) // New entity
1193 aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
1195 // Scalar value (used for the distance entities)
1196 AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
1198 Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
1199 if (!isEntExists) // New entity
1200 aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
1204 /// \todo Other types of entities
1206 Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type
1209 myNeedToSolve = myNeedToSolve || isNeedToSolve;
1210 aResult = aEntIter->second;
1211 } else if (aNewEntity.h != SLVS_E_UNKNOWN) {
1212 myEntities.push_back(aNewEntity);
1213 myEntOfConstr.push_back(false);
1214 myEntityAttrMap[theEntity] = aNewEntity.h;
1215 aResult = aNewEntity.h;
1218 // If the attribute was changed by the user, we need to fix it before solving
1219 if (myNeedToSolve && theEntity->isImmutable())
1220 addTemporaryConstraintWhereDragged(theEntity, false);
1225 // ============================================================================
1226 // Function: changeEntity
1227 // Class: SketchSolver_ConstraintGroup
1228 // Purpose: create/update the element defined by the feature affected by any constraint
1229 // ============================================================================
1230 Slvs_hEntity SketchSolver_ConstraintGroup::changeEntityFeature(FeaturePtr theEntity)
1232 if (!theEntity->data()->isValid())
1233 return SLVS_E_UNKNOWN;
1234 // If the entity is already in the group, try to find it
1235 std::map<FeaturePtr, Slvs_hEntity>::const_iterator aEntIter = myEntityFeatMap.find(theEntity);
1236 // defines that the entity already exists
1237 const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
1239 Slvs_Entity aNewEntity;
1240 aNewEntity.h = SLVS_E_UNKNOWN;
1242 // SketchPlugin features
1243 std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
1244 SketchPlugin_Feature>(theEntity);
1245 if (aFeature) { // Verify the feature by its kind
1246 const std::string& aFeatureKind = aFeature->getKind();
1247 AttributePtr anAttribute;
1250 if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
1251 anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
1252 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1253 Slvs_hEntity aStart = changeEntity(anAttribute);
1255 anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
1256 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1257 Slvs_hEntity aEnd = changeEntity(anAttribute);
1259 if (!isEntExists) // New entity
1260 aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
1263 else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
1264 anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
1265 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1266 Slvs_hEntity aCenter = changeEntity(anAttribute);
1268 anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
1269 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1270 Slvs_hEntity aRadius = changeEntity(anAttribute);
1272 if (!isEntExists) // New entity
1273 aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter,
1274 myWorkplane.normal, aRadius);
1277 else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
1278 anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
1279 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1280 Slvs_hEntity aCenter = changeEntity(anAttribute);
1282 anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
1283 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1284 Slvs_hEntity aStart = changeEntity(anAttribute);
1286 anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
1287 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1288 Slvs_hEntity aEnd = changeEntity(anAttribute);
1291 aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h,
1292 myWorkplane.normal, aCenter, aStart, aEnd);
1294 // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
1295 else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) {
1296 anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
1297 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
1298 Slvs_hEntity aPoint = changeEntity(anAttribute);
1301 return aEntIter->second;
1303 // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
1304 myEntityFeatMap[theEntity] = aPoint;
1305 myNeedToSolve = true;
1309 /// \todo Other types of features
1312 return aEntIter->second;
1314 if (aNewEntity.h != SLVS_E_UNKNOWN) {
1315 myEntities.push_back(aNewEntity);
1316 myEntOfConstr.push_back(false);
1317 myEntityFeatMap[theEntity] = aNewEntity.h;
1318 myNeedToSolve = true;
1319 return aNewEntity.h;
1322 // Unsupported or wrong entity type
1323 return SLVS_E_UNKNOWN;
1326 // ============================================================================
1327 // Function: changeNormal
1328 // Class: SketchSolver_ConstraintGroup
1329 // Purpose: create/update the normal of workplane
1330 // ============================================================================
1331 Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal(
1332 std::shared_ptr<ModelAPI_Attribute> theDirX,
1333 std::shared_ptr<ModelAPI_Attribute> theNorm)
1335 std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNorm);
1336 std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
1337 if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance))
1338 return SLVS_E_UNKNOWN;
1339 // calculate Y direction
1340 std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
1342 // quaternion parameters of normal vector
1343 double qw, qx, qy, qz;
1344 Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
1346 double aNormCoord[4] = { qw, qx, qy, qz };
1348 // Try to find existent normal
1349 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
1350 myEntityAttrMap.find(theNorm);
1351 std::vector<Slvs_Param>::iterator aParamIter; // looks to the first parameter of already existent entity or to the end of vector otherwise
1352 if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
1353 aParamIter = myParams.end();
1354 else { // the entity already exists, update it
1355 int aEntPos = Search(aEntIter->second, myEntities);
1356 int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
1357 aParamIter = myParams.begin() + aParamPos;
1360 // Change parameters of the normal
1361 Slvs_hParam aNormParams[4];
1362 for (int i = 0; i < 4; i++)
1363 aNormParams[i] = changeParameter(aNormCoord[i], aParamIter);
1365 if (aEntIter != myEntityAttrMap.end()) // the entity already exists
1366 return aEntIter->second;
1369 Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, aNormParams[0], aNormParams[1],
1370 aNormParams[2], aNormParams[3]);
1371 myEntities.push_back(aNormal);
1372 myEntOfConstr.push_back(false);
1373 myEntityAttrMap[theNorm] = aNormal.h;
1377 // ============================================================================
1378 // Function: addWorkplane
1379 // Class: SketchSolver_ConstraintGroup
1380 // Purpose: create workplane for the group
1381 // ============================================================================
1382 bool SketchSolver_ConstraintGroup::addWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch)
1384 if (myWorkplane.h || theSketch->getKind().compare(SketchPlugin_Sketch::ID()) != 0)
1385 return false; // the workplane already exists or the function parameter is not Sketch
1387 mySketch = theSketch;
1392 // ============================================================================
1393 // Function: updateWorkplane
1394 // Class: SketchSolver_ConstraintGroup
1395 // Purpose: update parameters of workplane
1396 // ============================================================================
1397 bool SketchSolver_ConstraintGroup::updateWorkplane()
1399 if (!mySketch->data())
1400 return false; // case sketch is deleted
1401 // Get parameters of workplane
1402 std::shared_ptr<ModelAPI_Attribute> aDirX = mySketch->data()->attribute(
1403 SketchPlugin_Sketch::DIRX_ID());
1404 std::shared_ptr<ModelAPI_Attribute> aNorm = mySketch->data()->attribute(
1405 SketchPlugin_Sketch::NORM_ID());
1406 std::shared_ptr<ModelAPI_Attribute> anOrigin = mySketch->data()->attribute(
1407 SketchPlugin_Sketch::ORIGIN_ID());
1408 // Transform them into SolveSpace format
1409 Slvs_hEntity aNormalWP = changeNormal(aDirX, aNorm);
1412 Slvs_hEntity anOriginWP = changeEntity(anOrigin);
1416 if (!myWorkplane.h) {
1418 myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
1419 // Workplane should be added to the list of entities
1420 myEntities.push_back(myWorkplane);
1421 myEntOfConstr.push_back(false);
1426 // ============================================================================
1427 // Function: changeParameter
1428 // Class: SketchSolver_ConstraintGroup
1429 // Purpose: create/update value of parameter
1430 // ============================================================================
1431 Slvs_hParam SketchSolver_ConstraintGroup::changeParameter(
1432 double theParam, std::vector<Slvs_Param>::iterator& thePrmIter)
1434 if (thePrmIter != myParams.end()) { // Parameter should be updated
1435 int aParamPos = thePrmIter - myParams.begin();
1436 if (fabs(thePrmIter->val - theParam) > tolerance) {
1437 myNeedToSolve = true; // parameter is changed, need to resolve constraints
1438 myParams[aParamPos].val = theParam;
1441 return myParams[aParamPos].h;
1444 // Newly created parameter
1445 Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
1446 myParams.push_back(aParam);
1447 myNeedToSolve = true;
1448 // The list of parameters is changed, move iterator to the end of the list to avoid problems
1449 thePrmIter = myParams.end();
1453 // ============================================================================
1454 // Function: resolveConstraints
1455 // Class: SketchSolver_ConstraintGroup
1456 // Purpose: solve the set of constraints for the current group
1457 // ============================================================================
1458 bool SketchSolver_ConstraintGroup::resolveConstraints()
1463 myConstrSolver.setGroupID(myID);
1464 myConstrSolver.setParameters(myParams);
1465 myConstrSolver.setEntities(myEntities);
1466 myConstrSolver.setConstraints(myConstraints);
1467 myConstrSolver.setDraggedParameters(myTempPointWhereDragged);
1469 int aResult = myConstrSolver.solve();
1470 if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes
1471 // Obtain result into the same list of parameters
1472 if (!myConstrSolver.getResult(myParams))
1475 // We should go through the attributes map, because only attributes have valued parameters
1476 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntIter =
1477 myEntityAttrMap.begin();
1478 for (; anEntIter != myEntityAttrMap.end(); anEntIter++) {
1479 if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
1480 anEntIter->first->owner()->data()->blockSendAttributeUpdated(true);
1481 if (updateAttribute(anEntIter->first, anEntIter->second))
1482 updateRelatedConstraints(anEntIter->first);
1484 updateFilletConstraints();
1485 // unblock all features then
1486 for (anEntIter = myEntityAttrMap.begin(); anEntIter != myEntityAttrMap.end(); anEntIter++) {
1487 if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
1488 anEntIter->first->owner()->data()->blockSendAttributeUpdated(false);
1490 } else if (!myConstraints.empty())
1491 Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
1493 removeTemporaryConstraints();
1494 myNeedToSolve = false;
1498 // ============================================================================
1499 // Function: mergeGroups
1500 // Class: SketchSolver_ConstraintGroup
1501 // Purpose: append specified group to the current group
1502 // ============================================================================
1503 void SketchSolver_ConstraintGroup::mergeGroups(const SketchSolver_ConstraintGroup& theGroup)
1505 // If specified group is empty, no need to merge
1506 if (theGroup.myConstraintMap.empty())
1509 // Map between old and new indexes of SolveSpace constraints
1510 std::map<Slvs_hConstraint, Slvs_hConstraint> aConstrMap;
1512 // Add all constraints from theGroup to the current group
1513 ConstraintMap::const_iterator aConstrIter = theGroup.myConstraintMap.begin();
1514 for (; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++)
1515 if (changeConstraint(aConstrIter->first))
1516 aConstrMap[aConstrIter->second.back()] = myConstrMaxID; // the constraint was added => store its ID
1518 // Add temporary constraints from theGroup
1519 std::list<Slvs_hConstraint>::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin();
1520 for (; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++) {
1521 std::map<Slvs_hConstraint, Slvs_hConstraint>::iterator aFind = aConstrMap.find(
1523 if (aFind != aConstrMap.end())
1524 myTempConstraints.push_back(aFind->second);
1527 if (myTempPointWhereDragged.empty())
1528 myTempPointWhereDragged = theGroup.myTempPointWhereDragged;
1529 else if (!theGroup.myTempPointWhereDragged.empty()) { // Need to create additional transient constraint
1530 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aFeatureIter =
1531 theGroup.myEntityAttrMap.begin();
1532 for (; aFeatureIter != theGroup.myEntityAttrMap.end(); aFeatureIter++)
1533 if (aFeatureIter->second == myTempPointWDrgdID) {
1534 addTemporaryConstraintWhereDragged(aFeatureIter->first);
1539 myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve;
1542 // ============================================================================
1543 // Function: splitGroup
1544 // Class: SketchSolver_ConstraintGroup
1545 // Purpose: divide the group into several subgroups
1546 // ============================================================================
1547 void SketchSolver_ConstraintGroup::splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts)
1549 // Divide constraints and entities into several groups
1550 std::vector<std::set<Slvs_hEntity> > aGroupsEntities;
1551 std::vector<std::set<Slvs_hConstraint> > aGroupsConstr;
1552 int aMaxNbEntities = 0; // index of the group with maximal nuber of elements (this group will be left in the current)
1553 std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1554 for (; aConstrIter != myConstraints.end(); aConstrIter++) {
1555 Slvs_hEntity aConstrEnt[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA,
1556 aConstrIter->entityB };
1557 std::vector<int> anIndexes;
1558 // Go through the groupped entities and find even one of entities of current constraint
1559 std::vector<std::set<Slvs_hEntity> >::iterator aGrEntIter;
1560 for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++) {
1561 bool isFound = false;
1562 for (int i = 0; i < 4 && !isFound; i++)
1563 if (aConstrEnt[i] != 0) {
1564 isFound = (aGrEntIter->find(aConstrEnt[i]) != aGrEntIter->end());
1565 // Also we need to check sub-entities
1566 int aEntPos = Search(aConstrEnt[i], myEntities);
1567 if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
1568 Slvs_hEntity* aSub = myEntities[aEntPos].point;
1569 for (int j = 0; *aSub != 0 && j < 4 && !isFound; aSub++, j++)
1570 isFound = (aGrEntIter->find(*aSub) != aGrEntIter->end());
1574 anIndexes.push_back(aGrEntIter - aGroupsEntities.begin());
1576 // Add new group if no one is found
1577 if (anIndexes.empty()) {
1578 std::set<Slvs_hEntity> aNewGrEnt;
1579 for (int i = 0; i < 4; i++)
1580 if (aConstrEnt[i] != 0) {
1581 aNewGrEnt.insert(aConstrEnt[i]);
1582 int aEntPos = Search(aConstrEnt[i], myEntities);
1583 if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
1584 Slvs_hEntity* aSub = myEntities[aEntPos].point;
1585 for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
1586 aNewGrEnt.insert(*aSub);
1589 std::set<Slvs_hConstraint> aNewGrConstr;
1590 aNewGrConstr.insert(aConstrIter->h);
1592 aGroupsEntities.push_back(aNewGrEnt);
1593 aGroupsConstr.push_back(aNewGrConstr);
1594 if (aNewGrEnt.size() > aGroupsEntities[aMaxNbEntities].size())
1595 aMaxNbEntities = aGroupsEntities.size() - 1;
1596 } else { // Add entities indexes into the found group
1597 aGrEntIter = aGroupsEntities.begin() + anIndexes.front();
1598 for (int i = 0; i < 4; i++)
1599 if (aConstrEnt[i] != 0) {
1600 aGrEntIter->insert(aConstrEnt[i]);
1601 int aEntPos = Search(aConstrEnt[i], myEntities);
1602 if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
1603 Slvs_hEntity* aSub = myEntities[aEntPos].point;
1604 for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
1605 aGrEntIter->insert(*aSub);
1608 aGroupsConstr[anIndexes.front()].insert(aConstrIter->h);
1609 if (aGrEntIter->size() > aGroupsEntities[aMaxNbEntities].size())
1610 aMaxNbEntities = aGrEntIter - aGroupsEntities.begin();
1611 if (anIndexes.size() > 1) { // There are found several connected groups, merge them
1612 std::vector<std::set<Slvs_hEntity> >::iterator aFirstGroup = aGroupsEntities.begin()
1613 + anIndexes.front();
1614 std::vector<std::set<Slvs_hConstraint> >::iterator aFirstConstr = aGroupsConstr.begin()
1615 + anIndexes.front();
1616 std::vector<int>::iterator anInd = anIndexes.begin();
1617 for (++anInd; anInd != anIndexes.end(); anInd++) {
1618 aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end());
1619 aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end());
1621 if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size())
1622 aMaxNbEntities = anIndexes.front();
1623 // Remove merged groups
1624 for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--) {
1625 aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd));
1626 aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd));
1632 if (aGroupsEntities.size() <= 1)
1635 // Remove the group with maximum elements as it will be left in the current group
1636 aGroupsEntities.erase(aGroupsEntities.begin() + aMaxNbEntities);
1637 aGroupsConstr.erase(aGroupsConstr.begin() + aMaxNbEntities);
1639 // Add new groups of constraints and divide current group
1640 std::vector<SketchSolver_ConstraintGroup*> aNewGroups;
1641 for (int i = aGroupsEntities.size(); i > 0; i--) {
1642 SketchSolver_ConstraintGroup* aG = new SketchSolver_ConstraintGroup(mySketch);
1643 aNewGroups.push_back(aG);
1645 ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.begin();
1646 int aConstrMapPos = 0; // position of iterator in the map (used to restore iterator after removing constraint)
1647 while (aConstrMapIter != myConstraintMap.end()) {
1648 std::vector<std::set<Slvs_hConstraint> >::const_iterator aGIter = aGroupsConstr.begin();
1649 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroup = aNewGroups.begin();
1650 for (; aGIter != aGroupsConstr.end(); aGIter++, aGroup++)
1651 if (aGIter->find(aConstrMapIter->second.front()) != aGIter->end()) {
1652 (*aGroup)->changeConstraint(aConstrMapIter->first);
1653 removeConstraint(aConstrMapIter->first);
1655 aConstrMapIter = myConstraintMap.begin();
1656 for (int i = 0; i < aConstrMapPos; i++)
1660 if (aGIter == aGroupsConstr.end()) {
1666 theCuts.insert(theCuts.end(), aNewGroups.begin(), aNewGroups.end());
1669 // ============================================================================
1670 // Function: updateGroup
1671 // Class: SketchSolver_ConstraintGroup
1672 // Purpose: search removed entities and constraints
1673 // ============================================================================
1674 bool SketchSolver_ConstraintGroup::updateGroup()
1676 ConstraintMap::reverse_iterator aConstrIter = myConstraintMap.rbegin();
1677 bool isAllValid = true;
1678 bool isCCRemoved = false; // indicates that at least one of coincidence constraints was removed
1679 int aConstrIndex = 0;
1680 while (/*isAllValid && */aConstrIter != myConstraintMap.rend()) {
1681 if (!aConstrIter->first->data() || !aConstrIter->first->data()->isValid()) {
1682 if (aConstrIter->first->getKind().compare(SketchPlugin_ConstraintCoincidence::ID()) == 0)
1684 removeConstraint(aConstrIter->first);
1686 // Get back the correct position of iterator after the "remove" operation
1687 aConstrIter = myConstraintMap.rbegin();
1688 for (int i = 0; i < aConstrIndex && aConstrIter != myConstraintMap.rend(); i++)
1696 // Check if some entities are invalid too
1697 std::set<Slvs_hEntity> anEntToRemove;
1698 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
1699 anAttrIter = myEntityAttrMap.begin();
1700 while (anAttrIter != myEntityAttrMap.end()) {
1701 if (!anAttrIter->first->owner() || !anAttrIter->first->owner()->data() ||
1702 !anAttrIter->first->owner()->data()->isValid()) {
1703 anEntToRemove.insert(anAttrIter->second);
1704 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
1705 aRemovedIter = anAttrIter;
1707 myEntityAttrMap.erase(aRemovedIter);
1711 std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myEntityFeatMap.begin();
1712 while (aFeatIter != myEntityFeatMap.end()) {
1713 if (!aFeatIter->first || !aFeatIter->first->data() ||
1714 !aFeatIter->first->data()->isValid()) {
1715 anEntToRemove.insert(aFeatIter->second);
1716 std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = aFeatIter;
1718 myEntityFeatMap.erase(aRemovedIter);
1722 removeEntitiesById(anEntToRemove);
1724 // Probably, need to update coincidence constraints
1725 if (isCCRemoved && !myExtraCoincidence.empty()) {
1726 // Make a copy, because the new list of unused constrtaints will be generated
1727 std::set<std::shared_ptr<SketchPlugin_Constraint> > anExtraCopy = myExtraCoincidence;
1728 myExtraCoincidence.clear();
1730 std::set<std::shared_ptr<SketchPlugin_Constraint> >::iterator aCIter = anExtraCopy.begin();
1731 for (; aCIter != anExtraCopy.end(); aCIter++)
1732 if ((*aCIter)->data() && (*aCIter)->data()->isValid())
1733 changeConstraint(*aCIter);
1739 // ============================================================================
1740 // Function: updateAttribute
1741 // Class: SketchSolver_ConstraintGroup
1742 // Purpose: update features of sketch after resolving constraints
1743 // ============================================================================
1744 bool SketchSolver_ConstraintGroup::updateAttribute(
1745 std::shared_ptr<ModelAPI_Attribute> theAttribute, const Slvs_hEntity& theEntityID)
1747 // Search the position of the first parameter of the entity
1748 int anEntPos = Search(theEntityID, myEntities);
1749 int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
1751 // Look over supported types of entities
1754 std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1757 if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance
1758 || fabs(aPoint->y() - myParams[aFirstParamPos + 1].val) > tolerance
1759 || fabs(aPoint->z() - myParams[aFirstParamPos + 2].val) > tolerance) {
1760 aPoint->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val,
1761 myParams[aFirstParamPos + 2].val);
1768 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
1769 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
1771 if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance
1772 || fabs(aPoint2D->y() - myParams[aFirstParamPos + 1].val) > tolerance) {
1773 aPoint2D->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val);
1780 AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
1782 if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance) {
1783 aScalar->setValue(myParams[aFirstParamPos].val);
1789 /// \todo Support other types of entities
1793 // ============================================================================
1794 // Function: updateEntityIfPossible
1795 // Class: SketchSolver_ConstraintGroup
1796 // Purpose: search the entity in this group and update it
1797 // ============================================================================
1798 void SketchSolver_ConstraintGroup::updateEntityIfPossible(
1799 std::shared_ptr<ModelAPI_Attribute> theEntity)
1801 if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) {
1802 // If the attribute is a point and it is changed (the group needs to rebuild),
1803 // probably user has dragged this point into this position,
1804 // so it is necessary to add constraint which will guarantee the point will not change
1806 // Store myNeedToSolve flag to verify the entity is really changed
1807 bool aNeedToSolveCopy = myNeedToSolve;
1808 myNeedToSolve = false;
1810 changeEntity(theEntity);
1812 if (myNeedToSolve) // the entity is changed
1814 // Verify the entity is a point and add temporary constraint of permanency
1815 std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1817 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D = std::dynamic_pointer_cast<
1818 GeomDataAPI_Point2D>(theEntity);
1819 if (aPoint || aPoint2D)
1820 addTemporaryConstraintWhereDragged(theEntity);
1823 // Restore flag of changes
1824 myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
1827 updateRelatedConstraints(theEntity);
1831 // ============================================================================
1832 // Function: addTemporaryConstraintWhereDragged
1833 // Class: SketchSolver_ConstraintGroup
1834 // Purpose: add transient constraint SLVS_C_WHERE_DRAGGED for the entity,
1835 // which was moved by user
1836 // ============================================================================
1837 void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged(
1838 std::shared_ptr<ModelAPI_Attribute> theEntity,
1841 // Find identifier of the entity
1842 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
1843 myEntityAttrMap.find(theEntity);
1844 if (anEntIter == myEntityAttrMap.end())
1847 // Get identifiers of all dragged points
1848 std::set<Slvs_hEntity> aDraggedPntID;
1849 aDraggedPntID.insert(myTempPointWDrgdID);
1850 std::list<Slvs_hConstraint>::const_iterator aTmpCoIter = myTempConstraints.begin();
1851 for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) {
1852 unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
1853 if (aConstrPos < myConstraints.size())
1854 aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
1856 std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1857 for (; aConstrIter != myConstraints.end(); aConstrIter++)
1858 if (aConstrIter->type == SLVS_C_WHERE_DRAGGED)
1859 aDraggedPntID.insert(aConstrIter->ptA);
1860 // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
1861 std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1862 for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) {
1863 if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
1864 continue; // the entity was not found in current set
1866 // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
1867 std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
1868 for (; aDrgIter != aDraggedPntID.end(); aDrgIter++)
1869 if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
1870 return; // the SLVS_C_WHERE_DRAGGED constraint already exists
1872 if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end())
1875 // If this is a first dragged point, its parameters should be placed
1876 // into Slvs_System::dragged field to avoid system inconsistense
1877 if (myTempPointWhereDragged.empty() && theAllowToFit) {
1878 int anEntPos = Search(anEntIter->second, myEntities);
1879 Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
1880 for (int i = 0; i < 4; i++, aDraggedParam++)
1881 if (*aDraggedParam != 0)
1882 myTempPointWhereDragged.push_back(*aDraggedParam);
1883 myTempPointWDrgdID = myEntities[anEntPos].h;
1887 // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
1888 Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
1889 myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
1890 myConstraints.push_back(aWDConstr);
1891 myTempConstraints.push_back(aWDConstr.h);
1894 // ============================================================================
1895 // Function: removeTemporaryConstraints
1896 // Class: SketchSolver_ConstraintGroup
1897 // Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after
1898 // resolving the set of constraints
1899 // ============================================================================
1900 void SketchSolver_ConstraintGroup::removeTemporaryConstraints(
1901 const std::set<Slvs_hConstraint>& theRemoved)
1903 std::list<Slvs_hConstraint>::reverse_iterator aTmpConstrIter;
1904 for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend();
1906 if (!theRemoved.empty() && theRemoved.find(*aTmpConstrIter) == theRemoved.end())
1908 unsigned int aConstrPos = Search(*aTmpConstrIter, myConstraints);
1909 if (aConstrPos >= myConstraints.size())
1911 myConstraints.erase(myConstraints.begin() + aConstrPos);
1913 // If the removing constraint has higher index, decrease the indexer
1914 if (*aTmpConstrIter == myConstrMaxID)
1917 myTempConstraints.clear();
1919 // Clear basic dragged point
1920 myTempPointWhereDragged.clear();
1921 myTempPointWDrgdID = SLVS_E_UNKNOWN;
1924 // ============================================================================
1925 // Function: removeConstraint
1926 // Class: SketchSolver_ConstraintGroup
1927 // Purpose: remove constraint and all unused entities
1928 // ============================================================================
1929 void SketchSolver_ConstraintGroup::removeConstraint(
1930 std::shared_ptr<SketchPlugin_Constraint> theConstraint)
1932 ConstraintMap::iterator anIterToRemove = myConstraintMap.find(theConstraint);
1933 if (anIterToRemove == myConstraintMap.end())
1936 std::vector<Slvs_hConstraint> aCnstrToRemove = anIterToRemove->second;
1937 // Remove constraint from the map
1938 myConstraintMap.erase(anIterToRemove);
1940 std::set<Slvs_hEntity> anEntToRemove;
1942 // Find unused entities
1943 std::vector<Slvs_hConstraint>::iterator aCnstrToRemoveIter = aCnstrToRemove.begin();
1944 for (; aCnstrToRemoveIter != aCnstrToRemove.end(); aCnstrToRemoveIter++) {
1945 int aConstrPos = Search(*aCnstrToRemoveIter, myConstraints);
1946 Slvs_hEntity aCnstEnt[] = { myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB,
1947 myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB };
1948 for (int i = 0; i < 4; i++)
1949 if (aCnstEnt[i] != 0)
1950 anEntToRemove.insert(aCnstEnt[i]);
1951 myConstraints.erase(myConstraints.begin() + aConstrPos);
1952 if (*aCnstrToRemoveIter == myConstrMaxID)
1956 // Find all entities which are based on these unused
1957 std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
1958 for ( ; anEntIter != myEntities.end(); anEntIter++)
1959 if (anEntIter->type == SLVS_E_LINE_SEGMENT || anEntIter->type == SLVS_E_CIRCLE ||
1960 anEntIter->type == SLVS_E_ARC_OF_CIRCLE) {
1961 for (int i = 0; i < 4; i++)
1962 if (anEntToRemove.find(anEntIter->point[i]) != anEntToRemove.end()) {
1963 anEntToRemove.insert(anEntIter->h);
1964 for (int j = 0; j < 4; j++)
1965 if (anEntIter->point[j] != 0)
1966 anEntToRemove.insert(anEntIter->point[j]);
1971 // Find entities used by remaining constraints and remove them from the list to delete
1972 std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1973 for (; aConstrIter != myConstraints.end(); aConstrIter++) {
1974 Slvs_hEntity aEnts[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA, aConstrIter
1976 for (int i = 0; i < 4; i++)
1977 if (aEnts[i] != 0 && anEntToRemove.find(aEnts[i]) != anEntToRemove.end()) {
1978 anEntToRemove.erase(aEnts[i]);
1979 // remove from the list all points of current entity
1980 int aEntPos = Search(aEnts[i], myEntities);
1981 for (int j = 0; j < 4; j++)
1982 if (myEntities[aEntPos].point[j] != 0)
1983 anEntToRemove.erase(myEntities[aEntPos].point[j]);
1987 if (anEntToRemove.empty())
1990 // Remove unused entities
1991 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntAttrIter =
1992 myEntityAttrMap.begin();
1993 while (anEntAttrIter != myEntityAttrMap.end()) {
1994 if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end()) {
1995 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator aRemovedIter =
1998 myEntityAttrMap.erase(aRemovedIter);
2002 std::map<FeaturePtr, Slvs_hEntity>::iterator anEntFeatIter = myEntityFeatMap.begin();
2003 while (anEntFeatIter != myEntityFeatMap.end()) {
2004 if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end()) {
2005 std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = anEntFeatIter;
2007 myEntityFeatMap.erase(aRemovedIter);
2012 removeEntitiesById(anEntToRemove);
2014 if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty())
2015 myCoincidentPoints.clear();
2018 // ============================================================================
2019 // Function: removeEntitiesById
2020 // Class: SketchSolver_ConstraintGroup
2021 // Purpose: Removes specified entities and their parameters
2022 // ============================================================================
2023 void SketchSolver_ConstraintGroup::removeEntitiesById(const std::set<Slvs_hEntity>& theEntities)
2025 std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = theEntities.rbegin();
2026 for (; aRemIter != theEntities.rend(); aRemIter++) {
2027 unsigned int anEntPos = Search(*aRemIter, myEntities);
2028 if (anEntPos >= myEntities.size())
2030 if (myEntities[anEntPos].param[0] != 0) {
2031 unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
2032 if (aParamPos >= myParams.size())
2035 while (myEntities[anEntPos].param[aNbParams] != 0)
2037 if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID)
2038 myParamMaxID -= aNbParams;
2039 myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
2040 if (*aRemIter == myEntityMaxID)
2043 myEntities.erase(myEntities.begin() + anEntPos);
2044 myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos);
2046 // Remove entity's ID from the lists of conincident points
2047 std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
2048 for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
2049 aCoPtIter->erase(*aRemIter);
2053 // ============================================================================
2054 // Function: addCoincidentPoints
2055 // Class: SketchSolver_ConstraintGroup
2056 // Purpose: add coincident point the appropriate list of such points
2057 // ============================================================================
2058 bool SketchSolver_ConstraintGroup::addCoincidentPoints(const Slvs_hEntity& thePoint1,
2059 const Slvs_hEntity& thePoint2)
2061 std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
2062 std::vector<std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
2063 while (aCoPtIter != myCoincidentPoints.end()) {
2064 bool isFound[2] = { // indicate which point ID was already in coincidence constraint
2065 aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2)
2066 != aCoPtIter->end(), };
2067 if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need additional one
2069 if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) {
2070 if (aFirstFound != myCoincidentPoints.end()) { // there are two groups of coincident points connected by created constraint => merge them
2071 int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
2072 int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
2073 aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
2074 myCoincidentPoints.erase(aCoPtIter);
2075 aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
2076 aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
2079 aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
2080 aFirstFound = aCoPtIter;
2085 // No points were found, need to create new set
2086 if (aFirstFound == myCoincidentPoints.end()) {
2087 std::set<Slvs_hEntity> aNewSet;
2088 aNewSet.insert(thePoint1);
2089 aNewSet.insert(thePoint2);
2090 myCoincidentPoints.push_back(aNewSet);
2096 // ============================================================================
2097 // Function: updateRelatedConstraints
2098 // Class: SketchSolver_ConstraintGroup
2099 // Purpose: emit the signal to update constraints
2100 // ============================================================================
2101 void SketchSolver_ConstraintGroup::updateRelatedConstraints(
2102 std::shared_ptr<ModelAPI_Attribute> theEntity) const
2104 ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
2105 for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
2106 std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
2107 ->attributes(std::string());
2109 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
2110 for (; anAttrIter != anAttributes.end(); anAttrIter++) {
2111 bool isUpd = (*anAttrIter == theEntity);
2112 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
2113 ModelAPI_AttributeRefAttr>(*anAttrIter);
2114 if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
2118 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
2119 ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
2126 void SketchSolver_ConstraintGroup::updateRelatedConstraintsFeature(
2127 std::shared_ptr<ModelAPI_Feature> theFeature) const
2129 ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
2130 for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
2131 std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
2132 ->attributes(std::string());
2134 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
2135 for (; anAttrIter != anAttributes.end(); anAttrIter++) {
2136 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
2137 ModelAPI_AttributeRefAttr>(*anAttrIter);
2138 if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature) {
2139 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
2140 ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
2147 // ============================================================================
2148 // Function: updateFilletConstraints
2149 // Class: SketchSolver_ConstraintGroup
2150 // Purpose: change fillet arc to be less than 180 degree
2151 // ============================================================================
2152 void SketchSolver_ConstraintGroup::updateFilletConstraints()
2154 ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
2155 for (; aConstrIter != myConstraintMap.end(); aConstrIter++)
2156 if (aConstrIter->first->getKind() == SketchPlugin_ConstraintFillet::ID()) {
2157 AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
2158 aConstrIter->first->data()->attribute(SketchPlugin_ConstraintFillet::ENTITY_C()));
2159 if (!aFilletRefList)
2161 ObjectPtr anArcObj = aFilletRefList->object(2);
2162 std::shared_ptr<GeomDataAPI_Point2D> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
2163 anArcObj->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
2164 std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
2165 anArcObj->data()->attribute(SketchPlugin_Arc::START_ID()));
2166 std::shared_ptr<GeomDataAPI_Point2D> aEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
2167 anArcObj->data()->attribute(SketchPlugin_Arc::END_ID()));
2168 double aCosA = aStart->x() - aCenter->x();
2169 double aSinA = aStart->y() - aCenter->y();
2170 double aCosB = aEnd->x() - aCenter->x();
2171 double aSinB = aEnd->y() - aCenter->y();
2172 if (aCosA * aSinB - aSinA * aCosB <= 0.0) {
2173 anArcObj->data()->blockSendAttributeUpdated(true);
2174 double x = aStart->x();
2175 double y = aStart->y();
2176 aStart->setValue(aEnd->x(), aEnd->y());
2177 aEnd->setValue(x, y);
2178 // Update constraint data
2179 changeFilletConstraint(aConstrIter->first);
2180 anArcObj->data()->blockSendAttributeUpdated(false);
2185 // ============================================================================
2186 // Function: makeMirrorEntity
2187 // Class: SketchSolver_ConstraintGroup
2188 // Purpose: change entities parameters to make them symmetric relating to the mirror line
2189 // ============================================================================
2190 void SketchSolver_ConstraintGroup::makeMirrorEntity(const Slvs_hEntity& theBase,
2191 const Slvs_hEntity& theMirror,
2192 const Slvs_hEntity& theMirrorLine)
2194 Slvs_Entity aBase = myEntities[Search(theBase, myEntities)];
2195 Slvs_Entity aMirror = myEntities[Search(theMirror, myEntities)];
2197 if (aBase.type != SLVS_E_ARC_OF_CIRCLE) {
2198 while (aBase.point[i] != 0 && aMirror.point[i] != 0) {
2199 makeMirrorEntity(aBase.point[i], aMirror.point[i], theMirrorLine);
2203 // swap mirroring first and last points of an arc
2204 makeMirrorEntity(aBase.point[0], aMirror.point[0], theMirrorLine);
2205 makeMirrorEntity(aBase.point[1], aMirror.point[2], theMirrorLine);
2206 makeMirrorEntity(aBase.point[2], aMirror.point[1], theMirrorLine);
2208 if (aBase.param[0] != 0 && aMirror.param[0] != 0) { // this is a point, copy it
2209 Slvs_Entity aMirrorLine = myEntities[Search(theMirrorLine, myEntities)];
2210 std::shared_ptr<GeomAPI_XY> aLinePoints[2];
2211 for (i = 0; i < 2; i++) {
2212 Slvs_Entity aPoint = myEntities[Search(aMirrorLine.point[i], myEntities)];
2213 int aParamPos = Search(aPoint.param[0], myParams);
2214 aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
2215 new GeomAPI_XY(myParams[aParamPos].val, myParams[1+aParamPos].val));
2217 int aBaseParamPos = Search(aBase.param[0], myParams);
2218 int aMirrorParamPos = Search(aMirror.param[0], myParams);
2219 std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(
2220 new GeomAPI_XY(myParams[aBaseParamPos].val, myParams[1+aBaseParamPos].val));
2222 // direction of a mirror line
2223 std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
2224 new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
2225 // orthogonal direction
2226 aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
2228 std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
2229 new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
2230 double aDist = aVec->dot(aDir->xy());
2231 std::shared_ptr<GeomAPI_XY> aMirrorPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
2233 myParams[aMirrorParamPos].val = aMirrorPoint->x();
2234 myParams[1+aMirrorParamPos].val = aMirrorPoint->y();
2238 // ============================================================================
2239 // Function: changeMirrorPoints
2240 // Class: SketchSolver_ConstraintGroup
2241 // Purpose: creates/updates mirror constraint for two points
2242 // ============================================================================
2243 Slvs_hConstraint SketchSolver_ConstraintGroup::changeMirrorPoints(
2244 const Slvs_hEntity& theBasePoint,
2245 const Slvs_hEntity& theMirrorPoint,
2246 const Slvs_hEntity& theMirrorLine,
2247 std::vector<Slvs_Constraint>& thePrevConstr,
2248 std::map<Slvs_hEntity, Slvs_hEntity>& thePrevMirror)
2250 std::map<Slvs_hEntity, Slvs_hEntity>::iterator aMapIter = thePrevMirror.find(theBasePoint);
2251 if (aMapIter != thePrevMirror.end()) {
2252 thePrevMirror.erase(aMapIter);
2253 std::vector<Slvs_Constraint>::iterator anIter = thePrevConstr.begin();
2254 for (; anIter != thePrevConstr.end(); anIter++)
2255 if (anIter->ptA == theBasePoint) {
2256 if (anIter->ptB != theMirrorPoint) {
2257 int aConstrInd = Search(anIter->h, myConstraints);
2258 myConstraints[aConstrInd].ptB = theMirrorPoint;
2259 myConstraints[aConstrInd].entityA = theMirrorLine;
2261 Slvs_hConstraint aResult = anIter->h;
2262 thePrevConstr.erase(anIter);
2267 // Newly created constraint
2268 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
2269 ++myConstrMaxID, myID, SLVS_C_SYMMETRIC_LINE, myWorkplane.h, 0.0,
2270 theBasePoint, theMirrorPoint, theMirrorLine, SLVS_E_UNKNOWN);
2271 myConstraints.push_back(aConstraint);
2272 return aConstraint.h;
2276 // ============================================================================
2277 // Function: calculateMiddlePoint
2278 // Class: SketchSolver_ConstraintGroup
2279 // Purpose: calculates middle point on line or arc
2280 // ============================================================================
2281 void SketchSolver_ConstraintGroup::calculateMiddlePoint(
2282 const Slvs_hEntity& theEntity,
2286 int anInd = Search(theEntity, myEntities);
2287 if (myEntities[anInd].type == SLVS_E_LINE_SEGMENT) {
2289 for (int i = 0; i < 2; i++) {
2290 int aPtPos = Search(myEntities[anInd].point[i], myEntities);
2291 aLineParams[i] = Search(myEntities[aPtPos].param[0], myParams);
2293 theX = 0.5 * (myParams[aLineParams[0]].val + myParams[aLineParams[1]].val);
2294 theY = 0.5 * (myParams[1 + aLineParams[0]].val + myParams[1 + aLineParams[1]].val);
2295 } else if (myEntities[anInd].type == SLVS_E_ARC_OF_CIRCLE) {
2296 double anArcPoint[3][2];
2297 for (int i = 0; i < 3; i++) {
2298 int aPtPos = Search(myEntities[anInd].point[i], myEntities);
2299 int anArcParam = Search(myEntities[aPtPos].param[0], myParams);
2300 anArcPoint[i][0] = myParams[anArcParam].val;
2301 anArcPoint[i][1] = myParams[1 + anArcParam].val;
2303 // project last point of arc on the arc
2304 double x = anArcPoint[1][0] - anArcPoint[0][0];
2305 double y = anArcPoint[1][1] - anArcPoint[0][1];
2306 double aRad = sqrt(x*x + y*y);
2307 x = anArcPoint[2][0] - anArcPoint[0][0];
2308 y = anArcPoint[2][1] - anArcPoint[0][1];
2309 double aNorm = sqrt(x*x + y*y);
2310 if (aNorm >= tolerance) {
2311 anArcPoint[2][0] = anArcPoint[0][0] + x * aRad / aNorm;
2312 anArcPoint[2][1] = anArcPoint[0][1] + y * aRad / aNorm;
2315 x = anArcPoint[1][0] + anArcPoint[2][0] - 2.0 * anArcPoint[0][0];
2316 y = anArcPoint[1][1] + anArcPoint[2][1] - 2.0 * anArcPoint[0][1];
2317 aNorm = sqrt(x*x + y*y);
2318 if (aNorm >= tolerance) {
2321 } else { // obtain orthogonal direction
2322 x = 0.5 * (anArcPoint[2][1] - anArcPoint[1][1]);
2323 y = -0.5 * (anArcPoint[2][0] - anArcPoint[1][0]);
2325 theX = anArcPoint[0][0] + x;
2326 theY = anArcPoint[0][1] + y;
2331 // ========================================================
2332 // ========= Auxiliary functions ===============
2333 // ========================================================
2335 template<typename T>
2336 int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
2338 int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
2339 int aVecSize = theEntities.size();
2340 while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
2342 while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
2344 if (aResIndex == -1)
2345 aResIndex = aVecSize;