1 // File: SketchSolver_ConstraintGroup.cpp
2 // Created: 27 May 2014
3 // Author: Artem ZHIDKOV
5 #include "SketchSolver_ConstraintGroup.h"
7 #include <SketchSolver_Constraint.h>
9 #include <Events_Error.h>
10 #include <Events_Loop.h>
11 #include <GeomDataAPI_Dir.h>
12 #include <GeomDataAPI_Point.h>
13 #include <GeomDataAPI_Point2D.h>
14 #include <ModelAPI_AttributeDouble.h>
15 #include <ModelAPI_AttributeRefList.h>
16 #include <ModelAPI_Document.h>
17 #include <ModelAPI_Events.h>
18 #include <ModelAPI_ResultConstruction.h>
20 #include <SketchPlugin_Constraint.h>
21 #include <SketchPlugin_ConstraintLength.h>
22 #include <SketchPlugin_ConstraintCoincidence.h>
24 #include <SketchPlugin_Arc.h>
25 #include <SketchPlugin_Circle.h>
26 #include <SketchPlugin_Line.h>
27 #include <SketchPlugin_Point.h>
28 #include <SketchPlugin_Sketch.h>
33 /// Tolerance for value of parameters
34 const double tolerance = 1.e-10;
37 * Collects all sketch solver error' codes
38 * as inline static functions
39 * TODO: Move this class into a separate file
41 class SketchSolver_Error {
43 /// The value parameter for the constraint
44 inline static const std::string& CONSTRAINTS()
46 static const std::string MY_ERROR_VALUE("Conflicting constraints");
47 return MY_ERROR_VALUE;
51 /// This value is used to give unique index to the groups
52 static Slvs_hGroup myGroupIndexer = 0;
54 /** \brief Search the entity/parameter with specified ID in the list of elements
55 * \param[in] theEntityID unique ID of the element
56 * \param[in] theEntities list of elements
57 * \return position of the found element or -1 if the element is not found
60 static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
63 // ========================================================
64 // ========= SketchSolver_ConstraintGroup ===============
65 // ========================================================
67 SketchSolver_ConstraintGroup::
68 SketchSolver_ConstraintGroup(boost::shared_ptr<SketchPlugin_Feature> theWorkplane)
69 : myID(++myGroupIndexer),
79 myConstraints.clear();
81 myTempConstraints.clear();
82 myTempPointWhereDragged.clear();
83 myTempPointWDrgdID = 0;
85 // Initialize workplane
86 myWorkplane.h = SLVS_E_UNKNOWN;
88 assert(addWorkplane(theWorkplane));
90 addWorkplane(theWorkplane);
94 SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
98 myConstraints.clear();
99 myConstraintMap.clear();
100 myTempConstraints.clear();
101 myTempPointWhereDragged.clear();
103 // If the group with maximal identifier is deleted, decrease the indexer
104 if (myID == myGroupIndexer)
108 // ============================================================================
109 // Function: isBaseWorkplane
110 // Class: SketchSolver_ConstraintGroup
111 // Purpose: verify the group is based on the given workplane
112 // ============================================================================
113 bool SketchSolver_ConstraintGroup::isBaseWorkplane(
114 boost::shared_ptr<SketchPlugin_Feature> theWorkplane) const
116 return theWorkplane == mySketch;
119 // ============================================================================
120 // Function: isInteract
121 // Class: SketchSolver_ConstraintGroup
122 // Purpose: verify are there any entities in the group used by given constraint
123 // ============================================================================
124 bool SketchSolver_ConstraintGroup::isInteract(
125 boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
127 // Check the group is empty
128 if (myWorkplane.h != SLVS_E_UNKNOWN && myConstraints.empty())
131 // Go through constraint entities and verify if some of them already in the group
132 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++)
134 boost::shared_ptr<ModelAPI_AttributeRefAttr> aCAttrRef =
135 boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
136 theConstraint->data()->attribute(SketchPlugin_Constraint::ATTRIBUTE(i))
138 if (!aCAttrRef) continue;
139 if (!aCAttrRef->isObject() &&
140 myEntityAttrMap.find(aCAttrRef->attr()) != myEntityAttrMap.end())
142 if (aCAttrRef->isObject())
143 { // Obtain a base feature for the object
144 ResultConstructionPtr aRC =
145 boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aCAttrRef->object());
147 boost::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
148 FeaturePtr aFeature = aDoc->feature(aRC);
149 if (myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
154 // Entities did not found
158 // ============================================================================
159 // Function: changeConstraint
160 // Class: SketchSolver_ConstraintGroup
161 // Purpose: create/update the constraint in the group
162 // ============================================================================
163 bool SketchSolver_ConstraintGroup::changeConstraint(
164 boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
166 // There is no workplane yet, something wrong
167 if (myWorkplane.h == SLVS_E_UNKNOWN)
170 // Search this constraint in the current group to update it
171 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
172 aConstrMapIter = myConstraintMap.find(theConstraint);
173 std::vector<Slvs_Constraint>::iterator aConstrIter;
174 if (aConstrMapIter != myConstraintMap.end())
176 int aConstrPos = Search(aConstrMapIter->second, myConstraints);
177 aConstrIter = myConstraints.begin() + aConstrPos;
180 // Get constraint type and verify the constraint parameters are correct
181 SketchSolver_Constraint aConstraint(theConstraint);
182 int aConstrType = aConstraint.getType();
183 if (aConstrType == SLVS_C_UNKNOWN ||
184 (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
186 const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
188 // Create constraint parameters
189 double aDistance = 0.0; // scalar value of the constraint
190 AttributeDoublePtr aDistAttr =
191 boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE()));
194 aDistance = aDistAttr->value();
195 // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
196 if (aConstrType == SLVS_C_DIAMETER)
198 if (aConstrMapIter != myConstraintMap.end() && fabs(aConstrIter->valA - aDistance) > tolerance)
200 myNeedToSolve = true;
201 aConstrIter->valA = aDistance;
205 Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
206 for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
208 aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
209 boost::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr =
210 boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
211 theConstraint->data()->attribute(aConstraintAttributes[indAttr])
213 if (!aConstrAttr) continue;
215 // Convert the object of the attribute to the feature
217 if (aConstrAttr->isObject() && aConstrAttr->object())
219 ResultConstructionPtr aRC =
220 boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aConstrAttr->object());
222 boost::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
223 aFeature = aDoc->feature(aRC);
226 // For the length constraint the start and end points of the line should be added to the entities list instead of line
227 if (aConstrType == SLVS_C_PT_PT_DISTANCE && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0)
229 boost::shared_ptr<ModelAPI_Data> aData = aFeature->data();
230 aConstrEnt[indAttr] = changeEntity(aData->attribute(SketchPlugin_Line::START_ID()));
231 aConstrEnt[indAttr+1] = changeEntity(aData->attribute(SketchPlugin_Line::END_ID()));
232 // measured object is added into the map of objects to avoid problems with interaction between constraint and group
233 myEntityFeatMap[aFeature] = 0;
234 break; // there should be no other entities
236 else if (aConstrAttr->isObject())
237 aConstrEnt[indAttr] = changeEntity(aFeature);
239 aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
242 if (aConstrMapIter == myConstraintMap.end())
244 // Several points may be coincident, it is not necessary to store all constraints between them.
245 // Try to find sequence of coincident points which connects the points of new constraint
246 if (aConstrType == SLVS_C_POINTS_COINCIDENT)
248 if (aConstrEnt[0] == aConstrEnt[1]) // no need to add self coincidence
250 if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1]))
252 myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes
257 // Create SolveSpace constraint structure
258 Slvs_Constraint aConstraint =
259 Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h,
260 aDistance, aConstrEnt[0], aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
261 myConstraints.push_back(aConstraint);
262 myConstraintMap[theConstraint] = aConstraint.h;
267 // ============================================================================
268 // Function: changeEntity
269 // Class: SketchSolver_ConstraintGroup
270 // Purpose: create/update the element affected by any constraint
271 // ============================================================================
272 Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
273 boost::shared_ptr<ModelAPI_Attribute> theEntity)
275 // If the entity is already in the group, try to find it
276 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
277 aEntIter = myEntityAttrMap.find(theEntity);
278 std::vector<Slvs_Param>::const_iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise
279 if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
280 aParamIter = myParams.end();
282 { // the entity already exists
283 int aEntPos = Search(aEntIter->second, myEntities);
284 int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
285 aParamIter = myParams.begin() + aParamPos;
287 const bool isEntExists = (aEntIter != myEntityAttrMap.end()); // defines that the entity already exists
289 // Look over supported types of entities
292 boost::shared_ptr<GeomDataAPI_Point> aPoint =
293 boost::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
296 Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
297 Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
298 Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
301 return aEntIter->second;
304 Slvs_Entity aPtEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
305 myEntities.push_back(aPtEntity);
306 myEntityAttrMap[theEntity] = aPtEntity.h;
310 // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
311 if (myWorkplane.h == SLVS_E_UNKNOWN)
312 return SLVS_E_UNKNOWN;
315 boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
316 boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
319 Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
320 Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
323 return aEntIter->second;
326 Slvs_Entity aPt2DEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
327 myEntities.push_back(aPt2DEntity);
328 myEntityAttrMap[theEntity] = aPt2DEntity.h;
329 return aPt2DEntity.h;
332 // Scalar value (used for the distance entities)
333 AttributeDoublePtr aScalar =
334 boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
337 Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
340 return aEntIter->second;
343 Slvs_Entity aDistance = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
344 myEntities.push_back(aDistance);
345 myEntityAttrMap[theEntity] = aDistance.h;
349 /// \todo Other types of entities
351 // Unsupported or wrong entity type
352 return SLVS_E_UNKNOWN;
356 // ============================================================================
357 // Function: changeEntity
358 // Class: SketchSolver_ConstraintGroup
359 // Purpose: create/update the element defined by the feature affected by any constraint
360 // ============================================================================
361 Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
362 FeaturePtr theEntity)
364 // If the entity is already in the group, try to find it
365 std::map<FeaturePtr, Slvs_hEntity>::const_iterator
366 aEntIter = myEntityFeatMap.find(theEntity);
367 // defines that the entity already exists
368 const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
370 // SketchPlugin features
371 boost::shared_ptr<SketchPlugin_Feature> aFeature =
372 boost::dynamic_pointer_cast<SketchPlugin_Feature>(theEntity);
374 { // Verify the feature by its kind
375 const std::string& aFeatureKind = aFeature->getKind();
378 if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0)
380 Slvs_hEntity aStart = changeEntity(aFeature->data()->attribute(SketchPlugin_Line::START_ID()));
381 Slvs_hEntity aEnd = changeEntity(aFeature->data()->attribute(SketchPlugin_Line::END_ID()));
384 return aEntIter->second;
387 Slvs_Entity aLineEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
388 myEntities.push_back(aLineEntity);
389 myEntityFeatMap[theEntity] = aLineEntity.h;
390 return aLineEntity.h;
393 else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0)
395 Slvs_hEntity aCenter = changeEntity(aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID()));
396 Slvs_hEntity aRadius = changeEntity(aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()));
399 return aEntIter->second;
402 Slvs_Entity aCircleEntity =
403 Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter, myWorkplane.normal, aRadius);
404 myEntities.push_back(aCircleEntity);
405 myEntityFeatMap[theEntity] = aCircleEntity.h;
406 return aCircleEntity.h;
409 else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0)
411 Slvs_hEntity aCenter = changeEntity(aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
412 Slvs_hEntity aStart = changeEntity(aFeature->data()->attribute(SketchPlugin_Arc::START_ID()));
413 Slvs_hEntity aEnd = changeEntity(aFeature->data()->attribute(SketchPlugin_Arc::END_ID()));
416 return aEntIter->second;
418 Slvs_Entity anArcEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID,
419 myWorkplane.h, myWorkplane.normal, aCenter, aStart, aEnd);
420 myEntities.push_back(anArcEntity);
421 myEntityFeatMap[theEntity] = anArcEntity.h;
422 return anArcEntity.h;
424 // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
425 else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0)
427 Slvs_hEntity aPoint = changeEntity(aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()));
430 return aEntIter->second;
432 // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
433 myEntityFeatMap[theEntity] = aPoint;
438 /// \todo Other types of features
440 // Unsupported or wrong entity type
441 return SLVS_E_UNKNOWN;
444 // ============================================================================
445 // Function: changeNormal
446 // Class: SketchSolver_ConstraintGroup
447 // Purpose: create/update the normal of workplane
448 // ============================================================================
449 Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal(
450 boost::shared_ptr<ModelAPI_Attribute> theDirX,
451 boost::shared_ptr<ModelAPI_Attribute> theDirY,
452 boost::shared_ptr<ModelAPI_Attribute> theNorm)
454 boost::shared_ptr<GeomDataAPI_Dir> aDirX =
455 boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
456 boost::shared_ptr<GeomDataAPI_Dir> aDirY =
457 boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirY);
458 if (!aDirX || !aDirY ||
459 (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
460 (fabs(aDirY->x()) + fabs(aDirY->y()) + fabs(aDirY->z()) < tolerance))
461 return SLVS_E_UNKNOWN;
463 // quaternion parameters of normal vector
464 double qw, qx, qy, qz;
465 Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(),
466 aDirY->x(), aDirY->y(), aDirY->z(),
468 double aNormCoord[4] = {qw, qx, qy, qz};
470 // Try to find existent normal
471 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
472 aEntIter = myEntityAttrMap.find(theNorm);
473 std::vector<Slvs_Param>::const_iterator aParamIter; // looks to the first parameter of already existent entity or to the end of vector otherwise
474 if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
475 aParamIter = myParams.end();
477 { // the entity already exists, update it
478 int aEntPos = Search(aEntIter->second, myEntities);
479 int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
480 aParamIter = myParams.begin() + aParamPos;
483 // Change parameters of the normal
484 Slvs_hParam aNormParams[4];
485 for (int i = 0; i < 4; i++)
486 aNormParams[i] = changeParameter(aNormCoord[i], aParamIter);
488 if (aEntIter != myEntityAttrMap.end()) // the entity already exists
489 return aEntIter->second;
492 Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID,
493 aNormParams[0], aNormParams[1], aNormParams[2], aNormParams[3]);
494 myEntities.push_back(aNormal);
495 myEntityAttrMap[theNorm] = aNormal.h;
500 // ============================================================================
501 // Function: addWorkplane
502 // Class: SketchSolver_ConstraintGroup
503 // Purpose: create workplane for the group
504 // ============================================================================
505 bool SketchSolver_ConstraintGroup::addWorkplane(
506 boost::shared_ptr<SketchPlugin_Feature> theSketch)
508 if (myWorkplane.h || theSketch->getKind().compare(SketchPlugin_Sketch::ID()) != 0)
509 return false; // the workplane already exists or the function parameter is not Sketch
511 mySketch = theSketch;
516 // ============================================================================
517 // Function: updateWorkplane
518 // Class: SketchSolver_ConstraintGroup
519 // Purpose: update parameters of workplane
520 // ============================================================================
521 bool SketchSolver_ConstraintGroup::updateWorkplane()
523 // Get parameters of workplane
524 boost::shared_ptr<ModelAPI_Attribute> aDirX = mySketch->data()->attribute(SketchPlugin_Sketch::DIRX_ID());
525 boost::shared_ptr<ModelAPI_Attribute> aDirY = mySketch->data()->attribute(SketchPlugin_Sketch::DIRY_ID());
526 boost::shared_ptr<ModelAPI_Attribute> aNorm = mySketch->data()->attribute(SketchPlugin_Sketch::NORM_ID());
527 boost::shared_ptr<ModelAPI_Attribute> anOrigin = mySketch->data()->attribute(SketchPlugin_Sketch::ORIGIN_ID());
528 // Transform them into SolveSpace format
529 Slvs_hEntity aNormalWP = changeNormal(aDirX, aDirY, aNorm);
530 if (!aNormalWP) return false;
531 Slvs_hEntity anOriginWP = changeEntity(anOrigin);
532 if (!anOriginWP) return false;
537 myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
538 // Workplane should be added to the list of entities
539 myEntities.push_back(myWorkplane);
544 // ============================================================================
545 // Function: changeParameter
546 // Class: SketchSolver_ConstraintGroup
547 // Purpose: create/update value of parameter
548 // ============================================================================
549 Slvs_hParam SketchSolver_ConstraintGroup::changeParameter(
550 const double& theParam,
551 std::vector<Slvs_Param>::const_iterator& thePrmIter)
553 if (thePrmIter != myParams.end())
554 { // Parameter should be updated
555 int aParamPos = thePrmIter - myParams.begin();
556 if (fabs(thePrmIter->val - theParam) > tolerance)
558 myNeedToSolve = true; // parameter is changed, need to resolve constraints
559 myParams[aParamPos].val = theParam;
562 return myParams[aParamPos].h;
565 // Newly created parameter
566 Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
567 myParams.push_back(aParam);
568 myNeedToSolve = true;
569 // The list of parameters is changed, move iterator to the end of the list to avoid problems
570 thePrmIter = myParams.end();
574 // ============================================================================
575 // Function: resolveConstraints
576 // Class: SketchSolver_ConstraintGroup
577 // Purpose: solve the set of constraints for the current group
578 // ============================================================================
579 void SketchSolver_ConstraintGroup::resolveConstraints()
584 myConstrSolver.setGroupID(myID);
585 myConstrSolver.setParameters(myParams);
586 myConstrSolver.setEntities(myEntities);
587 myConstrSolver.setConstraints(myConstraints);
588 myConstrSolver.setDraggedParameters(myTempPointWhereDragged);
590 int aResult = myConstrSolver.solve();
591 if (aResult == SLVS_RESULT_OKAY)
592 { // solution succeeded, store results into correspondent attributes
593 // Obtain result into the same list of parameters
594 if (!myConstrSolver.getResult(myParams))
597 // We should go through the attributes map, because only attributes have valued parameters
598 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
599 anEntIter = myEntityAttrMap.begin();
600 for ( ; anEntIter != myEntityAttrMap.end(); anEntIter++)
601 if (updateAttribute(anEntIter->first, anEntIter->second))
602 updateRelatedConstraints(anEntIter->first);
604 else if (!myConstraints.empty())
605 Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
607 removeTemporaryConstraints();
608 myNeedToSolve = false;
611 // ============================================================================
612 // Function: mergeGroups
613 // Class: SketchSolver_ConstraintGroup
614 // Purpose: append specified group to the current group
615 // ============================================================================
616 void SketchSolver_ConstraintGroup::mergeGroups(
617 const SketchSolver_ConstraintGroup& theGroup)
619 // If specified group is empty, no need to merge
620 if (theGroup.myConstraintMap.empty())
623 // Map between old and new indexes of SolveSpace constraints
624 std::map<Slvs_hConstraint, Slvs_hConstraint> aConstrMap;
626 // Add all constraints from theGroup to the current group
627 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
628 aConstrIter = theGroup.myConstraintMap.begin();
629 for ( ; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++)
630 if (changeConstraint(aConstrIter->first))
631 aConstrMap[aConstrIter->second] = myConstrMaxID; // the constraint was added => store its ID
633 // Add temporary constraints from theGroup
634 std::list<Slvs_hConstraint>::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin();
635 for ( ; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++)
637 std::map<Slvs_hConstraint, Slvs_hConstraint>::iterator aFind = aConstrMap.find(*aTempConstrIter);
638 if (aFind != aConstrMap.end())
639 myTempConstraints.push_back(aFind->second);
642 if (myTempPointWhereDragged.empty())
643 myTempPointWhereDragged = theGroup.myTempPointWhereDragged;
644 else if (!theGroup.myTempPointWhereDragged.empty())
645 { // Need to create additional transient constraint
646 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
647 aFeatureIter = theGroup.myEntityAttrMap.begin();
648 for (; aFeatureIter != theGroup.myEntityAttrMap.end(); aFeatureIter++)
649 if (aFeatureIter->second == myTempPointWDrgdID)
651 addTemporaryConstraintWhereDragged(aFeatureIter->first);
656 myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve;
659 // ============================================================================
660 // Function: splitGroup
661 // Class: SketchSolver_ConstraintGroup
662 // Purpose: divide the group into several subgroups
663 // ============================================================================
664 void SketchSolver_ConstraintGroup::splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts)
666 // Divide constraints and entities into several groups
667 std::vector< std::set<Slvs_hEntity> > aGroupsEntities;
668 std::vector< std::set<Slvs_hConstraint> > aGroupsConstr;
669 int aMaxNbEntities = 0; // index of the group with maximal nuber of elements (this group will be left in the current)
670 std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
671 for ( ; aConstrIter != myConstraints.end(); aConstrIter++)
673 Slvs_hEntity aConstrEnt[] = {
674 aConstrIter->ptA, aConstrIter->ptB,
675 aConstrIter->entityA, aConstrIter->entityB};
676 std::vector<int> anIndexes;
677 // Go through the groupped entities and find even one of entities of current constraint
678 std::vector< std::set<Slvs_hEntity> >::iterator aGrEntIter;
679 for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++)
681 bool isFound = false;
682 for (int i = 0; i < 4 && !isFound; i++)
683 if (aConstrEnt[i] != 0)
684 isFound = (aGrEntIter->find(aConstrEnt[i]) != aGrEntIter->end());
686 anIndexes.push_back(aGrEntIter - aGroupsEntities.begin());
688 // Add new group if no one is found
689 if (anIndexes.empty())
691 std::set<Slvs_hEntity> aNewGrEnt;
692 for (int i = 0; i < 4; i++)
693 if (aConstrEnt[i] != 0)
694 aNewGrEnt.insert(aConstrEnt[i]);
695 std::set<Slvs_hConstraint> aNewGrConstr;
696 aNewGrConstr.insert(aConstrIter->h);
698 aGroupsEntities.push_back(aNewGrEnt);
699 aGroupsConstr.push_back(aNewGrConstr);
700 if (aNewGrEnt.size() > aGroupsEntities[aMaxNbEntities].size())
701 aMaxNbEntities = aGroupsEntities.size() - 1;
703 else if (anIndexes.size() == 1)
704 { // Add entities indexes into the found group
705 aGrEntIter = aGroupsEntities.begin() + anIndexes.front();
706 for (int i = 0; i < 4; i++)
707 if (aConstrEnt[i] != 0)
708 aGrEntIter->insert(aConstrEnt[i]);
709 aGroupsConstr[anIndexes.front()].insert(aConstrIter->h);
710 if (aGrEntIter->size() > aGroupsEntities[aMaxNbEntities].size())
711 aMaxNbEntities = aGrEntIter - aGroupsEntities.begin();
714 { // There are found several connected groups, merge them
715 std::vector< std::set<Slvs_hEntity> >::iterator aFirstGroup =
716 aGroupsEntities.begin() + anIndexes.front();
717 std::vector< std::set<Slvs_hConstraint> >::iterator aFirstConstr =
718 aGroupsConstr.begin() + anIndexes.front();
719 std::vector<int>::iterator anInd = anIndexes.begin();
720 for (++anInd; anInd != anIndexes.end(); anInd++)
722 aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end());
723 aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end());
725 if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size())
726 aMaxNbEntities = anIndexes.front();
727 // Remove merged groups
728 for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--)
730 aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd));
731 aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd));
736 if (aGroupsEntities.size() <= 1)
739 // Remove the group with maximum elements as it will be left in the current group
740 aGroupsEntities.erase(aGroupsEntities.begin() + aMaxNbEntities);
741 aGroupsConstr.erase(aGroupsConstr.begin() + aMaxNbEntities);
743 // Add new groups of constraints and divide current group
744 std::vector<SketchSolver_ConstraintGroup*> aNewGroups;
745 for (int i = aGroupsEntities.size(); i > 0; i--)
747 SketchSolver_ConstraintGroup* aG = new SketchSolver_ConstraintGroup(mySketch);
748 aNewGroups.push_back(aG);
750 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
751 aConstrMapIter = myConstraintMap.begin();
752 int aConstrMapPos = 0; // position of iterator in the map (used to restore iterator after removing constraint)
753 while (aConstrMapIter != myConstraintMap.end())
755 std::vector< std::set<Slvs_hConstraint> >::const_iterator aGIter = aGroupsConstr.begin();
756 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroup = aNewGroups.begin();
757 for ( ; aGIter != aGroupsConstr.end(); aGIter++, aGroup++)
758 if (aGIter->find(aConstrMapIter->second) != aGIter->end())
760 (*aGroup)->changeConstraint(aConstrMapIter->first);
761 removeConstraint(aConstrMapIter->first);
763 aConstrMapIter = myConstraintMap.begin();
764 for (int i = 0; i < aConstrMapPos; i++)
768 if (aGIter == aGroupsConstr.end())
775 theCuts.insert(theCuts.end(), aNewGroups.begin(), aNewGroups.end());
778 // ============================================================================
779 // Function: updateGroup
780 // Class: SketchSolver_ConstraintGroup
781 // Purpose: search removed entities and constraints
782 // ============================================================================
783 bool SketchSolver_ConstraintGroup::updateGroup()
785 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::reverse_iterator
786 aConstrIter = myConstraintMap.rbegin();
787 bool isAllValid = true;
788 bool isCCRemoved = false; // indicates that at least one of coincidence constraints was removed
789 while (isAllValid && aConstrIter != myConstraintMap.rend())
791 if (!aConstrIter->first->data()->isValid())
793 if (aConstrIter->first->getKind().compare(SketchPlugin_ConstraintCoincidence::ID()) == 0)
795 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::reverse_iterator
796 aCopyIter = aConstrIter++;
797 removeConstraint(aCopyIter->first);
803 // Probably, need to update coincidence constraints
804 if (isCCRemoved && !myExtraCoincidence.empty())
806 // Make a copy, because the new list of unused constrtaints will be generated
807 std::set< boost::shared_ptr<SketchPlugin_Constraint> > anExtraCopy = myExtraCoincidence;
808 myExtraCoincidence.clear();
810 std::set< boost::shared_ptr<SketchPlugin_Constraint> >::iterator
811 aCIter = anExtraCopy.begin();
812 for ( ; aCIter != anExtraCopy.end(); aCIter++)
813 if ((*aCIter)->data()->isValid())
814 changeConstraint(*aCIter);
820 // ============================================================================
821 // Function: updateAttribute
822 // Class: SketchSolver_ConstraintGroup
823 // Purpose: update features of sketch after resolving constraints
824 // ============================================================================
825 bool SketchSolver_ConstraintGroup::updateAttribute(
826 boost::shared_ptr<ModelAPI_Attribute> theAttribute,
827 const Slvs_hEntity& theEntityID)
829 // Search the position of the first parameter of the entity
830 int anEntPos = Search(theEntityID, myEntities);
831 int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
833 // Look over supported types of entities
836 boost::shared_ptr<GeomDataAPI_Point> aPoint =
837 boost::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
840 if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance ||
841 fabs(aPoint->y() - myParams[aFirstParamPos+1].val) > tolerance ||
842 fabs(aPoint->z() - myParams[aFirstParamPos+2].val) > tolerance)
844 aPoint->setValue(myParams[aFirstParamPos].val,
845 myParams[aFirstParamPos+1].val,
846 myParams[aFirstParamPos+2].val);
853 boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
854 boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
857 if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance ||
858 fabs(aPoint2D->y() - myParams[aFirstParamPos+1].val) > tolerance)
860 aPoint2D->setValue(myParams[aFirstParamPos].val,
861 myParams[aFirstParamPos+1].val);
868 AttributeDoublePtr aScalar =
869 boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
872 if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance)
874 aScalar->setValue(myParams[aFirstParamPos].val);
880 /// \todo Support other types of entities
884 // ============================================================================
885 // Function: updateEntityIfPossible
886 // Class: SketchSolver_ConstraintGroup
887 // Purpose: search the entity in this group and update it
888 // ============================================================================
889 void SketchSolver_ConstraintGroup::updateEntityIfPossible(
890 boost::shared_ptr<ModelAPI_Attribute> theEntity)
892 if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end())
894 // If the attribute is a point and it is changed (the group needs to rebuild),
895 // probably user has dragged this point into this position,
896 // so it is necessary to add constraint which will guarantee the point will not change
898 // Store myNeedToSolve flag to verify the entity is really changed
899 bool aNeedToSolveCopy = myNeedToSolve;
900 myNeedToSolve = false;
902 changeEntity(theEntity);
904 if (myNeedToSolve) // the entity is changed
906 // Verify the entity is a point and add temporary constraint of permanency
907 boost::shared_ptr<GeomDataAPI_Point> aPoint =
908 boost::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
909 boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
910 boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
911 if (aPoint || aPoint2D)
912 addTemporaryConstraintWhereDragged(theEntity);
915 // Restore flag of changes
916 myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
919 updateRelatedConstraints(theEntity);
923 // ============================================================================
924 // Function: addTemporaryConstraintWhereDragged
925 // Class: SketchSolver_ConstraintGroup
926 // Purpose: add transient constraint SLVS_C_WHERE_DRAGGED for the entity,
927 // which was moved by user
928 // ============================================================================
929 void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged(
930 boost::shared_ptr<ModelAPI_Attribute> theEntity)
932 // Find identifier of the entity
933 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
934 anEntIter = myEntityAttrMap.find(theEntity);
935 if (anEntIter == myEntityAttrMap.end())
938 // If this is a first dragged point, its parameters should be placed
939 // into Slvs_System::dragged field to avoid system inconsistense
940 if (myTempPointWhereDragged.empty())
942 int anEntPos = Search(anEntIter->second, myEntities);
943 Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
944 for (int i = 0; i < 4; i++, aDraggedParam++)
945 if (*aDraggedParam != 0)
946 myTempPointWhereDragged.push_back(*aDraggedParam);
947 myTempPointWDrgdID = myEntities[anEntPos].h;
951 // Get identifiers of all dragged points
952 std::set<Slvs_hEntity> aDraggedPntID;
953 aDraggedPntID.insert(myTempPointWDrgdID);
954 std::list<Slvs_hConstraint>::iterator aTmpCoIter = myTempConstraints.begin();
955 for ( ; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++)
957 unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
958 if (aConstrPos < myConstraints.size())
959 aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
961 // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
962 std::vector< std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
963 for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
965 if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
966 continue; // the entity was not found in current set
968 // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
969 std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
970 for ( ; aDrgIter != aDraggedPntID.end(); aDrgIter++)
971 if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
972 return ; // the SLVS_C_WHERE_DRAGGED constraint already exists
975 // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
976 Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
977 myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
978 myConstraints.push_back(aWDConstr);
979 myTempConstraints.push_back(aWDConstr.h);
982 // ============================================================================
983 // Function: removeTemporaryConstraints
984 // Class: SketchSolver_ConstraintGroup
985 // Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after
986 // resolving the set of constraints
987 // ============================================================================
988 void SketchSolver_ConstraintGroup::removeTemporaryConstraints()
990 std::list<Slvs_hConstraint>::reverse_iterator aTmpConstrIter;
991 for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend(); aTmpConstrIter++)
993 unsigned int aConstrPos = Search(*aTmpConstrIter, myConstraints);
994 if (aConstrPos >= myConstraints.size())
996 myConstraints.erase(myConstraints.begin() + aConstrPos);
998 // If the removing constraint has higher index, decrease the indexer
999 if (*aTmpConstrIter == myConstrMaxID)
1002 myTempConstraints.clear();
1004 // Clear basic dragged point
1005 myTempPointWhereDragged.clear();
1008 // ============================================================================
1009 // Function: removeConstraint
1010 // Class: SketchSolver_ConstraintGroup
1011 // Purpose: remove constraint and all unused entities
1012 // ============================================================================
1013 void SketchSolver_ConstraintGroup::removeConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
1015 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::iterator
1016 anIterToRemove = myConstraintMap.find(theConstraint);
1017 if (anIterToRemove == myConstraintMap.end())
1020 Slvs_hConstraint aCnstrToRemove = anIterToRemove->second;
1021 // Remove constraint from the map
1022 myConstraintMap.erase(anIterToRemove);
1024 // Find unused entities
1025 int aConstrPos = Search(aCnstrToRemove, myConstraints);
1026 std::set<Slvs_hEntity> anEntToRemove;
1027 Slvs_hEntity aCnstEnt[] = {myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB,
1028 myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB};
1029 for (int i = 0; i < 4; i++)
1030 if (aCnstEnt[i] != 0)
1031 anEntToRemove.insert(aCnstEnt[i]);
1032 myConstraints.erase(myConstraints.begin() + aConstrPos);
1033 if (aCnstrToRemove == myConstrMaxID)
1035 std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1036 for ( ; aConstrIter != myConstraints.end(); aConstrIter++)
1038 Slvs_hEntity aEnts[] = {aConstrIter->ptA, aConstrIter->ptB,
1039 aConstrIter->entityA, aConstrIter->entityB};
1040 for (int i = 0; i < 4; i++)
1041 if (aEnts[i] != 0 && anEntToRemove.find(aEnts[i]) != anEntToRemove.end())
1042 anEntToRemove.erase(aEnts[i]);
1045 if (anEntToRemove.empty())
1048 // Remove unused entities
1049 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
1050 anEntAttrIter = myEntityAttrMap.begin();
1051 while (anEntAttrIter != myEntityAttrMap.end())
1053 if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end())
1055 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
1056 aRemovedIter = anEntAttrIter;
1058 myEntityAttrMap.erase(aRemovedIter);
1060 else anEntAttrIter++;
1062 std::map<FeaturePtr, Slvs_hEntity>::iterator
1063 anEntFeatIter = myEntityFeatMap.begin();
1064 while (anEntFeatIter != myEntityFeatMap.end())
1066 if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end())
1068 std::map<FeaturePtr, Slvs_hEntity>::iterator
1069 aRemovedIter = anEntFeatIter;
1071 myEntityFeatMap.erase(aRemovedIter);
1073 else anEntFeatIter++;
1075 std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = anEntToRemove.rbegin();
1076 for ( ; aRemIter != anEntToRemove.rend(); aRemIter++)
1078 unsigned int anEntPos = Search(*aRemIter, myEntities);
1079 if (anEntPos >= myEntities.size())
1081 unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
1082 if (aParamPos >= myParams.size())
1085 while (myEntities[anEntPos].param[aNbParams] != 0)
1087 if (myEntities[anEntPos].param[aNbParams-1] == myParamMaxID)
1088 myParamMaxID -= aNbParams;
1089 myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
1090 if (*aRemIter == myEntityMaxID)
1092 myEntities.erase(myEntities.begin() + anEntPos);
1094 // Remove entity's ID from the lists of conincident points
1095 std::vector< std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1096 for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
1097 aCoPtIter->erase(*aRemIter);
1099 if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty())
1100 myCoincidentPoints.clear();
1104 // ============================================================================
1105 // Function: addCoincidentPoints
1106 // Class: SketchSolver_ConstraintGroup
1107 // Purpose: add coincident point the appropriate list of such points
1108 // ============================================================================
1109 bool SketchSolver_ConstraintGroup::addCoincidentPoints(
1110 const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2)
1112 std::vector< std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1113 std::vector< std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
1114 while (aCoPtIter != myCoincidentPoints.end())
1116 bool isFound[2] = { // indicate which point ID was already in coincidence constraint
1117 aCoPtIter->find(thePoint1) != aCoPtIter->end(),
1118 aCoPtIter->find(thePoint2) != aCoPtIter->end(),
1120 if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need additional one
1122 if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1]))
1124 if (aFirstFound != myCoincidentPoints.end())
1125 { // there are two groups of coincident points connected by created constraint => merge them
1126 int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
1127 int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
1128 aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
1129 myCoincidentPoints.erase(aCoPtIter);
1130 aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
1131 aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
1136 aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
1137 aFirstFound = aCoPtIter;
1142 // No points were found, need to create new set
1143 if (aFirstFound == myCoincidentPoints.end())
1145 std::set<Slvs_hEntity> aNewSet;
1146 aNewSet.insert(thePoint1);
1147 aNewSet.insert(thePoint2);
1148 myCoincidentPoints.push_back(aNewSet);
1155 // ============================================================================
1156 // Function: updateRelatedConstraints
1157 // Class: SketchSolver_ConstraintGroup
1158 // Purpose: emit the signal to update constraints
1159 // ============================================================================
1160 void SketchSolver_ConstraintGroup::updateRelatedConstraints(
1161 boost::shared_ptr<ModelAPI_Attribute> theEntity) const
1163 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
1164 aConstrIter = myConstraintMap.begin();
1165 for ( ; aConstrIter != myConstraintMap.end(); aConstrIter++)
1167 std::list< boost::shared_ptr<ModelAPI_Attribute> > anAttributes =
1168 aConstrIter->first->data()->attributes(std::string());
1170 std::list< boost::shared_ptr<ModelAPI_Attribute> >::iterator
1171 anAttrIter = anAttributes.begin();
1172 for ( ; anAttrIter != anAttributes.end(); anAttrIter++)
1174 bool isUpd = (*anAttrIter == theEntity);
1175 boost::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1176 boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
1177 if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
1182 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1183 ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
1190 void SketchSolver_ConstraintGroup::updateRelatedConstraints(
1191 boost::shared_ptr<ModelAPI_Feature> theFeature) const
1193 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
1194 aConstrIter = myConstraintMap.begin();
1195 for ( ; aConstrIter != myConstraintMap.end(); aConstrIter++)
1197 std::list< boost::shared_ptr<ModelAPI_Attribute> > anAttributes =
1198 aConstrIter->first->data()->attributes(std::string());
1200 std::list< boost::shared_ptr<ModelAPI_Attribute> >::iterator
1201 anAttrIter = anAttributes.begin();
1202 for ( ; anAttrIter != anAttributes.end(); anAttrIter++)
1204 boost::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1205 boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
1206 if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature)
1208 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1209 ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
1218 // ========================================================
1219 // ========= Auxiliary functions ===============
1220 // ========================================================
1222 template <typename T>
1223 int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
1225 int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
1226 int aVecSize = theEntities.size();
1227 while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
1229 while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
1231 if (aResIndex == -1)
1232 aResIndex = aVecSize;