]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Do not allow user to move fixed entities (issue #1043)
authorazv <azv@opencascade.com>
Fri, 27 Nov 2015 13:27:41 +0000 (16:27 +0300)
committerdbv <dbv@opencascade.com>
Tue, 8 Dec 2015 08:45:27 +0000 (11:45 +0300)
src/SketchSolver/SketchSolver_Constraint.cpp
src/SketchSolver/SketchSolver_ConstraintMovement.cpp
src/SketchSolver/SketchSolver_ConstraintMovement.h
src/SketchSolver/SketchSolver_ConstraintRigid.cpp
src/SketchSolver/SketchSolver_ConstraintRigid.h
src/SketchSolver/SketchSolver_Group.cpp
src/SketchSolver/SketchSolver_Storage.cpp
src/SketchSolver/SketchSolver_Storage.h

index 11cdff04bb22f3a64ba17e97d661ef9ce38d2a12..b4b888fa3b75607f333ce26e27e8779247068f31 100644 (file)
@@ -394,6 +394,10 @@ Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int&
   }
 
   Slvs_hGroup aGroupID = myGroup->getId();
+  // do not update entity from another group
+  if (aCurrentEntity.h != SLVS_E_UNKNOWN && aGroupID != aCurrentEntity.group)
+    return aCurrentEntity.h;
+
   // Point in 3D
   std::shared_ptr<GeomDataAPI_Point> aPoint =
       std::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
@@ -488,6 +492,10 @@ Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& th
   }
 
   Slvs_hGroup aGroupID = myGroup->getId();
+  // do not update entity from another group
+  if (aCurrentEntity.h != SLVS_E_UNKNOWN && aGroupID != aCurrentEntity.group)
+    return aCurrentEntity.h;
+
   Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
   DataPtr aData = theEntity->data();
 
