Salome HOME
updated copyright message
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_Storage.cpp
index 586f693cc6ed596c094a243a7aadb8e973d00cc4..deefed48c7ee7b0d93d75ff4c57d91b9dfd08c72 100644 (file)
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    PlaneGCSSolver_Storage.cpp
-// Created: 14 Dec 2015
-// Author:  Artem ZHIDKOV
+// Copyright (C) 2014-2023  CEA, EDF
+//
+// 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 <PlaneGCSSolver_Storage.h>
-#include <PlaneGCSSolver_Builder.h>
 #include <PlaneGCSSolver_Solver.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
 #include <PlaneGCSSolver_ConstraintWrapper.h>
-#include <PlaneGCSSolver_EntityWrapper.h>
+#include <PlaneGCSSolver_EdgeWrapper.h>
 #include <PlaneGCSSolver_PointWrapper.h>
-#include <PlaneGCSSolver_ScalarWrapper.h>
-#include <PlaneGCSSolver_ParameterWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
+
+#include <PlaneGCSSolver_AttributeBuilder.h>
+#include <PlaneGCSSolver_FeatureBuilder.h>
+#include <PlaneGCSSolver_EntityDestroyer.h>
 
-#include <GeomAPI_Edge.h>
 #include <GeomAPI_Dir2d.h>
 #include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_XY.h>
 #include <GeomDataAPI_Point2D.h>
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_ConstraintTangent.h>
+#include <GeomDataAPI_Point2DArray.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_Projection.h>
 
 #include <cmath>
 
 
-PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const GroupID& theGroup)
-  : SketchSolver_Storage(theGroup),
-    myEntityLastID(EID_SKETCH),
+static void constraintsToSolver(const ConstraintWrapperPtr& theConstraint,
+                                const SolverPtr& theSolver)
+{
+  const std::list<GCSConstraintPtr>& aConstraints =
+      std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint)->constraints();
+  theSolver->addConstraint(theConstraint->id(), aConstraints);
+}
+
+
+PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const SolverPtr& theSolver)
+  : SketchSolver_Storage(theSolver),
     myConstraintLastID(CID_UNKNOWN)
 {
 }
 
 void PlaneGCSSolver_Storage::addConstraint(
-    ConstraintPtr                   theConstraint,
-    std::list<ConstraintWrapperPtr> theSolverConstraints)
+    ConstraintPtr        theConstraint,
+    ConstraintWrapperPtr theSolverConstraint)
 {
-  SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraints);
-
-  // update point-point coincidence
-  if (!theSolverConstraints.empty() &&
-      theSolverConstraints.front()->type() == CONSTRAINT_PT_PT_COINCIDENT) {
-    std::list<ConstraintWrapperPtr>::iterator aCIt = theSolverConstraints.begin();
-    for (; aCIt != theSolverConstraints.end(); ++aCIt)
-      update(*aCIt);
-  }
-}
+  SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraint);
 
+  theSolverConstraint->setId(++myConstraintLastID);
+  constraintsToSolver(theSolverConstraint, mySketchSolver);
+}
 
-bool PlaneGCSSolver_Storage::update(ConstraintWrapperPtr theConstraint)
+void PlaneGCSSolver_Storage::addMovementConstraint(
+    const ConstraintWrapperPtr& theSolverConstraint)
 {
-  bool isUpdated = false;
-  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
-      std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
-
-  // point-Line distance should be positive
-  if (aConstraint->type() == CONSTRAINT_PT_LINE_DISTANCE && aConstraint->value() < 0.0)
-    aConstraint->setValue(-aConstraint->value());
-
-  // make value of constraint unchangeable
-  ParameterWrapperPtr aValue = aConstraint->valueParameter();
-  if (aValue)
-    isUpdated = update(aValue) || isUpdated;
-
-  // update constrained entities
-  std::list<EntityWrapperPtr> anEntities = theConstraint->entities();
-  std::list<EntityWrapperPtr>::iterator anIt = anEntities.begin();
-  for (; anIt != anEntities.end(); ++anIt)
-    isUpdated = update(*anIt) || isUpdated;
-
-  if (aConstraint->id() == CID_UNKNOWN) {
-    const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
-    // check middle-point constraint conflicts with point-on-line
-    if (aConstraint->type() == CONSTRAINT_MIDDLE_POINT) {
-      std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
-          anIt = myConstraintMap.begin();
-      for (; anIt != myConstraintMap.end(); ++anIt) {
-        EntityWrapperPtr aPoint, aLine;
-        if (anIt->second.empty())
-          continue;
-        ConstraintWrapperPtr aCurrentConstr = anIt->second.front();
-        if (aCurrentConstr->type() != CONSTRAINT_PT_ON_LINE)
-          continue;
-        const std::list<EntityWrapperPtr>& aCurSubs = aCurrentConstr->entities();
-        std::list<EntityWrapperPtr>::const_iterator aSIt1, aSIt2;
-        for (aSIt1 = aSubs.begin(); aSIt1 != aSubs.end(); ++aSIt1) {
-          if ((*aSIt1)->type() == ENTITY_POINT)
-            aPoint = *aSIt1;
-          else if((*aSIt1)->type() == ENTITY_LINE)
-            aLine = *aSIt1;
-          else
-            continue;
-          for (aSIt2 = aCurSubs.begin(); aSIt2 != aCurSubs.end(); ++aSIt2)
-            if ((*aSIt1)->id() == (*aSIt2)->id())
-              break;
-          if (aSIt2 == aCurSubs.end())
-            break;
-        }
-        // point-on-line found, change it to bisector
-        if (aSIt1 == aSubs.end()) {
-          std::list<GCSConstraintPtr> aConstrList = aConstraint->constraints();
-          aConstrList.pop_front();
-          aConstraint->setConstraints(aConstrList);
-          break;
-        }
-      }
-    }
+  // before adding movement constraint to solver, re-check its DOF
+  if (mySketchSolver->dof() == 0)
+    mySketchSolver->diagnose();
 
-    // Change ID of constraints
-    aConstraint->setId(++myConstraintLastID);
-  }
+  theSolverConstraint->setId(CID_MOVEMENT);
+  constraintsToSolver(theSolverConstraint, mySketchSolver);
+}
 
-  return isUpdated;
+
+EntityWrapperPtr PlaneGCSSolver_Storage::createFeature(
+    const FeaturePtr&             theFeature,
+    PlaneGCSSolver_EntityBuilder* theBuilder)
+{
+  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+  std::list<AttributePtr>::const_iterator anIt = anAttributes.begin();
+  for (; anIt != anAttributes.end(); ++anIt)
+    createAttribute(*anIt, theBuilder);
+
+  EntityWrapperPtr aResult = theBuilder->createFeature(theFeature);
+  if (aResult)
+    addEntity(theFeature, aResult);
+  return aResult;
 }
 
-/// \brief Update coordinates of the point or scalar using its base attribute
-static bool updateValues(EntityWrapperPtr& theEntity)
+EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute(
+    const AttributePtr&           theAttribute,
+    PlaneGCSSolver_EntityBuilder* theBuilder)
 {
-  const double aTol = 1000. * tolerance;
-  bool isUpdated = false;
-  AttributePtr anAttr = theEntity->baseAttribute();
-  const std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
-
-  double aCoord[2];
-
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
-  if (aPoint2D) {
-    aCoord[0] = aPoint2D->x();
-    aCoord[1] = aPoint2D->y();
-  } else {
-    AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttr);
-    if (aScalar)
-      aCoord[0] = aScalar->value();
-  }
+  EntityWrapperPtr aResult = theBuilder->createAttribute(theAttribute);
+  if (aResult)
+    addEntity(theAttribute, aResult);
+  return aResult;
+}
 
