Salome HOME
Correct processing arcs in SketchSolver with SolveSpace (issue #1144)
[modules/shaper.git] / src / SketchSolver / SolveSpaceSolver / SolveSpaceSolver_Storage.cpp
index 7843cd88c29d9afaa7baa28633ba7ab2efe04a7b..d48730926de2283aa027aedee5272dbf776bf200 100644 (file)
@@ -19,6 +19,7 @@
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
 #include <ModelAPI_AttributeDouble.h>
+#include <SketchPlugin_Arc.h>
 
 /** \brief Search the entity/parameter with specified ID in the list of elements
  *  \param[in] theEntityID unique ID of the element
@@ -73,6 +74,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) {
@@ -158,6 +162,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)
@@ -171,7 +184,23 @@ bool SolveSpaceSolver_Storage::update(EntityWrapperPtr& theEntity)
 
     if (anEntity->type() == ENTITY_SKETCH)
       storeWorkplane(anEntity);
+
+    // For the correct work with arcs we will add them if their parameter is added
+    if (theEntity->baseAttribute()) {
+      FeaturePtr aFeature = ModelAPI_Feature::feature(theEntity->baseAttribute()->owner());
+      if (aFeature->getKind() == SketchPlugin_Arc::ID() &&
+          myFeatureMap.find(aFeature) == myFeatureMap.end()) {
+        // Additional checking that all attributes are initialized
+        if (aFeature->attribute(SketchPlugin_Arc::CENTER_ID())->isInitialized() && 
+            aFeature->attribute(SketchPlugin_Arc::START_ID())->isInitialized() && 
+            aFeature->attribute(SketchPlugin_Arc::END_ID())->isInitialized()) {
+          myFeatureMap[aFeature] = EntityWrapperPtr();
+          return SketchSolver_Storage::update(aFeature);
+        }
+      }
+    }
   }
+
   return isUpdated;
 }
 
@@ -185,8 +214,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 +321,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 +341,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 +566,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 +596,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 +692,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 +773,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 +867,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 +921,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 +1048,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 +1059,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 +1078,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 +1105,6 @@ bool SolveSpaceSolver_Storage::removeConstraint(const Slvs_hConstraint& theConst
         }
     }
   }
-////  else if (myRemovedConstraints.find(theConstraintID) != myRemovedConstraints.end())
-////    return true;
   return aResult;
 }
 
@@ -1141,80 +1140,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 +1177,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 +1235,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,183 +1474,6 @@ 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)
-{
-  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;
-    }
-  }
-  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;
-}
-
-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();
-  }
-
-  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;
-}
-
 
 bool SolveSpaceSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
 {
@@ -1829,42 +1491,18 @@ bool SolveSpaceSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
     return true;
 
   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;
-  }
-
-  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 +1513,21 @@ 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) {
+    // 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 +1553,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,7 +1584,7 @@ void SolveSpaceSolver_Storage::refresh(bool theFixedOnly) const
     }
   }
 
-  blockEvents(false);
+  //blockEvents(false);
 }
 
 void SolveSpaceSolver_Storage::verifyFixed()