Salome HOME
Issue #1157: Using parameters in point coordinates
[modules/shaper.git] / src / SketchSolver / SolveSpaceSolver / SolveSpaceSolver_Storage.cpp
index 7843cd88c29d9afaa7baa28633ba7ab2efe04a7b..999f43eefc46a7e7451a83382f998de382839106 100644 (file)
@@ -19,6 +19,9 @@
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
 #include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
 
 /** \brief Search the entity/parameter with specified ID in the list of elements
  *  \param[in] theEntityID unique ID of the element
@@ -47,7 +50,7 @@ SolveSpaceSolver_Storage::SolveSpaceSolver_Storage(const GroupID& theGroup)
 {
 }
 
-bool SolveSpaceSolver_Storage::update(ConstraintWrapperPtr& theConstraint)
+bool SolveSpaceSolver_Storage::update(ConstraintWrapperPtr theConstraint)
 {
   bool isUpdated = false;
   std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
@@ -73,6 +76,9 @@ bool SolveSpaceSolver_Storage::update(ConstraintWrapperPtr& theConstraint)
   std::list<EntityWrapperPtr>::iterator anIt = anEntities.begin();
   for (; anIt != anEntities.end(); ++anIt) {
     isUpdated = update(*anIt) || isUpdated;
+    // do not update constrained entities for Multi constraints
+    if (aSlvsConstr.type == SLVS_C_MULTI_ROTATION || aSlvsConstr.type != SLVS_C_MULTI_TRANSLATION)
+      continue;
 
     Slvs_hEntity anID = (Slvs_hEntity)(*anIt)->id();
     if ((*anIt)->type() == ENTITY_POINT) {
@@ -105,7 +111,7 @@ bool SolveSpaceSolver_Storage::update(ConstraintWrapperPtr& theConstraint)
   return isUpdated;
 }
 
-bool SolveSpaceSolver_Storage::update(EntityWrapperPtr& theEntity)
+bool SolveSpaceSolver_Storage::update(EntityWrapperPtr theEntity)
 {
   bool isUpdated = false;
   std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity = 
@@ -158,6 +164,15 @@ bool SolveSpaceSolver_Storage::update(EntityWrapperPtr& theEntity)
       isUpdated = true;
     }
   }
+  if (theEntity->type() == ENTITY_POINT && aSubEntities.size() == 1) {
+    // theEntity is based on SketchPlugin_Point => need to substitute its attribute instead
+    bool isNew = (aSlvsEnt.h == SLVS_E_UNKNOWN);
+    aSlvsEnt = getEntity(aSlvsEnt.point[0]);
+    if (isNew) {
+      anEntity->changeEntity() = aSlvsEnt;
+      isUpdated = true;
+    }
+  }
 
   // update entity itself
   if (aSlvsEnt.wrkpl == SLVS_E_UNKNOWN && myWorkplaneID != SLVS_E_UNKNOWN)
@@ -165,17 +180,18 @@ bool SolveSpaceSolver_Storage::update(EntityWrapperPtr& theEntity)
   if (aSlvsEnt.group == SLVS_G_UNKNOWN)
     aSlvsEnt.group = (Slvs_hGroup)myGroupID;
   Slvs_hEntity anEntID = updateEntity(aSlvsEnt);
-  if (aSlvsEnt.h == SLVS_E_UNKNOWN) {
+  if (aSlvsEnt.h == SLVS_E_UNKNOWN || isUpdated) {
     anEntity->changeEntity() = getEntity(anEntID);
     isUpdated = true;
 
     if (anEntity->type() == ENTITY_SKETCH)
       storeWorkplane(anEntity);
   }
+
   return isUpdated;
 }
 
-bool SolveSpaceSolver_Storage::update(ParameterWrapperPtr& theParameter)
+bool SolveSpaceSolver_Storage::update(ParameterWrapperPtr theParameter)
 {
   std::shared_ptr<SolveSpaceSolver_ParameterWrapper> aParameter = 
       std::dynamic_pointer_cast<SolveSpaceSolver_ParameterWrapper>(theParameter);
@@ -185,8 +201,6 @@ bool SolveSpaceSolver_Storage::update(ParameterWrapperPtr& theParameter)
   Slvs_Param aParamToUpd = aParameter->parameter();
   if (aParamToUpd.group == SLVS_G_UNKNOWN)
     aParamToUpd.group = aParameter->isParametric() ? (Slvs_hGroup)GID_OUTOFGROUP : (Slvs_hGroup)myGroupID;
-////  else if (aParameter->isParametric() && aParamToUpd.group != (Slvs_hGroup)GID_OUTOFGROUP)
-////    aParameter->setGroup(GID_OUTOFGROUP);
   Slvs_hParam anID = updateParameter(aParamToUpd);
   if (aParam.h == SLVS_E_UNKNOWN) // new parameter
     aParameter->changeParameter() = getParameter(anID);
@@ -294,8 +308,9 @@ void SolveSpaceSolver_Storage::addCoincidentPoints(
     replaceInFeatures(theSlave, theMaster);
     replaceInConstraints(theSlave, theMaster);
 
-    // Remove slave entity
-    removeEntity((Slvs_hEntity)theSlave->id());
+    // Remove slave entity (if the IDs are equal no need to remove slave entity, just update it)
+    if (theMaster->id() != theSlave->id())
+      removeEntity((Slvs_hEntity)theSlave->id());
 
     std::shared_ptr<SolveSpaceSolver_EntityWrapper> aPointMaster = 
         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMaster);
@@ -313,6 +328,8 @@ void SolveSpaceSolver_Storage::replaceInFeatures(
 {
   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator anIt = myFeatureMap.begin();
   for (; anIt != myFeatureMap.end(); ++anIt) {
+    if (!anIt->second)
+      continue;
     bool isUpdated = false;
     std::list<EntityWrapperPtr> aSubs = anIt->second->subEntities();
     std::list<EntityWrapperPtr>::iterator aSubIt = aSubs.begin();
@@ -536,8 +553,10 @@ Slvs_hParam SolveSpaceSolver_Storage::updateParameter(const Slvs_Param& theParam
     // parameter already used, rewrite it
     int aPos = Search(theParam.h, myParameters);
     if (aPos >= 0 && aPos < (int)myParameters.size()) {
-      if (IsNotEqual(myParameters[aPos], theParam))
+      if (IsNotEqual(myParameters[aPos], theParam)) {
         myUpdatedParameters.insert(theParam.h);
+        setNeedToResolve(true);
+      }
       myParameters[aPos] = theParam;
       return theParam.h;
     }
@@ -564,11 +583,7 @@ bool SolveSpaceSolver_Storage::removeParameter(const Slvs_hParam& theParamID)
     myParameters.erase(myParameters.begin() + aPos);
     myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h;
     myNeedToResolve = true;
-////    myRemovedParameters.insert(theParamID);
-    return true;
   }
-////  else if (myRemovedParameters.find(theParamID) != myRemovedParameters.end())
-////    return true;
   return true;
 }
 
@@ -664,12 +679,7 @@ bool SolveSpaceSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
       if (anEntity.point[i] != SLVS_E_UNKNOWN)
         aResult = removeEntity(anEntity.point[i]) && aResult;
     myNeedToResolve = true;
-////    myRemovedEntities.insert(theEntityID);
-////    if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D)
-////      removeCoincidentPoint(theEntityID);
   }
-////  else if (myRemovedEntities.find(theEntityID) != myRemovedEntities.end())
-////    return true;
   return aResult;
 }
 
@@ -750,9 +760,6 @@ void SolveSpaceSolver_Storage::removeUnusedEntities()
       for (int i = 0; i < 4; i++)
         if (anEntity.point[i] != SLVS_E_UNKNOWN)
           removeEntity(anEntity.point[i]);
-////      myRemovedEntities.insert(*anEntIt);
-////      if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D)
-////        removeCoincidentPoint(*anEntIt);
     }
   }
 
@@ -847,12 +854,6 @@ bool SolveSpaceSolver_Storage::isPointFixed(
   // Search the set of coincident points
   std::set<Slvs_hEntity> aCoincident;
   aCoincident.insert(thePointID);
-////  std::vector< std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
-////  for (; aCPIter != myCoincidentPoints.end(); aCPIter++)
-////    if (aCPIter->find(thePointID) != aCPIter->end()) {
-////      aCoincident = *aCPIter;
-////      break;
-////    }
 
   // Check whether one of coincident points is out-of-group
   std::set<Slvs_hEntity>::const_iterator aCoincIt = aCoincident.begin();
@@ -907,12 +908,6 @@ bool SolveSpaceSolver_Storage::isEntityFixed(const Slvs_hEntity& theEntityID, bo
 
     std::set<Slvs_hEntity> aCoincident;
     aCoincident.insert(aPoint);
-////    std::vector< std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
-////    for (; aCPIter != myCoincidentPoints.end(); aCPIter++)
-////      if (aCPIter->find(aPoint) != aCPIter->end()) {
-////        aCoincident = *aCPIter;
-////        break;
-////      }
 
     // Search the Rigid constraint
     std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
@@ -1040,8 +1035,6 @@ Slvs_hConstraint SolveSpaceSolver_Storage::addConstraint(const Slvs_Constraint&
     aConstraint.h = ++myConstrMaxID;
   myConstraints.push_back(aConstraint);
   myNeedToResolve = true;
-////  if (aConstraint.type == SLVS_C_POINTS_COINCIDENT)
-////    addCoincidentPoints(aConstraint.ptA, aConstraint.ptB);
   return aConstraint.h;
 }
 
@@ -1053,8 +1046,6 @@ Slvs_hConstraint SolveSpaceSolver_Storage::updateConstraint(const Slvs_Constrain
     if (aPos >= 0 && aPos < (int)myConstraints.size()) {
       myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint);
       myConstraints[aPos] = theConstraint;
-////      if (theConstraint.type == SLVS_C_POINTS_COINCIDENT)
-////        addCoincidentPoints(theConstraint.ptA, theConstraint.ptB);
       return theConstraint.h;
     }
   }
@@ -1074,9 +1065,6 @@ bool SolveSpaceSolver_Storage::removeConstraint(const Slvs_hConstraint& theConst
     myConstraints.erase(myConstraints.begin() + aPos);
     myConstrMaxID = myConstraints.empty() ? SLVS_E_UNKNOWN : myConstraints.back().h;
     myNeedToResolve = true;
-////    myRemovedConstraints.insert(theConstraintID);
-////    if (aConstraint.type == SLVS_C_POINTS_COINCIDENT)
-////      removeCoincidence(aConstraint);
 
     // Remove all entities
     Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB,
@@ -1104,8 +1092,6 @@ bool SolveSpaceSolver_Storage::removeConstraint(const Slvs_hConstraint& theConst
         }
     }
   }
-////  else if (myRemovedConstraints.find(theConstraintID) != myRemovedConstraints.end())
-////    return true;
   return aResult;
 }
 
@@ -1141,80 +1127,6 @@ void SolveSpaceSolver_Storage::addConstraintWhereDragged(const Slvs_hConstraint&
     myFixed = theConstraintID;
 }
 
-void SolveSpaceSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
-{
-  myTemporaryConstraints.insert(theConstraintID);
-}
-
-void SolveSpaceSolver_Storage::removeAllTemporary()
-{
-  myTemporaryConstraints.clear();
-}
-
-size_t SolveSpaceSolver_Storage::removeTemporary(size_t theNbConstraints)
-{
-  if (myTemporaryConstraints.empty())
-    return 0;
-  // Search the point-on-line or a non-rigid constraint
-  std::set<Slvs_hConstraint>::iterator aCIt = myTemporaryConstraints.begin();
-  for (; aCIt != myTemporaryConstraints.end(); aCIt++) {
-    int aPos = Search(*aCIt, myConstraints);
-    if (aPos >= (int)myConstraints.size() || myConstraints[aPos].type != SLVS_C_WHERE_DRAGGED)
-      break;
-    std::vector<Slvs_Constraint>::iterator anIt = myConstraints.begin();
-    for (; anIt != myConstraints.end(); anIt++)
-      if (anIt->type == SLVS_C_PT_ON_LINE && anIt->ptA == myConstraints[aPos].ptA)
-        break;
-    if (anIt != myConstraints.end())
-      break;
-  }
-  if (aCIt == myTemporaryConstraints.end())
-    aCIt = myTemporaryConstraints.begin();
-  bool aNewFixed = false;
-
-  size_t aNbRemain = theNbConstraints;
-  while (aNbRemain > 0 && aCIt != myTemporaryConstraints.end()) {
-    aNewFixed = aNewFixed || (*aCIt == myFixed);
-    --aNbRemain;
-
-    std::set<Slvs_hConstraint>::iterator aRemoveIt = aCIt++;
-    removeConstraint(*aRemoveIt);
-    myTemporaryConstraints.erase(aRemoveIt);
-    if (aCIt == myTemporaryConstraints.end())
-      aCIt = myTemporaryConstraints.begin();
-  }
-
-  if (aNewFixed) {
-    for (aCIt = myTemporaryConstraints.begin(); aCIt != myTemporaryConstraints.end(); aCIt++) {
-      int aPos = Search(*aCIt, myConstraints);
-      if (myConstraints[aPos].type == SLVS_C_WHERE_DRAGGED) {
-        myFixed = *aCIt;
-        break;
-      }
-    }
-  }
-  return myTemporaryConstraints.size();
-}
-
-bool SolveSpaceSolver_Storage::isTemporary(const Slvs_hConstraint& theConstraintID) const
-{
-  return myTemporaryConstraints.find(theConstraintID) != myTemporaryConstraints.end();
-}
-
-
-////void SolveSpaceSolver_Storage::getRemoved(
-////    std::set<Slvs_hParam>& theParameters,
-////    std::set<Slvs_hEntity>& theEntities,
-////    std::set<Slvs_hConstraint>& theConstraints)
-////{
-////  theParameters = myRemovedParameters;
-////  theEntities = myRemovedEntities;
-////  theConstraints = myRemovedConstraints;
-////
-////  myRemovedParameters.clear();
-////  myRemovedEntities.clear();
-////  myRemovedConstraints.clear();
-////}
 
 void SolveSpaceSolver_Storage::initializeSolver(SolverPtr theSolver)
 {
@@ -1252,96 +1164,10 @@ void SolveSpaceSolver_Storage::initializeSolver(SolverPtr theSolver)
   aSolver->setConstraints(aConstraints.data(), (int)aConstraints.size());
 }
 
-////void SolveSpaceSolver_Storage::addCoincidentPoints(
-////    const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2)
-////{
-////  std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
-////  std::vector< std::set<Slvs_hEntity> >::iterator aFoundIter = myCoincidentPoints.end(); // already found coincidence
-////  bool isFound = false;
-////  for (; aCIter != myCoincidentPoints.end(); aCIter++) {
-////    bool isFirstFound = aCIter->find(thePoint1) != aCIter->end();
-////    bool isSecondFound = aCIter->find(thePoint2) != aCIter->end();
-////    isFound = isFound || isFirstFound || isSecondFound;
-////    if (isFirstFound && isSecondFound)
-////      break; // already coincident
-////    else if (isFirstFound || isSecondFound) {
-////      if (aFoundIter != myCoincidentPoints.end()) {
-////        // merge two sets
-////        aFoundIter->insert(aCIter->begin(), aCIter->end());
-////        myCoincidentPoints.erase(aCIter);
-////        break;
-////      } else
-////        aFoundIter = aCIter;
-////      aCIter->insert(thePoint1);
-////      aCIter->insert(thePoint2);
-////    }
-////  }
-////  // coincident points not found
-////  if (!isFound) {
-////    std::set<Slvs_hEntity> aNewSet;
-////    aNewSet.insert(thePoint1);
-////    aNewSet.insert(thePoint2);
-////    myCoincidentPoints.push_back(aNewSet);
-////  }
-////}
-////
-////void SolveSpaceSolver_Storage::removeCoincidentPoint(const Slvs_hEntity& thePoint)
-////{
-////  std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
-////  for (; aCIter != myCoincidentPoints.end(); aCIter++)
-////    if (aCIter->find(thePoint) != aCIter->end()) {
-////      aCIter->erase(thePoint);
-////      if (aCIter->size() <= 1)
-////        myCoincidentPoints.erase(aCIter);
-////      break;
-////    }
-////}
-////
-////void SolveSpaceSolver_Storage::removeCoincidence(const Slvs_Constraint& theCoincidence)
-////{
-////  // Find set of coincident points
-////  std::vector< std::set<Slvs_hEntity> >::iterator aCIt = myCoincidentPoints.begin();
-////  for (; aCIt != myCoincidentPoints.end(); ++aCIt)
-////    if (aCIt->find(theCoincidence.ptA) != aCIt->end() ||
-////        aCIt->find(theCoincidence.ptB) != aCIt->end())
-////      break;
-////  if (aCIt == myCoincidentPoints.end())
-////    return;
-////
-////  // Leave only the points which are still coincident
-////  std::set<Slvs_hEntity> aRemainCoincidence;
-////  std::vector<Slvs_Constraint>::const_iterator aConstrIt = myConstraints.begin();
-////  for (; aConstrIt != myConstraints.end(); ++aConstrIt) {
-////    if (aConstrIt->type != SLVS_C_POINTS_COINCIDENT)
-////      continue;
-////    if (aCIt->find(aConstrIt->ptA) != aCIt->end() ||
-////        aCIt->find(aConstrIt->ptB) != aCIt->end()) {
-////      aRemainCoincidence.insert(aConstrIt->ptA);
-////      aRemainCoincidence.insert(aConstrIt->ptB);
-////    }
-////  }
-////  if (aRemainCoincidence.size() <= 1)
-////    myCoincidentPoints.erase(aCIt);
-////  else
-////    aCIt->swap(aRemainCoincidence);
-////}
-////
-////bool SolveSpaceSolver_Storage::isCoincident(
-////    const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const
-////{
-////  std::vector< std::set<Slvs_hEntity> >::const_iterator aCIter = myCoincidentPoints.begin();
-////  for (; aCIter != myCoincidentPoints.end(); aCIter++)
-////    if (aCIter->find(thePoint1) != aCIter->end() && aCIter->find(thePoint2) != aCIter->end())
-////      return true;
-////  return false;
-////}
 
 bool SolveSpaceSolver_Storage::isEqual(
     const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const
 {
-////  if (isCoincident(thePoint1, thePoint2))
-////    return true;
-
   // Precise checking of coincidence: verify that points have equal coordinates
   int aEnt1Pos = Search(thePoint1, myEntities);
   int aEnt2Pos = Search(thePoint2, myEntities);
@@ -1396,7 +1222,7 @@ void SolveSpaceSolver_Storage::fixPoint(const Slvs_Entity& thePoint,
   Slvs_Constraint aConstraint;
   Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN;
   bool isFixed = isPointFixed(thePoint.h, aConstrID, true);
-  bool isForceUpdate = (isFixed && isTemporary(aConstrID));
+  bool isForceUpdate = (isFixed /*&& isTemporary(aConstrID)*/);
   if (!isForceUpdate) { // create new constraint
     if (isFixed) return;
     aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, thePoint.group, SLVS_C_WHERE_DRAGGED, thePoint.wrkpl,
@@ -1635,184 +1461,106 @@ bool SolveSpaceSolver_Storage::isUsedInEqual(
   return false;
 }
 
-////bool SolveSpaceSolver_Storage::isNeedToResolve()
-////{
-////  if (myConstraints.empty())
-////    return false;
-////
-////  if (!myNeedToResolve) {
-////    // Verify the updated parameters are used in constraints
-////    std::set<Slvs_hEntity> aPoints;
-////    std::vector<Slvs_Entity>::const_iterator anEntIt = myEntities.begin();
-////    for (; anEntIt != myEntities.end(); ++anEntIt) {
-////      for (int i = 0; i < 4 && anEntIt->param[i] != SLVS_E_UNKNOWN; ++i)
-////        if (myUpdatedParameters.find(anEntIt->param[i]) != myUpdatedParameters.end()) {
-////          aPoints.insert(anEntIt->h);
-////          break;
-////        }
-////    }
-////    std::set<Slvs_hEntity> anEntities = aPoints;
-////    for (anEntIt = myEntities.begin(); anEntIt != myEntities.end(); ++anEntIt) {
-////      for (int i = 0; i < 4 && anEntIt->point[i] != SLVS_E_UNKNOWN; ++i)
-////        if (aPoints.find(anEntIt->point[i]) != aPoints.end()) {
-////          anEntities.insert(anEntIt->h);
-////          break;
-////        }
-////    }
-////
-////    std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
-////    for (; aCIt != myConstraints.end() && !myNeedToResolve; ++aCIt) {
-////      Slvs_hEntity anAttrs[6] =
-////        {aCIt->ptA, aCIt->ptB, aCIt->entityA, aCIt->entityB, aCIt->entityC, aCIt->entityD};
-////      for (int i = 0; i < 6; i++)
-////        if (anAttrs[i] != SLVS_E_UNKNOWN && anEntities.find(anAttrs[i]) != anEntities.end()) {
-////          myNeedToResolve = true;
-////          break;
-////        }
-////    }
-////  }
-////
-////  myUpdatedParameters.clear();
-////  return myNeedToResolve;
-////}
-
-void SolveSpaceSolver_Storage::setTemporary(ConstraintPtr theConstraint)
-{
-  // TODO
-}
 
-bool SolveSpaceSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
+bool SolveSpaceSolver_Storage::removeCoincidence(ConstraintWrapperPtr theConstraint)
 {
-  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::iterator
-      aFound = myConstraintMap.find(theConstraint);
-  if (aFound == myConstraintMap.end())
-    return true; // no constraint, already deleted
-
-  // Remove constraint
-  std::list<ConstraintWrapperPtr> aConstrList = aFound->second;
-  myConstraintMap.erase(aFound);
-  // Remove SolveSpace constraints
-  bool isFullyRemoved = true;
-  std::list<ConstraintWrapperPtr>::iterator anIt = aConstrList.begin();
-  while (anIt != aConstrList.end()) {
-    if (remove(*anIt)) {
-      std::list<ConstraintWrapperPtr>::iterator aRemoveIt = anIt++;
-      aConstrList.erase(aRemoveIt);
-    } else {
-      isFullyRemoved = false;
-      ++anIt;
-    }
+  std::list<EntityWrapperPtr> aPoints = theConstraint->entities();
+  std::list<EntityWrapperPtr>::const_iterator aPIt;
+
+  CoincidentPointsMap::iterator aPtPtIt = myCoincidentPoints.begin();
+  for (; aPtPtIt != myCoincidentPoints.end(); ++aPtPtIt) {
+    for (aPIt = aPoints.begin(); aPIt != aPoints.end(); ++aPIt)
+      if (aPtPtIt->first == *aPIt ||
+          aPtPtIt->second.find(*aPIt) != aPtPtIt->second.end())
+        break;
+    if (aPIt != aPoints.end())
+      break;
   }
-  if (!isFullyRemoved)
-    myConstraintMap[theConstraint] = aConstrList;
-  return isFullyRemoved;
-}
-
-template <class ENT_TYPE>
-static bool isUsed(ConstraintWrapperPtr theConstraint, ENT_TYPE theEntity)
-{
-  std::list<EntityWrapperPtr>::const_iterator anEntIt = theConstraint->entities().begin();
-  for (; anEntIt != theConstraint->entities().end(); ++anEntIt)
-    if (std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anEntIt)->isBase(theEntity))
-      return true;
-  return false;
-}
-
-static bool isUsed(EntityWrapperPtr theFeature, AttributePtr theSubEntity)
-{
-  std::list<EntityWrapperPtr>::const_iterator aSubIt = theFeature->subEntities().begin();
-  for (; aSubIt != theFeature->subEntities().end(); ++aSubIt)
-    if (std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*aSubIt)->isBase(theSubEntity))
-      return true;
-  return false;
-}
 