-  std::list<ParameterWrapperPtr>::const_iterator anIt = aParams.begin();
-  for (int i = 0; anIt != aParams.end(); ++anIt, ++i)
-    if (fabs((*anIt)->value() - aCoord[i]) > aTol) {
-      (*anIt)->setValue(aCoord[i]);
-      isUpdated = true;
-    }
-  return isUpdated;
+static bool hasReference(std::shared_ptr<SketchPlugin_Feature> theFeature,
+                         const std::string& theFeatureKind)
+{
+  const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
+  for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
+       aRefIt != aRefs.end(); ++aRefIt) {
+     FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
+     if (anOwner && !anOwner->isMacro() && anOwner->getKind() == theFeatureKind)
+       return true;
+  }
+  return false;
 }
 
-bool PlaneGCSSolver_Storage::update(EntityWrapperPtr theEntity)
+static bool isCopyFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
 {
-  if (theEntity->type() == ENTITY_SKETCH)
-    return true; // sketch is not necessary for PlaneGCS, so it is always says true
+  return theFeature && theFeature->isCopy();
+}
 
+bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
+{
+  bool sendNotify = false;
   bool isUpdated = false;
+  std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
+  EntityWrapperPtr aRelated = entity(theFeature);
+  if (aRelated) // send signal to subscribers
+    sendNotify = true;
+  else { // Feature is not exist, create it
+    bool isCopy = isCopyFeature(aSketchFeature);
+    bool isProjReferred = hasReference(aSketchFeature, SketchPlugin_Projection::ID());
+    // the feature is a copy in "Multi" constraint and does not used in other constraints
+    if (!theForce && (isCopy && !isProjReferred) &&
+        myFeatureMap.find(theFeature) == myFeatureMap.end())
+      return false;
+
+    // external feature processing
+    bool isExternal =
+        (aSketchFeature && (aSketchFeature->isExternal() || isCopy || isProjReferred));
+
+    PlaneGCSSolver_FeatureBuilder aBuilder(isExternal ? 0 : this);
+
+    // Reserve the feature in the map of features
+    // (do not want to add several copies of it while adding attributes)
+    aRelated = createFeature(theFeature, &aBuilder);
+    myFeatureMap[theFeature] = aRelated;
+    createAuxiliaryConstraints(aRelated);
+    isUpdated = true;
+  }
 
-  if (theEntity->baseAttribute()) {
-    isUpdated = updateValues(theEntity);
-    if (isUpdated) {
-      setNeedToResolve(true);
-      if (theEntity->type() == ENTITY_POINT && theEntity->group() != myGroupID)
-        updateCoincident(theEntity);
-    }
+  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+  std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
+  for (; anAttrIt != anAttributes.end(); ++anAttrIt)
+    if (PlaneGCSSolver_Tools::isAttributeApplicable((*anAttrIt)->id(), theFeature->getKind()))
+      isUpdated = update(*anAttrIt) || isUpdated;
+
+  // check external attribute is changed
+  bool isExternal = aSketchFeature &&
+                   (aSketchFeature->isExternal() || isCopyFeature(aSketchFeature));
+  if (aRelated && isExternal != aRelated->isExternal()) {
+    if (isExternal)
+      makeExternal(aRelated);
+    else
+      makeNonExternal(aRelated);
+    isUpdated = true;
   }
 
-  // update parameters
-  std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
-  std::list<ParameterWrapperPtr>::iterator aPIt = aParams.begin();
-  for (; aPIt != aParams.end(); ++aPIt)
-    isUpdated = update(*aPIt) || isUpdated;
+  // send notification to listeners due to at least one attribute is changed
+  if (sendNotify && isUpdated)
+    notify(theFeature);
 
-  // update sub-entities
-  std::list<EntityWrapperPtr> aSubEntities = theEntity->subEntities();
-  std::list<EntityWrapperPtr>::iterator aSIt = aSubEntities.begin();
-  for (; aSIt != aSubEntities.end(); ++aSIt)
-    isUpdated = update(*aSIt) || isUpdated;
+  // update arc
+  if (aRelated)
+    PlaneGCSSolver_Tools::recalculateArcParameters(aRelated);
 
-  // additional constraints for the arc processing
-  if (theEntity->type() == ENTITY_ARC)
-    processArc(theEntity);
-
-  // Change entity's ID, if necessary
-  if (theEntity->id() == EID_UNKNOWN) {
-    if (theEntity->type() == ENTITY_POINT) {
-      std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
-          std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity);
-      if (!aPoint) {
-        aPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
-            theEntity->subEntities().front());
-      }
-      aPoint->setId(++myEntityLastID);
-    } else if (theEntity->type() == ENTITY_SCALAR) {
-      std::shared_ptr<PlaneGCSSolver_ScalarWrapper> aScalar =
-          std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theEntity);
-      aScalar->setId(++myEntityLastID);
-    } else {
-      std::shared_ptr<PlaneGCSSolver_EntityWrapper> aGCSEnt =
-          std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theEntity);
-      aGCSEnt->setId(++myEntityLastID);
-    }
-  }
   return isUpdated;
 }
 
-bool PlaneGCSSolver_Storage::update(ParameterWrapperPtr theParameter)
+bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce)
 {
-  std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam =
-      std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(theParameter);
-  if (aParam->isProcessed())
+  if (!theAttribute->isInitialized())
     return false;
-  if (theParameter->group() != myGroupID || theParameter->isParametric())
-    myConst.push_back(aParam->parameter());
-  else
-    myParameters.push_back(aParam->parameter());
-  aParam->setProcessed(true);
-  return true;
-}
 
+  AttributePtr anAttribute = theAttribute;
+  AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
+  if (aRefAttr) {
+    if (aRefAttr->isObject()) {
+      FeaturePtr aFeature;
+      /// TODO: Check resultToFeatureOrAttribute() precisely.
+      resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute);
+      if (aFeature)
+        return update(aFeature, theForce);
+    } else
+      anAttribute = aRefAttr->attr();
+  }
 
