]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Changes due to the problem with too many coincidence constraints. SolveSpace
authorazv <azv@opencascade.com>
Wed, 28 May 2014 05:20:17 +0000 (09:20 +0400)
committerazv <azv@opencascade.com>
Wed, 28 May 2014 05:20:17 +0000 (09:20 +0400)
SolveSpace can not find solution if the number of constraints is more than number of unknowns.

src/SketchSolver/SketchSolver_ConstraintGroup.cpp
src/SketchSolver/SketchSolver_ConstraintGroup.h
src/SketchSolver/SketchSolver_Solver.cpp
src/SketchSolver/SketchSolver_Solver.h

index 1cbeafc89decacd9d5cd0d5589344c9e40ca91cb..b1a6d73e0b3c0643158681b87278dbbf74a71123 100644 (file)
@@ -58,6 +58,10 @@ SketchSolver_ConstraintGroup::
   myParams.clear();
   myEntities.clear();
   myConstraints.clear();
+  
+  myTempConstraints.clear();
+  myTempPointWhereDragged.clear();
+  myTempPointWDrgdID = 0;
 
   // Initialize workplane
   myWorkplane.h = SLVS_E_UNKNOWN;
@@ -74,6 +78,8 @@ SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
   myEntities.clear();
   myConstraints.clear();
   myConstraintMap.clear();
+  myTempConstraints.clear();
+  myTempPointWhereDragged.clear();
 
   // If the group with maximal identifier is deleted, decrease the indexer
   if (myID == myGroupIndexer)
@@ -177,6 +183,48 @@ bool SketchSolver_ConstraintGroup::changeConstraint(
 
   if (aConstrMapIter == myConstraintMap.end())
   {
+    // Several points may be coincident, it is not necessary to store all constraints between them.
+    // Try to find sequence of coincident points which connects the points of new constraint
+    if (aConstrType == SLVS_C_POINTS_COINCIDENT)
+    {
+      std::vector< std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
+      std::vector< std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
+      for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
+      {
+        bool isFound[2] = { // indicate which point ID was already in coincidence constraint
+          aCoPtIter->find(aConstrEnt[0]) != aCoPtIter->end(),
+          aCoPtIter->find(aConstrEnt[1]) != aCoPtIter->end(),
+        };
+        if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need to additional one
+          return false;
+        if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1]))
+        {
+          if (aFirstFound != myCoincidentPoints.end())
+          { // there are two groups of coincident points connected by created constraint => merge them
+            int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
+            int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
+            aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
+            myCoincidentPoints.erase(aCoPtIter);
+            aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
+            aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
+          }
+          else
+          {
+            aCoPtIter->insert(aConstrEnt[isFound[0] ? 1 : 0]);
+            aFirstFound = aCoPtIter;
+          }
+        }
+      }
+      // No points were found, need to create new set
+      if (aFirstFound == myCoincidentPoints.end())
+      {
+        std::set<Slvs_hEntity> aNewSet;
+        aNewSet.insert(aConstrEnt[0]);
+        aNewSet.insert(aConstrEnt[1]);
+        myCoincidentPoints.push_back(aNewSet);
+      }
+    }
+
     // Create SolveSpace constraint structure
     Slvs_Constraint aConstraint =
       Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h,
@@ -486,8 +534,10 @@ void SketchSolver_ConstraintGroup::resolveConstraints()
   myConstrSolver.setParameters(myParams);
   myConstrSolver.setEntities(myEntities);
   myConstrSolver.setConstraints(myConstraints);
+  myConstrSolver.setDraggedParameters(myTempPointWhereDragged);
 
-  if (myConstrSolver.solve() == SLVS_RESULT_OKAY)
+  int aResult = myConstrSolver.solve();
+  if (aResult == SLVS_RESULT_OKAY)
   { // solution succeeded, store results into correspondent attributes
     // Obtain result into the same list of parameters
     if (!myConstrSolver.getResult(myParams))
@@ -603,6 +653,26 @@ void SketchSolver_ConstraintGroup::mergeGroups(
   }
   myTempConstraints.sort();
 
+  if (myTempPointWhereDragged.empty())
+    myTempPointWhereDragged = theGroup.myTempPointWhereDragged;
+  else if (!theGroup.myTempPointWhereDragged.empty())
+  { // Need to create additional transient constraint
+    std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
+      aFeatureIter = theGroup.myEntityMap.begin();
+    for (; aFeatureIter != theGroup.myEntityMap.end(); aFeatureIter++)
+      if (aFeatureIter->second == myTempPointWDrgdID)
+      {
+        addTemporaryConstraintWhereDragged(aFeatureIter->first);
+        break;
+      }
+  }
+
+  // Merge the lists of coincidence points. As the groups were separated, there was 
+  // no coincidence constraint, so each two points from different groups don't coincide
+  myCoincidentPoints.insert(myCoincidentPoints.end(),
+                            theGroup.myCoincidentPoints.begin(),
+                            theGroup.myCoincidentPoints.end());
+
   myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve;
 }
 