-bool SolveSpaceSolver_Storage::isUsed(FeaturePtr theFeature) const
-{
-  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
-      aCIt = myConstraintMap.begin();
-  std::list<ConstraintWrapperPtr>::const_iterator aCWIt;
-  for (; aCIt != myConstraintMap.end(); ++aCIt)
-    for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt)
-      if (::isUsed(*aCWIt, theFeature))
-        return true;
-  // check attributes
-  std::list<AttributePtr> anAttrList = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
-  std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
-  for (; anIt != anAttrList.end(); ++anIt)
-    if (isUsed(*anIt))
-      return true;
-  return false;
-}
+  if (aPtPtIt == myCoincidentPoints.end())
+    return true; // already removed
 
-bool SolveSpaceSolver_Storage::isUsed(AttributePtr theAttribute) const
-{
-  AttributePtr anAttribute = theAttribute;
-  AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
-  if (aRefAttr) {
-    if (aRefAttr->isObject())
-      return isUsed(ModelAPI_Feature::feature(aRefAttr->object()));
-    else
-      anAttribute = aRefAttr->attr();
+  // Create new copies of coincident points
+  BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
+  std::list<EntityWrapperPtr> aNewPoints;
+  for (aPIt = aPoints.begin(); aPIt != aPoints.end(); ++aPIt)
+    aNewPoints.push_back(aBuilder->createAttribute(
+        (*aPIt)->baseAttribute(), myGroupID, myWorkplaneID));
+
+  // Find all points fallen out of group of coincident points
+  std::map<EntityWrapperPtr, EntityWrapperPtr> aNotCoinc;
+  aNotCoinc[aPtPtIt->first] = EntityWrapperPtr();
+  std::set<EntityWrapperPtr>::const_iterator aTempIt = aPtPtIt->second.begin();
+  for (; aTempIt != aPtPtIt->second.end(); ++aTempIt)
+    aNotCoinc[*aTempIt] = EntityWrapperPtr();
+  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::iterator
+      aConstrIt = myConstraintMap.begin();
+  for (; aConstrIt != myConstraintMap.end(); ++aConstrIt)
+    if (aConstrIt->first->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+      AttributeRefAttrPtr aRefAttrA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+          aConstrIt->first->attribute(SketchPlugin_Constraint::ENTITY_A()));
+      AttributeRefAttrPtr aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+          aConstrIt->first->attribute(SketchPlugin_Constraint::ENTITY_B()));
+      if (!aRefAttrA || !aRefAttrB || aRefAttrA->isObject() || aRefAttrB->isObject())
+        continue;
+      std::map<AttributePtr, EntityWrapperPtr>::iterator
+          aFound = myAttributeMap.find(aRefAttrA->attr());
+      if (aFound != myAttributeMap.end())
+        aNotCoinc.erase(aFound->second);
+      aFound = myAttributeMap.find(aRefAttrB->attr());
+      if (aFound != myAttributeMap.end())
+        aNotCoinc.erase(aFound->second);
+    }
+  if (aNotCoinc.empty())
+    return false;
+  std::list<EntityWrapperPtr>::const_iterator aNewPIt;
+  for (aPIt = aPoints.begin(), aNewPIt = aNewPoints.begin();
+       aPIt != aPoints.end(); ++aPIt, ++aNewPIt) {
+    if (aNotCoinc.find(*aPIt) != aNotCoinc.end())
+      aNotCoinc[*aPIt] = *aNewPIt;
   }
 