-bool PlaneGCSSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
-{
-  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
-    std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
-
-  bool isFullyRemoved = true;
-  // remove point-point coincidence
-  if (aConstraint->type() == CONSTRAINT_PT_PT_COINCIDENT)
-    isFullyRemoved = removeCoincidence(theConstraint) && isFullyRemoved;
-  // remove sub-entities
-  const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
-  std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
-  for (; aSIt != aSubs.end(); ++ aSIt)
-    isFullyRemoved = remove(*aSIt) && isFullyRemoved;
-
-  if (aConstraint->valueParameter())
-    isFullyRemoved = remove(aConstraint->valueParameter()) && isFullyRemoved;
-  if (!isFullyRemoved && aConstraint->baseConstraint() &&
-     (!aConstraint->baseConstraint()->data() || !aConstraint->baseConstraint()->data()->isValid()))
-    isFullyRemoved = true;
-  setNeedToResolve(true);
-  myRemovedConstraints.insert(myRemovedConstraints.end(),
-      aConstraint->constraints().begin(), aConstraint->constraints().end());
-
-  if (isFullyRemoved && theConstraint->id() == myConstraintLastID)
-    --myConstraintLastID;
-
-  return isFullyRemoved;
-}
-
-bool PlaneGCSSolver_Storage::remove(EntityWrapperPtr theEntity)
-{
-  // do not remove entity, if it is used by constraints or other entities
-  if ((theEntity->baseFeature() && isUsed(theEntity->baseFeature())) ||
-      (theEntity->baseAttribute() && isUsed(theEntity->baseAttribute())))
-    return false;
+  EntityWrapperPtr aRelated = entity(anAttribute);
+  FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
+  if (!aRelated) { // Attribute does not exist, create it.
+    // First of all check if the parent feature exists. If not, add it.
+    if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
+      return update(aFeature, theForce); // theAttribute has been processed while adding feature
+    return aRelated.get() != 0;
+  }
 
-  bool isFullyRemoved = SketchSolver_Storage::remove(theEntity);
-  if (isFullyRemoved) {
-    if (theEntity->type() == ENTITY_ARC) {
-      // remove arc additional constraints
-      std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >::iterator
-          aFound = myArcConstraintMap.find(theEntity);
-      if (aFound != myArcConstraintMap.end()) {
-        myRemovedConstraints.insert(myRemovedConstraints.end(),
-            aFound->second.begin(), aFound->second.end());
-        myArcConstraintMap.erase(aFound);
-      }
-    }
-    if (theEntity->id() == myEntityLastID)
-      --myEntityLastID;
+  PlaneGCSSolver_AttributeBuilder aBuilder(aRelated->isExternal() ? 0 : this);
+  bool isUpdated = aBuilder.updateAttribute(anAttribute, aRelated);
+  if (isUpdated) {
+    setNeedToResolve(true);
+    notify(aFeature);
   }
-  return isFullyRemoved;
+  return isUpdated;
 }
 
-bool PlaneGCSSolver_Storage::remove(ParameterWrapperPtr theParameter)
+void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity)
 {
-  std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam =
-      std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(theParameter);
-  if (aParam->isProcessed()) {
-    double* aValPtr = aParam->parameter();
-    GCS::VEC_pD::iterator anIt =  myParameters.begin();
-    for (; anIt != myParameters.end(); ++anIt)
-      if (*anIt == aValPtr)
-        break;
-    if (anIt != myParameters.end()) {
-      myParameters.erase(anIt);
-      setNeedToResolve(true);
-      aParam->setProcessed(false);
-    }
-    else {
-      for (anIt = myConst.begin(); anIt != myConst.end(); ++anIt)
-        if (*anIt == aValPtr)
-          break;
-      if (anIt != myConst.end()) {
-        myConst.erase(anIt);
-        setNeedToResolve(true);
-        aParam->setProcessed(false);
-      }
-    }
-  }
-  return true;
-}
+  if (theEntity->isExternal())
+    return;
 
+  removeAuxiliaryConstraints(theEntity);
 
-void PlaneGCSSolver_Storage::addCoincidentPoints(
-    EntityWrapperPtr theMaster, EntityWrapperPtr theSlave)
+  GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
+  mySketchSolver->removeParameters(aParameters);
+  theEntity->setExternal(true);
+  myNeedToResolve = true;
+}
+
+void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity)
 {
-  if (theMaster->type() != ENTITY_POINT || theSlave->type() != ENTITY_POINT)
+  if (!theEntity->isExternal())
     return;
 
-  std::shared_ptr<PlaneGCSSolver_PointWrapper> aMaster =
-      std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theMaster);
-  if (!aMaster)
-    aMaster = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
-      std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theMaster)->subEntities().front());
-  std::shared_ptr<PlaneGCSSolver_PointWrapper> aSlave =
-      std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSlave);
-  if (!aSlave)
-    aSlave = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
-      std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theSlave)->subEntities().front());
-
-  // Search available coincidence
-  CoincidentPointsMap::iterator aMasterFound = myCoincidentPoints.find(aMaster);
-  CoincidentPointsMap::iterator aSlaveFound = myCoincidentPoints.find(aSlave);
-  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) {
-      if (anIt->second.find(aMaster) != anIt->second.end())
-        aMasterFound = anIt;
-      else if (anIt->second.find(aSlave) != anIt->second.end())
-        aSlaveFound = anIt;
-
-      if (aMasterFound != myCoincidentPoints.end() &&  aSlaveFound != myCoincidentPoints.end())
-        break;
-    }
-  }
+  GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
+  mySketchSolver->addParameters(aParameters);
+  theEntity->setExternal(false);
 
-  if (aMasterFound == myCoincidentPoints.end()) {
-    // create new group
-    myCoincidentPoints[aMaster] = std::set<EntityWrapperPtr>();
-    aMasterFound = myCoincidentPoints.find(aMaster);
-  } else if (aMasterFound == aSlaveFound)
-    return; // already coincident
-
-  if (aSlaveFound != myCoincidentPoints.end()) {
-    // A slave has been found, we need to attach all points coincident with it to the new master
-    std::set<EntityWrapperPtr> aNewSlaves = aSlaveFound->second;
-    aNewSlaves.insert(aSlaveFound->first);
-    myCoincidentPoints.erase(aSlaveFound);
-
-    std::set<EntityWrapperPtr>::const_iterator aSlIt = aNewSlaves.begin();
-    for (; aSlIt != aNewSlaves.end(); ++aSlIt)
-      addCoincidentPoints(aMaster, *aSlIt);
-  } else {
-    //std::list<ParameterWrapperPtr> aSlaveParams = aSlave->parameters();
-    //aSlave->setParameters(aMaster->parameters());
-
-    //// Remove slave's parameters
-    //std::list<ParameterWrapperPtr>::iterator aParIt = aSlaveParams.begin();
-    //for (; aParIt != aSlaveParams.end(); ++aParIt)
-    //  remove(*aParIt);
-
-    aMasterFound->second.insert(aSlave);
-  }
+  createAuxiliaryConstraints(theEntity);
+
+  myNeedToResolve = true;
 }
 
 