@@ -631,6 +701,7 @@ bool SketchSolver_ConstraintGroup::updateGroup()
   // There only constraint will be deleted (parameters and entities) will be removed below
   std::list< boost::shared_ptr<SketchPlugin_Constraint> > aConstrToDelete;
   std::map<Slvs_hEntity, bool> anEntToDelete; // entities will be removed if no valid constraints use them
+  std::map<Slvs_hEntity, bool> aCoincPtToDelete; // list of entities (points) used in coincidence constaints which will be removed;
   for (aConstrIter = myConstraintMap.rbegin(); aConstrIter != myConstraintMap.rend(); aConstrIter++)
   {
     bool isValid = aConstrIter->first->data()->isValid();
@@ -645,9 +716,15 @@ bool SketchSolver_ConstraintGroup::updateGroup()
         if (aConstrEnt[i] != SLVS_E_UNKNOWN)
         {
           if (anEntToDelete.find(aConstrEnt[i]) == anEntToDelete.end())
+          {
             anEntToDelete[aConstrEnt[i]] = !isValid;
+            aCoincPtToDelete[aConstrEnt[i]] = !isValid && (myConstraints[aConstrPos].type == SLVS_C_POINTS_COINCIDENT);
+          }
           else if (isValid) // constraint is valid => no need to remove its entities
+          {
             anEntToDelete[aConstrEnt[i]] = false;
+            aCoincPtToDelete[aConstrEnt[i]] = false;
+          }
         }
       if (!isValid)
       {
@@ -664,8 +741,10 @@ bool SketchSolver_ConstraintGroup::updateGroup()
 
   // Remove invalid and unused entities
   std::map<Slvs_hEntity, bool>::reverse_iterator aEDelIter;
-  for (aEDelIter = anEntToDelete.rbegin(); aEDelIter != anEntToDelete.rend(); aEDelIter++)
-    if (aEDelIter->second)
+  std::map<Slvs_hEntity, bool>::reverse_iterator aPtDelIter = aCoincPtToDelete.rbegin();
+  for (aEDelIter = anEntToDelete.rbegin(); aEDelIter != anEntToDelete.rend(); aEDelIter++, aPtDelIter++)
+  {
+    if (aEDelIter->second) // remove entity
     {
       int anEntPos = Search(aEDelIter->first, myEntities);
       std::vector<Slvs_Entity>::iterator aEntIter = myEntities.begin() + anEntPos;
@@ -694,6 +773,13 @@ bool SketchSolver_ConstraintGroup::updateGroup()
       if (anEntMapIter != myEntityMap.end())
         myEntityMap.erase(anEntMapIter);
     }
+    if (aPtDelIter->second) // remove link for this entity from list of coincident points
+    {
+      std::vector< std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
+      for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
+        aCoPtIter->erase(aPtDelIter->first);
+    }
+  }
 
   return false;
 }
@@ -794,8 +880,47 @@ void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged(
   // Find identifier of the entity
   std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
     anEntIter = myEntityMap.find(theEntity);
+  if (anEntIter == myEntityMap.end())
+    return ;
 
-  // Create SLVS_C_WHERE_DRAGGED constraint
+  // If this is a first dragged point, its parameters should be placed 
+  // into Slvs_System::dragged field to avoid system inconsistense
+  if (myTempPointWhereDragged.empty())
+  {
+    int anEntPos = Search(anEntIter->second, myEntities);
+    Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
+    for (int i = 0; i < 4; i++, aDraggedParam++)
+      if (*aDraggedParam != 0)
+        myTempPointWhereDragged.push_back(*aDraggedParam);
+    myTempPointWDrgdID = myEntities[anEntPos].h;
+    return ;
+  }
+
+  // Get identifiers of all dragged points
+  std::set<Slvs_hEntity> aDraggedPntID;
+  aDraggedPntID.insert(myTempPointWDrgdID);
+  std::list<Slvs_hConstraint>::iterator aTmpCoIter = myTempConstraints.begin();
+  for ( ; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++)
+  {
+    unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
+    if (aConstrPos < myConstraints.size())
+      aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
+  }
+  // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
+  std::vector< std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
+  for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
+  {
+    if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
+      continue; // the entity was not found in current set
+
+    // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
+    std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
+    for ( ; aDrgIter != aDraggedPntID.end(); aDrgIter++)
+      if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
+        return ; // the SLVS_C_WHERE_DRAGGED constraint already exists
+  }
+
+  // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
   Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
                                                   myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
   myConstraints.push_back(aWDConstr);
@@ -813,7 +938,9 @@ void SketchSolver_ConstraintGroup::removeTemporaryConstraints()
   std::list<Slvs_hConstraint>::reverse_iterator aTmpConstrIter;
   for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend(); aTmpConstrIter++)
   {
-    int aConstrPos = Search(*aTmpConstrIter, myConstraints);
+    unsigned int aConstrPos = Search(*aTmpConstrIter, myConstraints);
+    if (aConstrPos >= myConstraints.size())
+      continue;
     myConstraints.erase(myConstraints.begin() + aConstrPos);
 
     // If the removing constraint has higher index, decrease the indexer
@@ -821,6 +948,9 @@ void SketchSolver_ConstraintGroup::removeTemporaryConstraints()
       myConstrMaxID--;
   }
   myTempConstraints.clear();
+
+  // Clear basic dragged point
+  myTempPointWhereDragged.clear();
 }
 
 