-  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
-      aCIt = myConstraintMap.begin();
-  std::list<ConstraintWrapperPtr>::const_iterator aCWIt;
-  for (; aCIt != myConstraintMap.end(); ++aCIt)
-    for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt)
-      if (::isUsed(*aCWIt, anAttribute))
-        return true;
-  return false;
-}
-
-
-bool SolveSpaceSolver_Storage::removeEntity(FeaturePtr theFeature)
-{
-  std::map<FeaturePtr, EntityWrapperPtr>::iterator aFound = myFeatureMap.find(theFeature);
-  if (aFound == myFeatureMap.end())
-    return false; // feature not found, nothing to delete
-
-  // Check the feature is not used by constraints
-  if (isUsed(theFeature))
-    return false; // the feature is used, don't remove it
-
-  // Remove feature
-  EntityWrapperPtr anEntity = aFound->second;
-  myFeatureMap.erase(aFound);
-  if (remove(anEntity))
-    return true;
-  // feature is not removed, revert operation
-  myFeatureMap[theFeature] = anEntity;
-  return false;
-}
-
-bool SolveSpaceSolver_Storage::removeEntity(AttributePtr theAttribute)
-{
-  std::map<AttributePtr, EntityWrapperPtr>::iterator aFound = myAttributeMap.find(theAttribute);
-  if (aFound == myAttributeMap.end())
-    return false; // attribute not found, nothing to delete
-
-  // Check the attribute is not used by constraints
-  if (isUsed(theAttribute))
-    return false; // the attribute is used, don't remove it
-  // Check the attribute is not used by other features
-  std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
-  for (; aFIt != myFeatureMap.end(); ++aFIt)
-    if (::isUsed(aFIt->second, theAttribute)) // the attribute is used, don't remove it
-      return false;
-
-  // Remove attribute
-  EntityWrapperPtr anEntity = aFound->second;
-  myAttributeMap.erase(aFound);
-  if (remove(anEntity))
-    return true;
-  // attribute is not removed, revert operation
-  myAttributeMap[theAttribute] = anEntity;
-  return false;
+  // Find all features and constraints uses coincident points
+  std::map<EntityWrapperPtr, EntityWrapperPtr>::iterator aNotCIt;
+  std::set<EntityWrapperPtr> anUpdFeatures;
+  std::map<FeaturePtr, EntityWrapperPtr>::iterator aFIt = myFeatureMap.begin();
+  for (; aFIt != myFeatureMap.end(); ++aFIt) {
+    for (aNotCIt = aNotCoinc.begin(); aNotCIt != aNotCoinc.end(); ++aNotCIt) {
+      if (!aFIt->second->isUsed(aNotCIt->first->baseAttribute()))
+        continue;
+      std::list<EntityWrapperPtr> aSubs = aFIt->second->subEntities();
+      std::list<EntityWrapperPtr>::iterator aSIt = aSubs.begin();
+      for (; aSIt != aSubs.end(); ++aSIt)
+        if (*aSIt == aNotCIt->first)
+          *aSIt = aNotCIt->second;
+      aFIt->second->setSubEntities(aSubs);
+      anUpdFeatures.insert(aFIt->second);
+    }
+  }
+  // update features
+  std::set<EntityWrapperPtr>::iterator anUpdIt = anUpdFeatures.begin();
+  for (; anUpdIt != anUpdFeatures.end(); ++anUpdIt)
+    update(EntityWrapperPtr(*anUpdIt));
+
+  // remove not coincident points
+  for (aNotCIt = aNotCoinc.begin(); aNotCIt != aNotCoinc.end(); ++aNotCIt) {
+    if (aPtPtIt->second.size() <= 1) {
+      myCoincidentPoints.erase(aPtPtIt);
+      break;
+    }
+    if (aPtPtIt->first == aNotCIt->first) {
+      std::set<EntityWrapperPtr> aSlaves = aPtPtIt->second;
+      EntityWrapperPtr aNewMaster = *aSlaves.begin();
+      aSlaves.erase(aSlaves.begin());
+      myCoincidentPoints[aNewMaster] = aSlaves;
+      myCoincidentPoints.erase(aPtPtIt);
+      aPtPtIt = myCoincidentPoints.find(aNewMaster);
+    } else
+      aPtPtIt->second.erase(aNotCIt->first);
+  }
+  return true;
 }
 