-void PlaneGCSSolver_Storage::changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup)
+static void createArcConstraints(const EntityWrapperPtr& theArc,
+                                 const SolverPtr& theSolver,
+                                 const ConstraintID theConstraintID,
+                                 std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
 {
-  theEntity->setGroup(theGroup);
-  if (theGroup == myGroupID)
-    makeVariable(theEntity);
-  else {
-    if (theEntity->type() == ENTITY_POINT)
-      update(theEntity);
-    makeConstant(theEntity);
+  EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theArc);
+  std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
+
+  // Additional constaints to fix arc's extra DoF (if the arc is not external):
+  std::list<GCSConstraintPtr> anArcConstraints;
+  // 1. distances from center till start and end points are equal to radius
+  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+      anArc->center, anArc->start, anArc->rad)));
+  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+      anArc->center, anArc->end, anArc->rad)));
+  // 2. angles of start and end points should be equal to the arc angles
+  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
+      anArc->center, anArc->start, anArc->startAngle)));
+  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
+      anArc->center, anArc->end, anArc->endAngle)));
+
+  ConstraintWrapperPtr aWrapper(
+    new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
+  aWrapper->setId(theConstraintID);
+  constraintsToSolver(aWrapper, theSolver);
+
+  theConstraints[theArc] = aWrapper;
+}
+
+static void createEllipseConstraints(
+    const EntityWrapperPtr& theEllipse,
+    const SolverPtr& theSolver,
+    const ConstraintID theConstraintID,
+    std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
+{
+  EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipse);
+  std::shared_ptr<GCS::Ellipse> anEllipse =
+      std::dynamic_pointer_cast<GCS::Ellipse>(anEdge->entity());
+
+  // Additional constaints to fix ellipse's extra points
+  std::list<GCSConstraintPtr> anEllipseConstraints;
+
+  const std::map<std::string, EntityWrapperPtr>& anAttributes = theEllipse->additionalAttributes();
+  for (std::map<std::string, EntityWrapperPtr>::const_iterator anIt = anAttributes.begin();
+       anIt != anAttributes.end(); ++anIt) {
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
+        std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
+    if (!aPoint)
+      continue;
+
+    GCS::InternalAlignmentType anAlignmentX, anAlignmentY;
+    if (anIt->first == SketchPlugin_Ellipse::SECOND_FOCUS_ID())
+      anAlignmentX = GCS::EllipseFocus2X;
+    else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID())
+      anAlignmentX = GCS::EllipseNegativeMajorX;
+    else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID())
+      anAlignmentX = GCS::EllipsePositiveMajorX;
+    else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_START_ID())
+      anAlignmentX = GCS::EllipseNegativeMinorX;
+    else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_END_ID())
+      anAlignmentX = GCS::EllipsePositiveMinorX;
+
+    anEllipseConstraints.push_back(GCSConstraintPtr(
+        new GCS::ConstraintInternalAlignmentPoint2Ellipse(
+        *anEllipse, *(aPoint->point()), anAlignmentX)));
+    anAlignmentY = (GCS::InternalAlignmentType)((int)anAlignmentX + 1);
+    anEllipseConstraints.push_back(GCSConstraintPtr(
+        new GCS::ConstraintInternalAlignmentPoint2Ellipse(
+        *anEllipse, *(aPoint->point()), anAlignmentY)));
   }
+
+  // constraint to bind the major radius value
+  std::shared_ptr<PlaneGCSSolver_PointWrapper> aMajorAxisStart =
+      std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
+      anAttributes.at(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()));
+  ScalarWrapperPtr aMajorRadius =
+      std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(
+      anAttributes.at(SketchPlugin_Ellipse::MAJOR_RADIUS_ID()));
+  anEllipseConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+      anEllipse->center, *(aMajorAxisStart->point()), aMajorRadius->scalar())));
+
+  ConstraintWrapperPtr aWrapper(
+    new PlaneGCSSolver_ConstraintWrapper(anEllipseConstraints, CONSTRAINT_UNKNOWN));
+  aWrapper->setId(theConstraintID);
+  if (theSolver)
+    constraintsToSolver(aWrapper, theSolver);
+
+  theConstraints[theEllipse] = aWrapper;
 }
 
-void PlaneGCSSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup)
+static void createEllipticArcConstraints(
+    const EntityWrapperPtr& theEllipticArc,
+    const SolverPtr& theSolver,
+    const ConstraintID theConstraintID,
+    std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
 {
-  // TODO
+  // create base constraints for the ellipse without adding them to solver
+  createEllipseConstraints(theEllipticArc, SolverPtr(), theConstraintID, theConstraints);
+
+  ConstraintWrapperPtr& aConstraint = theConstraints[theEllipticArc];
+  std::list<GCSConstraintPtr> anEllArcConstraints = aConstraint->constraints();
+
+  // constrain extremities of the elliptic arc
+  EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipticArc);
+  std::shared_ptr<GCS::ArcOfEllipse> anArc =
+      std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
+
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->start, anArc->start.x, *anArc, anArc->startAngle)));
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->start, anArc->start.y, *anArc, anArc->startAngle)));
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->end, anArc->end.x, *anArc, anArc->endAngle)));
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->end, anArc->end.y, *anArc, anArc->endAngle)));
+
+  aConstraint->setConstraints(anEllArcConstraints);
+  constraintsToSolver(aConstraint, theSolver);
 }
 
-void PlaneGCSSolver_Storage::verifyFixed()
+static void createBSplineConstraints(
+    const EntityWrapperPtr& theCurve,
+    const SolverPtr& theSolver,
+    const ConstraintID theConstraintID,
+    std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
 {
-  // TODO
+  // set start and end point of B-spline equal to first and last pole correspondingly
+  EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theCurve);
+  std::shared_ptr<GCS::BSpline> aBSpline =
+      std::dynamic_pointer_cast<GCS::BSpline>(anEdge->entity());
+  if (aBSpline->periodic)
+    return; // additional constraints are not necessary
+
+  std::list<GCSConstraintPtr> aBSplineConstraints;
+
+  const std::map<std::string, EntityWrapperPtr>& anAdditional = anEdge->additionalAttributes();
+  PointWrapperPtr aStartPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
+      anAdditional.at(SketchPlugin_BSpline::START_ID()));
+
+  const GCS::Point& sp = *aStartPoint->point();
+  const GCS::Point& p0 = aBSpline->poles.front();
+  aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.x, sp.x)));
+  aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.y, sp.y)));
+
+  PointWrapperPtr aEndPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
+      anAdditional.at(SketchPlugin_BSpline::END_ID()));
+
+  const GCS::Point& ep = *aEndPoint->point();
+  const GCS::Point& pN = aBSpline->poles.back();
+  aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.x, ep.x)));
+  aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.y, ep.y)));
+
+  ConstraintWrapperPtr aWrapper(
+      new PlaneGCSSolver_ConstraintWrapper(aBSplineConstraints, CONSTRAINT_UNKNOWN));
+  aWrapper->setId(theConstraintID);
+  if (theSolver)
+    constraintsToSolver(aWrapper, theSolver);
+
+  theConstraints[theCurve] = aWrapper;
 }
 
-void PlaneGCSSolver_Storage::processArc(const EntityWrapperPtr& theArc)
+void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
 {
-  // Calculate additional parameters necessary for PlaneGCS
-  const std::list<EntityWrapperPtr>& aSubs = theArc->subEntities();
-  std::list<EntityWrapperPtr>::const_iterator aSubIt = aSubs.begin();
-  while ((*aSubIt)->type() == ENTITY_POINT) // search scalar entities
-    ++aSubIt;
-  double* aStartAngle = 
-    std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt++)->scalar();
-  double* aEndAngle =
-    std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt++)->scalar();
-  double* aRadius = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt)->scalar();
-
-  std::shared_ptr<SketchPlugin_Feature> anArcFeature =
-      std::dynamic_pointer_cast<SketchPlugin_Feature>(theArc->baseFeature());
-  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()));
-  std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      anArcFeature->attribute(SketchPlugin_Arc::START_ID()));
-  std::shared_ptr<GeomDataAPI_Point2D> aEndAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      anArcFeature->attribute(SketchPlugin_Arc::END_ID()));
-  if (!aCenterAttr || !aStartAttr || !aEndAttr)
+  if (!theEntity || theEntity->isExternal())
     return;
