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_Events.h>
18 #include <SketchPlugin_Constraint.h>
19 #include <SketchPlugin_ConstraintLength.h>
20 #include <SketchPlugin_ConstraintCoincidence.h>
22 #include <SketchPlugin_Arc.h>
23 #include <SketchPlugin_Circle.h>
24 #include <SketchPlugin_Line.h>
25 #include <SketchPlugin_Point.h>
26 #include <SketchPlugin_Sketch.h>
31 /// Tolerance for value of parameters
32 const double tolerance = 1.e-10;
35 * Collects all sketch solver error' codes
36 * as inline static functions
37 * TODO: Move this class into a separate file
39 class SketchSolver_Error {
41 /// The value parameter for the constraint
42 inline static const std::string& CONSTRAINTS()
44 static const std::string MY_ERROR_VALUE("Conflicting constraints");
45 return MY_ERROR_VALUE;
49 /// This value is used to give unique index to the groups
50 static Slvs_hGroup myGroupIndexer = 0;
52 /** \brief Search the entity/parameter with specified ID in the list of elements
53 * \param[in] theEntityID unique ID of the element
54 * \param[in] theEntities list of elements
55 * \return position of the found element or -1 if the element is not found
58 static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
61 // ========================================================
62 // ========= SketchSolver_ConstraintGroup ===============
63 // ========================================================
65 SketchSolver_ConstraintGroup::
66 SketchSolver_ConstraintGroup(boost::shared_ptr<SketchPlugin_Feature> theWorkplane)
67 : myID(++myGroupIndexer),
77 myConstraints.clear();
79 myTempConstraints.clear();
80 myTempPointWhereDragged.clear();
81 myTempPointWDrgdID = 0;
83 // Initialize workplane
84 myWorkplane.h = SLVS_E_UNKNOWN;
86 assert(addWorkplane(theWorkplane));
88 addWorkplane(theWorkplane);
92 SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
96 myConstraints.clear();
97 myConstraintMap.clear();
98 myTempConstraints.clear();
99 myTempPointWhereDragged.clear();
101 // If the group with maximal identifier is deleted, decrease the indexer
102 if (myID == myGroupIndexer)
106 // ============================================================================
107 // Function: isBaseWorkplane
108 // Class: SketchSolver_ConstraintGroup
109 // Purpose: verify the group is based on the given workplane
110 // ============================================================================
111 bool SketchSolver_ConstraintGroup::isBaseWorkplane(
112 boost::shared_ptr<SketchPlugin_Feature> theWorkplane) const
114 return theWorkplane == mySketch;
117 // ============================================================================
118 // Function: isInteract
119 // Class: SketchSolver_ConstraintGroup
120 // Purpose: verify are there any entities in the group used by given constraint
121 // ============================================================================
122 bool SketchSolver_ConstraintGroup::isInteract(
123 boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
125 // Check the group is empty
126 if (myWorkplane.h != SLVS_E_UNKNOWN && myConstraints.empty())
129 // Go through constraint entities and verify if some of them already in the group
130 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++)
132 boost::shared_ptr<ModelAPI_AttributeRefAttr> aCAttrRef =
133 boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
134 theConstraint->data()->attribute(SketchPlugin_Constraint::ATTRIBUTE(i))
136 if (!aCAttrRef) continue;
137 if (!aCAttrRef->isObject() &&
138 myEntityAttrMap.find(aCAttrRef->attr()) != myEntityAttrMap.end())
140 if (aCAttrRef->isObject() &&
141 myEntityFeatMap.find(boost::dynamic_pointer_cast<ModelAPI_Feature>(aCAttrRef->object()))
142 != myEntityFeatMap.end())
146 // Entities did not found
150 // ============================================================================
151 // Function: changeConstraint
152 // Class: SketchSolver_ConstraintGroup
153 // Purpose: create/update the constraint in the group
154 // ============================================================================
155 bool SketchSolver_ConstraintGroup::changeConstraint(
156 boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
158 // There is no workplane yet, something wrong
159 if (myWorkplane.h == SLVS_E_UNKNOWN)
162 // Search this constraint in the current group to update it
163 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
164 aConstrMapIter = myConstraintMap.find(theConstraint);
165 std::vector<Slvs_Constraint>::iterator aConstrIter;
166 if (aConstrMapIter != myConstraintMap.end())
168 int aConstrPos = Search(aConstrMapIter->second, myConstraints);
169 aConstrIter = myConstraints.begin() + aConstrPos;
172 // Get constraint type and verify the constraint parameters are correct
173 SketchSolver_Constraint aConstraint(theConstraint);
174 int aConstrType = aConstraint.getType();
175 if (aConstrType == SLVS_C_UNKNOWN ||
176 (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
178 const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
180 // Create constraint parameters
181 double aDistance = 0.0; // scalar value of the constraint
182 AttributeDoublePtr aDistAttr =
183 boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE()));
186 aDistance = aDistAttr->value();
187 // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
188 if (aConstrType == SLVS_C_DIAMETER)
190 if (aConstrMapIter != myConstraintMap.end() && fabs(aConstrIter->valA - aDistance) > tolerance)
192 myNeedToSolve = true;
193 aConstrIter->valA = aDistance;
197 Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
198 for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
200 aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
201 boost::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr =
202 boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
203 theConstraint->data()->attribute(aConstraintAttributes[indAttr])
205 if (!aConstrAttr) continue;
207 // For the length constraint the start and end points of the line should be added to the entities list instead of line
208 if (aConstrType == SLVS_C_PT_PT_DISTANCE && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0)
210 boost::shared_ptr<ModelAPI_Data> aData = aConstrAttr->object()->data();
211 aConstrEnt[indAttr] = changeEntity(aData->attribute(SketchPlugin_Line::START_ID()));
212 aConstrEnt[indAttr+1] = changeEntity(aData->attribute(SketchPlugin_Line::END_ID()));
213 // measured object is added into the map of objects to avoid problems with interaction betwee constraint and group
214 myEntityFeatMap[boost::dynamic_pointer_cast<ModelAPI_Feature>(aConstrAttr->object())] = 0;
215 break; // there should be no other entities
217 else if (aConstrAttr->isObject())
218 aConstrEnt[indAttr] = changeEntity(boost::dynamic_pointer_cast<ModelAPI_Feature>(aConstrAttr->object()));
220 aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
223 if (aConstrMapIter == myConstraintMap.end())
225 // Several points may be coincident, it is not necessary to store all constraints between them.
226 // Try to find sequence of coincident points which connects the points of new constraint
227 if (aConstrType == SLVS_C_POINTS_COINCIDENT)
229 if (aConstrEnt[0] == aConstrEnt[1]) // no need to add self coincidence
233 if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1]))
235 myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes
240 // Create SolveSpace constraint structure
241 Slvs_Constraint aConstraint =
242 Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h,
243 aDistance, aConstrEnt[0], aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
244 myConstraints.push_back(aConstraint);
245 myConstraintMap[theConstraint] = aConstraint.h;
250 // ============================================================================
251 // Function: changeEntity
252 // Class: SketchSolver_ConstraintGroup
253 // Purpose: create/update the element affected by any constraint
254 // ============================================================================
255 Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
256 boost::shared_ptr<ModelAPI_Attribute> theEntity)
258 // If the entity is already in the group, try to find it
259 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
260 aEntIter = myEntityAttrMap.find(theEntity);
261 std::vector<Slvs_Param>::const_iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise
262 if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
263 aParamIter = myParams.end();
265 { // the entity already exists
266 int aEntPos = Search(aEntIter->second, myEntities);
267 int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
268 aParamIter = myParams.begin() + aParamPos;
270 const bool isEntExists = (aEntIter != myEntityAttrMap.end()); // defines that the entity already exists
272 // Look over supported types of entities
275 boost::shared_ptr<GeomDataAPI_Point> aPoint =
276 boost::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
279 Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
280 Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
281 Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
284 return aEntIter->second;
287 Slvs_Entity aPtEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
288 myEntities.push_back(aPtEntity);
289 myEntityAttrMap[theEntity] = aPtEntity.h;
293 // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
294 if (myWorkplane.h == SLVS_E_UNKNOWN)
295 return SLVS_E_UNKNOWN;
298 boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
299 boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
302 Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
303 Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
306 return aEntIter->second;
309 Slvs_Entity aPt2DEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
310 myEntities.push_back(aPt2DEntity);
311 myEntityAttrMap[theEntity] = aPt2DEntity.h;
312 return aPt2DEntity.h;
315 // Scalar value (used for the distance entities)
316 AttributeDoublePtr aScalar =
317 boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
320 Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
323 return aEntIter->second;
326 Slvs_Entity aDistance = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
327 myEntities.push_back(aDistance);
328 myEntityAttrMap[theEntity] = aDistance.h;
332 /// \todo Other types of entities
334 // Unsupported or wrong entity type
335 return SLVS_E_UNKNOWN;
339 // ============================================================================
340 // Function: changeEntity
341 // Class: SketchSolver_ConstraintGroup
342 // Purpose: create/update the element defined by the feature affected by any constraint
343 // ============================================================================
344 Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
345 FeaturePtr theEntity)
347 // If the entity is already in the group, try to find it
348 std::map<FeaturePtr, Slvs_hEntity>::const_iterator
349 aEntIter = myEntityFeatMap.find(theEntity);
350 // defines that the entity already exists
351 const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
353 // SketchPlugin features
354 boost::shared_ptr<SketchPlugin_Feature> aFeature =
355 boost::dynamic_pointer_cast<SketchPlugin_Feature>(theEntity);
357 { // Verify the feature by its kind
358 const std::string& aFeatureKind = aFeature->getKind();
361 if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0)
363 Slvs_hEntity aStart = changeEntity(aFeature->data()->attribute(SketchPlugin_Line::START_ID()));
364 Slvs_hEntity aEnd = changeEntity(aFeature->data()->attribute(SketchPlugin_Line::END_ID()));
367 return aEntIter->second;
370 Slvs_Entity aLineEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
371 myEntities.push_back(aLineEntity);
372 myEntityFeatMap[theEntity] = aLineEntity.h;
373 return aLineEntity.h;
376 else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0)
378 Slvs_hEntity aCenter = changeEntity(aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID()));
379 Slvs_hEntity aRadius = changeEntity(aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()));
382 return aEntIter->second;
385 Slvs_Entity aCircleEntity =
386 Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter, myWorkplane.normal, aRadius);
387 myEntities.push_back(aCircleEntity);
388 myEntityFeatMap[theEntity] = aCircleEntity.h;
389 return aCircleEntity.h;
392 else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0)
394 Slvs_hEntity aCenter = changeEntity(aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
395 Slvs_hEntity aStart = changeEntity(aFeature->data()->attribute(SketchPlugin_Arc::START_ID()));
396 Slvs_hEntity aEnd = changeEntity(aFeature->data()->attribute(SketchPlugin_Arc::END_ID()));
399 return aEntIter->second;
401 Slvs_Entity anArcEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID,
402 myWorkplane.h, myWorkplane.normal, aCenter, aStart, aEnd);
403 myEntities.push_back(anArcEntity);
404 myEntityFeatMap[theEntity] = anArcEntity.h;
405 return anArcEntity.h;
407 // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
408 else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0)
410 Slvs_hEntity aPoint = changeEntity(aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()));
413 return aEntIter->second;
415 // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
416 myEntityFeatMap[theEntity] = aPoint;
421 /// \todo Other types of features
423 // Unsupported or wrong entity type
424 return SLVS_E_UNKNOWN;
427 // ============================================================================
428 // Function: changeNormal
429 // Class: SketchSolver_ConstraintGroup
430 // Purpose: create/update the normal of workplane
431 // ============================================================================
432 Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal(
433 boost::shared_ptr<ModelAPI_Attribute> theDirX,
434 boost::shared_ptr<ModelAPI_Attribute> theDirY,
435 boost::shared_ptr<ModelAPI_Attribute> theNorm)
437 boost::shared_ptr<GeomDataAPI_Dir> aDirX =
438 boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
439 boost::shared_ptr<GeomDataAPI_Dir> aDirY =
440 boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirY);
441 if (!aDirX || !aDirY ||
442 (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
443 (fabs(aDirY->x()) + fabs(aDirY->y()) + fabs(aDirY->z()) < tolerance))
444 return SLVS_E_UNKNOWN;
446 // quaternion parameters of normal vector
447 double qw, qx, qy, qz;
448 Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(),
449 aDirY->x(), aDirY->y(), aDirY->z(),
451 double aNormCoord[4] = {qw, qx, qy, qz};
453 // Try to find existent normal
454 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
455 aEntIter = myEntityAttrMap.find(theNorm);
456 std::vector<Slvs_Param>::const_iterator aParamIter; // looks to the first parameter of already existent entity or to the end of vector otherwise
457 if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
458 aParamIter = myParams.end();
460 { // the entity already exists, update it
461 int aEntPos = Search(aEntIter->second, myEntities);
462 int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
463 aParamIter = myParams.begin() + aParamPos;
466 // Change parameters of the normal
467 Slvs_hParam aNormParams[4];
468 for (int i = 0; i < 4; i++)
469 aNormParams[i] = changeParameter(aNormCoord[i], aParamIter);
471 if (aEntIter != myEntityAttrMap.end()) // the entity already exists
472 return aEntIter->second;
475 Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID,
476 aNormParams[0], aNormParams[1], aNormParams[2], aNormParams[3]);
477 myEntities.push_back(aNormal);
478 myEntityAttrMap[theNorm] = aNormal.h;
483 // ============================================================================
484 // Function: addWorkplane
485 // Class: SketchSolver_ConstraintGroup
486 // Purpose: create workplane for the group
487 // ============================================================================
488 bool SketchSolver_ConstraintGroup::addWorkplane(
489 boost::shared_ptr<SketchPlugin_Feature> theSketch)
491 if (myWorkplane.h || theSketch->getKind().compare(SketchPlugin_Sketch::ID()) != 0)
492 return false; // the workplane already exists or the function parameter is not Sketch
494 mySketch = theSketch;
499 // ============================================================================
500 // Function: updateWorkplane
501 // Class: SketchSolver_ConstraintGroup
502 // Purpose: update parameters of workplane
503 // ============================================================================
504 bool SketchSolver_ConstraintGroup::updateWorkplane()
506 // Get parameters of workplane
507 boost::shared_ptr<ModelAPI_Attribute> aDirX = mySketch->data()->attribute(SketchPlugin_Sketch::DIRX_ID());
508 boost::shared_ptr<ModelAPI_Attribute> aDirY = mySketch->data()->attribute(SketchPlugin_Sketch::DIRY_ID());
509 boost::shared_ptr<ModelAPI_Attribute> aNorm = mySketch->data()->attribute(SketchPlugin_Sketch::NORM_ID());
510 boost::shared_ptr<ModelAPI_Attribute> anOrigin = mySketch->data()->attribute(SketchPlugin_Sketch::ORIGIN_ID());
511 // Transform them into SolveSpace format
512 Slvs_hEntity aNormalWP = changeNormal(aDirX, aDirY, aNorm);
513 if (!aNormalWP) return false;
514 Slvs_hEntity anOriginWP = changeEntity(anOrigin);
515 if (!anOriginWP) return false;
520 myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
521 // Workplane should be added to the list of entities
522 myEntities.push_back(myWorkplane);
527 // ============================================================================
528 // Function: changeParameter
529 // Class: SketchSolver_ConstraintGroup
530 // Purpose: create/update value of parameter
531 // ============================================================================
532 Slvs_hParam SketchSolver_ConstraintGroup::changeParameter(
533 const double& theParam,
534 std::vector<Slvs_Param>::const_iterator& thePrmIter)
536 if (thePrmIter != myParams.end())
537 { // Parameter should be updated
538 int aParamPos = thePrmIter - myParams.begin();
539 if (fabs(thePrmIter->val - theParam) > tolerance)
541 myNeedToSolve = true; // parameter is changed, need to resolve constraints
542 myParams[aParamPos].val = theParam;
545 return myParams[aParamPos].h;
548 // Newly created parameter
549 Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
550 myParams.push_back(aParam);
551 myNeedToSolve = true;
552 // The list of parameters is changed, move iterator to the end of the list to avoid problems
553 thePrmIter = myParams.end();
557 // ============================================================================
558 // Function: resolveConstraints
559 // Class: SketchSolver_ConstraintGroup
560 // Purpose: solve the set of constraints for the current group
561 // ============================================================================
562 void SketchSolver_ConstraintGroup::resolveConstraints()
567 myConstrSolver.setGroupID(myID);
568 myConstrSolver.setParameters(myParams);
569 myConstrSolver.setEntities(myEntities);
570 myConstrSolver.setConstraints(myConstraints);
571 myConstrSolver.setDraggedParameters(myTempPointWhereDragged);
573 int aResult = myConstrSolver.solve();
574 if (aResult == SLVS_RESULT_OKAY)
575 { // solution succeeded, store results into correspondent attributes
576 // Obtain result into the same list of parameters
577 if (!myConstrSolver.getResult(myParams))
580 // We should go through the attributes map, because only attributes have valued parameters
581 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
582 anEntIter = myEntityAttrMap.begin();
583 for ( ; anEntIter != myEntityAttrMap.end(); anEntIter++)
584 if (updateAttribute(anEntIter->first, anEntIter->second))
585 updateRelatedConstraints(anEntIter->first);
587 else if (!myConstraints.empty())
588 Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
590 removeTemporaryConstraints();
591 myNeedToSolve = false;
594 // ============================================================================
595 // Function: mergeGroups
596 // Class: SketchSolver_ConstraintGroup
597 // Purpose: append specified group to the current group
598 // ============================================================================
599 void SketchSolver_ConstraintGroup::mergeGroups(
600 const SketchSolver_ConstraintGroup& theGroup)
602 // If specified group is empty, no need to merge
603 if (theGroup.myConstraintMap.empty())
606 // Map between old and new indexes of SolveSpace constraints
607 std::map<Slvs_hConstraint, Slvs_hConstraint> aConstrMap;
609 // Add all constraints from theGroup to the current group
610 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
611 aConstrIter = theGroup.myConstraintMap.begin();
612 for ( ; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++)
613 if (changeConstraint(aConstrIter->first))
614 aConstrMap[aConstrIter->second] = myConstrMaxID; // the constraint was added => store its ID
616 // Add temporary constraints from theGroup
617 std::list<Slvs_hConstraint>::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin();
618 for ( ; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++)
620 std::map<Slvs_hConstraint, Slvs_hConstraint>::iterator aFind = aConstrMap.find(*aTempConstrIter);
621 if (aFind != aConstrMap.end())
622 myTempConstraints.push_back(aFind->second);
625 if (myTempPointWhereDragged.empty())
626 myTempPointWhereDragged = theGroup.myTempPointWhereDragged;
627 else if (!theGroup.myTempPointWhereDragged.empty())
628 { // Need to create additional transient constraint
629 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
630 aFeatureIter = theGroup.myEntityAttrMap.begin();
631 for (; aFeatureIter != theGroup.myEntityAttrMap.end(); aFeatureIter++)
632 if (aFeatureIter->second == myTempPointWDrgdID)
634 addTemporaryConstraintWhereDragged(aFeatureIter->first);
639 myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve;
642 // ============================================================================
643 // Function: splitGroup
644 // Class: SketchSolver_ConstraintGroup
645 // Purpose: divide the group into several subgroups
646 // ============================================================================
647 void SketchSolver_ConstraintGroup::splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts)
649 // Divide constraints and entities into several groups
650 std::vector< std::set<Slvs_hEntity> > aGroupsEntities;
651 std::vector< std::set<Slvs_hConstraint> > aGroupsConstr;
652 int aMaxNbEntities = 0; // index of the group with maximal nuber of elements (this group will be left in the current)
653 std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
654 for ( ; aConstrIter != myConstraints.end(); aConstrIter++)
656 Slvs_hEntity aConstrEnt[] = {
657 aConstrIter->ptA, aConstrIter->ptB,
658 aConstrIter->entityA, aConstrIter->entityB};
659 std::vector<int> anIndexes;
660 // Go through the groupped entities and find even one of entities of current constraint
661 std::vector< std::set<Slvs_hEntity> >::iterator aGrEntIter;
662 for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++)
664 bool isFound = false;
665 for (int i = 0; i < 4 && !isFound; i++)
666 if (aConstrEnt[i] != 0)
667 isFound = (aGrEntIter->find(aConstrEnt[i]) != aGrEntIter->end());
669 anIndexes.push_back(aGrEntIter - aGroupsEntities.begin());
671 // Add new group if no one is found
672 if (anIndexes.empty())
674 std::set<Slvs_hEntity> aNewGrEnt;
675 for (int i = 0; i < 4; i++)
676 if (aConstrEnt[i] != 0)
677 aNewGrEnt.insert(aConstrEnt[i]);
678 std::set<Slvs_hConstraint> aNewGrConstr;
679 aNewGrConstr.insert(aConstrIter->h);
681 aGroupsEntities.push_back(aNewGrEnt);
682 aGroupsConstr.push_back(aNewGrConstr);
683 if (aNewGrEnt.size() > aGroupsEntities[aMaxNbEntities].size())
684 aMaxNbEntities = aGroupsEntities.size() - 1;
686 else if (anIndexes.size() == 1)
687 { // Add entities indexes into the found group
688 aGrEntIter = aGroupsEntities.begin() + anIndexes.front();
689 for (int i = 0; i < 4; i++)
690 if (aConstrEnt[i] != 0)
691 aGrEntIter->insert(aConstrEnt[i]);
692 aGroupsConstr[anIndexes.front()].insert(aConstrIter->h);
693 if (aGrEntIter->size() > aGroupsEntities[aMaxNbEntities].size())
694 aMaxNbEntities = aGrEntIter - aGroupsEntities.begin();
697 { // There are found several connected groups, merge them
698 std::vector< std::set<Slvs_hEntity> >::iterator aFirstGroup =
699 aGroupsEntities.begin() + anIndexes.front();
700 std::vector< std::set<Slvs_hConstraint> >::iterator aFirstConstr =
701 aGroupsConstr.begin() + anIndexes.front();
702 std::vector<int>::iterator anInd = anIndexes.begin();
703 for (++anInd; anInd != anIndexes.end(); anInd++)
705 aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end());
706 aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end());
708 if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size())
709 aMaxNbEntities = anIndexes.front();
710 // Remove merged groups
711 for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--)
713 aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd));
714 aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd));
719 if (aGroupsEntities.size() <= 1)
722 // Remove the group with maximum elements as it will be left in the current group
723 aGroupsEntities.erase(aGroupsEntities.begin() + aMaxNbEntities);
724 aGroupsConstr.erase(aGroupsConstr.begin() + aMaxNbEntities);
726 // Add new groups of constraints and divide current group
727 std::vector<SketchSolver_ConstraintGroup*> aNewGroups;
728 for (int i = aGroupsEntities.size(); i > 0; i--)
730 SketchSolver_ConstraintGroup* aG = new SketchSolver_ConstraintGroup(mySketch);
731 aNewGroups.push_back(aG);
733 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
734 aConstrMapIter = myConstraintMap.begin();
735 int aConstrMapPos = 0; // position of iterator in the map (used to restore iterator after removing constraint)
736 while (aConstrMapIter != myConstraintMap.end())
738 std::vector< std::set<Slvs_hConstraint> >::const_iterator aGIter = aGroupsConstr.begin();
739 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroup = aNewGroups.begin();
740 for ( ; aGIter != aGroupsConstr.end(); aGIter++, aGroup++)
741 if (aGIter->find(aConstrMapIter->second) != aGIter->end())
743 (*aGroup)->changeConstraint(aConstrMapIter->first);
744 removeConstraint(aConstrMapIter->first);
746 aConstrMapIter = myConstraintMap.begin();
747 for (int i = 0; i < aConstrMapPos; i++)
751 if (aGIter == aGroupsConstr.end())
758 theCuts.insert(theCuts.end(), aNewGroups.begin(), aNewGroups.end());
761 // ============================================================================
762 // Function: updateGroup
763 // Class: SketchSolver_ConstraintGroup
764 // Purpose: search removed entities and constraints
765 // ============================================================================
766 bool SketchSolver_ConstraintGroup::updateGroup()
768 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::reverse_iterator
769 aConstrIter = myConstraintMap.rbegin();
770 bool isAllValid = true;
771 bool isCCRemoved = false; // indicates that at least one of coincidence constraints was removed
772 while (isAllValid && aConstrIter != myConstraintMap.rend())
774 if (!aConstrIter->first->data()->isValid())
776 if (aConstrIter->first->getKind().compare(SketchPlugin_ConstraintCoincidence::ID()) == 0)
778 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::reverse_iterator
779 aCopyIter = aConstrIter++;
780 removeConstraint(aCopyIter->first);
786 // Probably, need to update coincidence constraints
787 if (isCCRemoved && !myExtraCoincidence.empty())
789 // Make a copy, because the new list of unused constrtaints will be generated
790 std::set< boost::shared_ptr<SketchPlugin_Constraint> > anExtraCopy = myExtraCoincidence;
791 myExtraCoincidence.clear();
793 std::set< boost::shared_ptr<SketchPlugin_Constraint> >::iterator
794 aCIter = anExtraCopy.begin();
795 for ( ; aCIter != anExtraCopy.end(); aCIter++)
796 if ((*aCIter)->data()->isValid())
797 changeConstraint(*aCIter);
803 // ============================================================================
804 // Function: updateAttribute
805 // Class: SketchSolver_ConstraintGroup
806 // Purpose: update features of sketch after resolving constraints
807 // ============================================================================
808 bool SketchSolver_ConstraintGroup::updateAttribute(
809 boost::shared_ptr<ModelAPI_Attribute> theAttribute,
810 const Slvs_hEntity& theEntityID)
812 // Search the position of the first parameter of the entity
813 int anEntPos = Search(theEntityID, myEntities);
814 int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
816 // Look over supported types of entities
819 boost::shared_ptr<GeomDataAPI_Point> aPoint =
820 boost::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
823 if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance ||
824 fabs(aPoint->y() - myParams[aFirstParamPos+1].val) > tolerance ||
825 fabs(aPoint->z() - myParams[aFirstParamPos+2].val) > tolerance)
827 aPoint->setValue(myParams[aFirstParamPos].val,
828 myParams[aFirstParamPos+1].val,
829 myParams[aFirstParamPos+2].val);
836 boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
837 boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
840 if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance ||
841 fabs(aPoint2D->y() - myParams[aFirstParamPos+1].val) > tolerance)
843 aPoint2D->setValue(myParams[aFirstParamPos].val,
844 myParams[aFirstParamPos+1].val);
851 AttributeDoublePtr aScalar =
852 boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
855 if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance)
857 aScalar->setValue(myParams[aFirstParamPos].val);
863 /// \todo Support other types of entities
867 // ============================================================================
868 // Function: updateEntityIfPossible
869 // Class: SketchSolver_ConstraintGroup
870 // Purpose: search the entity in this group and update it
871 // ============================================================================
872 void SketchSolver_ConstraintGroup::updateEntityIfPossible(
873 boost::shared_ptr<ModelAPI_Attribute> theEntity)
875 if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end())
877 // If the attribute is a point and it is changed (the group needs to rebuild),
878 // probably user has dragged this point into this position,
879 // so it is necessary to add constraint which will guarantee the point will not change
881 // Store myNeedToSolve flag to verify the entity is really changed
882 bool aNeedToSolveCopy = myNeedToSolve;
883 myNeedToSolve = false;
885 changeEntity(theEntity);
887 if (myNeedToSolve) // the entity is changed
889 // Verify the entity is a point and add temporary constraint of permanency
890 boost::shared_ptr<GeomDataAPI_Point> aPoint =
891 boost::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
892 boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
893 boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
894 if (aPoint || aPoint2D)
895 addTemporaryConstraintWhereDragged(theEntity);
898 // Restore flag of changes
899 myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
902 updateRelatedConstraints(theEntity);
906 // ============================================================================
907 // Function: addTemporaryConstraintWhereDragged
908 // Class: SketchSolver_ConstraintGroup
909 // Purpose: add transient constraint SLVS_C_WHERE_DRAGGED for the entity,
910 // which was moved by user
911 // ============================================================================
912 void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged(
913 boost::shared_ptr<ModelAPI_Attribute> theEntity)
915 // Find identifier of the entity
916 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
917 anEntIter = myEntityAttrMap.find(theEntity);
918 if (anEntIter == myEntityAttrMap.end())
921 // If this is a first dragged point, its parameters should be placed
922 // into Slvs_System::dragged field to avoid system inconsistense
923 if (myTempPointWhereDragged.empty())
925 int anEntPos = Search(anEntIter->second, myEntities);
926 Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
927 for (int i = 0; i < 4; i++, aDraggedParam++)
928 if (*aDraggedParam != 0)
929 myTempPointWhereDragged.push_back(*aDraggedParam);
930 myTempPointWDrgdID = myEntities[anEntPos].h;
934 // Get identifiers of all dragged points
935 std::set<Slvs_hEntity> aDraggedPntID;
936 aDraggedPntID.insert(myTempPointWDrgdID);
937 std::list<Slvs_hConstraint>::iterator aTmpCoIter = myTempConstraints.begin();
938 for ( ; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++)
940 unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
941 if (aConstrPos < myConstraints.size())
942 aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
944 // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
945 std::vector< std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
946 for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
948 if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
949 continue; // the entity was not found in current set
951 // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
952 std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
953 for ( ; aDrgIter != aDraggedPntID.end(); aDrgIter++)
954 if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
955 return ; // the SLVS_C_WHERE_DRAGGED constraint already exists
958 // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
959 Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
960 myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
961 myConstraints.push_back(aWDConstr);
962 myTempConstraints.push_back(aWDConstr.h);
965 // ============================================================================
966 // Function: removeTemporaryConstraints
967 // Class: SketchSolver_ConstraintGroup
968 // Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after
969 // resolving the set of constraints
970 // ============================================================================
971 void SketchSolver_ConstraintGroup::removeTemporaryConstraints()
973 std::list<Slvs_hConstraint>::reverse_iterator aTmpConstrIter;
974 for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend(); aTmpConstrIter++)
976 unsigned int aConstrPos = Search(*aTmpConstrIter, myConstraints);
977 if (aConstrPos >= myConstraints.size())
979 myConstraints.erase(myConstraints.begin() + aConstrPos);
981 // If the removing constraint has higher index, decrease the indexer
982 if (*aTmpConstrIter == myConstrMaxID)
985 myTempConstraints.clear();
987 // Clear basic dragged point
988 myTempPointWhereDragged.clear();
991 // ============================================================================
992 // Function: removeConstraint
993 // Class: SketchSolver_ConstraintGroup
994 // Purpose: remove constraint and all unused entities
995 // ============================================================================
996 void SketchSolver_ConstraintGroup::removeConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
998 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::iterator
999 anIterToRemove = myConstraintMap.find(theConstraint);
1000 if (anIterToRemove == myConstraintMap.end())
1003 Slvs_hConstraint aCnstrToRemove = anIterToRemove->second;
1004 // Remove constraint from the map
1005 myConstraintMap.erase(anIterToRemove);
1007 // Find unused entities
1008 int aConstrPos = Search(aCnstrToRemove, myConstraints);
1009 std::set<Slvs_hEntity> anEntToRemove;
1010 Slvs_hEntity aCnstEnt[] = {myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB,
1011 myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB};
1012 for (int i = 0; i < 4; i++)
1013 if (aCnstEnt[i] != 0)
1014 anEntToRemove.insert(aCnstEnt[i]);
1015 myConstraints.erase(myConstraints.begin() + aConstrPos);
1016 if (aCnstrToRemove == myConstrMaxID)
1018 std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1019 for ( ; aConstrIter != myConstraints.end(); aConstrIter++)
1021 Slvs_hEntity aEnts[] = {aConstrIter->ptA, aConstrIter->ptB,
1022 aConstrIter->entityA, aConstrIter->entityB};
1023 for (int i = 0; i < 4; i++)
1024 if (aEnts[i] != 0 && anEntToRemove.find(aEnts[i]) != anEntToRemove.end())
1025 anEntToRemove.erase(aEnts[i]);
1028 if (anEntToRemove.empty())
1031 // Remove unused entities
1032 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
1033 anEntAttrIter = myEntityAttrMap.begin();
1034 while (anEntAttrIter != myEntityAttrMap.end())
1036 if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end())
1038 std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
1039 aRemovedIter = anEntAttrIter;
1041 myEntityAttrMap.erase(aRemovedIter);
1043 else anEntAttrIter++;
1045 std::map<FeaturePtr, Slvs_hEntity>::iterator
1046 anEntFeatIter = myEntityFeatMap.begin();
1047 while (anEntFeatIter != myEntityFeatMap.end())
1049 if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end())
1051 std::map<FeaturePtr, Slvs_hEntity>::iterator
1052 aRemovedIter = anEntFeatIter;
1054 myEntityFeatMap.erase(aRemovedIter);
1056 else anEntFeatIter++;
1058 std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = anEntToRemove.rbegin();
1059 for ( ; aRemIter != anEntToRemove.rend(); aRemIter++)
1061 unsigned int anEntPos = Search(*aRemIter, myEntities);
1062 if (anEntPos >= myEntities.size())
1064 unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
1065 if (aParamPos >= myParams.size())
1068 while (myEntities[anEntPos].param[aNbParams] != 0)
1070 if (myEntities[anEntPos].param[aNbParams-1] == myParamMaxID)
1071 myParamMaxID -= aNbParams;
1072 myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
1073 if (*aRemIter == myEntityMaxID)
1075 myEntities.erase(myEntities.begin() + anEntPos);
1077 // Remove entity's ID from the lists of conincident points
1078 std::vector< std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1079 for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
1080 aCoPtIter->erase(*aRemIter);
1082 if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty())
1083 myCoincidentPoints.clear();
1087 // ============================================================================
1088 // Function: addCoincidentPoints
1089 // Class: SketchSolver_ConstraintGroup
1090 // Purpose: add coincident point the appropriate list of such points
1091 // ============================================================================
1092 bool SketchSolver_ConstraintGroup::addCoincidentPoints(
1093 const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2)
1095 std::vector< std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1096 std::vector< std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
1097 while (aCoPtIter != myCoincidentPoints.end())
1099 bool isFound[2] = { // indicate which point ID was already in coincidence constraint
1100 aCoPtIter->find(thePoint1) != aCoPtIter->end(),
1101 aCoPtIter->find(thePoint2) != aCoPtIter->end(),
1103 if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need additional one
1105 if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1]))
1107 if (aFirstFound != myCoincidentPoints.end())
1108 { // there are two groups of coincident points connected by created constraint => merge them
1109 int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
1110 int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
1111 aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
1112 myCoincidentPoints.erase(aCoPtIter);
1113 aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
1114 aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
1119 aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
1120 aFirstFound = aCoPtIter;
1125 // No points were found, need to create new set
1126 if (aFirstFound == myCoincidentPoints.end())
1128 std::set<Slvs_hEntity> aNewSet;
1129 aNewSet.insert(thePoint1);
1130 aNewSet.insert(thePoint2);
1131 myCoincidentPoints.push_back(aNewSet);
1138 // ============================================================================
1139 // Function: updateRelatedConstraints
1140 // Class: SketchSolver_ConstraintGroup
1141 // Purpose: emit the signal to update constraints
1142 // ============================================================================
1143 void SketchSolver_ConstraintGroup::updateRelatedConstraints(
1144 boost::shared_ptr<ModelAPI_Attribute> theEntity) const
1146 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
1147 aConstrIter = myConstraintMap.begin();
1148 for ( ; aConstrIter != myConstraintMap.end(); aConstrIter++)
1150 std::list< boost::shared_ptr<ModelAPI_Attribute> > anAttributes =
1151 aConstrIter->first->data()->attributes(std::string());
1153 std::list< boost::shared_ptr<ModelAPI_Attribute> >::iterator
1154 anAttrIter = anAttributes.begin();
1155 for ( ; anAttrIter != anAttributes.end(); anAttrIter++)
1157 bool isUpd = (*anAttrIter == theEntity);
1158 boost::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1159 boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
1160 if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
1165 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1166 ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
1173 void SketchSolver_ConstraintGroup::updateRelatedConstraints(
1174 boost::shared_ptr<ModelAPI_Feature> theFeature) const
1176 std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
1177 aConstrIter = myConstraintMap.begin();
1178 for ( ; aConstrIter != myConstraintMap.end(); aConstrIter++)
1180 std::list< boost::shared_ptr<ModelAPI_Attribute> > anAttributes =
1181 aConstrIter->first->data()->attributes(std::string());
1183 std::list< boost::shared_ptr<ModelAPI_Attribute> >::iterator
1184 anAttrIter = anAttributes.begin();
1185 for ( ; anAttrIter != anAttributes.end(); anAttrIter++)
1187 boost::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1188 boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
1189 if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature)
1191 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1192 ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
1201 // ========================================================
1202 // ========= Auxiliary functions ===============
1203 // ========================================================
1205 template <typename T>
1206 int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
1208 int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
1209 int aVecSize = theEntities.size();
1210 while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
1212 while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
1214 if (aResIndex == -1)
1215 aResIndex = aVecSize;