-
 bool SolveSpaceSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
 {
   std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
@@ -1830,41 +1578,22 @@ bool SolveSpaceSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
 
   bool isFullyRemoved = removeConstraint((Slvs_hConstraint)aConstraint->id());
 
-  std::list<EntityWrapperPtr>::const_iterator anIt = aConstraint->entities().begin();
-  for (; anIt != aConstraint->entities().end(); ++anIt) {
-    std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity = 
-        std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
-    FeaturePtr aBaseFeature = anEntity->baseFeature();
-    if (aBaseFeature)
-      isFullyRemoved = removeEntity(aBaseFeature) && isFullyRemoved;
-    else
-      isFullyRemoved = removeEntity(anEntity->baseAttribute()) && isFullyRemoved;
-  }
+  // remove point-point coincidence
+  if (aConstraint->type() == CONSTRAINT_PT_PT_COINCIDENT)
+    isFullyRemoved = removeCoincidence(theConstraint);
 
-  return isFullyRemoved;
+  return SketchSolver_Storage::remove(theConstraint) && isFullyRemoved;
 }
 
 bool SolveSpaceSolver_Storage::remove(EntityWrapperPtr theEntity)
 {
+  if (!theEntity)
+    return false;
+
   std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity = 
         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theEntity);
   bool isFullyRemoved = removeEntity((Slvs_hEntity)anEntity->id());