-  std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = aCenterAttr->pnt();
-  std::shared_ptr<GeomAPI_Pnt2d> aStartPnt  = aStartAttr->pnt();
-  std::shared_ptr<GeomAPI_Pnt2d> aEndPnt    = aEndAttr->pnt();
 
-  *aRadius = aCenterPnt->distance(aStartPnt);
-  if (!anArcFeature->lastResult())
-    return;
-  std::shared_ptr<GeomAPI_Edge> anArcEdge =
-      std::dynamic_pointer_cast<GeomAPI_Edge>(anArcFeature->lastResult()->shape());
-  if (!anArcEdge)
-    return;
-  anArcEdge->getRange(*aStartAngle, *aEndAngle);
-  // verify the range is correct and not shifted to an angle
-  std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(cos(*aStartAngle), sin(*aStartAngle)));
-  std::shared_ptr<GeomAPI_Pnt2d> aCalcStartPnt(
-      new GeomAPI_Pnt2d(aCenterPnt->xy()->added(aDir->xy()->multiplied(*aRadius))));
-  if (aCalcStartPnt->distance(aStartPnt) > tolerance) {
-    std::shared_ptr<GeomAPI_Dir2d> aDirToStart(
-        new GeomAPI_Dir2d(aStartPnt->xy()->decreased(aCenterPnt->xy())));
-    double anAngle = aDir->angle(aDirToStart);
-    *aStartAngle += anAngle;
-    *aEndAngle += anAngle;
+  if (theEntity->type() == ENTITY_ARC)
+    createArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
+  else if (theEntity->type() == ENTITY_ELLIPSE)
+    createEllipseConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
+  else if (theEntity->type() == ENTITY_ELLIPTIC_ARC) {
+    createEllipticArcConstraints(theEntity, mySketchSolver,
+                                 ++myConstraintLastID, myAuxConstraintMap);
   }
-
-  // no need to constraint a fixed or a copied arc
-  if (theArc->group() == GID_OUTOFGROUP || anArcFeature->isCopy())
-    return;
-  // No need to add constraints if they are already exist
-  std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >::const_iterator
-      aFound = myArcConstraintMap.find(theArc);
-  if (aFound != myArcConstraintMap.end())
-    return;
-
-  // Prepare additional constraints to produce the arc
-  std::vector<GCSConstraintPtr> anArcConstraints;
-  std::shared_ptr<PlaneGCSSolver_EntityWrapper> anArcEnt =
-      std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theArc);
-  std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anArcEnt->entity());
-  // Distances from center till start and end points are equal to radius
-  GCSConstraintPtr aNew = GCSConstraintPtr(new GCS::ConstraintP2PDistance(
-      anArc->center, anArc->start, anArc->rad));
-//  aNew->setTag((int)(++myConstraintLastID));
-  anArcConstraints.push_back(aNew);
-  aNew = GCSConstraintPtr(new GCS::ConstraintP2PDistance(
-      anArc->center, anArc->end, anArc->rad));
-//  aNew->setTag((int)myConstraintLastID);
-  anArcConstraints.push_back(aNew);
-  // Angles of start and end points should be equal to given angles
-  aNew = GCSConstraintPtr(new GCS::ConstraintP2PAngle(
-      anArc->center, anArc->start, anArc->startAngle));
-//  aNew->setTag((int)myConstraintLastID);
-  anArcConstraints.push_back(aNew);
-  aNew = GCSConstraintPtr(new GCS::ConstraintP2PAngle(
-      anArc->center, anArc->end, anArc->endAngle));
-//  aNew->setTag((int)myConstraintLastID);
-  anArcConstraints.push_back(aNew);
-
-  myArcConstraintMap[theArc] = anArcConstraints;
+  else if (theEntity->type() == ENTITY_BSPLINE)
+    createBSplineConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
 }
 
-
-void PlaneGCSSolver_Storage::makeConstant(const EntityWrapperPtr& theEntity)
+void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
 {
-  toggleEntity(theEntity, myParameters, myConst);
-  if (theEntity->type() == ENTITY_POINT)
-    updateCoincident(theEntity);
+  std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator
+      aFound = myAuxConstraintMap.find(theEntity);
+  if (aFound != myAuxConstraintMap.end()) {
+    mySketchSolver->removeConstraint(aFound->second->id());
+    myAuxConstraintMap.erase(aFound);
+  }
 }
 
-void PlaneGCSSolver_Storage::makeVariable(const EntityWrapperPtr& theEntity)
+template <typename ARCTYPE>
+void adjustArcParametrization(ARCTYPE& theArc, bool theReversed)
 {
-  toggleEntity(theEntity, myConst, myParameters);
+  // tune start angle of the arc to be in [0, 2PI]
+  while (*theArc.startAngle < -PI)
+    *theArc.startAngle += 2.0 * PI;
+  while (*theArc.startAngle >= PI)
+    *theArc.startAngle -= 2.0 * PI;
+  // adjust end angle of the arc
+  if (theReversed) {
+    while (*theArc.endAngle > *theArc.startAngle)
+      *theArc.endAngle -= 2.0 * PI;
+    while (*theArc.endAngle + 2 * PI < *theArc.startAngle)
+      *theArc.endAngle += 2.0 * PI;
+  }
+  else {
+    while (*theArc.endAngle < *theArc.startAngle)
+      *theArc.endAngle += 2.0 * PI;
+    while (*theArc.endAngle > *theArc.startAngle + 2 * PI)
+      *theArc.endAngle -= 2.0 * PI;
+  }
 }
 