index 030274ac2dcc831be74167f26a689dcb20acb1ab..b97d1a754fde25fbc659b8bfa8e0e771e1502c48 100644 (file)
@@ -2,6 +2,11 @@
 #include <SketchSolver_Error.h>
 #include <SketchSolver_Group.h>
 
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+
 SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(FeaturePtr theFeature)
   : SketchSolver_ConstraintRigid(theFeature)
 {
@@ -45,6 +50,7 @@ void SketchSolver_ConstraintMovement::getAttributes(
   theIsFullyMoved = true;
   int aType = SLVS_E_UNKNOWN; // type of created entity
   Slvs_hEntity anEntityID = SLVS_E_UNKNOWN;
+  Slvs_hEntity anEntMaxID = myStorage->entityMaxID();
   anEntityID = myGroup->getFeatureId(myBaseFeature);
   if (anEntityID == SLVS_E_UNKNOWN) {
     anEntityID = changeEntity(myBaseFeature, aType);
@@ -65,17 +71,28 @@ void SketchSolver_ConstraintMovement::getAttributes(
      isComplexFeature = true;
   }
 
+  int aNbOutOfGroup = 0;
   if (isComplexFeature) {
      std::list<AttributePtr> aPoints =
         myBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
      std::list<AttributePtr>::iterator anIt = aPoints.begin();
      for (; anIt != aPoints.end(); ++anIt) {
-       Slvs_hEntity anAttr = myGroup->getAttributeId(*anIt);
+       std::map<AttributePtr, Slvs_hEntity>::const_iterator aFound = myAttributeMap.find(*anIt);
+       Slvs_hEntity anAttr = aFound != myAttributeMap.end() ?
+                             aFound->second : myGroup->getAttributeId(*anIt);
+       Slvs_Entity anAttrEnt = myStorage->getEntity(anAttr);
 
        // Check the attribute changes coordinates
        std::shared_ptr<GeomDataAPI_Point2D> aPt =
           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt);
-       if (isMoved(aPt, anAttr)) {
+       // Check the entity is not lying in the current group or it is not moved
+       if (anAttr == SLVS_E_UNKNOWN || anAttrEnt.group != myGroup->getId() ||
+           (anAttr <= anEntMaxID && !isMoved(aPt, anAttrEnt))) {
+         if (anAttrEnt.group == SLVS_G_OUTOFGROUP)
+           ++aNbOutOfGroup;
+         theIsFullyMoved = false;
+       }
+       else {
          theAttributes.push_back(anAttr);
          // update point coordinates
          Slvs_Entity anAttrEnt = myStorage->getEntity(anAttr);
@@ -86,11 +103,21 @@ void SketchSolver_ConstraintMovement::getAttributes(
            myStorage->updateParameter(aParam);
          }
        }
-       else
-         theIsFullyMoved = false;
      }
   }
 
+  // Additional checking, which leads to fix whole feature, if it has fixed points
+  if (!theIsFullyMoved) {
+    Slvs_Entity aFeature = myStorage->getEntity(anEntityID);
+    int aNbPoints = 4;
+    while (aNbPoints > 0 && aFeature.point[aNbPoints-1] == SLVS_E_UNKNOWN)
+      --aNbPoints;
+    if (aNbPoints == aNbOutOfGroup + (int)theAttributes.size()) {
+      theIsFullyMoved = true;
+      return;
+    }
+  }
+
   // Leave only points which are used in constraints
   if (myStorage->isUsedByConstraints(anEntityID))
     return;
@@ -107,12 +134,43 @@ void SketchSolver_ConstraintMovement::getAttributes(
 }
 
 bool SketchSolver_ConstraintMovement::isMoved(
-    std::shared_ptr<GeomDataAPI_Point2D> thePoint, Slvs_hEntity theEntity)
+    std::shared_ptr<GeomDataAPI_Point2D> thePoint, const Slvs_Entity& theEntity)
 {
-  Slvs_Entity anAttrEnt = myStorage->getEntity(theEntity);
-  double aDeltaX = myStorage->getParameter(anAttrEnt.param[0]).val;
-  double aDeltaY = myStorage->getParameter(anAttrEnt.param[1]).val;
+  double aDeltaX = myStorage->getParameter(theEntity.param[0]).val;
+  double aDeltaY = myStorage->getParameter(theEntity.param[1]).val;
   aDeltaX -= thePoint->x();
   aDeltaY -= thePoint->y();
   return aDeltaX * aDeltaX + aDeltaY * aDeltaY >= tolerance * tolerance;
 }
+
+void SketchSolver_ConstraintMovement::fixFeature()
+{
+  Slvs_hEntity anEntID = fixedEntity();
+
+  std::string aKind;
+  std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFIt = myFeatureMap.begin();
+  for (; aFIt != myFeatureMap.end() && aKind.empty(); ++aFIt)
+    if (aFIt->second == anEntID)
+      aKind = aFIt->first->getKind();
+  std::map<AttributePtr, Slvs_hEntity>::const_iterator anAtIt = myAttributeMap.begin();
+  for (; anAtIt != myAttributeMap.end() && aKind.empty(); ++anAtIt)
+    if (anAtIt->second == anEntID)
+      aKind = anAtIt->first->attributeType();
+
+  if (aKind == SketchPlugin_Line::ID()) {
+    Slvs_Entity aLine = myStorage->getEntity(anEntID);
+    fixLine(aLine);
+  }
+  else if (aKind == SketchPlugin_Arc::ID()) {
+    Slvs_Entity anArc = myStorage->getEntity(anEntID);
+    fixArc(anArc);
+  }
+  else if (aKind == SketchPlugin_Circle::ID()) {
+    Slvs_Entity aCirc = myStorage->getEntity(anEntID);
+    fixCircle(aCirc);
+  }
+  else if (aKind == SketchPlugin_Point::ID() || aKind == GeomDataAPI_Point2D::typeId()) {
+    fixPoint(anEntID);
+  }
+}
+
index dd2b0df741368b380db0aa2459d789dc89cd649e..dbec1b020e25ea06bf4a910cb4431c84f5417e9d 100644 (file)
@@ -38,9 +38,12 @@ protected:
   /// \param[out] theIsFullyMoved shows that the feature is moved, in other case only one point of the feature is shifted
   virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes, bool& theIsFullyMoved);
 
+  /// \brief Fixed feature basing on its type
+  virtual void fixFeature();
+
 private:
   /// \brief Check the coordinates of point are differ than coordinates of correponding SolveSpace entity
-  bool isMoved(std::shared_ptr<GeomDataAPI_Point2D> thePoint, Slvs_hEntity theEntity);
+  bool isMoved(std::shared_ptr<GeomDataAPI_Point2D> thePoint, const Slvs_Entity& theEntity);
 };
 
 #endif
index 3f52e19922f7378498cf097d97e8dafad49cdc4c..ed8ae371271336fa7c9ef9724b6c92a0a5c0c46c 100644 (file)
@@ -40,42 +40,72 @@ void SketchSolver_ConstraintRigid::process()
   fixFeature();
 }
 