index 1d29742961444fb9d07b5be531644c85776c898e..d182233a571c9695a01311fb0999e0c18d6f276d 100644 (file)
@@ -157,13 +157,21 @@ private:
 
   SketchSolver_Solver          myConstrSolver;  ///< Solver for set of equations obtained by constraints
 
+  std::vector<Slvs_hParam>     myTempPointWhereDragged; ///< Parameters of one of the points which is moved by user
+  Slvs_hEntity                 myTempPointWDrgdID;      ///< Identifier of such point
+  std::list<Slvs_hConstraint>  myTempConstraints;       ///< The list of identifiers of temporary constraints (SLVS_C_WHERE_DRAGGED) applied for all other points moved by user
+                                                        //   NOTE: First ID in the list corresponds to myTempPointWhereDragged parameters and does not added to myConstraints list
+
+  std::vector< std::set<Slvs_hEntity> >
+                               myCoincidentPoints; ///< Stores the lists of identifiers of coincident points (to avoid unnecessary coincidence constraints)
+
   // SketchPlugin entities
-  boost::shared_ptr<SketchPlugin_Feature> mySketch; ///< Equivalent to workplane
+  boost::shared_ptr<SketchPlugin_Feature>
+                               mySketch;        ///< Equivalent to workplane
   std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>
-                                myConstraintMap;    ///< The map between SketchPlugin and SolveSpace constraints
-  std::list<Slvs_hConstraint> myTempConstraints;    ///< The list of identifiers of temporary constraints
+                               myConstraintMap; ///< The map between SketchPlugin and SolveSpace constraints
   std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>
-                                myEntityMap;        ///< The map between parameters of constraints and their equivalent SolveSpace entities
+                               myEntityMap;     ///< The map between parameters of constraints and their equivalent SolveSpace entities
 };
 
 #endif
index f9ed8c37204c788a6de8c685faac995fe3b30af9..be307be93dda2682dca7c54e645e03b9ea3f4285 100644 (file)
@@ -16,6 +16,11 @@ SketchSolver_Solver::SketchSolver_Solver()
   myEquationsSystem.failed = 0;
   myEquationsSystem.faileds = 0;
 
+  myEquationsSystem.dragged[0] = 0;
+  myEquationsSystem.dragged[1] = 0;
+  myEquationsSystem.dragged[2] = 0;
+  myEquationsSystem.dragged[3] = 0;
+
   // If the set of constraints is inconsistent,
   // the failed field will contain wrong constraints
   myEquationsSystem.calculateFaileds = 1;
@@ -49,6 +54,20 @@ void SketchSolver_Solver::setParameters(const std::vector<Slvs_Param>& theParame
     myEquationsSystem.param[i] = *aParamIter;
 }
 
+void SketchSolver_Solver::setDraggedParameters(const std::vector<Slvs_hParam>& theDragged)
+{
+  if (theDragged.size() == 0)
+  {
+    myEquationsSystem.dragged[0] = 0;
+    myEquationsSystem.dragged[1] = 0;
+    myEquationsSystem.dragged[2] = 0;
+    myEquationsSystem.dragged[3] = 0;
+    return;
+  }
+  for (unsigned int i = 0; i < theDragged.size(); i++)
+    myEquationsSystem.dragged[i] = theDragged[i];
+}
+
 void SketchSolver_Solver::setEntities(const std::vector<Slvs_Entity>& theEntities)
 {
   if (theEntities.size() != myEquationsSystem.entities) // number of entities was changed => reallocate the memory
@@ -73,6 +92,12 @@ void SketchSolver_Solver::setConstraints(const std::vector<Slvs_Constraint>& the
       delete [] myEquationsSystem.constraint;
     myEquationsSystem.constraints = theConstraints.size();
     myEquationsSystem.constraint = new Slvs_Constraint[theConstraints.size()];
+
+    // Assign the memory for the failed constraints
+    if (myEquationsSystem.failed)
+      delete [] myEquationsSystem.failed;
+    myEquationsSystem.failed = new Slvs_hConstraint[theConstraints.size()];
+    myEquationsSystem.faileds = 0;
   }
 
   // Copy data
index 19408410a35415e49fc297d9db20873e5efb035a..8a4f9964e95a7795389fc3563c538b99a22c91d2 100644 (file)
@@ -53,6 +53,12 @@ public:
    */
   void setConstraints(const std::vector<Slvs_Constraint>& theConstraints);
 
+  /** \brief Store the parameters of the point which was moved by user.
+   *         The solver will watch this items to be constant
+   *  \param[in] theDragged list of parameters (not more than 4) which should not be changed during solving
+   */
+  void setDraggedParameters(const std::vector<Slvs_hParam>& theDragged);
+
   /** \brief Solve the set of equations
    *  \return identifier whether solution succeeded
    */