-static void getParametersToMove(const EntityWrapperPtr& theEntity, std::set<double*>& theParamList)
+void PlaneGCSSolver_Storage::adjustParametrizationOfArcs()
 {
-  const std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
-  std::list<ParameterWrapperPtr>::const_iterator aPIt = aParams.begin();
-  for (; aPIt != aParams.end(); ++aPIt)
-    theParamList.insert(
-        std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(*aPIt)->parameter());
-
-  const std::list<EntityWrapperPtr> aSubs = theEntity->subEntities();
-  std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
-
-  if (theEntity->type() == ENTITY_ARC) {
-    // workaround for the arc processing, because the arc is fixed by a set of constraints,
-    // which will conflict with all parameters fixed:
-    // 1. take center
-    getParametersToMove(*aSIt++, theParamList);
-    // 2. skip start and end points
-    ++aSIt;
-    // 3. take radius, start angle and end angle parameters
-    getParametersToMove(*(++aSIt), theParamList);
-    getParametersToMove(*(++aSIt), theParamList);
-    getParametersToMove(*(++aSIt), theParamList);
-  } else {
-    for (; aSIt != aSubs.end(); ++aSIt)
-      getParametersToMove(*aSIt, theParamList);
+  std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator anIt = myAuxConstraintMap.begin();
+  for (; anIt != myAuxConstraintMap.end(); ++anIt) {
+    EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(anIt->first);
+    std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
+    if (anArc)
+      adjustArcParametrization(*anArc, anEdge->isReversed());
+    else {
+      std::shared_ptr<GCS::ArcOfEllipse> aEllArc =
+          std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
+      if (aEllArc)
+        adjustArcParametrization(*aEllArc, anEdge->isReversed());
+    }
   }
+
+  // update parameters of Middle point constraint for point on arc
+  std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator aCIt = myConstraintMap.begin();
+  for (; aCIt != myConstraintMap.end(); ++aCIt)
+    if (aCIt->second->type() == CONSTRAINT_MIDDLE_POINT) {
+      notify(aCIt->first);
+    }
 }
 
-void PlaneGCSSolver_Storage::toggleEntity(
-    const EntityWrapperPtr& theEntity, GCS::VEC_pD& theFrom, GCS::VEC_pD& theTo)
-{
-  std::set<double*> aParamsToMove;
-  getParametersToMove(theEntity, aParamsToMove);
 
-  GCS::VEC_pD::iterator anIt = theFrom.begin();
-  while (anIt != theFrom.end()) {
-    if (aParamsToMove.find(*anIt) == aParamsToMove.end()) {
-      ++anIt;
-      continue;
+bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
+{
+  std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator
+      aFound = myConstraintMap.find(theConstraint);
+  if (aFound != myConstraintMap.end()) {
+    ConstraintWrapperPtr aCW = aFound->second;
+    ConstraintID anID = aCW->id();
+
+    // Remove solver's constraints
+    mySketchSolver->removeConstraint(anID);
+
+    // Remove value if exists
+    const ScalarWrapperPtr& aValue = aCW->valueParameter();
+    if (aValue) {
+      GCS::SET_pD aParToRemove;
+      aParToRemove.insert(aValue->scalar());
+      removeParameters(aParToRemove);
     }
 
-    theTo.push_back(*anIt);
-    int aShift = int(anIt - theFrom.begin());
-    theFrom.erase(anIt);
-    anIt = theFrom.begin() + aShift;
-  }
-}
+    // Remove constraint
+    myConstraintMap.erase(aFound);
 
-void PlaneGCSSolver_Storage::updateCoincident(const EntityWrapperPtr& thePoint)
-{
-  CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin();
-  for (; anIt != myCoincidentPoints.end(); ++anIt) {
-    if (anIt->first == thePoint || anIt->second.find(thePoint) != anIt->second.end()) {
-      std::set<EntityWrapperPtr> aCoincident = anIt->second;
-      aCoincident.insert(anIt->first);
-
-      const std::list<ParameterWrapperPtr>& aBaseParams = thePoint->parameters();
-      std::list<ParameterWrapperPtr> aParams;
-      std::list<ParameterWrapperPtr>::const_iterator aBaseIt, anUpdIt;
-
-      std::set<EntityWrapperPtr>::const_iterator aCoincIt = aCoincident.begin();
-      for (; aCoincIt != aCoincident.end(); ++aCoincIt)
-        if (*aCoincIt != thePoint && (*aCoincIt)->group() != GID_OUTOFGROUP) {
-          aParams = (*aCoincIt)->parameters();
-          aBaseIt = aBaseParams.begin();
-          for (anUpdIt = aParams.begin(); anUpdIt != aParams.end(); ++anUpdIt, ++aBaseIt)
-            (*anUpdIt)->setValue((*aBaseIt)->value());
-        }
+    if (anID != CID_MOVEMENT)
+      myNeedToResolve = true;
 
-      break;
-    }
+    // notify subscibers
+    notify(theConstraint);
   }
+  return true;
 }
 
-
-bool PlaneGCSSolver_Storage::isRedundant(
-    GCSConstraintPtr theCheckedConstraint,
-    ConstraintWrapperPtr theParentConstraint,
-    std::list<std::set<double*> >& theCoincidentPoints) const
+void PlaneGCSSolver_Storage::removeInvalidEntities()
 {
-  if (theParentConstraint->type() == CONSTRAINT_SYMMETRIC) {
-    if (theCheckedConstraint->getTypeId() == GCS::Perpendicular) {
-      BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
-      // check the initial point is placed on the mirror line
-      std::list<EntityWrapperPtr> aSubs = theParentConstraint->entities();
-      std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(aSubs.front());
-      std::shared_ptr<GeomAPI_Lin2d> aLine = aBuilder->line(aSubs.back());
-      return aLine->distance(aPoint) < tolerance;
-    }
-  }
-  else if (theParentConstraint->type() == CONSTRAINT_PT_PT_COINCIDENT) {
-    // Verify that the coincidence between points is already added
-    GCS::VEC_pD aParams = theCheckedConstraint->params();
-
-    std::list<std::set<double*> >::iterator aCoincIt, aFound1, aFound2;
-    aFound1 = aFound2 = theCoincidentPoints.end();
-    for (aCoincIt = theCoincidentPoints.begin(); 
-         aCoincIt != theCoincidentPoints.end(); ++aCoincIt) {
-      if (aFound1 == theCoincidentPoints.end() && aCoincIt->find(aParams[0]) != aCoincIt->end())
-        aFound1 = aCoincIt;
-      if (aFound2 == theCoincidentPoints.end() && aCoincIt->find(aParams[1]) != aCoincIt->end())
-        aFound2 = aCoincIt;
-      if (aFound1 != theCoincidentPoints.end() && aFound2 != theCoincidentPoints.end())
-        break;
+  PlaneGCSSolver_EntityDestroyer aDestroyer;
+
+  // Remove invalid constraints
+  std::list<ConstraintPtr> anInvalidConstraints;
+  std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
+      aCIter = myConstraintMap.begin();
+  for (; aCIter != myConstraintMap.end(); ++aCIter)
+    if (!aCIter->first->data() || !aCIter->first->data()->isValid())
+      anInvalidConstraints.push_back(aCIter->first);
+  std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
+  for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
+    removeConstraint(*anInvCIt);
+
+  // Remove invalid features
+  std::list<FeaturePtr> anInvalidFeatures;
+  std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
+  for (; aFIter != myFeatureMap.end(); aFIter++)
+    if (!aFIter->first->data() || !aFIter->first->data()->isValid()) {
+      anInvalidFeatures.push_back(aFIter->first);
+      if (aFIter->second)
+        aDestroyer.remove(aFIter->second);
+
+      // remove invalid arc
+      removeAuxiliaryConstraints(aFIter->second);
     }
-    if (aCoincIt != theCoincidentPoints.end()) { // both point are found
-      if (aFound1 == aFound2)
-        return true;
-      // merge two groups of coincidence
-      aFound1->insert(aFound2->begin(), aFound2->end());
-      theCoincidentPoints.erase(aFound2);
-    } else {
-      if (aFound1 != theCoincidentPoints.end())
-        aFound1->insert(aParams[1]);
-      else if (aFound2 != theCoincidentPoints.end())
-        aFound2->insert(aParams[0]);
-      else {
-        std::set<double*> aNewCoincidence;
-        aNewCoincidence.insert(aParams[0]);
-        aNewCoincidence.insert(aParams[1]);
-        theCoincidentPoints.push_back(aNewCoincidence);
-      }
+  std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
+  for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
+    removeFeature(*anInvFIt);
+
+  // Remove invalid attributes
+  std::list<AttributePtr> anInvalidAttributes;
+  std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAttrIt = myAttributeMap.begin();
+  for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
+    FeaturePtr anOwner = ModelAPI_Feature::feature(anAttrIt->first->owner());
+    if (!anOwner || !anOwner->data() || !anOwner->data()->isValid()) {
+      anInvalidAttributes.push_back(anAttrIt->first);
+      aDestroyer.remove(anAttrIt->second);
     }
   }
+  std::list<AttributePtr>::const_iterator anInvAtIt = anInvalidAttributes.begin();
+  for (; anInvAtIt != anInvalidAttributes.end(); ++anInvAtIt)
+    removeAttribute(*anInvAtIt);
 
-  return false;
+  // free memory occupied by parameters
+  removeParameters(aDestroyer.parametersToRemove());
+
+  /// TODO: Think on optimization of checking invalid features and attributes
 }
 
-void PlaneGCSSolver_Storage::initializeSolver(SolverPtr theSolver)
+
+
+double* PlaneGCSSolver_Storage::createParameter()
 {
-  std::shared_ptr<PlaneGCSSolver_Solver> aSolver =
-      std::dynamic_pointer_cast<PlaneGCSSolver_Solver>(theSolver);
-  if (!aSolver)
-    return;
-  aSolver->clear();
-
-  if (myExistArc)
-    processArcs();
-
-  // initialize constraints
-  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
-      aCIt = myConstraintMap.begin();
-  GCS::SET_I aTangentIDs;
-  std::list<std::set<double*> > aCoincidentPoints;
-  for (; aCIt != myConstraintMap.end(); ++aCIt) {
-    std::list<ConstraintWrapperPtr>::const_iterator aCWIt = aCIt->second.begin();
-    for (; aCWIt != aCIt->second.end(); ++ aCWIt) {
-      std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aGCS =
-          std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(*aCWIt);
-      std::list<GCSConstraintPtr>::const_iterator anIt = aGCS->constraints().begin();
-      for (; anIt != aGCS->constraints().end(); ++anIt)
-        if (!isRedundant(*anIt, aGCS, aCoincidentPoints))
-          aSolver->addConstraint(*anIt, aGCS->type());
-    }
-    // store IDs of tangent constraints to avoid incorrect report of redundant constraints
-    if (aCIt->first && aCIt->first->getKind() == SketchPlugin_ConstraintTangent::ID())
-      for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++ aCWIt)
-        aTangentIDs.insert((int)(*aCWIt)->id());
-  }
-  // additional constraints for arcs
-  std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >::const_iterator
-      anArcIt = myArcConstraintMap.begin();
-  for (; anArcIt != myArcConstraintMap.end(); ++anArcIt) {
-    std::vector<GCSConstraintPtr>::const_iterator anIt = anArcIt->second.begin();
-    for (; anIt != anArcIt->second.end(); ++anIt)
-      aSolver->addConstraint(*anIt, CONSTRAINT_UNKNOWN);
-  }
-  // removed waste constraints
-  std::list<GCSConstraintPtr>::const_iterator aRemIt = myRemovedConstraints.begin();
-  for (; aRemIt != myRemovedConstraints.end(); ++aRemIt)
-    aSolver->removeConstraint(*aRemIt);
-  myRemovedConstraints.clear();
-  // set list of tangent constraints
-  aSolver->setTangent(aTangentIDs);
-  // initialize unknowns
-  aSolver->setParameters(myParameters);
+  return mySketchSolver->createParameter();
+}
+
+void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams)
+{
+  mySketchSolver->removeParameters(theParams);
+  //for (GCS::SET_pD::iterator it = theParams.begin(); it != theParams.end(); ++it)
+  //  delete *it;
 }
 
 // indicates attribute containing in the external feature
-bool isExternalAttribute(const AttributePtr& theAttribute)
+static bool isExternalAttribute(const AttributePtr& theAttribute)
 {
   if (!theAttribute)
     return false;
-  std::shared_ptr<SketchPlugin_Feature> aSketchFeature = 
+  std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
       std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
   return aSketchFeature.get() && aSketchFeature->isExternal();
 }
 
-void PlaneGCSSolver_Storage::refresh(bool theFixedOnly) const
+static void addOwnerToSet(const AttributePtr& theAttribute, std::set<FeaturePtr>& theFeatures)
 {
-  //blockEvents(true);
+  FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
+  if (anOwner)
+    theFeatures.insert(anOwner);
+}
+
+void PlaneGCSSolver_Storage::refresh() const
+{
+  const double aTol = 1000. * tolerance; // tolerance to prevent frequent updates
+
+  std::set<FeaturePtr> anUpdatedFeatures;
 
   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, 
+    if (!anIt->first->isInitialized())
+      continue;
+
+    // the external feature always should keep the up to date values, so,
     // refresh from the solver is never needed
-    bool isExternal = isExternalAttribute(anIt->first);
-
-    // update parameter wrappers and obtain values of attributes
-    aParams = anIt->second->parameters();
-    double aCoords[3];
-    bool isUpd[3] = {false};
-    int i = 0;
-    for (aParIt = aParams.begin(); i < 3 && aParIt != aParams.end(); ++aParIt, ++i) {
-      if (!theFixedOnly || isExternal ||
-          (*aParIt)->group() == GID_OUTOFGROUP || (*aParIt)->isParametric()) {
-        aCoords[i] = (*aParIt)->value();
-        isUpd[i] = true;
-      }
-    }
-    if (!isUpd[0] && !isUpd[1] && !isUpd[2])
-      continue; // nothing is updated
+    if (isExternalAttribute(anIt->first))
+      continue;
 
     std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
     if (aPoint2D) {
-      if ((isUpd[0] && fabs(aPoint2D->x() - aCoords[0]) > tolerance) ||
-          (isUpd[1] && fabs(aPoint2D->y() - aCoords[1]) > tolerance) || isExternal) {
-        // Find points coincident with this one (probably not in GID_OUTOFGROUP)
-        CoincidentPointsMap::const_iterator aCoincIt = myCoincidentPoints.begin();
-        for (; aCoincIt != myCoincidentPoints.end(); ++aCoincIt)
-          if (aCoincIt->first == anIt->second ||
-              aCoincIt->second.find(anIt->second) != aCoincIt->second.end())
-            break;
-        // get coordinates of "master"-point
-        std::shared_ptr<GeomDataAPI_Point2D> aMaster = aCoincIt != myCoincidentPoints.end() ?
-            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCoincIt->first->baseAttribute()) :
-            aPoint2D;
-        if (!isUpd[0] || isExternal) aCoords[0] = aMaster->x();
-        if (!isUpd[1] || isExternal) aCoords[1] = aMaster->y();
-        if (!isExternal)
-          aPoint2D->setValue(aCoords[0], aCoords[1]);
-        if (aCoincIt != myCoincidentPoints.end()) {
-          if (aMaster && !isExternalAttribute(aMaster))
-            aMaster->setValue(aCoords[0], aCoords[1]);
-          std::set<EntityWrapperPtr>::const_iterator aSlaveIt = aCoincIt->second.begin();
-          for (; aSlaveIt != aCoincIt->second.end(); ++aSlaveIt) {
-            aPoint2D = std::dynamic_pointer_cast<GeomDataAPI_Point2D>((*aSlaveIt)->baseAttribute());
-            if (aPoint2D && !isExternalAttribute(aPoint2D))
-              aPoint2D->setValue(aCoords[0], aCoords[1]);
-          }
+      std::shared_ptr<PlaneGCSSolver_PointWrapper> aPointWrapper =
+          std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
+      GCSPointPtr aGCSPoint = aPointWrapper->point();
+      if (fabs(aPoint2D->x() - (*aGCSPoint->x)) > aTol ||
+          fabs(aPoint2D->y() - (*aGCSPoint->y)) > aTol) {
+        aPoint2D->setValue(*aGCSPoint->x, *aGCSPoint->y);
+        addOwnerToSet(anIt->first, anUpdatedFeatures);
+      }
+      continue;
+    }
+    std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anIt->first);
+    if (aPointArray) {
+      std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> anArrayWrapper =
+          std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
+      int aSize = aPointArray->size();
+      for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+        GeomPnt2dPtr anOriginal = aPointArray->pnt(anIndex);
+        GCSPointPtr aGCSPoint = anArrayWrapper->value(anIndex)->point();
+        if (fabs(anOriginal->x() - (*aGCSPoint->x)) > aTol ||
+            fabs(anOriginal->y() - (*aGCSPoint->y)) > aTol) {
+          aPointArray->setPnt(anIndex, *aGCSPoint->x, *aGCSPoint->y);
+          addOwnerToSet(anIt->first, anUpdatedFeatures);
         }
       }
       continue;
     }
     AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
-    if (aScalar && !isExternal) {
-      if (isUpd[0] && fabs(aScalar->value() - aCoords[0]) > tolerance)
-        aScalar->setValue(aCoords[0]);
+    if (aScalar) {
+      ScalarWrapperPtr aScalarWrapper =
+          std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
+      if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol) {
+        aScalar->setValue(aScalarWrapper->value());
+        addOwnerToSet(anIt->first, anUpdatedFeatures);
+      }
+      continue;
+    }
+    AttributeDoubleArrayPtr aRealArray =
+        std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(anIt->first);
+    if (aRealArray) {
+      std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> anArrayWrapper =
+          std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
+      int aSize = aRealArray->size();
+      for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+        if (fabs(aRealArray->value(anIndex) - *anArrayWrapper->array()[anIndex]) > aTol) {
+          aRealArray->setValue(anIndex, *anArrayWrapper->array()[anIndex]);
+          addOwnerToSet(anIt->first, anUpdatedFeatures);
+        }
+      }
       continue;
     }
   }
 
-  //blockEvents(false);
+  // notify listeners about features update
+  std::set<FeaturePtr>::const_iterator aFIt = anUpdatedFeatures.begin();
+  for (; aFIt != anUpdatedFeatures.end(); ++aFIt)
+    notify(*aFIt);
 }
 
-EntityWrapperPtr PlaneGCSSolver_Storage::calculateMiddlePoint(
-    EntityWrapperPtr theBase, double theCoeff)
+PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeometry() const
 {
-  std::shared_ptr<PlaneGCSSolver_Builder> aBuilder =
-      std::dynamic_pointer_cast<PlaneGCSSolver_Builder>(PlaneGCSSolver_Builder::getInstance());
-
-  std::shared_ptr<GeomAPI_XY> aMidPoint;
-  if (theBase->type() == ENTITY_LINE) {
-    std::shared_ptr<GeomAPI_Pnt2d> aPoints[2];
-    const std::list<EntityWrapperPtr>& aSubs = theBase->subEntities();
-    std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
-    for (int i = 0; i < 2; ++i, ++anIt)
-      aPoints[i] = aBuilder->point(*anIt);
-    aMidPoint = aPoints[0]->xy()->multiplied(1.0 - theCoeff)->added(
-        aPoints[1]->xy()->multiplied(theCoeff));
+  std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
+  for (; aFIt != myFeatureMap.end(); ++aFIt) {
+    EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aFIt->second);
+    if (anEdge && anEdge->isDegenerated())
+      return PlaneGCSSolver_Solver::STATUS_DEGENERATED;
   }
-  else if (theBase->type() == ENTITY_ARC) {
-    double theX, theY;
-    double anArcPoint[3][2];
-    const std::list<EntityWrapperPtr>& aSubs = theBase->subEntities();
-    std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
-    for (int i = 0; i < 3; ++i, ++anIt) {
-      std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(*anIt);
-      anArcPoint[i][0] = aPoint->x();
-      anArcPoint[i][1] = aPoint->y();
-    }
-    // project last point of arc on the arc
-    double x = anArcPoint[1][0] - anArcPoint[0][0];
-    double y = anArcPoint[1][1] - anArcPoint[0][1];
-    double aRad = sqrt(x*x + y*y);
-    x = anArcPoint[2][0] - anArcPoint[0][0];
-    y = anArcPoint[2][1] - anArcPoint[0][1];
-    double aNorm = sqrt(x*x + y*y);
-    if (aNorm >= tolerance) {
-      anArcPoint[2][0] = x * aRad / aNorm;
-      anArcPoint[2][1] = y * aRad / aNorm;
-    }
-    anArcPoint[1][0] -= anArcPoint[0][0];
-    anArcPoint[1][1] -= anArcPoint[0][1];
-    if (theCoeff < tolerance) {
-      theX = anArcPoint[0][0] + anArcPoint[1][0];
-      theY = anArcPoint[0][1] + anArcPoint[1][1];
-    } else if (1 - theCoeff < tolerance) {
-      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]));
-      double anAngle = aStartDir->angle(aEndDir);
-      if (anAngle < 0)
-        anAngle += 2.0 * PI;
-      anAngle *= theCoeff;
-      double aCos = cos(anAngle);
-      double aSin = sin(anAngle);
-      theX = anArcPoint[0][0] + anArcPoint[1][0] * aCos - anArcPoint[1][1] * aSin;
-      theY = anArcPoint[0][1] + anArcPoint[1][0] * aSin + anArcPoint[1][1] * aCos;
-    }
-    aMidPoint = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(theX, theY));
-  }
-
-  if (!aMidPoint)
-    return EntityWrapperPtr();
+  return PlaneGCSSolver_Solver::STATUS_OK;
+}
 