+void SketchSolver_ConstraintRigid::update(ConstraintPtr theConstraint)
+{
+  cleanErrorMsg();
+  if (theConstraint && theConstraint == myBaseConstraint &&
+      theConstraint->getKind() == myBaseConstraint->getKind() &&
+      checkAttributesChanged(theConstraint)) {
+    // remove previous constraint and set the given one
+    remove(myBaseConstraint);
+    myBaseConstraint = theConstraint;
+    process();
+  }
+}
+
+static void fixEntity(StoragePtr theStorage, const Slvs_hEntity& theEntID)
+{
+  Slvs_Entity anEntity = theStorage->getEntity(theEntID);
+  anEntity.group = SLVS_G_OUTOFGROUP;
+  theStorage->updateEntity(anEntity);
+  // move out of group all sub-entities
+  for (int i = 0; i < 4; ++i)
+    if (anEntity.point[i] != SLVS_E_UNKNOWN)
+      fixEntity(theStorage, anEntity.point[i]);
+  // move out of group the radius of circle
+  if (anEntity.distance != SLVS_E_UNKNOWN)
+    fixEntity(theStorage, anEntity.distance);
+  // move out of group parameters
+  for (int i = 0; i < 4; ++i)
+    if (anEntity.param[i] != SLVS_E_UNKNOWN) {
+      Slvs_Param aParam = theStorage->getParameter(anEntity.param[i]);
+      aParam.group = SLVS_G_OUTOFGROUP;
+      theStorage->updateParameter(aParam);
+    }
+}
+
 void SketchSolver_ConstraintRigid::fixFeature()
 {
-  Slvs_hEntity anEntID;
-  if (!myFeatureMap.empty())
-    anEntID = myFeatureMap.begin()->second;
-  else
-    anEntID = myAttributeMap.begin()->second;
-  //if (myStorage->isEntityFixed(anEntID, true)) {
-  //  myErrorMsg = SketchSolver_Error::ALREADY_FIXED();
-  //  return;
-  //}
-
-  std::string aKind;
-  if (!myFeatureMap.empty())
-    aKind = myFeatureMap.begin()->first->getKind();
-  else
-    aKind = myAttributeMap.begin()->first->attributeType();
+  Slvs_hEntity anEntID = fixedEntity();
+  if (anEntID != SLVS_E_UNKNOWN)
+    fixEntity(myStorage, anEntID);
+}
 
-  if (aKind == SketchPlugin_Line::ID()) {
-    Slvs_Entity aLine = myStorage->getEntity(anEntID);
-    fixLine(aLine);
-  }
-  else if (aKind == SketchPlugin_Arc::ID()) {
-    Slvs_Entity anArc = myStorage->getEntity(anEntID);
-    fixArc(anArc);
-  }
-  else if (aKind == SketchPlugin_Circle::ID()) {
-    Slvs_Entity aCirc = myStorage->getEntity(anEntID);
-    fixCircle(aCirc);
+Slvs_hEntity SketchSolver_ConstraintRigid::fixedEntity() const
+{
+  Slvs_hEntity anEntID = SLVS_E_UNKNOWN;
+  if (myBaseConstraint) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+    if (aRefAttr->isObject()) {
+      FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+      std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFound = myFeatureMap.find(aFeature);
+      if (aFound != myFeatureMap.end())
+        anEntID = aFound->second;
+    } else {
+      std::map<AttributePtr, Slvs_hEntity>::const_iterator aFound = myAttributeMap.find(aRefAttr->attr());
+      if (aFound != myAttributeMap.end())
+        anEntID = aFound->second;
+    }
   }
-  else if (aKind == SketchPlugin_Point::ID() || aKind == GeomDataAPI_Point2D::typeId()) {
-    fixPoint(anEntID);
+  else if (myBaseFeature) {
+    std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFound = myFeatureMap.find(myBaseFeature);
+    if (aFound != myFeatureMap.end())
+      anEntID = aFound->second;
   }
+  return anEntID;
 }
 
-
 void SketchSolver_ConstraintRigid::getAttributes(
     double& theValue,
     std::vector<Slvs_hEntity>& theAttributes)
@@ -116,38 +146,6 @@ void SketchSolver_ConstraintRigid::getAttributes(
     theAttributes.push_back(anEntityID);
 }
 
-void SketchSolver_ConstraintRigid::adjustConstraint()
-{
-  if (myFeatureMap.empty() || (
-      myFeatureMap.begin()->first->getKind() != SketchPlugin_Arc::ID() && 
-      myFeatureMap.begin()->first->getKind() != SketchPlugin_Circle::ID()))
-    return;
-  FeaturePtr aFeature = myFeatureMap.begin()->first;
-
-  // Search radius constraints and update them
-  Slvs_Constraint aConstraint;
-  std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
-  for (; aCIter != mySlvsConstraints.end(); aCIter++) {
-    aConstraint = myStorage->getConstraint(*aCIter);
-    if (aConstraint.type != SLVS_C_DIAMETER)
-      continue;
-    double aRadius = 0.0;
-    if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
-      std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        aFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
-      std::shared_ptr<GeomAPI_Pnt2d> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        aFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
-      aRadius = aCenter->distance(aStart);
-    } else {
-      aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-          aFeature->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
-    }
-
-    aConstraint.valA = aRadius * 2.0;
-    *aCIter = myStorage->updateConstraint(aConstraint);
-  }
-}
-
 
 bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint)
 {
@@ -155,10 +153,19 @@ bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint)
   if (theConstraint && theConstraint != myBaseConstraint)
     return false;
   bool isFullyRemoved = true;
