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_Pnt2d.h>
15 #include <GeomDataAPI_Dir.h>
16 #include <GeomDataAPI_Point.h>
17 #include <GeomDataAPI_Point2D.h>
18 #include <ModelAPI_AttributeDouble.h>
19 #include <ModelAPI_AttributeRefList.h>
20 #include <ModelAPI_Document.h>
21 #include <ModelAPI_Events.h>
22 #include <ModelAPI_ResultConstruction.h>
24 #include <SketchPlugin_Constraint.h>
25 #include <SketchPlugin_ConstraintLength.h>
26 #include <SketchPlugin_ConstraintCoincidence.h>
27 #include <SketchPlugin_ConstraintRigid.h>
29 #include <SketchPlugin_Arc.h>
30 #include <SketchPlugin_Circle.h>
31 #include <SketchPlugin_Line.h>
32 #include <SketchPlugin_Point.h>
33 #include <SketchPlugin_Sketch.h>
38 /// Tolerance for value of parameters
39 const double tolerance = 1.e-10;
42 * Collects all sketch solver error' codes
43 * as inline static functions
45 // TODO: Move this class into a separate file
46 class SketchSolver_Error
49 /// The value parameter for the constraint
50 inline static const std::string& CONSTRAINTS()
52 static const std::string MY_ERROR_VALUE("Conflicting constraints");
53 return MY_ERROR_VALUE;
55 /// The entities need to have shared point, but they have not
56 inline static const std::string& NO_COINCIDENT_POINTS()
58 static const std::string MY_ERROR_VALUE("Objects should have coincident point");
59 return MY_ERROR_VALUE;
63 /// This value is used to give unique index to the groups
64 static Slvs_hGroup myGroupIndexer = 0;
66 /** \brief Search the entity/parameter with specified ID in the list of elements
67 * \param[in] theEntityID unique ID of the element
68 * \param[in] theEntities list of elements
69 * \return position of the found element or -1 if the element is not found
72 static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
74 // ========================================================
75 // ========= SketchSolver_ConstraintGroup ===============
76 // ========================================================
78 SketchSolver_ConstraintGroup::SketchSolver_ConstraintGroup(
79 std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
80 : myID(++myGroupIndexer),
90 myEntOfConstr.clear();
91 myConstraints.clear();
93 myTempConstraints.clear();
94 myTempPointWhereDragged.clear();
95 myTempPointWDrgdID = 0;
97 // Initialize workplane
98 myWorkplane.h = SLVS_E_UNKNOWN;
100 assert(addWorkplane(theWorkplane));
102 addWorkplane(theWorkplane);
106 SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
110 myEntOfConstr.clear();
111 myConstraints.clear();
112 myConstraintMap.clear();
113 myTempConstraints.clear();
114 myTempPointWhereDragged.clear();
116 // If the group with maximal identifier is deleted, decrease the indexer
117 if (myID == myGroupIndexer)
121 // ============================================================================
122 // Function: isBaseWorkplane
123 // Class: SketchSolver_ConstraintGroup
124 // Purpose: verify the group is based on the given workplane
125 // ============================================================================
126 bool SketchSolver_ConstraintGroup::isBaseWorkplane(
127 std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane) const
129 return theWorkplane == mySketch;
132 // ============================================================================
133 // Function: isInteract
134 // Class: SketchSolver_ConstraintGroup
135 // Purpose: verify are there any entities in the group used by given constraint
136 // ============================================================================
137 bool SketchSolver_ConstraintGroup::isInteract(
138 std::shared_ptr<SketchPlugin_Feature> theFeature) const
140 // Check the group is empty
144 // Check if the feature is already in the group
145 if (myEntityFeatMap.find(theFeature) != myEntityFeatMap.end())
147 std::shared_ptr<SketchPlugin_Constraint> aConstr =
148 std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
149 if (aConstr && myConstraintMap.find(aConstr) != myConstraintMap.end())
152 // Go through the attributes and verify if some of them already in the group
153 std::list<std::shared_ptr<ModelAPI_Attribute>>
154 anAttrList = theFeature->data()->attributes(std::string());
155 std::list<std::shared_ptr<ModelAPI_Attribute>>::const_iterator
156 anAttrIter = anAttrList.begin();
157 for ( ; anAttrIter != anAttrList.end(); anAttrIter++) {
158 std::shared_ptr<ModelAPI_AttributeRefAttr> aCAttrRef =
159 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
160 if (!aCAttrRef || !aCAttrRef->isObject()) {
161 std::shared_ptr<ModelAPI_Attribute> anAttr =
162 aCAttrRef ? aCAttrRef->attr() : *anAttrIter;
163 if (myEntityAttrMap.find(anAttr) != myEntityAttrMap.end())
166 ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
167 aCAttrRef->object());
170 std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
171 FeaturePtr aFeature = aDoc->feature(aRC);
172 if (myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
174 // search attributes of a feature to be parameters of constraint
175 std::list<std::shared_ptr<ModelAPI_Attribute> > aFeatAttrList =
176 aFeature->data()->attributes(std::string());
177 std::list<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aFAIter = aFeatAttrList
179 for (; aFAIter != aFeatAttrList.end(); aFAIter++)
180 if (myEntityAttrMap.find(*aFAIter) != myEntityAttrMap.end())
185 // Entities did not found
189 // ============================================================================
190 // Function: checkConstraintConsistence
191 // Class: SketchSolver_ConstraintGroup
192 // Purpose: verifies and changes parameters of the constraint
193 // ============================================================================
194 void SketchSolver_ConstraintGroup::checkConstraintConsistence(Slvs_Constraint& theConstraint)
196 if (theConstraint.type == SLVS_C_PT_LINE_DISTANCE) {
197 // Get constraint parameters and check the sign of constraint value
200 int aPtPos = Search(theConstraint.ptA, myEntities);
201 int aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
202 std::shared_ptr<GeomAPI_XY> aPoint(
203 new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
206 int aLnPos = Search(theConstraint.entityA, myEntities);
207 aPtPos = Search(myEntities[aLnPos].point[0], myEntities);
208 aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
209 std::shared_ptr<GeomAPI_XY> aStart(
210 new GeomAPI_XY(-myParams[aPtParamPos].val, -myParams[aPtParamPos + 1].val));
211 aPtPos = Search(myEntities[aLnPos].point[1], myEntities);
212 aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
213 std::shared_ptr<GeomAPI_XY> aEnd(
214 new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
216 aEnd = aEnd->added(aStart);
217 aPoint = aPoint->added(aStart);
218 if (aPoint->cross(aEnd) * theConstraint.valA < 0.0)
219 theConstraint.valA *= -1.0;
223 // ============================================================================
224 // Function: changeConstraint
225 // Class: SketchSolver_ConstraintGroup
226 // Purpose: create/update the constraint in the group
227 // ============================================================================
228 bool SketchSolver_ConstraintGroup::changeConstraint(
229 std::shared_ptr<SketchPlugin_Constraint> theConstraint)
231 // There is no workplane yet, something wrong
232 if (myWorkplane.h == SLVS_E_UNKNOWN)
235 if (theConstraint && theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID())
236 return changeRigidConstraint(theConstraint);
238 // Search this constraint in the current group to update it
239 ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
240 std::vector<Slvs_Constraint>::iterator aConstrIter;
241 if (aConstrMapIter != myConstraintMap.end()) {
242 int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
243 aConstrIter = myConstraints.begin() + aConstrPos;
246 // Get constraint type and verify the constraint parameters are correct
247 SketchSolver_Constraint aConstraint(theConstraint);
248 int aConstrType = aConstraint.getType();
249 if (aConstrType == SLVS_C_UNKNOWN
250 || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
252 const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
254 // Create constraint parameters
255 double aDistance = 0.0; // scalar value of the constraint
256 AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
257 theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE()));
259 aDistance = aDistAttr->value();
260 // Issue #196: checking the positivity of the distance constraint
261 if (aDistance < tolerance &&
262 (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE))
264 // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
265 if (aConstrType == SLVS_C_DIAMETER)
267 if (aConstrMapIter != myConstraintMap.end()
268 && fabs(aConstrIter->valA - aDistance) > tolerance) {
269 myNeedToSolve = true;
270 aConstrIter->valA = aDistance;
274 size_t aNbTmpConstraints = myTempConstraints.size();
275 Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
276 for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
277 aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
278 std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
279 ModelAPI_AttributeRefAttr>(
280 theConstraint->data()->attribute(aConstraintAttributes[indAttr]));
284 // Convert the object of the attribute to the feature
286 if (aConstrAttr->isObject() && aConstrAttr->object()) {
287 ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
288 aConstrAttr->object());
291 std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
292 aFeature = aDoc->feature(aRC);
295 // For the length constraint the start and end points of the line should be added to the entities list instead of line
296 if (aConstrType == SLVS_C_PT_PT_DISTANCE
297 && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0) {
298 Slvs_hEntity aLineEnt = changeEntityFeature(aFeature);
299 int aEntPos = Search(aLineEnt, myEntities);
300 aConstrEnt[indAttr++] = myEntities[aEntPos].point[0];
301 aConstrEnt[indAttr++] = myEntities[aEntPos].point[1];
302 while (indAttr < CONSTRAINT_ATTR_SIZE)
303 aConstrEnt[indAttr++] = 0;
304 break; // there should be no other entities
305 } else if (aConstrAttr->isObject())
306 aConstrEnt[indAttr] = changeEntityFeature(aFeature);
308 aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
311 if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
312 // Several points may be coincident, it is not necessary to store all constraints between them.
313 // Try to find sequence of coincident points which connects the points of new constraint
314 if (aConstrType == SLVS_C_POINTS_COINCIDENT) {
315 if (aConstrEnt[0] == aConstrEnt[1]) // no need to add self coincidence
317 if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) {
318 myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes
321 if (aNbTmpConstraints < myTempConstraints.size()) {
322 // There was added temporary constraint. Check that there is no coincident points which already rigid.
324 // Get list of already fixed points
325 std::set<Slvs_hEntity> anAlreadyFixed;
326 std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
327 for (; aCIter != myConstraints.end(); aCIter++)
328 if (aCIter->type == SLVS_C_WHERE_DRAGGED) {
329 std::list<Slvs_hConstraint>::const_iterator aTmpIt = myTempConstraints.begin();
330 for (; aTmpIt != myTempConstraints.end(); aTmpIt++)
331 if (*aTmpIt == aCIter->h)
333 if (aTmpIt == myTempConstraints.end())
334 anAlreadyFixed.insert(aCIter->ptA);
337 std::set<Slvs_hConstraint> aTmpConstrToDelete;
338 std::list<Slvs_hConstraint>::reverse_iterator aTmpIter = myTempConstraints.rbegin();
339 size_t aCurSize = myTempConstraints.size();
340 for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend();
341 aTmpIter++, aCurSize--) {
342 int aConstrPos = Search(*aTmpIter, myConstraints);
343 std::vector<std::set<Slvs_hEntity> >::const_iterator
344 aCoincIter = myCoincidentPoints.begin();
345 for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
346 if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) {
347 std::set<Slvs_hEntity>::const_iterator anIt;
348 for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++)
349 if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) {
350 aTmpConstrToDelete.insert(*aTmpIter);
356 if (!aTmpConstrToDelete.empty())
357 removeTemporaryConstraints(aTmpConstrToDelete);
360 // For the tangency constraints it is necessary to identify which points of entities are coincident
361 int aSlvsOtherFlag = 0;
362 int aSlvsOther2Flag = 0;
363 if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) {
364 // Search entities used by constraint
365 int anEnt1Pos = Search(aConstrEnt[2], myEntities);
366 int anEnt2Pos = Search(aConstrEnt[3], myEntities);
367 // Obtain start and end points of entities
368 Slvs_hEntity aPointsToFind[4];
369 aPointsToFind[0] = myEntities[anEnt1Pos].point[1];
370 aPointsToFind[1]= myEntities[anEnt1Pos].point[2];
371 bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT);
372 aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1];
373 aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2];
374 // Search coincident points
375 bool isPointFound[4];
376 std::vector<std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
377 for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) {
378 for (int i = 0; i < 4; i++)
379 isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end());
380 if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) {
381 // the arc is tangent by end point
382 if (isPointFound[1]) aSlvsOtherFlag = 1;
383 // the second item is an arc and it is tangent by end point too
384 if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1;
388 if (aCPIter == myCoincidentPoints.end()) {
389 // There is no coincident points between tangential objects. Generate error message
390 Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
395 // Create SolveSpace constraint structure
396 Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
397 myWorkplane.h, aDistance, aConstrEnt[0],
398 aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
399 if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag;
400 if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag;
401 myConstraints.push_back(aSlvsConstr);
402 myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aSlvsConstr.h);
403 int aConstrPos = Search(aSlvsConstr.h, myConstraints);
404 aConstrIter = myConstraints.begin() + aConstrPos;
405 myNeedToSolve = true;
406 } else { // Attributes of constraint may be changed => update constraint
407 Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB,
408 &aConstrIter->entityA, &aConstrIter->entityB,
409 &aConstrIter->entityC, &aConstrIter->entityD};
410 for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
411 if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr])
413 *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr];
414 myNeedToSolve = true;
419 // Update flags of entities to be used by constraints
420 for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
421 if (aConstrEnt[indAttr] != 0) {
422 int aPos = Search(aConstrEnt[indAttr], myEntities);
423 myEntOfConstr[aPos] = true;
424 // Sub-entities should be used implcitly
425 Slvs_hEntity* aEntPtr = myEntities[aPos].point;
426 while (*aEntPtr != 0) {
427 aPos = Search(*aEntPtr, myEntities);
428 myEntOfConstr[aPos] = true;
433 checkConstraintConsistence(*aConstrIter);
437 // ============================================================================
438 // Function: changeRigidConstraint
439 // Class: SketchSolver_ConstraintGroup
440 // Purpose: create/update the "Rigid" constraint in the group
441 // ============================================================================
442 bool SketchSolver_ConstraintGroup::changeRigidConstraint(
443 std::shared_ptr<SketchPlugin_Constraint> theConstraint)
445 // Search this constraint in the current group to update it
446 ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
447 std::vector<Slvs_Constraint>::iterator aConstrIter;
448 if (aConstrMapIter != myConstraintMap.end()) {
449 int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
450 aConstrIter = myConstraints.begin() + aConstrPos;
453 // Get constraint type and verify the constraint parameters are correct
454 SketchSolver_Constraint aConstraint(theConstraint);
455 int aConstrType = aConstraint.getType();
456 if (aConstrType == SLVS_C_UNKNOWN
457 || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
459 const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
461 Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN;
462 std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
463 ModelAPI_AttributeRefAttr>(
464 theConstraint->data()->attribute(aConstraintAttributes[0]));
468 // Convert the object of the attribute to the feature
470 if (aConstrAttr->isObject() && aConstrAttr->object()) {
471 ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
472 aConstrAttr->object());
475 std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
476 aFeature = aDoc->feature(aRC);
479 aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr());
481 if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
482 // Check the fixed entity is not a point.
483 std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
484 ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0]));
485 std::shared_ptr<GeomDataAPI_Point> aPoint =
486 std::dynamic_pointer_cast<GeomDataAPI_Point>(aConstrAttr->attr());
487 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
488 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aConstrAttr->attr());
489 if (aPoint || aPoint2D) {
490 // Create SolveSpace constraint structure
491 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
492 ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
493 aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
494 myConstraints.push_back(aConstraint);
495 myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aConstraint.h);
496 int aConstrPos = Search(aConstraint.h, myConstraints);
497 aConstrIter = myConstraints.begin() + aConstrPos;
498 myNeedToSolve = true;
500 myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>();
502 // To avoid SolveSpace problems:
503 // * if the circle is rigid, we will fix its center and radius;
504 // * if the arc is rigid, we will fix its start and end points and radius.
505 double aRadius = 0.0;
507 bool isCircle = false;
509 if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
510 std::shared_ptr<GeomDataAPI_Point2D> aCenter =
511 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
512 aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
513 std::shared_ptr<GeomDataAPI_Point2D> aStart =
514 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
515 aFeature->data()->attribute(SketchPlugin_Arc::START_ID()));
516 aRadius = aStart->pnt()->distance(aCenter->pnt());
518 } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
519 aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
520 aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
525 // Get list of already fixed points
526 std::set<Slvs_hEntity> anAlreadyFixed;
527 std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
528 for (; aCIter != myConstraints.end(); aCIter++)
529 if (aCIter->type == SLVS_C_WHERE_DRAGGED)
530 anAlreadyFixed.insert(aCIter->ptA);
532 // Create constraints to fix the parameters of the entity
533 int aEntPos = Search(aConstrEnt, myEntities);
534 Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point;
535 if (isArc) aPointsPtr++; // avoid to fix center of arc
536 while (*aPointsPtr != 0) {
537 // Avoid to create additional "Rigid" constraints for coincident points
538 bool isCoincAlreadyFixed = false;
539 if (!anAlreadyFixed.empty()) {
540 if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end())
541 isCoincAlreadyFixed = true;
543 std::vector<std::set<Slvs_hEntity> >::const_iterator aCoincIter =
544 myCoincidentPoints.begin();
545 for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) {
546 if (aCoincIter->find(*aPointsPtr) == aCoincIter->end())
548 std::set<Slvs_hEntity>::const_iterator anIter = anAlreadyFixed.begin();
549 for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++)
550 if (aCoincIter->find(*anIter) != aCoincIter->end())
551 isCoincAlreadyFixed = true;
555 if (!isCoincAlreadyFixed) {
556 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
557 ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
558 *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
559 myConstraints.push_back(aConstraint);
560 myConstraintMap[theConstraint].push_back(aConstraint.h);
565 if (isArc || isCircle) { // add radius constraint
566 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
567 ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius,
568 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN);
569 myConstraints.push_back(aConstraint);
570 myConstraintMap[theConstraint].push_back(aConstraint.h);
573 // The object is already rigid, so there is no constraints added
574 if (myConstraintMap[theConstraint].empty()) {
575 myConstraintMap.erase(theConstraint);
576 myNeedToSolve = false;
579 myNeedToSolve = true;
585 // ============================================================================
586 // Function: changeEntity
587 // Class: SketchSolver_ConstraintGroup
588 // Purpose: create/update the element affected by any constraint
589 // ============================================================================
590 Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
591 std::shared_ptr<ModelAPI_Attribute> theEntity)
593 // If the entity is already in the group, try to find it
594 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
595 myEntityAttrMap.find(theEntity);
597 std::vector<Slvs_Param>::const_iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise
598 if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
599 aParamIter = myParams.end();
600 else { // the entity already exists
601 aEntPos = Search(aEntIter->second, myEntities);
602 int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
603 aParamIter = myParams.begin() + aParamPos;
605 const bool isEntExists = (aEntIter != myEntityAttrMap.end()); // defines that the entity already exists
606 const bool isNeedToSolve = myNeedToSolve;
607 myNeedToSolve = false;
610 // Verify that the entity is not used by "Rigid" constraint.
611 // If it is used, the object should not move.
612 std::vector<std::set<Slvs_hEntity> >::iterator aCoincIter = myCoincidentPoints.begin();
613 for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
614 if (aCoincIter->find(aEntIter->second) != aCoincIter->end())
616 std::set<Slvs_hEntity> aCoincident;
617 if (aCoincIter != myCoincidentPoints.end()) {
618 aCoincident = *aCoincIter;
619 aCoincident.erase(aEntIter->second);
621 std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
622 for (; aConstrIter != myConstraints.end(); aConstrIter++)
623 if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
624 aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
625 myNeedToSolve = true;
626 return aEntIter->second;
631 // Look over supported types of entities
632 Slvs_Entity aNewEntity;
633 aNewEntity.h = SLVS_E_UNKNOWN;
636 std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
639 Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
640 Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
641 Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
642 if (!isEntExists) // New entity
643 aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
645 // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
646 if (myWorkplane.h == SLVS_E_UNKNOWN)
647 return SLVS_E_UNKNOWN;
650 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
651 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
653 Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
654 Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
655 if (!isEntExists) // New entity
656 aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
658 // Scalar value (used for the distance entities)
659 AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
661 Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
662 if (!isEntExists) // New entity
663 aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
667 /// \todo Other types of entities
669 Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type
672 myNeedToSolve = myNeedToSolve || isNeedToSolve;
673 aResult = aEntIter->second;
674 } else if (aNewEntity.h != SLVS_E_UNKNOWN) {
675 myEntities.push_back(aNewEntity);
676 myEntOfConstr.push_back(false);
677 myEntityAttrMap[theEntity] = aNewEntity.h;
678 aResult = aNewEntity.h;
681 // If the attribute was changed by the user, we need to fix it before solving
682 if (myNeedToSolve && theEntity->isImmutable())
683 addTemporaryConstraintWhereDragged(theEntity, false);
688 // ============================================================================
689 // Function: changeEntity
690 // Class: SketchSolver_ConstraintGroup
691 // Purpose: create/update the element defined by the feature affected by any constraint
692 // ============================================================================
693 Slvs_hEntity SketchSolver_ConstraintGroup::changeEntityFeature(FeaturePtr theEntity)
695 if (!theEntity->data()->isValid())
696 return SLVS_E_UNKNOWN;
697 // If the entity is already in the group, try to find it
698 std::map<FeaturePtr, Slvs_hEntity>::const_iterator aEntIter = myEntityFeatMap.find(theEntity);
699 // defines that the entity already exists
700 const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
702 Slvs_Entity aNewEntity;
703 aNewEntity.h = SLVS_E_UNKNOWN;
705 // SketchPlugin features
706 std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
707 SketchPlugin_Feature>(theEntity);
708 if (aFeature) { // Verify the feature by its kind
709 const std::string& aFeatureKind = aFeature->getKind();
710 AttributePtr anAttribute;
713 if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
714 anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
715 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
716 Slvs_hEntity aStart = changeEntity(anAttribute);
718 anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
719 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
720 Slvs_hEntity aEnd = changeEntity(anAttribute);
722 if (!isEntExists) // New entity
723 aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
726 else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
727 anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
728 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
729 Slvs_hEntity aCenter = changeEntity(anAttribute);
731 anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
732 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
733 Slvs_hEntity aRadius = changeEntity(anAttribute);
735 if (!isEntExists) // New entity
736 aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter,
737 myWorkplane.normal, aRadius);
740 else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
741 anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
742 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
743 Slvs_hEntity aCenter = changeEntity(anAttribute);
745 anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
746 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
747 Slvs_hEntity aStart = changeEntity(anAttribute);
749 anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
750 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
751 Slvs_hEntity aEnd = changeEntity(anAttribute);
754 aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h,
755 myWorkplane.normal, aCenter, aStart, aEnd);
757 // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
758 else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) {
759 anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
760 if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
761 Slvs_hEntity aPoint = changeEntity(anAttribute);
764 return aEntIter->second;
766 // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
767 myEntityFeatMap[theEntity] = aPoint;
768 myNeedToSolve = true;
772 /// \todo Other types of features
775 return aEntIter->second;
777 if (aNewEntity.h != SLVS_E_UNKNOWN) {
778 myEntities.push_back(aNewEntity);
779 myEntOfConstr.push_back(false);
780 myEntityFeatMap[theEntity] = aNewEntity.h;
781 myNeedToSolve = true;
785 // Unsupported or wrong entity type
786 return SLVS_E_UNKNOWN;
789 // ============================================================================
790 // Function: changeNormal
791 // Class: SketchSolver_ConstraintGroup
792 // Purpose: create/update the normal of workplane
793 // ============================================================================
794 Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal(
795 std::shared_ptr<ModelAPI_Attribute> theDirX, std::shared_ptr<ModelAPI_Attribute> theDirY,
796 std::shared_ptr<ModelAPI_Attribute> theNorm)
798 std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
799 std::shared_ptr<GeomDataAPI_Dir> aDirY = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirY);
800 if (!aDirX || !aDirY || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance)
801 || (fabs(aDirY->x()) + fabs(aDirY->y()) + fabs(aDirY->z()) < tolerance))
802 return SLVS_E_UNKNOWN;
804 // quaternion parameters of normal vector
805 double qw, qx, qy, qz;
806 Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
808 double aNormCoord[4] = { qw, qx, qy, qz };
810 // Try to find existent normal
811 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
812 myEntityAttrMap.find(theNorm);
813 std::vector<Slvs_Param>::const_iterator aParamIter; // looks to the first parameter of already existent entity or to the end of vector otherwise
814 if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
815 aParamIter = myParams.end();
816 else { // the entity already exists, update it
817 int aEntPos = Search(aEntIter->second, myEntities);
818 int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
819 aParamIter = myParams.begin() + aParamPos;
822 // Change parameters of the normal
823 Slvs_hParam aNormParams[4];
824 for (int i = 0; i < 4; i++)
825 aNormParams[i] = changeParameter(aNormCoord[i], aParamIter);
827 if (aEntIter != myEntityAttrMap.end()) // the entity already exists
828 return aEntIter->second;
831 Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, aNormParams[0], aNormParams[1],
832 aNormParams[2], aNormParams[3]);
833 myEntities.push_back(aNormal);
834 myEntOfConstr.push_back(false);
835 myEntityAttrMap[theNorm] = aNormal.h;
839 // ============================================================================
840 // Function: addWorkplane
841 // Class: SketchSolver_ConstraintGroup
842 // Purpose: create workplane for the group
843 // ============================================================================
844 bool SketchSolver_ConstraintGroup::addWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch)
846 if (myWorkplane.h || theSketch->getKind().compare(SketchPlugin_Sketch::ID()) != 0)
847 return false; // the workplane already exists or the function parameter is not Sketch
849 mySketch = theSketch;
854 // ============================================================================
855 // Function: updateWorkplane
856 // Class: SketchSolver_ConstraintGroup
857 // Purpose: update parameters of workplane
858 // ============================================================================
859 bool SketchSolver_ConstraintGroup::updateWorkplane()
861 if (!mySketch->data())
862 return false; // case sketch is deleted
863 // Get parameters of workplane
864 std::shared_ptr<ModelAPI_Attribute> aDirX = mySketch->data()->attribute(
865 SketchPlugin_Sketch::DIRX_ID());
866 std::shared_ptr<ModelAPI_Attribute> aDirY = mySketch->data()->attribute(
867 SketchPlugin_Sketch::DIRY_ID());
868 std::shared_ptr<ModelAPI_Attribute> aNorm = mySketch->data()->attribute(
869 SketchPlugin_Sketch::NORM_ID());
870 std::shared_ptr<ModelAPI_Attribute> anOrigin = mySketch->data()->attribute(
871 SketchPlugin_Sketch::ORIGIN_ID());
872 // Transform them into SolveSpace format
873 Slvs_hEntity aNormalWP = changeNormal(aDirX, aDirY, aNorm);
876 Slvs_hEntity anOriginWP = changeEntity(anOrigin);
880 if (!myWorkplane.h) {
882 myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
883 // Workplane should be added to the list of entities
884 myEntities.push_back(myWorkplane);
885 myEntOfConstr.push_back(false);
890 // ============================================================================
891 // Function: changeParameter
892 // Class: SketchSolver_ConstraintGroup
893 // Purpose: create/update value of parameter
894 // ============================================================================
895 Slvs_hParam SketchSolver_ConstraintGroup::changeParameter(
896 const double& theParam, std::vector<Slvs_Param>::const_iterator& thePrmIter)
898 if (thePrmIter != myParams.end()) { // Parameter should be updated
899 int aParamPos = thePrmIter - myParams.begin();
900 if (fabs(thePrmIter->val - theParam) > tolerance) {
901 myNeedToSolve = true; // parameter is changed, need to resolve constraints
902 myParams[aParamPos].val = theParam;
905 return myParams[aParamPos].h;
908 // Newly created parameter
909 Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
910 myParams.push_back(aParam);
911 myNeedToSolve = true;
912 // The list of parameters is changed, move iterator to the end of the list to avoid problems
913 thePrmIter = myParams.end();
917 // ============================================================================
918 // Function: resolveConstraints
919 // Class: SketchSolver_ConstraintGroup
920 // Purpose: solve the set of constraints for the current group
921 // ============================================================================
922 bool SketchSolver_ConstraintGroup::resolveConstraints()
927 myConstrSolver.setGroupID(myID);
928 myConstrSolver.setParameters(myParams);
929 myConstrSolver.setEntities(myEntities);
930 myConstrSolver.setConstraints(myConstraints);
931 myConstrSolver.setDraggedParameters(myTempPointWhereDragged);
933 int aResult = myConstrSolver.solve();
934 if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes
935 // Obtain result into the same list of parameters
936 if (!myConstrSolver.getResult(myParams))
939 // We should go through the attributes map, because only attributes have valued parameters
940 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntIter =
941 myEntityAttrMap.begin();
942 for (; anEntIter != myEntityAttrMap.end(); anEntIter++) {
943 if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
944 anEntIter->first->owner()->data()->blockSendAttributeUpdated(true);
945 if (updateAttribute(anEntIter->first, anEntIter->second))
946 updateRelatedConstraints(anEntIter->first);
948 // unblock all features then
949 for (anEntIter = myEntityAttrMap.begin(); anEntIter != myEntityAttrMap.end(); anEntIter++) {
950 if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
951 anEntIter->first->owner()->data()->blockSendAttributeUpdated(false);
953 } else if (!myConstraints.empty())
954 Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
956 removeTemporaryConstraints();
957 myNeedToSolve = false;
961 // ============================================================================
962 // Function: mergeGroups
963 // Class: SketchSolver_ConstraintGroup
964 // Purpose: append specified group to the current group
965 // ============================================================================
966 void SketchSolver_ConstraintGroup::mergeGroups(const SketchSolver_ConstraintGroup& theGroup)
968 // If specified group is empty, no need to merge
969 if (theGroup.myConstraintMap.empty())
972 // Map between old and new indexes of SolveSpace constraints
973 std::map<Slvs_hConstraint, Slvs_hConstraint> aConstrMap;
975 // Add all constraints from theGroup to the current group
976 ConstraintMap::const_iterator aConstrIter = theGroup.myConstraintMap.begin();
977 for (; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++)
978 if (changeConstraint(aConstrIter->first))
979 aConstrMap[aConstrIter->second.back()] = myConstrMaxID; // the constraint was added => store its ID
981 // Add temporary constraints from theGroup
982 std::list<Slvs_hConstraint>::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin();
983 for (; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++) {
984 std::map<Slvs_hConstraint, Slvs_hConstraint>::iterator aFind = aConstrMap.find(
986 if (aFind != aConstrMap.end())
987 myTempConstraints.push_back(aFind->second);
990 if (myTempPointWhereDragged.empty())
991 myTempPointWhereDragged = theGroup.myTempPointWhereDragged;
992 else if (!theGroup.myTempPointWhereDragged.empty()) { // Need to create additional transient constraint
993 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aFeatureIter =
994 theGroup.myEntityAttrMap.begin();
995 for (; aFeatureIter != theGroup.myEntityAttrMap.end(); aFeatureIter++)
996 if (aFeatureIter->second == myTempPointWDrgdID) {
997 addTemporaryConstraintWhereDragged(aFeatureIter->first);
1002 myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve;
1005 // ============================================================================
1006 // Function: splitGroup
1007 // Class: SketchSolver_ConstraintGroup
1008 // Purpose: divide the group into several subgroups
1009 // ============================================================================
1010 void SketchSolver_ConstraintGroup::splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts)
1012 // Divide constraints and entities into several groups
1013 std::vector<std::set<Slvs_hEntity> > aGroupsEntities;
1014 std::vector<std::set<Slvs_hConstraint> > aGroupsConstr;
1015 int aMaxNbEntities = 0; // index of the group with maximal nuber of elements (this group will be left in the current)
1016 std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1017 for (; aConstrIter != myConstraints.end(); aConstrIter++) {
1018 Slvs_hEntity aConstrEnt[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA,
1019 aConstrIter->entityB };
1020 std::vector<int> anIndexes;
1021 // Go through the groupped entities and find even one of entities of current constraint
1022 std::vector<std::set<Slvs_hEntity> >::iterator aGrEntIter;
1023 for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++) {
1024 bool isFound = false;
1025 for (int i = 0; i < 4 && !isFound; i++)
1026 if (aConstrEnt[i] != 0) {
1027 isFound = (aGrEntIter->find(aConstrEnt[i]) != aGrEntIter->end());
1028 // Also we need to check sub-entities
1029 int aEntPos = Search(aConstrEnt[i], myEntities);
1030 if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
1031 Slvs_hEntity* aSub = myEntities[aEntPos].point;
1032 for (int j = 0; *aSub != 0 && j < 4 && !isFound; aSub++, j++)
1033 isFound = (aGrEntIter->find(*aSub) != aGrEntIter->end());
1037 anIndexes.push_back(aGrEntIter - aGroupsEntities.begin());
1039 // Add new group if no one is found
1040 if (anIndexes.empty()) {
1041 std::set<Slvs_hEntity> aNewGrEnt;
1042 for (int i = 0; i < 4; i++)
1043 if (aConstrEnt[i] != 0) {
1044 aNewGrEnt.insert(aConstrEnt[i]);
1045 int aEntPos = Search(aConstrEnt[i], myEntities);
1046 if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
1047 Slvs_hEntity* aSub = myEntities[aEntPos].point;
1048 for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
1049 aNewGrEnt.insert(*aSub);
1052 std::set<Slvs_hConstraint> aNewGrConstr;
1053 aNewGrConstr.insert(aConstrIter->h);
1055 aGroupsEntities.push_back(aNewGrEnt);
1056 aGroupsConstr.push_back(aNewGrConstr);
1057 if (aNewGrEnt.size() > aGroupsEntities[aMaxNbEntities].size())
1058 aMaxNbEntities = aGroupsEntities.size() - 1;
1059 } else { // Add entities indexes into the found group
1060 aGrEntIter = aGroupsEntities.begin() + anIndexes.front();
1061 for (int i = 0; i < 4; i++)
1062 if (aConstrEnt[i] != 0) {
1063 aGrEntIter->insert(aConstrEnt[i]);
1064 int aEntPos = Search(aConstrEnt[i], myEntities);
1065 if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
1066 Slvs_hEntity* aSub = myEntities[aEntPos].point;
1067 for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
1068 aGrEntIter->insert(*aSub);
1071 aGroupsConstr[anIndexes.front()].insert(aConstrIter->h);
1072 if (aGrEntIter->size() > aGroupsEntities[aMaxNbEntities].size())
1073 aMaxNbEntities = aGrEntIter - aGroupsEntities.begin();
1074 if (anIndexes.size() > 1) { // There are found several connected groups, merge them
1075 std::vector<std::set<Slvs_hEntity> >::iterator aFirstGroup = aGroupsEntities.begin()
1076 + anIndexes.front();
1077 std::vector<std::set<Slvs_hConstraint> >::iterator aFirstConstr = aGroupsConstr.begin()
1078 + anIndexes.front();
1079 std::vector<int>::iterator anInd = anIndexes.begin();
1080 for (++anInd; anInd != anIndexes.end(); anInd++) {
1081 aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end());
1082 aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end());
1084 if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size())
1085 aMaxNbEntities = anIndexes.front();
1086 // Remove merged groups
1087 for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--) {
1088 aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd));
1089 aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd));
1095 if (aGroupsEntities.size() <= 1)
1098 // Remove the group with maximum elements as it will be left in the current group
1099 aGroupsEntities.erase(aGroupsEntities.begin() + aMaxNbEntities);
1100 aGroupsConstr.erase(aGroupsConstr.begin() + aMaxNbEntities);
1102 // Add new groups of constraints and divide current group
1103 std::vector<SketchSolver_ConstraintGroup*> aNewGroups;
1104 for (int i = aGroupsEntities.size(); i > 0; i--) {
1105 SketchSolver_ConstraintGroup* aG = new SketchSolver_ConstraintGroup(mySketch);
1106 aNewGroups.push_back(aG);
1108 ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.begin();
1109 int aConstrMapPos = 0; // position of iterator in the map (used to restore iterator after removing constraint)
1110 while (aConstrMapIter != myConstraintMap.end()) {
1111 std::vector<std::set<Slvs_hConstraint> >::const_iterator aGIter = aGroupsConstr.begin();
1112 std::vector<SketchSolver_ConstraintGroup*>::iterator aGroup = aNewGroups.begin();
1113 for (; aGIter != aGroupsConstr.end(); aGIter++, aGroup++)
1114 if (aGIter->find(aConstrMapIter->second.front()) != aGIter->end()) {
1115 (*aGroup)->changeConstraint(aConstrMapIter->first);
1116 removeConstraint(aConstrMapIter->first);
1118 aConstrMapIter = myConstraintMap.begin();
1119 for (int i = 0; i < aConstrMapPos; i++)
1123 if (aGIter == aGroupsConstr.end()) {
1129 theCuts.insert(theCuts.end(), aNewGroups.begin(), aNewGroups.end());
1132 // ============================================================================
1133 // Function: updateGroup
1134 // Class: SketchSolver_ConstraintGroup
1135 // Purpose: search removed entities and constraints
1136 // ============================================================================
1137 bool SketchSolver_ConstraintGroup::updateGroup()
1139 ConstraintMap::reverse_iterator aConstrIter = myConstraintMap.rbegin();
1140 bool isAllValid = true;
1141 bool isCCRemoved = false; // indicates that at least one of coincidence constraints was removed
1142 int aConstrIndex = 0;
1143 while (/*isAllValid && */aConstrIter != myConstraintMap.rend()) {
1144 if (!aConstrIter->first->data() || !aConstrIter->first->data()->isValid()) {
1145 if (aConstrIter->first->getKind().compare(SketchPlugin_ConstraintCoincidence::ID()) == 0)
1147 removeConstraint(aConstrIter->first);
1149 // Get back the correct position of iterator after the "remove" operation
1150 aConstrIter = myConstraintMap.rbegin();
1151 for (int i = 0; i < aConstrIndex && aConstrIter != myConstraintMap.rend(); i++)
1159 // Check if some entities are invalid too
1160 std::set<Slvs_hEntity> anEntToRemove;
1161 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
1162 anAttrIter = myEntityAttrMap.begin();
1163 while (anAttrIter != myEntityAttrMap.end()) {
1164 if (!anAttrIter->first->owner() || !anAttrIter->first->owner()->data() ||
1165 !anAttrIter->first->owner()->data()->isValid()) {
1166 anEntToRemove.insert(anAttrIter->second);
1167 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
1168 aRemovedIter = anAttrIter;
1170 myEntityAttrMap.erase(aRemovedIter);
1174 std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myEntityFeatMap.begin();
1175 while (aFeatIter != myEntityFeatMap.end()) {
1176 if (!aFeatIter->first || !aFeatIter->first->data() ||
1177 !aFeatIter->first->data()->isValid()) {
1178 anEntToRemove.insert(aFeatIter->second);
1179 std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = aFeatIter;
1181 myEntityFeatMap.erase(aRemovedIter);
1185 removeEntitiesById(anEntToRemove);
1187 // Probably, need to update coincidence constraints
1188 if (isCCRemoved && !myExtraCoincidence.empty()) {
1189 // Make a copy, because the new list of unused constrtaints will be generated
1190 std::set<std::shared_ptr<SketchPlugin_Constraint> > anExtraCopy = myExtraCoincidence;
1191 myExtraCoincidence.clear();
1193 std::set<std::shared_ptr<SketchPlugin_Constraint> >::iterator aCIter = anExtraCopy.begin();
1194 for (; aCIter != anExtraCopy.end(); aCIter++)
1195 if ((*aCIter)->data() && (*aCIter)->data()->isValid())
1196 changeConstraint(*aCIter);
1202 // ============================================================================
1203 // Function: updateAttribute
1204 // Class: SketchSolver_ConstraintGroup
1205 // Purpose: update features of sketch after resolving constraints
1206 // ============================================================================
1207 bool SketchSolver_ConstraintGroup::updateAttribute(
1208 std::shared_ptr<ModelAPI_Attribute> theAttribute, const Slvs_hEntity& theEntityID)
1210 // Search the position of the first parameter of the entity
1211 int anEntPos = Search(theEntityID, myEntities);
1212 int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
1214 // Look over supported types of entities
1217 std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1220 if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance
1221 || fabs(aPoint->y() - myParams[aFirstParamPos + 1].val) > tolerance
1222 || fabs(aPoint->z() - myParams[aFirstParamPos + 2].val) > tolerance) {
1223 aPoint->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val,
1224 myParams[aFirstParamPos + 2].val);
1231 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
1232 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
1234 if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance
1235 || fabs(aPoint2D->y() - myParams[aFirstParamPos + 1].val) > tolerance) {
1236 aPoint2D->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val);
1243 AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
1245 if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance) {
1246 aScalar->setValue(myParams[aFirstParamPos].val);
1252 /// \todo Support other types of entities
1256 // ============================================================================
1257 // Function: updateEntityIfPossible
1258 // Class: SketchSolver_ConstraintGroup
1259 // Purpose: search the entity in this group and update it
1260 // ============================================================================
1261 void SketchSolver_ConstraintGroup::updateEntityIfPossible(
1262 std::shared_ptr<ModelAPI_Attribute> theEntity)
1264 if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) {
1265 // If the attribute is a point and it is changed (the group needs to rebuild),
1266 // probably user has dragged this point into this position,
1267 // so it is necessary to add constraint which will guarantee the point will not change
1269 // Store myNeedToSolve flag to verify the entity is really changed
1270 bool aNeedToSolveCopy = myNeedToSolve;
1271 myNeedToSolve = false;
1273 changeEntity(theEntity);
1275 if (myNeedToSolve) // the entity is changed
1277 // Verify the entity is a point and add temporary constraint of permanency
1278 std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1280 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D = std::dynamic_pointer_cast<
1281 GeomDataAPI_Point2D>(theEntity);
1282 if (aPoint || aPoint2D)
1283 addTemporaryConstraintWhereDragged(theEntity);
1286 // Restore flag of changes
1287 myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
1290 updateRelatedConstraints(theEntity);
1294 // ============================================================================
1295 // Function: addTemporaryConstraintWhereDragged
1296 // Class: SketchSolver_ConstraintGroup
1297 // Purpose: add transient constraint SLVS_C_WHERE_DRAGGED for the entity,
1298 // which was moved by user
1299 // ============================================================================
1300 void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged(
1301 std::shared_ptr<ModelAPI_Attribute> theEntity,
1304 // Find identifier of the entity
1305 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
1306 myEntityAttrMap.find(theEntity);
1307 if (anEntIter == myEntityAttrMap.end())
1310 // Get identifiers of all dragged points
1311 std::set<Slvs_hEntity> aDraggedPntID;
1312 aDraggedPntID.insert(myTempPointWDrgdID);
1313 std::list<Slvs_hConstraint>::const_iterator aTmpCoIter = myTempConstraints.begin();
1314 for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) {
1315 unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
1316 if (aConstrPos < myConstraints.size())
1317 aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
1319 std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1320 for (; aConstrIter != myConstraints.end(); aConstrIter++)
1321 if (aConstrIter->type == SLVS_C_WHERE_DRAGGED)
1322 aDraggedPntID.insert(aConstrIter->ptA);
1323 // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
1324 std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1325 for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) {
1326 if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
1327 continue; // the entity was not found in current set
1329 // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
1330 std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
1331 for (; aDrgIter != aDraggedPntID.end(); aDrgIter++)
1332 if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
1333 return; // the SLVS_C_WHERE_DRAGGED constraint already exists
1335 if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end())
1338 // If this is a first dragged point, its parameters should be placed
1339 // into Slvs_System::dragged field to avoid system inconsistense
1340 if (myTempPointWhereDragged.empty() && theAllowToFit) {
1341 int anEntPos = Search(anEntIter->second, myEntities);
1342 Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
1343 for (int i = 0; i < 4; i++, aDraggedParam++)
1344 if (*aDraggedParam != 0)
1345 myTempPointWhereDragged.push_back(*aDraggedParam);
1346 myTempPointWDrgdID = myEntities[anEntPos].h;
1350 // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
1351 Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
1352 myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
1353 myConstraints.push_back(aWDConstr);
1354 myTempConstraints.push_back(aWDConstr.h);
1357 // ============================================================================
1358 // Function: removeTemporaryConstraints
1359 // Class: SketchSolver_ConstraintGroup
1360 // Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after
1361 // resolving the set of constraints
1362 // ============================================================================
1363 void SketchSolver_ConstraintGroup::removeTemporaryConstraints(
1364 const std::set<Slvs_hConstraint>& theRemoved)
1366 std::list<Slvs_hConstraint>::reverse_iterator aTmpConstrIter;
1367 for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend();
1369 if (!theRemoved.empty() && theRemoved.find(*aTmpConstrIter) == theRemoved.end())
1371 unsigned int aConstrPos = Search(*aTmpConstrIter, myConstraints);
1372 if (aConstrPos >= myConstraints.size())
1374 myConstraints.erase(myConstraints.begin() + aConstrPos);
1376 // If the removing constraint has higher index, decrease the indexer
1377 if (*aTmpConstrIter == myConstrMaxID)
1380 myTempConstraints.clear();
1382 // Clear basic dragged point
1383 myTempPointWhereDragged.clear();
1384 myTempPointWDrgdID = SLVS_E_UNKNOWN;
1387 // ============================================================================
1388 // Function: removeConstraint
1389 // Class: SketchSolver_ConstraintGroup
1390 // Purpose: remove constraint and all unused entities
1391 // ============================================================================
1392 void SketchSolver_ConstraintGroup::removeConstraint(
1393 std::shared_ptr<SketchPlugin_Constraint> theConstraint)
1395 ConstraintMap::iterator anIterToRemove = myConstraintMap.find(theConstraint);
1396 if (anIterToRemove == myConstraintMap.end())
1399 std::vector<Slvs_hConstraint> aCnstrToRemove = anIterToRemove->second;
1400 // Remove constraint from the map
1401 myConstraintMap.erase(anIterToRemove);
1403 std::set<Slvs_hEntity> anEntToRemove;
1405 // Find unused entities
1406 std::vector<Slvs_hConstraint>::iterator aCnstrToRemoveIter = aCnstrToRemove.begin();
1407 for (; aCnstrToRemoveIter != aCnstrToRemove.end(); aCnstrToRemoveIter++) {
1408 int aConstrPos = Search(*aCnstrToRemoveIter, myConstraints);
1409 Slvs_hEntity aCnstEnt[] = { myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB,
1410 myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB };
1411 for (int i = 0; i < 4; i++)
1412 if (aCnstEnt[i] != 0)
1413 anEntToRemove.insert(aCnstEnt[i]);
1414 myConstraints.erase(myConstraints.begin() + aConstrPos);
1415 if (*aCnstrToRemoveIter == myConstrMaxID)
1419 // Find all entities which are based on these unused
1420 std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
1421 for ( ; anEntIter != myEntities.end(); anEntIter++)
1422 if (anEntIter->type == SLVS_E_LINE_SEGMENT || anEntIter->type == SLVS_E_CIRCLE ||
1423 anEntIter->type == SLVS_E_ARC_OF_CIRCLE) {
1424 for (int i = 0; i < 4; i++)
1425 if (anEntToRemove.find(anEntIter->point[i]) != anEntToRemove.end()) {
1426 anEntToRemove.insert(anEntIter->h);
1427 for (int j = 0; j < 4; j++)
1428 if (anEntIter->param[j] != 0)
1429 anEntToRemove.insert(anEntIter->point[j]);
1434 std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
1435 for (; aConstrIter != myConstraints.end(); aConstrIter++) {
1436 Slvs_hEntity aEnts[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA, aConstrIter
1438 for (int i = 0; i < 4; i++)
1439 if (aEnts[i] != 0 && anEntToRemove.find(aEnts[i]) != anEntToRemove.end())
1440 anEntToRemove.erase(aEnts[i]);
1443 if (anEntToRemove.empty())
1446 // Remove unused entities
1447 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntAttrIter =
1448 myEntityAttrMap.begin();
1449 while (anEntAttrIter != myEntityAttrMap.end()) {
1450 if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end()) {
1451 std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator aRemovedIter =
1454 myEntityAttrMap.erase(aRemovedIter);
1458 std::map<FeaturePtr, Slvs_hEntity>::iterator anEntFeatIter = myEntityFeatMap.begin();
1459 while (anEntFeatIter != myEntityFeatMap.end()) {
1460 if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end()) {
1461 std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = anEntFeatIter;
1463 myEntityFeatMap.erase(aRemovedIter);
1468 removeEntitiesById(anEntToRemove);
1470 if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty())
1471 myCoincidentPoints.clear();
1474 // ============================================================================
1475 // Function: removeEntitiesById
1476 // Class: SketchSolver_ConstraintGroup
1477 // Purpose: Removes specified entities and their parameters
1478 // ============================================================================
1479 void SketchSolver_ConstraintGroup::removeEntitiesById(const std::set<Slvs_hEntity>& theEntities)
1481 std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = theEntities.rbegin();
1482 for (; aRemIter != theEntities.rend(); aRemIter++) {
1483 unsigned int anEntPos = Search(*aRemIter, myEntities);
1484 if (anEntPos >= myEntities.size())
1486 if (myEntities[anEntPos].param[0] != 0) {
1487 unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
1488 if (aParamPos >= myParams.size())
1491 while (myEntities[anEntPos].param[aNbParams] != 0)
1493 if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID)
1494 myParamMaxID -= aNbParams;
1495 myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
1496 if (*aRemIter == myEntityMaxID)
1499 myEntities.erase(myEntities.begin() + anEntPos);
1500 myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos);
1502 // Remove entity's ID from the lists of conincident points
1503 std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1504 for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
1505 aCoPtIter->erase(*aRemIter);
1509 // ============================================================================
1510 // Function: addCoincidentPoints
1511 // Class: SketchSolver_ConstraintGroup
1512 // Purpose: add coincident point the appropriate list of such points
1513 // ============================================================================
1514 bool SketchSolver_ConstraintGroup::addCoincidentPoints(const Slvs_hEntity& thePoint1,
1515 const Slvs_hEntity& thePoint2)
1517 std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
1518 std::vector<std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
1519 while (aCoPtIter != myCoincidentPoints.end()) {
1520 bool isFound[2] = { // indicate which point ID was already in coincidence constraint
1521 aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2)
1522 != aCoPtIter->end(), };
1523 if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need additional one
1525 if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) {
1526 if (aFirstFound != myCoincidentPoints.end()) { // there are two groups of coincident points connected by created constraint => merge them
1527 int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
1528 int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
1529 aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
1530 myCoincidentPoints.erase(aCoPtIter);
1531 aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
1532 aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
1535 aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
1536 aFirstFound = aCoPtIter;
1541 // No points were found, need to create new set
1542 if (aFirstFound == myCoincidentPoints.end()) {
1543 std::set<Slvs_hEntity> aNewSet;
1544 aNewSet.insert(thePoint1);
1545 aNewSet.insert(thePoint2);
1546 myCoincidentPoints.push_back(aNewSet);
1552 // ============================================================================
1553 // Function: updateRelatedConstraints
1554 // Class: SketchSolver_ConstraintGroup
1555 // Purpose: emit the signal to update constraints
1556 // ============================================================================
1557 void SketchSolver_ConstraintGroup::updateRelatedConstraints(
1558 std::shared_ptr<ModelAPI_Attribute> theEntity) const
1560 ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
1561 for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
1562 std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
1563 ->attributes(std::string());
1565 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
1566 for (; anAttrIter != anAttributes.end(); anAttrIter++) {
1567 bool isUpd = (*anAttrIter == theEntity);
1568 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
1569 ModelAPI_AttributeRefAttr>(*anAttrIter);
1570 if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
1574 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1575 ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
1582 void SketchSolver_ConstraintGroup::updateRelatedConstraintsFeature(
1583 std::shared_ptr<ModelAPI_Feature> theFeature) const
1585 ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
1586 for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
1587 std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
1588 ->attributes(std::string());
1590 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
1591 for (; anAttrIter != anAttributes.end(); anAttrIter++) {
1592 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
1593 ModelAPI_AttributeRefAttr>(*anAttrIter);
1594 if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature) {
1595 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1596 ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
1603 // ========================================================
1604 // ========= Auxiliary functions ===============
1605 // ========================================================
1607 template<typename T>
1608 int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
1610 int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
1611 int aVecSize = theEntities.size();
1612 while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
1614 while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
1616 if (aResIndex == -1)
1617 aResIndex = aVecSize;