-
-  std::list<EntityWrapperPtr>::const_iterator anEntIt = anEntity->subEntities().begin();
-  for (; anEntIt != anEntity->subEntities().end(); ++anEntIt) {
-    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSubEntity = 
-        std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anEntIt);
-    FeaturePtr aBaseFeature = aSubEntity->baseFeature();
-    if (aBaseFeature)
-      isFullyRemoved = removeEntity(aBaseFeature) && isFullyRemoved;
-    else
-      isFullyRemoved = removeEntity(aSubEntity->baseAttribute()) && isFullyRemoved;
-  }
-
-  std::list<ParameterWrapperPtr>::const_iterator aParIt = anEntity->parameters().begin();
-  for (; aParIt != anEntity->parameters().end(); ++aParIt)
-    isFullyRemoved = remove(*aParIt) && isFullyRemoved;
-  return isFullyRemoved;
+  return SketchSolver_Storage::remove(theEntity) && isFullyRemoved;
 }
 
 bool SolveSpaceSolver_Storage::remove(ParameterWrapperPtr theParameter)
@@ -1875,12 +1604,23 @@ bool SolveSpaceSolver_Storage::remove(ParameterWrapperPtr theParameter)
 
 void SolveSpaceSolver_Storage::refresh(bool theFixedOnly) const
 {
-  blockEvents(true);
+  //blockEvents(true);
 
   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
   std::list<ParameterWrapperPtr> aParams;
   std::list<ParameterWrapperPtr>::const_iterator aParIt;
   for (; anIt != myAttributeMap.end(); ++anIt) {
+    if (!anIt->second)
+      continue;
+    // the external feature always should keep the up to date values, so, 
+    // refresh from the solver is never needed
+    if (anIt->first.get()) {
+      std::shared_ptr<SketchPlugin_Feature> aSketchFeature = 
+        std::dynamic_pointer_cast<SketchPlugin_Feature>(anIt->first->owner());
+      if (aSketchFeature.get() && aSketchFeature->isExternal())
+        continue;
+    }
+
     // update parameter wrappers and obtain values of attributes
     aParams = anIt->second->parameters();
     double aCoords[3];
@@ -1906,6 +1646,14 @@ void SolveSpaceSolver_Storage::refresh(bool theFixedOnly) const
         if (!isUpd[0]) aCoords[0] = aPoint2D->x();
         if (!isUpd[1]) aCoords[1] = aPoint2D->y();
         aPoint2D->setValue(aCoords[0], aCoords[1]);
+        // Find points coincident with this one (probably not in GID_OUTOFGROUP)
+        std::map<AttributePtr, EntityWrapperPtr>::const_iterator aLocIt =
+            theFixedOnly ? myAttributeMap.begin() : anIt;
+        for (++aLocIt; aLocIt != myAttributeMap.end(); ++aLocIt)
+          if (anIt->second->id() == aLocIt->second->id()) {
+            aPoint2D = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aLocIt->first);
+            aPoint2D->setValue(aCoords[0], aCoords[1]);
+          }
       }
       continue;
     }
@@ -1929,13 +1677,15 @@ void SolveSpaceSolver_Storage::refresh(bool theFixedOnly) const
     }
   }
 
-  blockEvents(false);
+  //blockEvents(false);
 }
 
 void SolveSpaceSolver_Storage::verifyFixed()
 {
   std::map<AttributePtr, EntityWrapperPtr>::iterator anAttrIt = myAttributeMap.begin();
   for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
+    if (!anAttrIt->second)
+      continue;
     const std::list<ParameterWrapperPtr>& aParameters = anAttrIt->second->parameters();
     std::list<ParameterWrapperPtr>::const_iterator aParIt = aParameters.begin();
     for (; aParIt != aParameters.end(); ++aParIt)