+
   std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
-  for (; aCIter != mySlvsConstraints.end(); aCIter++)
+  for (; aCIter != mySlvsConstraints.end(); ++aCIter)
     isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
 
+  std::map<FeaturePtr, Slvs_hEntity>::iterator aFIter = myFeatureMap.begin();
+  for (; aFIter != myFeatureMap.end(); ++aFIter)
+    isFullyRemoved = myStorage->removeEntity(aFIter->second) && isFullyRemoved;
+
+  std::map<AttributePtr, Slvs_hEntity>::iterator anAtIter = myAttributeMap.begin();
+  for (; anAtIter != myAttributeMap.end(); ++anAtIter)
+    isFullyRemoved = myStorage->removeEntity(anAtIter->second) && isFullyRemoved;
+
   if (isFullyRemoved) {
     myFeatureMap.clear();
     myAttributeMap.clear();
@@ -169,10 +176,10 @@ bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint)
   return true;
 }
 
-void SketchSolver_ConstraintRigid::fixPoint(const Slvs_hEntity& thePointID)
+Slvs_hConstraint SketchSolver_ConstraintRigid::fixPoint(const Slvs_hEntity& thePointID)
 {
   if (thePointID == SLVS_E_UNKNOWN)
-    return;
+    return SLVS_C_UNKNOWN;
 
   Slvs_Constraint aConstraint;
   Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN;
@@ -180,22 +187,23 @@ void SketchSolver_ConstraintRigid::fixPoint(const Slvs_hEntity& thePointID)
   bool isForceUpdate = (isFixed && !myBaseConstraint &&
                         myStorage->isTemporary(aConstrID));
   if (!isForceUpdate) { // create new constraint
-    if (isFixed) return;
-    aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
+    if (isFixed) return aConstrID;
+    aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
         0.0, thePointID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
     aConstraint.h = myStorage->addConstraint(aConstraint);
     mySlvsConstraints.push_back(aConstraint.h);
     if (!myBaseConstraint)
       myStorage->addConstraintWhereDragged(aConstraint.h);
   } else { // update already existent constraint
-    if (!isFixed || aConstrID == SLVS_E_UNKNOWN || myBaseConstraint)
-      return;
+    if (!isFixed || aConstrID == SLVS_C_UNKNOWN || myBaseConstraint)
+      return SLVS_C_UNKNOWN;
     aConstraint = myStorage->getConstraint(aConstrID);
     aConstraint.ptA = thePointID;
     myStorage->addConstraint(aConstraint);
     if (!myBaseConstraint)
       myStorage->addConstraintWhereDragged(aConstraint.h);
   }
+  return aConstraint.h;
 }
 
 void SketchSolver_ConstraintRigid::fixLine(const Slvs_Entity& theLine)
index 22f4c6dd50e3c794fae2554b20df0d19e96fd679..adac8c6a30a3ab42fdacdd1d22eec49ef6dde6e9 100644 (file)
  *  \brief   Stores data of Rigid (Fixed) constraint
  *
  *  Rigid constraint may have NULL basic SketchPlugin constraint,