-  std::list<ParameterWrapperPtr> aParameters;
-  aParameters.push_back(aBuilder->createParameter(myGroupID, aMidPoint->x()));
-  aParameters.push_back(aBuilder->createParameter(myGroupID, aMidPoint->y()));
-  // Create entity (parameters are not filled)
-  GCSPointPtr aPnt(new GCS::Point);
-  aPnt->x = 
-    std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(aParameters.front())->parameter();
-  aPnt->y = 
-    std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(aParameters.back())->parameter();
 
-  EntityWrapperPtr aResult(new PlaneGCSSolver_PointWrapper(AttributePtr(), aPnt));
-  aResult->setGroup(myGroupID);
-  aResult->setParameters(aParameters);
+void PlaneGCSSolver_Storage::getUnderconstrainedGeometry(std::set<ObjectPtr>& theFeatures) const
+{
+  std::set<double*> aFreeParams;
+  mySketchSolver->getFreeParameters(aFreeParams);
+  if (aFreeParams.empty())
+    return;
 
-  update(aResult);
-  return aResult;
+  for (std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
+       aFIt != myFeatureMap.end(); ++aFIt) {
+    if (!aFIt->second)
+      continue;
+    GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(aFIt->second);
+    for (GCS::SET_pD::iterator aPIt = aParams.begin(); aPIt != aParams.end(); ++aPIt)
+      if (aFreeParams.find(*aPIt) != aFreeParams.end()) {
+        theFeatures.insert(aFIt->first);
+        break;
+      }
+  }
 }