]> SALOME platform Git repositories - modules/shaper.git/blobdiff - src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.cpp
Salome HOME
Update copyrights
[modules/shaper.git] / src / SketchSolver / SolveSpaceSolver / SolveSpaceSolver_Storage.cpp
index 3006fd5b8f7e16468fb3e6795abcc65e5f83439b..3aabbecbd177487891e926fd0931df7c3d7d46d1 100644 (file)
@@ -1,8 +1,21 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SolveSpaceSolver_Storage.cpp
-// Created: 18 Mar 2015
-// Author:  Artem ZHIDKOV
+// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
 
 #include <SolveSpaceSolver_Storage.h>
 #include <SolveSpaceSolver_ConstraintWrapper.h>
@@ -21,7 +34,7 @@
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeRefAttr.h>
 #include <SketchPlugin_Arc.h>
-#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintMiddle.h>
 
 /** \brief Search the entity/parameter with specified ID in the list of elements
  *  \param[in] theEntityID unique ID of the element
@@ -36,7 +49,8 @@ static bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2)
 /// \brief Compare two entities to be different
 static bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2);
 /// \brief Compare two constraints to be different
-static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2);
+static bool IsNotEqual(const Slvs_Constraint& theConstraint1,
+                       const Slvs_Constraint& theConstraint2);
 
 
 SolveSpaceSolver_Storage::SolveSpaceSolver_Storage(const GroupID& theGroup)
@@ -59,8 +73,9 @@ bool SolveSpaceSolver_Storage::update(ConstraintWrapperPtr theConstraint)
     aSlvsConstr = aConstraint->constraint();
 
   // update value of constraint if exist
-  if (fabs(aSlvsConstr.valA - theConstraint->value()) > tolerance) {
-    aSlvsConstr.valA = theConstraint->value();
+  double aCoeff = aSlvsConstr.type == SLVS_C_DIAMETER ? 2.0 : 1.0;
+  if (fabs(aSlvsConstr.valA - theConstraint->value() * aCoeff) > tolerance) {
+    aSlvsConstr.valA = theConstraint->value() * aCoeff;
     isUpdated = true;
   }
 
@@ -75,8 +90,12 @@ 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)
+    // do not update constrained entities for Multi constraints,
+    // and for middle point constraint translated to equal lines
+    ConstraintPtr aBaseConstraint = theConstraint->baseConstraint();
+    if (aSlvsConstr.type == SLVS_C_MULTI_ROTATION || aSlvsConstr.type == SLVS_C_MULTI_TRANSLATION ||
+       (aBaseConstraint && aBaseConstraint->getKind() == SketchPlugin_ConstraintMiddle::ID() &&
+        aSlvsConstr.type != SLVS_C_AT_MIDPOINT))
       continue;
 
     Slvs_hEntity anID = (Slvs_hEntity)(*anIt)->id();
@@ -107,7 +126,7 @@ bool SolveSpaceSolver_Storage::update(ConstraintWrapperPtr theConstraint)
       aConstraint->changeConstraint() = getConstraint(aConstrID);
       isUpdated = true;
       // check duplicated constraints based on different attributes
-      if (myDuplicatedConstraint && !hasDupConstraints && findSameConstraint(aConstraint))
+      if (myDuplicatedConstraint && findSameConstraint(aConstraint) && !hasDupConstraints)
         myDuplicatedConstraint = false;
     }
   }
@@ -117,7 +136,7 @@ bool SolveSpaceSolver_Storage::update(ConstraintWrapperPtr theConstraint)
 bool SolveSpaceSolver_Storage::update(EntityWrapperPtr theEntity)
 {
   bool isUpdated = false;
-  std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity = 
+  std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity =
       std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theEntity);
   Slvs_Entity aSlvsEnt = getEntity((Slvs_hEntity)anEntity->id());
   if (aSlvsEnt.h == SLVS_E_UNKNOWN)
@@ -198,14 +217,15 @@ bool SolveSpaceSolver_Storage::update(EntityWrapperPtr theEntity)
 
 bool SolveSpaceSolver_Storage::update(ParameterWrapperPtr theParameter)
 {
-  std::shared_ptr<SolveSpaceSolver_ParameterWrapper> aParameter = 
+  std::shared_ptr<SolveSpaceSolver_ParameterWrapper> aParameter =
       std::dynamic_pointer_cast<SolveSpaceSolver_ParameterWrapper>(theParameter);
   const Slvs_Param& aParam = getParameter((Slvs_hParam)aParameter->id());
   if (aParam.h != SLVS_E_UNKNOWN && fabs(aParam.val - aParameter->value()) < tolerance)
     return false;
   Slvs_Param aParamToUpd = aParameter->parameter();
   if (aParamToUpd.group == SLVS_G_UNKNOWN)
-    aParamToUpd.group = aParameter->isParametric() ? (Slvs_hGroup)GID_OUTOFGROUP : (Slvs_hGroup)myGroupID;
+    aParamToUpd.group = aParameter->isParametric() ? (Slvs_hGroup)GID_OUTOFGROUP :
+                                                     (Slvs_hGroup)myGroupID;
   Slvs_hParam anID = updateParameter(aParamToUpd);
   if (aParam.h == SLVS_E_UNKNOWN) // new parameter
     aParameter->changeParameter() = getParameter(anID);
@@ -214,7 +234,8 @@ bool SolveSpaceSolver_Storage::update(ParameterWrapperPtr theParameter)
 
 void SolveSpaceSolver_Storage::storeWorkplane(EntityWrapperPtr theSketch)
 {
-  myWorkplaneID = (Slvs_hEntity)theSketch->id();
+  mySketchID = theSketch->id();
+  myWorkplaneID = (Slvs_hEntity)mySketchID;
 
   // Update sub-entities of the sketch
   std::list<EntityWrapperPtr> aSubEntities = theSketch->subEntities();
@@ -243,13 +264,12 @@ void SolveSpaceSolver_Storage::changeGroup(EntityWrapperPtr theEntity, const Gro
   for (; aSIt != aSubs.end(); ++aSIt)
     changeGroup(*aSIt, theGroup);
 
-  if (theEntity->group() != theGroup) {
-    theEntity->setGroup(theGroup);
-    int aPos = Search((Slvs_hEntity)theEntity->id(), myEntities);
-    if (aPos >= 0 && aPos < (int)myEntities.size()) {
-      myEntities[aPos].group = (Slvs_hGroup)theGroup;
+  theEntity->setGroup(theGroup);
+  int aPos = Search((Slvs_hEntity)theEntity->id(), myEntities);
+  if (aPos >= 0 && aPos < (int)myEntities.size()) {
+    if (myEntities[aPos].group != (Slvs_hGroup)theGroup)
       setNeedToResolve(true);
-    }
+    myEntities[aPos].group = (Slvs_hGroup)theGroup;
   }
 }
 
@@ -274,11 +294,18 @@ void SolveSpaceSolver_Storage::addCoincidentPoints(
 {
   if (theMaster->type() != ENTITY_POINT || theSlave->type() != ENTITY_POINT)
     return;
+  if (!theMaster->subEntities().empty() || !theSlave->subEntities().empty()) {
+    EntityWrapperPtr aSubMaster = theMaster->subEntities().empty() ?
+        theMaster : theMaster->subEntities().front();
+    EntityWrapperPtr aSubSlave = theSlave->subEntities().empty() ?
+        theSlave : theSlave->subEntities().front();
+    return addCoincidentPoints(aSubMaster, aSubSlave);
+  }
 
   // Search available coincidence
   CoincidentPointsMap::iterator aMasterFound = myCoincidentPoints.find(theMaster);
   CoincidentPointsMap::iterator aSlaveFound = myCoincidentPoints.find(theSlave);
-  if (aMasterFound == myCoincidentPoints.end() &&  aSlaveFound == myCoincidentPoints.end()) {
+  if (aMasterFound == myCoincidentPoints.end() || aSlaveFound == myCoincidentPoints.end()) {
     // try to find master and slave points in the lists of slaves of already existent coincidences
     CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin();
     for (; anIt != myCoincidentPoints.end(); ++anIt) {
@@ -317,9 +344,9 @@ void SolveSpaceSolver_Storage::addCoincidentPoints(
     if (theMaster->id() != theSlave->id())
       removeEntity((Slvs_hEntity)theSlave->id());
 
-    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aPointMaster = 
+    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aPointMaster =
         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMaster);
-    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aPointSlave = 
+    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aPointSlave =
         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSlave);
     aPointSlave->changeEntity() = aPointMaster->entity();
     aPointSlave->setParameters(aPointMaster->parameters());
@@ -391,6 +418,13 @@ void SolveSpaceSolver_Storage::replaceInConstraints(
 
       std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aWrapper =
           std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(*aCIt);
+      if (theSource->id() == theDest->id()) {
+        // No need to update SolveSpace constraint if the entities are the same
+        aWrapper->changeConstraint() = getConstraint((Slvs_hConstraint)aWrapper->id());
+        aWrapper->setEntities(aSubs);
+        continue;
+      }
+
       // change constraint entities
       Slvs_Constraint aConstr = aWrapper->constraint();
       if (aConstr.ptA == (Slvs_hEntity)theSource->id())
@@ -408,7 +442,12 @@ void SolveSpaceSolver_Storage::replaceInConstraints(
             aConstr.entityC == aSlvsCIt->entityC && aConstr.entityD == aSlvsCIt->entityD) {
           Slvs_hConstraint anIDToRemove = aConstr.h;
           aConstr = *aSlvsCIt;
+          int aShift = (int)(aSlvsCIt - myConstraints.begin());
           removeConstraint(anIDToRemove);
+          aSlvsCIt = myConstraints.begin() + aShift - 1;
+          for (; aSlvsCIt != myConstraints.end(); ++aSlvsCIt)
+            if (aSlvsCIt->h == aConstr.h)
+              break;
           break;
         }
 
@@ -423,7 +462,7 @@ void SolveSpaceSolver_Storage::replaceInConstraints(
               addSameConstraints(*aCIt2, aWrapper);
               break;
             }
-      } else 
+      } else
         aConstr.h = updateConstraint(aConstr);
       aWrapper->changeConstraint() = aConstr;
 
@@ -473,8 +512,8 @@ bool SolveSpaceSolver_Storage::findSameConstraint(ConstraintWrapperPtr theConstr
           (*aCWIt)->type() == CONSTRAINT_MULTI_TRANSLATION)
         continue;
       if ((*aCWIt)->type() == theConstraint->type()) {
-        const Slvs_Constraint& aCComp = std::dynamic_pointer_cast<
-            SolveSpaceSolver_ConstraintWrapper>(*aCWIt)->constraint();
+        const Slvs_Constraint& aCComp = getConstraint((Slvs_hConstraint)(*aCWIt)->id());
+
         if (aCBase.ptA == aCComp.ptA && aCBase.ptB == aCComp.ptB &&
             aCBase.entityA == aCComp.entityA && aCBase.entityB == aCComp.entityB &&
             aCBase.entityC == aCComp.entityC && aCBase.entityD == aCComp.entityD &&
@@ -533,8 +572,10 @@ EntityWrapperPtr SolveSpaceSolver_Storage::calculateMiddlePoint(
       theX = anArcPoint[0][0] + anArcPoint[2][0];
       theY = anArcPoint[0][1] + anArcPoint[2][1];
     } else {
-      std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1]));
-      std::shared_ptr<GeomAPI_Dir2d> aEndDir(new GeomAPI_Dir2d(anArcPoint[2][0], anArcPoint[2][1]));
+      std::shared_ptr<GeomAPI_Dir2d>
+        aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1]));
+      std::shared_ptr<GeomAPI_Dir2d>
+        aEndDir(new GeomAPI_Dir2d(anArcPoint[2][0], anArcPoint[2][1]));
       double anAngle = aStartDir->angle(aEndDir);
       if (anAngle < 0)
         anAngle += 2.0 * PI;
@@ -595,10 +636,8 @@ 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)) {
-        myUpdatedParameters.insert(theParam.h);
+      if (IsNotEqual(myParameters[aPos], theParam))
         setNeedToResolve(true);
-      }
       myParameters[aPos] = theParam;
       return theParam.h;
     }
@@ -713,7 +752,7 @@ bool SolveSpaceSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
     myEntities.erase(myEntities.begin() + aPos);
     myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
     if (anEntity.distance != SLVS_E_UNKNOWN)
-      aResult = aResult && removeParameter(anEntity.distance);
+      aResult = aResult && removeEntity(anEntity.distance);
     for (int i = 0; i < 4; i++)
       if (anEntity.param[i] != SLVS_E_UNKNOWN)
         aResult = removeParameter(anEntity.param[i]) && aResult;
@@ -722,105 +761,6 @@ bool SolveSpaceSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
   return aResult;
 }
 
-void SolveSpaceSolver_Storage::removeUnusedEntities()
-{
-  std::set<Slvs_hEntity> anUnusedEntities;
-  std::vector<Slvs_Entity>::const_iterator aEIt = myEntities.begin();
-  for (; aEIt != myEntities.end(); ++aEIt) {
-    if (aEIt->h == aEIt->wrkpl) {
-      // don't remove workplane
-      anUnusedEntities.erase(aEIt->point[0]);
-      anUnusedEntities.erase(aEIt->normal);
-      continue;
-    }
-    anUnusedEntities.insert(aEIt->h);
-  }
-
-  std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
-  for (; aCIt != myConstraints.end(); ++aCIt) {
-    Slvs_hEntity aSubs[6] = {
-        aCIt->entityA, aCIt->entityB,
-        aCIt->entityC, aCIt->entityD,
-        aCIt->ptA,     aCIt->ptB};
-    for (int i = 0; i < 6; i++) {
-      if (aSubs[i] != SLVS_E_UNKNOWN) {
-        anUnusedEntities.erase(aSubs[i]);
-        int aPos = Search(aSubs[i], myEntities);
-        if (aPos >= 0 && aPos < (int)myEntities.size()) {
-          for (int j = 0; j < 4; j++)
-            if (myEntities[aPos].point[j] != SLVS_E_UNKNOWN)
-              anUnusedEntities.erase(myEntities[aPos].point[j]);
-          if (myEntities[aPos].distance != SLVS_E_UNKNOWN)
-            anUnusedEntities.erase(myEntities[aPos].distance);
-        }
-      }
-    }
-  }
-
-  std::set<Slvs_hEntity>::const_iterator anEntIt = anUnusedEntities.begin();
-  while (anEntIt != anUnusedEntities.end()) {
-    int aPos = Search(*anEntIt, myEntities);
-    if (aPos < 0 && aPos >= (int)myEntities.size())
-      continue;
-    Slvs_Entity anEntity = myEntities[aPos];
-    // Remove entity if and only if all its parameters unused
-    bool isUsed = false;
-    if (anEntity.distance != SLVS_E_UNKNOWN && 
-      anUnusedEntities.find(anEntity.distance) == anUnusedEntities.end())
-      isUsed = true;
-    for (int i = 0; i < 4 && !isUsed; i++)
-      if (anEntity.point[i] != SLVS_E_UNKNOWN &&
-          anUnusedEntities.find(anEntity.point[i]) == anUnusedEntities.end())
-        isUsed = true;
-    if (isUsed) {
-      anUnusedEntities.erase(anEntity.distance);
-      for (int i = 0; i < 4; i++)
-        if (anEntity.point[i] != SLVS_E_UNKNOWN)
-          anUnusedEntities.erase(anEntity.point[i]);
-      std::set<Slvs_hEntity>::iterator aRemoveIt = anEntIt++;
-      anUnusedEntities.erase(aRemoveIt);
-      continue;
-    }
-    ++anEntIt;
-  }
-
-  for (anEntIt = anUnusedEntities.begin(); anEntIt != anUnusedEntities.end(); ++anEntIt) {
-    int aPos = Search(*anEntIt, myEntities);
-    if (aPos >= 0 && aPos < (int)myEntities.size()) {
-      // Remove entity and its parameters
-      Slvs_Entity anEntity = myEntities[aPos];
-      myEntities.erase(myEntities.begin() + aPos);
-      myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
-      if (anEntity.distance != SLVS_E_UNKNOWN)
-        removeParameter(anEntity.distance);
-      for (int i = 0; i < 4; i++)
-        if (anEntity.param[i] != SLVS_E_UNKNOWN)
-          removeParameter(anEntity.param[i]);
-      for (int i = 0; i < 4; i++)
-        if (anEntity.point[i] != SLVS_E_UNKNOWN)
-          removeEntity(anEntity.point[i]);
-    }
-  }
-
-  if (!anUnusedEntities.empty())
-    myNeedToResolve = true;
-}
-
-bool SolveSpaceSolver_Storage::isUsedByConstraints(const Slvs_hEntity& theEntityID) const
-{
-  std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
-  for (; aCIt != myConstraints.end(); ++aCIt) {
-    Slvs_hEntity aSubs[6] = {
-        aCIt->entityA, aCIt->entityB,
-        aCIt->entityC, aCIt->entityD,
-        aCIt->ptA,     aCIt->ptB};
-    for (int i = 0; i < 6; i++)
-      if (aSubs[i] != SLVS_E_UNKNOWN && aSubs[i] == theEntityID)
-        return true;
-  }
-  return false;
-}
-
 const Slvs_Entity& SolveSpaceSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const
 {
   int aPos = Search(theEntityID, myEntities);
@@ -833,59 +773,6 @@ const Slvs_Entity& SolveSpaceSolver_Storage::getEntity(const Slvs_hEntity& theEn
   return aDummy;
 }
 
-Slvs_hEntity SolveSpaceSolver_Storage::copyEntity(const Slvs_hEntity& theCopied)
-{
-  int aPos = Search(theCopied, myEntities);
-  if (aPos < 0 || aPos >= (int)myEntities.size())
-    return SLVS_E_UNKNOWN;
-
-  Slvs_Entity aCopy = myEntities[aPos];
-  aCopy.h = SLVS_E_UNKNOWN;
-  int i = 0;
-  while (aCopy.point[i] != SLVS_E_UNKNOWN) {
-    aCopy.point[i] = copyEntity(aCopy.point[i]);
-    i++;
-  }
-  if (aCopy.param[0] != SLVS_E_UNKNOWN) {
-    aPos = Search(aCopy.param[0], myParameters);
-    i = 0;
-    while (aCopy.param[i] != SLVS_E_UNKNOWN) {
-      Slvs_Param aNewParam = myParameters[aPos];
-      aNewParam.h = SLVS_E_UNKNOWN;
-      aCopy.param[i] = addParameter(aNewParam);
-      i++;
-      aPos++;
-    }
-  }
-  return addEntity(aCopy);
-}
-
-void SolveSpaceSolver_Storage::copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo)
-{
-  int aPosFrom = Search(theFrom, myEntities);
-  int aPosTo = Search(theTo, myEntities);
-  if (aPosFrom < 0 || aPosFrom >= (int)myEntities.size() || 
-      aPosTo < 0 || aPosTo >= (int)myEntities.size())
-    return;
-
-  Slvs_Entity aEntFrom = myEntities[aPosFrom];
-  Slvs_Entity aEntTo = myEntities[aPosTo];
-  int i = 0;
-  while (aEntFrom.point[i] != SLVS_E_UNKNOWN) {
-    copyEntity(aEntFrom.point[i], aEntTo.point[i]);
-    i++;
-  }
-  if (aEntFrom.param[0] != SLVS_E_UNKNOWN) {
-    aPosFrom = Search(aEntFrom.param[0], myParameters);
-    aPosTo = Search(aEntTo.param[0], myParameters);
-    i = 0;
-    while (aEntFrom.param[i] != SLVS_E_UNKNOWN) {
-      myParameters[aPosTo++].val = myParameters[aPosFrom++].val;
-      i++;
-    }
-  }
-}
-
 
 Slvs_hConstraint SolveSpaceSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
 {
@@ -905,7 +792,7 @@ Slvs_hConstraint SolveSpaceSolver_Storage::addConstraint(const Slvs_Constraint&
         aConstraint.entityA == aCIt->entityA && aConstraint.entityB == aCIt->entityB &&
         aConstraint.entityC == aCIt->entityC && aConstraint.entityD == aCIt->entityD) {
       myDuplicatedConstraint = true;
-      return aCIt->h;
+      break;
     }
   }
 
@@ -933,6 +820,30 @@ Slvs_hConstraint SolveSpaceSolver_Storage::updateConstraint(const Slvs_Constrain
   // Constraint is not found, add new one
   Slvs_Constraint aConstraint = theConstraint;
   aConstraint.h = 0;
+
+  // Firstly, check middle-point constraint conflicts with point-on-line
+  if (aConstraint.type == SLVS_C_AT_MIDPOINT) {
+    std::vector<Slvs_Constraint>::const_iterator anIt = myConstraints.begin();
+    for (; anIt != myConstraints.end(); ++anIt)
+      if (anIt->type == SLVS_C_PT_ON_LINE &&
+          anIt->ptA == aConstraint.ptA &&
+          anIt->entityA == aConstraint.entityA)
+        break;
+    if (anIt != myConstraints.end()) {
+      // change the constraint to the lengths equality to avoid conflicts
+      Slvs_Entity aLine = getEntity(aConstraint.entityA);
+      Slvs_Entity aNewLine1 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID,
+          myWorkplaneID, aLine.point[0], aConstraint.ptA);
+      aNewLine1.h = addEntity(aNewLine1);
+      Slvs_Entity aNewLine2 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID,
+          myWorkplaneID, aLine.point[1], aConstraint.ptA);
+      aNewLine2.h = addEntity(aNewLine2);
+      aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID,
+          SLVS_C_EQUAL_LENGTH_LINES,
+          myWorkplaneID, 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aNewLine1.h, aNewLine2.h);
+    }
+  }
+
   return addConstraint(aConstraint);
 }
 
@@ -944,11 +855,27 @@ bool SolveSpaceSolver_Storage::removeConstraint(const Slvs_hConstraint& theConst
     myConstraints.erase(myConstraints.begin() + aPos);
     myConstrMaxID = myConstraints.empty() ? SLVS_E_UNKNOWN : myConstraints.back().h;
     myNeedToResolve = true;
+
+    if (myDuplicatedConstraint) {
+      // Find a constraint with same type uses same arguments
+      std::vector<Slvs_Constraint>::iterator aCIt = myConstraints.begin();
+      for (; aCIt != myConstraints.end(); aCIt++) {
+        if (aConstraint.type != aCIt->type)
+          continue;
+        if (aConstraint.ptA == aCIt->ptA && aConstraint.ptB == aCIt->ptB &&
+            aConstraint.entityA == aCIt->entityA && aConstraint.entityB == aCIt->entityB &&
+            aConstraint.entityC == aCIt->entityC && aConstraint.entityD == aCIt->entityD) {
+          myDuplicatedConstraint = false;
+          break;
+        }
+      }
+    }
   }
   return true;
 }
 
-const Slvs_Constraint& SolveSpaceSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const
+const Slvs_Constraint& SolveSpaceSolver_Storage::
+  getConstraint(const Slvs_hConstraint& theConstraintID) const
 {
   int aPos = Search(theConstraintID, myConstraints);
   if (aPos >= 0 && aPos < (int)myConstraints.size())
@@ -985,131 +912,35 @@ void SolveSpaceSolver_Storage::initializeSolver(SolverPtr theSolver)
 }
 
 
-bool SolveSpaceSolver_Storage::removeCoincidence(ConstraintWrapperPtr theConstraint)
-{
-  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 (aPtPtIt == myCoincidentPoints.end())
-    return true; // already removed
-
-  // 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;
-  }
-
-  // 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 (!aNotCIt->second || !aFIt->second->isUsed(aNotCIt->first->baseAttribute()))
-        continue;
-      std::list<EntityWrapperPtr> aSubs = aFIt->second->subEntities();
-      std::list<EntityWrapperPtr>::iterator aSIt = aSubs.begin();
-      bool isUpd = false;
-      for (; aSIt != aSubs.end(); ++aSIt)
-        if (*aSIt == aNotCIt->first) {
-          *aSIt = aNotCIt->second;
-          isUpd = true;
-        }
-      if (isUpd) {
-        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.erase(aPtPtIt);
-      myCoincidentPoints[aNewMaster] = aSlaves;
-      aPtPtIt = myCoincidentPoints.find(aNewMaster);
-    } else
-      aPtPtIt->second.erase(aNotCIt->first);
-  }
-  return true;
-}
-
 bool SolveSpaceSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
 {
   std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
       std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
 
   // verify whether the constraint has duplicated
+  bool hasSameID = false;
   SameConstraintMap::iterator anEqIt = myEqualConstraints.begin();
-  for (; anEqIt != myEqualConstraints.end(); ++anEqIt)
-    if (anEqIt->find(aConstraint) != anEqIt->end()) {
+  for (; anEqIt != myEqualConstraints.end(); ++anEqIt) {
+    std::set<ConstraintWrapperPtr>::const_iterator aFound = anEqIt->find(aConstraint);
+    if (aFound != anEqIt->end()) {
+      // verify there is a constraint with same ID
+      std::set<ConstraintWrapperPtr>::const_iterator anIt = anEqIt->begin();
+      ConstraintID anID = (*aFound)->id();
+      for (++anIt; anIt != anEqIt->end() && !hasSameID; ++anIt)
+        if ((*anIt)->id() == anID && aFound != anIt)
+          hasSameID = true;
+      // erase constraint
       anEqIt->erase(aConstraint);
       break;
     }
-  if (anEqIt != myEqualConstraints.end())
+  }
+  if (anEqIt != myEqualConstraints.end() && hasSameID)
     return true;
 
   bool isFullyRemoved = removeConstraint((Slvs_hConstraint)aConstraint->id());
-
   // remove point-point coincidence
   if (aConstraint->type() == CONSTRAINT_PT_PT_COINCIDENT)
-    isFullyRemoved = removeCoincidence(theConstraint);
-
+    isFullyRemoved = removeCoincidence(theConstraint) && isFullyRemoved;
   return SketchSolver_Storage::remove(theConstraint) && isFullyRemoved;
 }
 
@@ -1118,10 +949,33 @@ bool SolveSpaceSolver_Storage::remove(EntityWrapperPtr theEntity)
   if (!theEntity)
     return false;
 
-  std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity = 
+  // Additional check for entity to be used in point-point coincidence
+  bool isCoincide = false;
+  if (theEntity->type() == ENTITY_POINT) {
+    CoincidentPointsMap::const_iterator anIt = myCoincidentPoints.begin();
+    std::set<EntityWrapperPtr>::const_iterator aCIt;
+    for (; anIt != myCoincidentPoints.end(); ++anIt) {
+      if (anIt->first == theEntity)
+        break;
+      for (aCIt = anIt->second.begin(); aCIt != anIt->second.end(); ++aCIt)
+        if (*aCIt == theEntity)
+          break;
+      if (aCIt != anIt->second.end())
+        break;
+    }
+    if (anIt != myCoincidentPoints.end()) {
+      if (anIt->first != theEntity && isUsed(anIt->first->baseAttribute()))
+        isCoincide = true;
+      for (aCIt = anIt->second.begin(); !isCoincide && aCIt != anIt->second.end(); ++aCIt)
+        if (*aCIt != theEntity && isUsed((*aCIt)->baseAttribute()))
+          isCoincide = true;
+    }
+  }
+
+  std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity =
         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theEntity);
-  bool isFullyRemoved = removeEntity((Slvs_hEntity)anEntity->id());
-  return SketchSolver_Storage::remove(theEntity) && isFullyRemoved;
+  bool isFullyRemoved = isCoincide ? true : removeEntity((Slvs_hEntity)anEntity->id());
+  return (SketchSolver_Storage::remove(theEntity) || isCoincide) && isFullyRemoved;
 }
 
 bool SolveSpaceSolver_Storage::remove(ParameterWrapperPtr theParameter)
@@ -1140,10 +994,10 @@ void SolveSpaceSolver_Storage::refresh(bool theFixedOnly) const
   for (; anIt != myAttributeMap.end(); ++anIt) {
     if (!anIt->second)
       continue;
-    // the external feature always should keep the up to date values, so, 
+    // 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::shared_ptr<SketchPlugin_Feature> aSketchFeature =
         std::dynamic_pointer_cast<SketchPlugin_Feature>(anIt->first->owner());
       if (aSketchFeature.get() && aSketchFeature->isExternal())
         continue;
@@ -1160,7 +1014,7 @@ void SolveSpaceSolver_Storage::refresh(bool theFixedOnly) const
     bool isUpd[3] = {false};
     int i = 0;
     for (aParIt = aParams.begin(); i < 3 && aParIt != aParams.end(); ++aParIt, ++i) {
-      std::shared_ptr<SolveSpaceSolver_ParameterWrapper> aWrapper = 
+      std::shared_ptr<SolveSpaceSolver_ParameterWrapper> aWrapper =
           std::dynamic_pointer_cast<SolveSpaceSolver_ParameterWrapper>(*aParIt);
       if (!theFixedOnly || aWrapper->group() == GID_OUTOFGROUP || aWrapper->isParametric()) {
         aWrapper->changeParameter().val = getParameter((Slvs_hParam)aWrapper->id()).val;
@@ -1181,7 +1035,7 @@ void SolveSpaceSolver_Storage::refresh(bool theFixedOnly) const
         aPoint2D->setValue(aCoords[0], aCoords[1]);
         // Find points coincident with this one (probably not in GID_OUTOFGROUP)
         std::map<AttributePtr, EntityWrapperPtr>::const_iterator aLocIt;
-        if (theFixedOnly) 
+        if (theFixedOnly)
           aLocIt = myAttributeMap.begin();
         else {
           aLocIt = anIt;
@@ -1190,7 +1044,7 @@ void SolveSpaceSolver_Storage::refresh(bool theFixedOnly) const
         for (; aLocIt != myAttributeMap.end(); ++aLocIt) {
           if (!aLocIt->second)
             continue;
-          std::shared_ptr<SketchPlugin_Feature> aSketchFeature = 
+          std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
             std::dynamic_pointer_cast<SketchPlugin_Feature>(aLocIt->first->owner());
           if (aSketchFeature && aSketchFeature->isExternal())
             continue;
@@ -1231,10 +1085,17 @@ void SolveSpaceSolver_Storage::verifyFixed()
   for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
     if (!anAttrIt->second)
       continue;
+    if (anAttrIt->second->group() == GID_OUTOFGROUP) {
+      Slvs_Entity anEnt = getEntity((Slvs_hEntity)anAttrIt->second->id());
+      if (anEnt.group != (Slvs_hEntity)GID_OUTOFGROUP)
+        anEnt.group = (Slvs_hEntity)GID_OUTOFGROUP;
+      updateEntity(anEnt);
+    }
+
     const std::list<ParameterWrapperPtr>& aParameters = anAttrIt->second->parameters();
     std::list<ParameterWrapperPtr>::const_iterator aParIt = aParameters.begin();
     for (; aParIt != aParameters.end(); ++aParIt)
-      if ((*aParIt)->group() == GID_OUTOFGROUP) {
+      if (anAttrIt->second->group() == GID_OUTOFGROUP || (*aParIt)->group() == GID_OUTOFGROUP) {
         Slvs_Param aParam = getParameter((Slvs_hParam)(*aParIt)->id());
         if (aParam.group != (Slvs_hParam)GID_OUTOFGROUP) {
           aParam.group = (Slvs_hParam)GID_OUTOFGROUP;
@@ -1258,7 +1119,7 @@ void SolveSpaceSolver_Storage::adjustArc(const Slvs_Entity& theArc)
     if (i > 0) {
       anArcPoints[i][0] -= anArcPoints[0][0];
       anArcPoints[i][1] -= anArcPoints[0][1];
-      aDist[i] = sqrt(anArcPoints[i][0] * anArcPoints[i][0] + 
+      aDist[i] = sqrt(anArcPoints[i][0] * anArcPoints[i][0] +
                       anArcPoints[i][1] * anArcPoints[i][1]);
     }
   }
@@ -1297,7 +1158,7 @@ template<typename T>
 int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
 {
   int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
-  int aVecSize = theEntities.size();
+  int aVecSize = (int)theEntities.size();
   if (theEntities.empty())
     return 1;
   while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)