- *  because the Rigid constraint may be temporary for correct moving of objects
+ *  because the Rigid constraint may be temporary for correct moving of objects.
+ *
+ *  Rigid constraint does not create a constraint, but builds the entities in separate group,
+ *  so they will not be moved while resolving the set of constraints.
  */
 class SketchSolver_ConstraintRigid : public SketchSolver_Constraint
 {
@@ -27,6 +30,9 @@ public:
   /// Creates temporary constraint based on feature
   SketchSolver_ConstraintRigid(FeaturePtr theFeature);
 
+  /// \brief Update constraint
+  virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
+
   /// \brief Tries to remove constraint
   /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
   virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
@@ -44,17 +50,16 @@ protected:
   /// \param[out] theAttributes list of attributes to be filled
   virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
 
-  /// \brief This method is used in derived objects to check consistence of constraint.
-  ///        E.g. the distance between line and point may be signed.
-  virtual void adjustConstraint();
-
   /// \brief Fixed feature basing on its type
-  void fixFeature();
+  virtual void fixFeature();
 
   /// \brief Fix given point
-  void fixPoint(const Slvs_hEntity& thePointID);
+  /// \return ID of the Fixed constraint
+  Slvs_hConstraint fixPoint(const Slvs_hEntity& thePointID);
+
+  /// \brief Returns ID of fixed entity
+  Slvs_hEntity fixedEntity() const;
 
-private:
   /// \brief Fixing line position (start and end points)
   void fixLine(const Slvs_Entity& theLine);
   /// \brief Fixing circle (center and radius)
index 5a9652fe6955ae404f23f248f5d8da9605bf81c3..9ad17d7508f15014737c74e2dbe5357fffea7b1e 100644 (file)
@@ -563,7 +563,8 @@ bool SketchSolver_Group::resolveConstraints()
     updateConstraints();
 
   bool aResolved = false;
-  if (myStorage->isNeedToResolve() && !isEmpty()) {
+  bool isGroupEmpty = isEmpty();
+  if (myStorage->isNeedToResolve() && !isGroupEmpty) {
     myConstrSolver.setGroupID(myID);
     myConstrSolver.calculateFailedConstraints(false);
     myStorage->initializeSolver(myConstrSolver);
@@ -631,6 +632,16 @@ bool SketchSolver_Group::resolveConstraints()
     }
 
     aResolved = true;
+  } else if (!isGroupEmpty) {
+    myFeatureStorage->blockEvents(true);
+    // Check there are constraints Fixed. If they exist, update parameters by stored values
+    ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
+    for (; aCIt != myConstraints.end(); ++aCIt)
+      if (aCIt->first->getKind() == SketchPlugin_ConstraintRigid::ID()) {
+        aCIt->second->refresh();
+        aResolved = true;
+      }
+     myFeatureStorage->blockEvents(false);
   }
   removeTemporaryConstraints();
   myStorage->setNeedToResolve(false);
index 4ed2112e4b81b999181e35b5be337f94597e7436..58cd67418755730d3f169b6bdde4c3f020c8db65 100644 (file)
@@ -371,6 +371,14 @@ bool SketchSolver_Storage::isPointFixed(
       break;
     }
 
+  // Check whether one of coincident points is out-of-group
+  std::set<Slvs_hEntity>::const_iterator aCoincIt = aCoincident.begin();
+  for (; aCoincIt != aCoincident.end(); ++aCoincIt) {
+    Slvs_Entity aPoint = getEntity(*aCoincIt);
+    if (aPoint.group == SLVS_G_OUTOFGROUP)
+      return true;
+  }
+
   // Search the Rigid constraint
   theFixed = SLVS_C_UNKNOWN;
   std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
index fb8e79eb211113771ec8148587115df88a2b8223..bb270d77d191a1083c0b9d53e6f03898a4b09ee9 100644 (file)
@@ -69,6 +69,9 @@ public:
   void copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo);
   /// \brief Check the entity is used in constraints
   bool isUsedByConstraints(const Slvs_hEntity& theEntityID) const;
+  /// \brief Returns maximal ID of entities in this storage
+  const Slvs_hEntity& entityMaxID() const
+  { return myEntityMaxID; }
 
   /// \brief Verifies the current point or another coincident one is fixed
   /// \param[in]  thePointID  entity to be checked fixed
@@ -105,6 +108,9 @@ public:
   const Slvs_Constraint& getConstraint(const Slvs_hConstraint& theConstraintID) const;
   /// \brief Returns list of constraints of specified type
   std::list<Slvs_Constraint> getConstraintsByType(int theConstraintType) const;
+  /// \brief Returns quantity of constraints in this storage
+  size_t nbConstraints() const
+  { return myConstraints.size(); }
 
   /// \brief Attach constraint SLVS_C_WHERE_DRAGGED to this storage. It need to make precise calculations
   void addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID);