Salome HOME
SketchSolver library refactoring
authorazv <azv@opencascade.com>
Wed, 18 Mar 2015 05:26:37 +0000 (08:26 +0300)
committerazv <azv@opencascade.com>
Fri, 3 Apr 2015 06:26:37 +0000 (09:26 +0300)
1. Implemented data storages and base constraint
2. Implemented coincidence and fixed constraints

24 files changed:
src/SketchPlugin/SketchPlugin_Constraint.h
src/SketchSolver/CMakeLists.txt
src/SketchSolver/SketchSolver.h
src/SketchSolver/SketchSolver_Builder.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_Builder.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_Constraint.cpp
src/SketchSolver/SketchSolver_Constraint.h
src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintCoincidence.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintGroup.cpp [deleted file]
src/SketchSolver/SketchSolver_ConstraintGroup.h [deleted file]
src/SketchSolver/SketchSolver_ConstraintManager.cpp
src/SketchSolver/SketchSolver_ConstraintManager.h
src/SketchSolver/SketchSolver_ConstraintRigid.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintRigid.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_Error.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_FeatureStorage.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_FeatureStorage.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_Group.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_Group.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_Solver.cpp
src/SketchSolver/SketchSolver_Solver.h
src/SketchSolver/SketchSolver_Storage.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_Storage.h [new file with mode: 0644]

index 62abd9eef9f3dd643fa9de391f78bea3c6c92f03..49f98b0cfb4983daacf7095704474f8d9acd49f6 100644 (file)
@@ -84,4 +84,6 @@ class SketchPlugin_Constraint : public SketchPlugin_Feature
   }
 };
 
+typedef std::shared_ptr<SketchPlugin_Constraint> ConstraintPtr;
+
 #endif
index 572c8b0c797aec82193cc5bfea5242b5bdc1fbff..fed46c0ec6414e91013c3e60e214087cca2343b0 100644 (file)
@@ -5,17 +5,28 @@ INCLUDE(FindSolveSpace)
 
 SET(PROJECT_HEADERS
     SketchSolver.h
+    SketchSolver_Error.h
     SketchSolver_Solver.h
     SketchSolver_Constraint.h
-    SketchSolver_ConstraintGroup.h
+    SketchSolver_ConstraintCoincidence.h
+    SketchSolver_ConstraintRigid.h
+    SketchSolver_Builder.h
+    SketchSolver_Group.h
     SketchSolver_ConstraintManager.h
+    SketchSolver_Storage.h
+    SketchSolver_FeatureStorage.h
 )
 
 SET(PROJECT_SOURCES
     SketchSolver_Solver.cpp
     SketchSolver_Constraint.cpp
-    SketchSolver_ConstraintGroup.cpp
+    SketchSolver_ConstraintCoincidence.cpp
+    SketchSolver_ConstraintRigid.cpp
+    SketchSolver_Builder.cpp
+    SketchSolver_Group.cpp
     SketchSolver_ConstraintManager.cpp
+    SketchSolver_Storage.cpp
+    SketchSolver_FeatureStorage.cpp
 )
 
 SET(PROJECT_LIBRARIES
index f31b7e49f65076ca43234ad50f1a5f5c1b50b258..77bb4029a701f8a8faa5e6174cad5cdba5e0195b 100644 (file)
@@ -17,4 +17,7 @@
 #endif
 #endif
 
+/// Tolerance for value of parameters
+const double tolerance = 1.e-10;
+
 #endif
diff --git a/src/SketchSolver/SketchSolver_Builder.cpp b/src/SketchSolver/SketchSolver_Builder.cpp
new file mode 100644 (file)
index 0000000..67fbdc1
--- /dev/null
@@ -0,0 +1,270 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Builder.cpp
+// Created: 25 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#include "SketchSolver_Builder.h"
+#include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchSolver_ConstraintRigid.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_Attribute.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_ResultConstruction.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintEqual.h>
+#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_ConstraintHorizontal.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintParallel.h>
+#include <SketchPlugin_ConstraintPerpendicular.h>
+#include <SketchPlugin_ConstraintRadius.h>
+#include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_ConstraintVertical.h>
+
+
+// Initialization of constraint builder self pointer
+SketchSolver_Builder* SketchSolver_Builder::mySelf = 0;
+
+SketchSolver_Builder* SketchSolver_Builder::getInstance()
+{
+  if (!mySelf)
+    mySelf = new SketchSolver_Builder();
+  return mySelf;
+}
+
+SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theConstraint)
+{
+  SolverConstraintPtr aResult;
+  DataPtr aData = theConstraint->data();
+  if (!aData || !aData->isValid())
+    return aResult;
+
+  if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintCoincidence(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintDistance(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintEqual::ID()) {
+////    return SolverConstraintPtr(new SketchSolver_ConstraintEqual(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
+////    return SolverConstraintPtr(new SketchSolver_ConstraintFillet(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintHorizontal::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintHorizontal(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintLength::ID()) {
+////    return SolverConstraintPtr(new SketchSolver_ConstraintLength(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
+////    return SolverConstraintPtr(new SketchSolver_ConstraintMirror(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintParallel::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintParallel(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintPerpendicular::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintPerpendicular(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintRadius::ID()) {
+////    return SolverConstraintPtr(new SketchSolver_ConstraintRadius(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID()) {
+////    return SolverConstraintPtr(new SketchSolver_ConstraintTangent(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintVertical::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintVertical(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theConstraint));
+  }
+  return aResult;
+}
+
+SolverConstraintPtr SketchSolver_Builder::createRigidConstraint(FeaturePtr theFixedFeature)
+{
+  DataPtr aData = theFixedFeature->data();
+  if (!aData || !aData->isValid())
+    return SolverConstraintPtr();
+  return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theFixedFeature));
+}
+
+
+
+bool SketchSolver_Builder::createWorkplane(
+    CompositeFeaturePtr theSketch,
+    std::vector<Slvs_Entity>& theEntities,
+    std::vector<Slvs_Param>& theParameters)
+{
+  DataPtr aSketchData = theSketch->data();
+  if (!aSketchData || !aSketchData->isValid())
+    return false; // the sketch is incorrect
+
+  // Get parameters of workplane
+  std::shared_ptr<ModelAPI_Attribute> aDirX = aSketchData->attribute(
+      SketchPlugin_Sketch::DIRX_ID());
+  std::shared_ptr<ModelAPI_Attribute> aNorm = aSketchData->attribute(
+      SketchPlugin_Sketch::NORM_ID());
+  std::shared_ptr<ModelAPI_Attribute> anOrigin = aSketchData->attribute(
+      SketchPlugin_Sketch::ORIGIN_ID());
+  // Create SolveSpace entity corresponding to the sketch origin
+  if (!createEntity(anOrigin, theEntities, theParameters))
+    return false;
+  Slvs_hEntity anOriginID = theEntities.back().h;
+  // Create SolveSpace entity corresponding the the sketch normal
+  if (!createNormal(aNorm, aDirX, theEntities, theParameters))
+    return false;
+  Slvs_hEntity aNormalID = theEntities.back().h;
+
+  // Create workplane
+  Slvs_hEntity aWorkplaneID = theEntities.back().h + 1;
+  Slvs_Entity aWorkplane = Slvs_MakeWorkplane(aWorkplaneID, SLVS_G_UNKNOWN, anOriginID, aNormalID);
+  theEntities.push_back(aWorkplane);
+  return true;
+}
+
+bool SketchSolver_Builder::createEntity(
+    AttributePtr theAttribute,
+    std::vector<Slvs_Entity>& theEntities,
+    std::vector<Slvs_Param>& theParameters)
+{
+  Slvs_hEntity anEntID = theEntities.empty() ? 0 : theEntities.back().h;
+  Slvs_hParam aParamID = theParameters.empty() ? 0 : theParameters.back().h;
+
+  // Point in 3D
+  std::shared_ptr<GeomDataAPI_Point> aPoint =
+      std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
+  if (aPoint) {
+    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->x()));
+    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->y()));
+    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->z()));
+    theEntities.push_back(Slvs_MakePoint3d(++anEntID, SLVS_G_UNKNOWN,
+        aParamID-2, aParamID-1, aParamID));
+    return true;
+  }
+  // Point in 2D
+  std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+  if (aPoint2D) {
+    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->x()));
+    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->y()));
+    theEntities.push_back(Slvs_MakePoint2d(++anEntID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
+      aParamID-1, aParamID));
+    return true;
+  }
+  // Scalar value (used for the distance entities)
+  AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+  if (aScalar) {
+    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aScalar->value()));
+    theEntities.push_back(Slvs_MakeDistance(++anEntID, SLVS_G_UNKNOWN,
+      SLVS_E_UNKNOWN, aParamID));
+    return true;
+  }
+  // unknown attribute type
+  return false;
+}
+
+bool SketchSolver_Builder::createEntity(
+    FeaturePtr theFeature,
+    std::vector<Slvs_Entity>& theEntities,
+    std::vector<Slvs_Param>& theParameters)
+{
+  if (!theFeature->data()->isValid())
+    return false;
+
+  // SketchPlugin features
+  std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
+      SketchPlugin_Feature>(theFeature);
+  if (!aFeature)
+    return false;
+
+  // Verify the feature by its kind
+  const std::string& aFeatureKind = aFeature->getKind();
+  DataPtr aData = aFeature->data();
+  // Line
+  if (aFeatureKind == SketchPlugin_Line::ID()) {
+    AttributePtr aStart = aData->attribute(SketchPlugin_Line::START_ID());
+    AttributePtr aEnd = aData->attribute(SketchPlugin_Line::END_ID());
+    if (!aStart->isInitialized() || !aEnd->isInitialized())
+      return false;
+    if (!createEntity(aStart, theEntities, theParameters) ||
+        !createEntity(aEnd, theEntities, theParameters))
+      return false;
+    Slvs_hEntity aLineID = theEntities.back().h + 1;
+    theEntities.push_back(Slvs_MakeLineSegment(aLineID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
+        aLineID-2, aLineID-1));
+  }
+  // Circle
+  else if (aFeatureKind == SketchPlugin_Circle::ID()) {
+    AttributePtr aCenter = aData->attribute(SketchPlugin_Circle::CENTER_ID());
+    AttributePtr aRadius = aData->attribute(SketchPlugin_Circle::RADIUS_ID());
+    if (!aCenter->isInitialized() || !aRadius->isInitialized())
+      return false;
+    if (!createEntity(aCenter, theEntities, theParameters) ||
+        !createEntity(aRadius, theEntities, theParameters))
+      return false;
+    Slvs_hEntity aCircID = theEntities.back().h;
+    theEntities.push_back(Slvs_MakeCircle(aCircID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, aCircID-2,
+      SLVS_E_UNKNOWN, aCircID-1));
+  }
+  // Arc
+  else if (aFeatureKind == SketchPlugin_Arc::ID()) {
+    AttributePtr aCenter = aData->attribute(SketchPlugin_Arc::CENTER_ID());
+    AttributePtr aStart = aData->attribute(SketchPlugin_Arc::START_ID());
+    AttributePtr aEnd = aData->attribute(SketchPlugin_Arc::END_ID());
+    if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
+      return false;
+    if (!createEntity(aCenter, theEntities, theParameters) ||
+        !createEntity(aStart, theEntities, theParameters) ||
+        !createEntity(aEnd, theEntities, theParameters))
+      return false;
+    Slvs_hEntity anArcID = theEntities.back().h;
+    theEntities.push_back(Slvs_MakeArcOfCircle(anArcID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
+        SLVS_E_UNKNOWN, anArcID-3, anArcID-2, anArcID-1));
+  }
+  // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
+  else if (aFeatureKind == SketchPlugin_Point::ID()) {
+    AttributePtr aPoint = aData->attribute(SketchPlugin_Point::COORD_ID());
+    if (!aPoint->isInitialized() ||
+        !createEntity(aPoint, theEntities, theParameters))
+      return false;
+    // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier.
+    // No need to add another entity.
+  }
+  return true;
+}
+
+bool SketchSolver_Builder::createNormal(
+    AttributePtr theNormal,
+    AttributePtr theDirX,
+    std::vector<Slvs_Entity>& theEntities,
+    std::vector<Slvs_Param>& theParameters)
+{
+  std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
+  std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
+  if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance))
+    return false;
+  // calculate Y direction
+  std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
+
+  // quaternion parameters of normal vector
+  double qw, qx, qy, qz;
+  Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
+                      &qx, &qy, &qz);
+  double aNormCoord[4] = { qw, qx, qy, qz };
+
+  // Create parameters of the normal
+  Slvs_hParam aCurParam = theParameters.back().h;
+  for (int i = 0; i < 4; i++)
+    theParameters.push_back(Slvs_MakeParam(++aCurParam, SLVS_G_UNKNOWN, aNormCoord[i]));
+
+  // Create a normal
+  Slvs_hEntity aCurEntity = theEntities.back().h + 1;
+  Slvs_Entity aNormal = Slvs_MakeNormal3d(aCurEntity, SLVS_G_UNKNOWN,
+      aCurParam-3, aCurParam-2, aCurParam-1, aCurParam);
+  theEntities.push_back(aNormal);
+  return true;
+}
diff --git a/src/SketchSolver/SketchSolver_Builder.h b/src/SketchSolver/SketchSolver_Builder.h
new file mode 100644 (file)
index 0000000..e9aa10d
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Builder.h
+// Created: 25 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_Builder_H_
+#define SketchSolver_Builder_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+#include <SketchPlugin_Constraint.h>
+
+#include <ModelAPI_CompositeFeature.h>
+
+/** \class   SketchSolver_Builder
+ *  \ingroup Plugins
+ *  \brief   Create bridges between SketchPlugin constraints and SolveSpace constraints
+ */
+class SketchSolver_Builder
+{
+private:
+  /// Default constructor
+  SketchSolver_Builder() {}
+
+public:
+  /// \brief Returns single instance of builder
+  static SketchSolver_Builder* getInstance();
+
+  /// \brief Creates a solver's constraint using given SketchPlugin constraint
+  ///        or returns empty pointer if not all attributes are correct
+  SolverConstraintPtr createConstraint(ConstraintPtr theConstraint);
+
+  /// \brief Creates temporary constraint to fix the placement of the feature
+  SolverConstraintPtr createRigidConstraint(FeaturePtr theFixedFeature);
+
+  /// \brief Converts sketch parameters to the list of SolveSpace entities.
+  ///        Identifiers of entities and parameters are local. They should be changed while adding into storage.
+  ///        The sketch entity goes last.
+  /// \param[in]  theSketch     the element to be converted
+  /// \param[out] theEntities   created list of entities
+  /// \param[out] theParameters created list of parameters of the entities
+  /// \return \c true if workplane created
+  bool createWorkplane(CompositeFeaturePtr theSketch,
+                       std::vector<Slvs_Entity>& theEntities,
+                       std::vector<Slvs_Param>& theParameters);
+
+  /// \brief Converts attribute to the list of entities.
+  ///        Identifiers are local (see createWorkplane).
+  ///        The main entity goes last.
+  bool createEntity(AttributePtr theAttribute,
+                    std::vector<Slvs_Entity>& theEntities,
+                    std::vector<Slvs_Param>& theParameters);
+  /// \brief Converts feature to the list of entities.
+  ///        Identifiers are local (see createWorkplane).
+  ///        The main entity goes last.
+  bool createEntity(FeaturePtr theFeature,
+                    std::vector<Slvs_Entity>& theEntities,
+                    std::vector<Slvs_Param>& theParameters);
+
+  /// \brief Converts normal and OX direction to the list of entities representing a normal in SolveSpace.
+  ///        Identifiers are local (see createWorkplane).
+  ///        The main entity goes last.
+  bool createNormal(AttributePtr theNormal,
+                    AttributePtr theDirX,
+                    std::vector<Slvs_Entity>& theEntities,
+                    std::vector<Slvs_Param>& theParameters);
+
+private:
+  static SketchSolver_Builder* mySelf;
+};
+
+#endif
index 4686f6f3c36f2f8114a343a1246b9ffeffbafa38..d8d3df086193ca2a2d3689d04b5a7d96464ce4ec 100644 (file)
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_Constraint.cpp
-// Created: 27 May 2014
-// Author:  Artem ZHIDKOV
-
-#include "SketchSolver_Constraint.h"
-#include <SketchSolver_Solver.h>
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
 
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_ConstraintCoincidence.h>
-#include <SketchPlugin_ConstraintDistance.h>
-#include <SketchPlugin_ConstraintEqual.h>
-#include <SketchPlugin_ConstraintFillet.h>
-#include <SketchPlugin_ConstraintHorizontal.h>
-#include <SketchPlugin_ConstraintLength.h>
-#include <SketchPlugin_ConstraintMirror.h>
-#include <SketchPlugin_ConstraintParallel.h>
-#include <SketchPlugin_ConstraintPerpendicular.h>
-#include <SketchPlugin_ConstraintRadius.h>
-#include <SketchPlugin_ConstraintRigid.h>
-#include <SketchPlugin_ConstraintTangent.h>
-#include <SketchPlugin_ConstraintVertical.h>
-
-#include <ModelAPI_AttributeRefAttr.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_Data.h>
-#include <ModelAPI_Document.h>
-#include <ModelAPI_Object.h>
-#include <ModelAPI_ResultConstruction.h>
 
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
-#include <GeomAPI_Edge.h>
-#include <GeomAPI_Shape.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_ResultConstruction.h>
+
 
-/// Possible types of attributes (used to determine constraint type)
-enum AttrType
+SketchSolver_Constraint::SketchSolver_Constraint(
+    ConstraintPtr  theConstraint)
+  : myBaseConstraint(theConstraint),
+    myGroup(0)
 {
-  UNKNOWN,  // Something wrong during type determination
-  POINT2D,
-  POINT3D,
-  LINE,
-  CIRCLE,
-  ARC
-};
-
-/// Calculate type of the attribute
-static AttrType typeOfAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute);
-
-SketchSolver_Constraint::SketchSolver_Constraint()
-    : myConstraint(std::shared_ptr<SketchPlugin_Constraint>()),
-      myType(SLVS_C_UNKNOWN),
-      myAttributesList()
+}
+
+SketchSolver_Constraint::~SketchSolver_Constraint()
 {
+  std::map<AttributePtr, Slvs_hParam>::const_iterator anIt1 = myValueMap.begin();
+  for (; anIt1 != myValueMap.end(); anIt1++)
+    myStorage->removeParameter(anIt1->second);
+  myValueMap.clear();
+
+  std::map<AttributePtr, Slvs_hEntity>::const_iterator anIt2 = myAttributeMap.begin();
+  for (; anIt2 != myAttributeMap.end(); anIt2++)
+    myStorage->removeEntity(anIt2->second);
+  myAttributeMap.clear();
+
+  std::map<FeaturePtr, Slvs_hEntity>::const_iterator anIt3 =  myFeatureMap.begin();
+  for (; anIt3 != myFeatureMap.end(); anIt3++)
+    myStorage->removeEntity(anIt3->second);
+  myFeatureMap.clear();
+
+  std::vector<Slvs_hConstraint>::const_iterator anIt4 = mySlvsConstraints.begin();
+  for (; anIt4 != mySlvsConstraints.end(); anIt4++)
+    myStorage->removeConstraint(*anIt4);
+  mySlvsConstraints.clear();
 }
 
-SketchSolver_Constraint::SketchSolver_Constraint(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-    : myConstraint(theConstraint),
-      myAttributesList()
+void SketchSolver_Constraint::setStorage(StoragePtr theStorage)
 {
-  myType = getType(myConstraint);
+  myStorage = theStorage;
+  process();
 }
 
-const int& SketchSolver_Constraint::getType(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+void SketchSolver_Constraint::setGroup(SketchSolver_Group* theGroup)
 {
-  myType = SLVS_C_UNKNOWN;
-  if (!theConstraint)
-    return getType();
-
-  DataPtr aConstrData = theConstraint->data();
-  if (!aConstrData || !aConstrData->isValid())
-    return getType();
-
-  // Assign empty names of attributes
-  myAttributesList.clear();
-  for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++)
-    myAttributesList.push_back(std::string());
-
-  const std::string& aConstraintKind = theConstraint->getKind();
-  // Constraint for coincidence of two points
-  if (aConstraintKind.compare(SketchPlugin_ConstraintCoincidence::ID()) == 0) {
-    int anAttrPos = 0;
-    // Verify the constraint has only two attributes and they are points
-    int aPt2d = 0;  // bit-mapped field, each bit indicates whether the attribute is 2D point
-    int aPt3d = 0;  // bit-mapped field, the same information for 3D points
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      if (!anAttr)
-        continue;
-      switch (typeOfAttribute(anAttr)) {
-        case POINT2D:  // the attribute is a 2D point
-          aPt2d |= (1 << indAttr);
-          myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-          break;
-        case POINT3D:  // the attribute is a 3D point
-          aPt3d |= (1 << indAttr);
-          myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-          break;
-        default:
-          // Attribute neither 2D nor 3D point is not supported by this type of constraint
-          return getType();
-      }
-    }
-    // The constrained points should be in first and second positions,
-    // so the expected value of aPt2d or aPt3d is 3
-    if (aPt2d + aPt3d == 3)
-      myType = SLVS_C_POINTS_COINCIDENT;
-    // Constraint parameters are wrong
-    return getType();
+  myGroup = theGroup;
+  process();
+}
+
+
+void SketchSolver_Constraint::process()
+{
+  cleanErrorMsg();
+  if (!myBaseConstraint || !myStorage || myGroup == 0) {
+    /// TODO: Put error message here
+    return;
   }
+  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+    update(myBaseConstraint);
 
-  // Constraint for distance between point and another entity
-  if (aConstraintKind.compare(SketchPlugin_ConstraintDistance::ID()) == 0) {
-    int aNbPoints = 0;
-    int aNbEntities = 0;
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      switch (typeOfAttribute(anAttr)) {
-        case POINT2D:
-        case POINT3D:
-          myAttributesList[aNbPoints++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-          break;
-        case LINE:
-          // entities are placed starting from SketchPlugin_Constraint::ENTITY_C() attribute
-          myAttributesList[2 + aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-          myType = SLVS_C_PT_LINE_DISTANCE;
-          break;
-      }
-    }
-    // Verify the correctness of constraint arguments
-    if (aNbPoints == 2 && aNbEntities == 0)
-      myType = SLVS_C_PT_PT_DISTANCE;
-    else if (aNbPoints != 1 || aNbEntities != 1)
-      myType = SLVS_C_UNKNOWN;
-    return getType();
+  int aConstrType = getType();
+  double aValue = 0.0;
+  std::vector<Slvs_hEntity> anAttributes;
+  getAttributes(aValue, anAttributes);
+  if (!myErrorMsg.empty())
+    return;
+
+  Slvs_hGroup aGroupID = myGroup->getId();
+  Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
+  Slvs_Constraint aConstraint;
+  if (mySlvsConstraints.empty())
+    aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, aGroupID, aConstrType, aWorkplaneID,
+        aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
+  else {
+    aConstraint = myStorage->getConstraint(mySlvsConstraints[0]);
+    aConstraint.valA = aValue;
+    static const int aNbAttrs = 6;
+    Slvs_hEntity* aConstrAttrs[aNbAttrs] = {
+        &aConstraint.ptA, &aConstraint.ptB,
+        &aConstraint.entityA, &aConstraint.entityB,
+        &aConstraint.entityC, &aConstraint.entityD};
+    std::vector<Slvs_hEntity>::const_iterator anIter = anAttributes.begin();
+    for (int i = 0; i < aNbAttrs && anIter != anAttributes.end(); i++, anIter++)
+      *(aConstrAttrs[i]) = *anIter;
   }
 
-  // Constraint for the given length of a line
-  if (aConstraintKind.compare(SketchPlugin_ConstraintLength::ID()) == 0) {
-    int aNbLines = 0;
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      if (typeOfAttribute(anAttr) == LINE)
-        myAttributesList[aNbLines++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-    }
-    if (aNbLines == 1)
-      myType = SLVS_C_PT_PT_DISTANCE;
-    return getType();
+  Slvs_hConstraint anID = myStorage->addConstraint(aConstraint);
+  if (mySlvsConstraints.empty())
+    mySlvsConstraints.push_back(anID);
+  else
+    mySlvsConstraints[0] = anID;
+}
+
+void SketchSolver_Constraint::update(ConstraintPtr theConstraint)
+{
+  cleanErrorMsg();
+  if (theConstraint && theConstraint != myBaseConstraint) {
+    if (theConstraint->getKind() != myBaseConstraint->getKind())
+      return;
+    remove(myBaseConstraint);
+    myBaseConstraint = theConstraint;
+    process();
   }
 
-  // Constraint for two parallel/perpendicular lines
-  bool isParallel = (aConstraintKind.compare(SketchPlugin_ConstraintParallel::ID()) == 0);
-  bool isPerpendicular = (aConstraintKind.compare(SketchPlugin_ConstraintPerpendicular::ID()) == 0);
-  if (isParallel || isPerpendicular) {
-    int aNbEntities = 2;  // lines in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      if (typeOfAttribute(anAttr) == LINE)
-        myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+  int aType;
+  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myFeatureMap.begin();
+  for (; aFeatIter != myFeatureMap.end(); aFeatIter++)
+    aFeatIter->second = changeEntity(aFeatIter->first, aType);
+  std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
+  for (; anAttrIter != myAttributeMap.end(); anAttrIter++)
+    anAttrIter->second = changeEntity(anAttrIter->first, aType);
+}
+
+bool SketchSolver_Constraint::remove(ConstraintPtr theConstraint)
+{
+  cleanErrorMsg();
+  if (theConstraint && theConstraint != myBaseConstraint)
+    return false;
+  bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints.front());
+  if (isFullyRemoved) {
+    myFeatureMap.clear();
+    myAttributeMap.clear();
+    myValueMap.clear();
+  } else
+    cleanRemovedEntities();
+  return true;
+}
+
+void SketchSolver_Constraint::cleanRemovedEntities()
+{
+  std::set<Slvs_hParam> aRemovedParams;
+  std::set<Slvs_hEntity> aRemovedEntities;
+  std::set<Slvs_hConstraint> aRemovedConstraints;
+  myStorage->getRemoved(aRemovedParams, aRemovedEntities, aRemovedConstraints);
+  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
+  while (aFeatIt != myFeatureMap.end()) {
+    if (aRemovedEntities.find(aFeatIt->second) == aRemovedEntities.end()) {
+      aFeatIt++;
+      continue;
+    }
+    std::map<FeaturePtr, Slvs_hEntity>::iterator aTmpIter = aFeatIt++;
+    myFeatureMap.erase(aTmpIter);
+  }
+  std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIt = myAttributeMap.begin();
+  while (anAttrIt != myAttributeMap.end()) {
+    if (aRemovedEntities.find(anAttrIt->second) == aRemovedEntities.end()) {
+      anAttrIt++;
+      continue;
     }
-    if (aNbEntities == 4)
-      myType = isParallel ? SLVS_C_PARALLEL : SLVS_C_PERPENDICULAR;
-    return getType();
+    std::map<AttributePtr, Slvs_hEntity>::iterator aTmpIter = anAttrIt++;
+    myAttributeMap.erase(aTmpIter);
   }
+  std::map<AttributePtr, Slvs_hParam>::iterator aValIt = myValueMap.begin();
+  while (aValIt != myValueMap.end()) {
+    if (aRemovedParams.find(aValIt->second) == aRemovedParams.end()) {
+      aValIt++;
+      continue;
+    }
+    std::map<AttributePtr, Slvs_hParam>::iterator aTmpIter = aValIt++;
+    myValueMap.erase(aTmpIter);
+  }
+}
+
+void SketchSolver_Constraint::getAttributes(
+    double& theValue,
+    std::vector<Slvs_hEntity>& theAttributes)
+{
+  static const int anInitNbOfAttr = 4;
+  theAttributes.assign(anInitNbOfAttr, SLVS_E_UNKNOWN);
+
+  DataPtr aData = myBaseConstraint->data();
 
-  // Constraint for radius of a circle or an arc of circle
-  if (aConstraintKind.compare(SketchPlugin_ConstraintRadius::ID()) == 0) {
-    int aNbEntities = 2;  // lines in SolveSpace constraints should started from SketchPlugin_Constraint::ENTITY_C() attribute
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      AttrType aType = typeOfAttribute(anAttr);
-      if (aType == CIRCLE || aType == ARC)
-        myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+  AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+    aData->attribute(SketchPlugin_Constraint::VALUE()));
+  theValue = aValueAttr ? aValueAttr->value() : 0.0;
+
+  int aPtInd = 0; // index of first point in the list of attributes
+  int aEntInd = 2; // index of first antity in the list of attributes
+  std::list<AttributePtr> aConstrAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId());
+  std::list<AttributePtr>::iterator anIter = aConstrAttrs.begin();
+  for (; anIter != aConstrAttrs.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr =
+        std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (!aRefAttr || !aRefAttr->isInitialized()) {
+      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+      return;
+    }
+
+    int aType = SLVS_E_UNKNOWN; // type of created entity
+    Slvs_hEntity anEntity = myGroup->getAttributeId(aRefAttr);
+    if (anEntity == SLVS_E_UNKNOWN)
+      anEntity = changeEntity(aRefAttr, aType);
+    else {
+      Slvs_Entity anEnt = myStorage->getEntity(anEntity);
+      aType = anEnt.type;
+    }
+
+    if (aType == SLVS_E_UNKNOWN)
+      continue;
+    else if (aType == SLVS_E_POINT_IN_2D || aType == SLVS_E_POINT_IN_3D)
+      theAttributes[aPtInd++] = anEntity; // the point is created
+    else { // another entity (not a point) is created
+      if (aEntInd < anInitNbOfAttr)
+        theAttributes[aEntInd] = anEntity;
+      else
+        theAttributes.push_back(anEntity);
+      aEntInd++;
     }
-    if (aNbEntities == 3)
-      myType = SLVS_C_DIAMETER;
-    return getType();
   }
+}
 
-  // Constraint for fixed entity
-  if (aConstraintKind.compare(SketchPlugin_ConstraintRigid::ID()) == 0) {
-    // Verify that only one entity is filled
-    int aNbAttrs = 0;
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      AttrType aType = typeOfAttribute(anAttr);
-      if (aType != UNKNOWN)
-        myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributeRefAttrPtr theAttribute, int& theType)
+{
+  // Convert the object of the attribute to the feature
+  FeaturePtr aFeature;
+  if (theAttribute->isObject() && theAttribute->object()) {
+    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+        theAttribute->object());
+    if (!aRC) {
+      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+      return SLVS_E_UNKNOWN;
     }
-    if (aNbAttrs == 1)
-      myType = SLVS_C_WHERE_DRAGGED;
-    return getType();
+    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
+    aFeature = aDoc->feature(aRC);
+
+    return changeEntity(aFeature, theType);
   }
 
-  // Constraint for horizontal/vertical line
-  bool isHorizontal = (aConstraintKind.compare(SketchPlugin_ConstraintHorizontal::ID()) == 0);
-  bool isVertical = (aConstraintKind.compare(SketchPlugin_ConstraintVertical::ID()) == 0);
-  if (isHorizontal || isVertical) {
-    int aNbEntities = 2;  // lines in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      if (typeOfAttribute(anAttr) == LINE)
-        myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+  return changeEntity(theAttribute->attr(), theType);
+}
+
+Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& theType)
+{
+  Slvs_hEntity aResult = SLVS_E_UNKNOWN;
+  if (!theEntity->isInitialized())
+    return SLVS_E_UNKNOWN;
+
+  // If the entity is already in the group, try to find it
+  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
+      myAttributeMap.find(theEntity);
+  Slvs_Entity aCurrentEntity;
+  aCurrentEntity.h = SLVS_E_UNKNOWN;
+  if (anEntIter != myAttributeMap.end())
+    aCurrentEntity = myStorage->getEntity(anEntIter->second);
+  else {
+    aResult = myGroup->getAttributeId(theEntity);
+    if (aResult != SLVS_E_UNKNOWN) {
+      Slvs_Entity anEnt = myStorage->getEntity(aResult);
+      theType = anEnt.type;
+      return aResult;
     }
-    if (aNbEntities == 3)
-      myType = isHorizontal ? SLVS_C_HORIZONTAL : SLVS_C_VERTICAL;
-    return getType();
   }
 
-  if (aConstraintKind.compare(SketchPlugin_ConstraintEqual::ID()) == 0) {
-    static const int aConstrType[3] = {
-        SLVS_C_EQUAL_RADIUS,
-        SLVS_C_EQUAL_LINE_ARC_LEN,
-        SLVS_C_EQUAL_LENGTH_LINES
-    };
-    int aNbLines = 0;
-    int aNbEntities = 2;  // lines and circles in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      AttrType aType = typeOfAttribute(anAttr);
-      if (aType == LINE) {
-        myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-        aNbLines++;
+  Slvs_hGroup aGroupID = myGroup->getId();
+  // Point in 3D
+  std::shared_ptr<GeomDataAPI_Point> aPoint =
+      std::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
+  if (aPoint) {
+    double aXYZ[3] = {aPoint->x(), aPoint->y(), aPoint->z()};
+    Slvs_hParam aParams[3];
+    for (int i = 0; i < 3; i++) {
+      Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
+          myStorage->getParameter(aCurrentEntity.param[i]) :
+          Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
+      aPar.val = aXYZ[i];
+      aParams[i] = myStorage->addParameter(aPar);
+    }
+
+    if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+      aCurrentEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, aGroupID, aParams[0], aParams[1], aParams[2]);
+    else { // update entity data
+      for (int i = 0; i < 3; i++)
+        aCurrentEntity.param[i] = aParams[i];
+    }
+    aResult = myStorage->addEntity(aCurrentEntity);
+  } else {
+    // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
+    Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
+    if (aWorkplaneID == SLVS_E_UNKNOWN)
+      return SLVS_E_UNKNOWN;
+
+    // Point in 2D
+    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
+    if (aPoint2D) {
+      double aXY[2] = {aPoint2D->x(), aPoint2D->y()};
+      Slvs_hParam aParams[2];
+      for (int i = 0; i < 2; i++) {
+        Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
+            myStorage->getParameter(aCurrentEntity.param[i]) :
+            Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
+        aPar.val = aXY[i];
+        aParams[i] = myStorage->addParameter(aPar);
+      }
+
+      if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+        aCurrentEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aParams[0], aParams[1]);
+      else { // update entity data
+        for (int i = 0; i < 2; i++)
+          aCurrentEntity.param[i] = aParams[i];
+      }
+      aResult = myStorage->addEntity(aCurrentEntity);
+    } else {
+      // Scalar value (used for the distance entities)
+      AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
+      if (aScalar) {
+        Slvs_Param aParam = aCurrentEntity.h != SLVS_E_UNKNOWN ?
+            myStorage->getParameter(aCurrentEntity.param[0]) :
+            Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
+        aParam.val = aScalar->value();
+        Slvs_hParam aValue = myStorage->addParameter(aParam);
+
+        if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+          aCurrentEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aValue);
+        else
+          aCurrentEntity.param[0] = aValue;
+        aResult = myStorage->addEntity(aCurrentEntity);
       }
-      else if (aType == CIRCLE || aType == ARC)
-        myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
     }
-    if (aNbEntities == 4)
-      myType = aConstrType[aNbLines];
-    return getType();
   }
 
-  if (aConstraintKind.compare(SketchPlugin_ConstraintTangent::ID()) == 0) {
-    static const int anArcPosDefault = 2;
-    static const int aLinePosDefault = 3;
-    int anArcPos = anArcPosDefault; // arc in tangency constraint should be placed before line
-    int aLinePos = aLinePosDefault;
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      AttrType aType = typeOfAttribute(anAttr);
-      if (aType == LINE && aLinePos < CONSTRAINT_ATTR_SIZE)
-        myAttributesList[aLinePos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-      else if (aType == ARC)
-        myAttributesList[anArcPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+  myAttributeMap[theEntity] = aResult;
+  theType = aCurrentEntity.type;
+  return aResult;
+}
+
+Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& theType)
+{
+  Slvs_hEntity aResult = SLVS_E_UNKNOWN;
+  if (!theEntity->data()->isValid())
+    return SLVS_E_UNKNOWN;
+  // If the entity is already in the group, try to find it
+  std::map<FeaturePtr, Slvs_hEntity>::const_iterator anEntIter = myFeatureMap.find(theEntity);
+  Slvs_Entity aCurrentEntity;
+  aCurrentEntity.h = SLVS_E_UNKNOWN;
+  if (anEntIter != myFeatureMap.end())
+    aCurrentEntity = myStorage->getEntity(anEntIter->second);
+  else {
+    aResult = myGroup->getFeatureId(theEntity);
+    if (aResult != SLVS_E_UNKNOWN) {
+      Slvs_Entity anEnt = myStorage->getEntity(aResult);
+      theType = anEnt.type;
+      return aResult;
     }
-    if (anArcPos - anArcPosDefault + aLinePos - aLinePosDefault == 2)
-      myType = aLinePos > 3 ? SLVS_C_ARC_LINE_TANGENT : SLVS_C_CURVE_CURVE_TANGENT;
-    return getType();
   }
 
-  if (aConstraintKind.compare(SketchPlugin_ConstraintMirror::ID()) == 0) {
-    int aNbAttrs = 0;
-    bool hasMirrorLine = false;
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      AttributeRefListPtr anAttrRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)));
-      if (anAttrRefList) {
-        aNbAttrs++;
-        myAttributesList[aNbAttrs] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-      }
+  Slvs_hGroup aGroupID = myGroup->getId();
+  Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
+  // SketchPlugin features
+  std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
+      SketchPlugin_Feature>(theEntity);
+  if (aFeature) {  // Verify the feature by its kind
+    const std::string& aFeatureKind = aFeature->getKind();
+    AttributePtr anAttribute;
+    int anAttrType;
+
+    // Line
+    if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
+      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
+      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+      Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
+
+      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
+      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+      Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
+
+      if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+        aCurrentEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aStart, aEnd);
       else {
-        std::shared_ptr<ModelAPI_Attribute> anAttr = 
-            aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-        if (typeOfAttribute(anAttr) == LINE) {
-          hasMirrorLine = !hasMirrorLine;
-          myAttributesList[0] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-        }
+        aCurrentEntity.point[0] = aStart;
+        aCurrentEntity.point[1] = aEnd;
       }
+      aResult = myStorage->addEntity(aCurrentEntity);
     }
-    if (aNbAttrs == 2 && hasMirrorLine)
-      myType = SLVS_C_SYMMETRIC_LINE;
-    return getType();
-  }
+    // Circle
+    else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
+      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
+      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+      Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
 
-  if (aConstraintKind.compare(SketchPlugin_ConstraintFillet::ID()) == 0) {
-    int aNbAttrs = 0;
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      AttributeRefListPtr anAttrRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)));
-      if (anAttrRefList)
-        myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-      else {
-        std::shared_ptr<ModelAPI_Attribute> anAttr = 
-            aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-        AttrType aType = typeOfAttribute(anAttr);
-        if (aType == LINE || aType == ARC)
-          myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
+      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+      Slvs_hEntity aRadius = changeEntity(anAttribute, anAttrType);
+
+      if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
+        Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
+        aCurrentEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
+                                         aCenter, aWorkplane.normal, aRadius);
+      } else {
+        aCurrentEntity.point[0] = aCenter;
+        aCurrentEntity.distance = aRadius;
       }
+      aResult = myStorage->addEntity(aCurrentEntity);
     }
-    if (aNbAttrs == 3)
-      myType = SLVS_C_FILLET;
-    return getType();
-  }
+    // Arc
+    else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
+      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
+      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+      Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
 
-  /// \todo Implement other kind of constraints
+      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
+      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+      Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
+
+      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
+      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+      Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
+
+      if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
+        Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
+        aCurrentEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
+                                              aWorkplane.normal, aCenter, aStart, aEnd);
+      } else {
+        aCurrentEntity.point[0] = aCenter;
+        aCurrentEntity.point[1] = aStart;
+        aCurrentEntity.point[2] = aEnd;
+      }
+      aResult = myStorage->addEntity(aCurrentEntity);
+    }
+    // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
+    else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) {
+      anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
+      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+      // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
+      aResult = changeEntity(anAttribute, anAttrType);
+      aCurrentEntity.type = SLVS_E_POINT_IN_3D;
+    }
+  }
 
-  return getType();
+  myFeatureMap[theEntity] = aResult;
+  theType = aCurrentEntity.type;
+  return aResult;
 }
 
-// ================= Auxiliary functions ==============================
-AttrType typeOfAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute)
+std::list<ConstraintPtr> SketchSolver_Constraint::constraints() const
 {
-  std::shared_ptr<ModelAPI_AttributeRefAttr> anAttrRef = std::dynamic_pointer_cast<
-      ModelAPI_AttributeRefAttr>(theAttribute);
-  if (!anAttrRef)
-    return UNKNOWN;
+  std::list<ConstraintPtr> aConstraints;
+  aConstraints.push_back(myBaseConstraint);
+  return aConstraints;
+}
 
-  if (anAttrRef->isObject()) {
-    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-        anAttrRef->object());
-    if (!aRC || !aRC->shape())
-      return UNKNOWN;
-
-    if (aRC->shape()->isVertex())
-      return POINT3D;
-    else if (aRC->shape()->isEdge()) {
-      std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(
-          aRC->shape());
-      if (anEdge->isLine())
-        return LINE;
-      else if (anEdge->isCircle())
-        return CIRCLE;
-      else if (anEdge->isArc())
-        return ARC;
+void SketchSolver_Constraint::refresh()
+{
+  cleanErrorMsg();
+  std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
+  for (; anAttrIter != myAttributeMap.end(); anAttrIter++) {
+    std::shared_ptr<GeomDataAPI_Point> aPoint =
+        std::dynamic_pointer_cast<GeomDataAPI_Point>(anAttrIter->first);
+    if (aPoint) {
+      Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
+      double aXYZ[3];
+      for (int i = 0; i < 3; i++) {
+        Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
+        aXYZ[i] = aPar.val;
+      }
+      aPoint->setValue(aXYZ[0], aXYZ[1], aXYZ[2]);
+    } else {
+      // Point in 2D
+      std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrIter->first);
+      if (aPoint2D) {
+        Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
+        double aXYZ[2];
+        for (int i = 0; i < 2; i++) {
+          Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
+          aXYZ[i] = aPar.val;
+        }
+        aPoint2D->setValue(aXYZ[0], aXYZ[1]);
+      } else {
+        // Scalar value (used for the distance entities)
+        AttributeDoublePtr aScalar =
+            std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
+        if (aScalar) {
+          Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
+          Slvs_Param aPar = myStorage->getParameter(anEntity.param[0]);
+          aScalar->setValue(aPar.val);
+        }
+      }
     }
-  } else {
-    if (anAttrRef->attr().get() != NULL) {
-      const std::string aType = anAttrRef->attr()->attributeType();
-      if (aType == GeomDataAPI_Point2D::typeId())
-        return POINT2D;
-      if (aType == GeomDataAPI_Point2D::typeId())
-        return POINT2D;
+  }
+
+  std::map<AttributePtr, Slvs_hParam>::iterator aValIter = myValueMap.begin();
+  for (; aValIter != myValueMap.end(); aValIter++) {
+    AttributeDoublePtr aScalar =
+        std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
+    if (aScalar) {
+      Slvs_Param aPar = myStorage->getParameter(anAttrIter->second);
+      aScalar->setValue(aPar.val);
     }
   }
+}
+
+Slvs_hEntity SketchSolver_Constraint::getId(FeaturePtr theFeature) const
+{
+  std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFIter = myFeatureMap.find(theFeature);
+  if (aFIter == myFeatureMap.end())
+    return SLVS_E_UNKNOWN;
+  return aFIter->second;
+}
 
-  return UNKNOWN;
+Slvs_hEntity SketchSolver_Constraint::getId(AttributePtr theAttribute) const
+{
+  std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrIter = myAttributeMap.find(theAttribute);
+  if (anAttrIter == myAttributeMap.end())
+    return SLVS_E_UNKNOWN;
+  return anAttrIter->second;
 }
 
index 5a98e31be6f885eb03435a4ba85a71d64ad96c9e..b7925d66c9c400190818c55426f0709d29d8efcf 100644 (file)
 #define SketchSolver_Constraint_H_
 
 #include "SketchSolver.h"
+#include <SketchSolver_Storage.h>
 
 #include <SketchPlugin_Constraint.h>
 
+#include <ModelAPI_AttributeRefAttr.h>
+
 #include <string>
 #include <vector>
 
+class SketchSolver_Group;
+
 /** \class   SketchSolver_Constraint
  *  \ingroup Plugins
- *  \brief   Obtain information about SketchPlugin's constraint
+ *  \brief   Stores mapping between SketchPlugin and SolveSpace constraints data
  */
 class SketchSolver_Constraint
 {
-public:
+protected:
   /// Default constructor
-  SketchSolver_Constraint();
-  /// Creates constraint to manage the given constraint from plugin
-  SketchSolver_Constraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
-  /** \brief Compute constraint type according to SolveSpace identifiers
-   *         and verify that constraint parameters are correct
-   *  \param[in]  theConstraint constraint which type should be determined
-   *  \return identifier of constraint type or SLVS_C_UNKNOWN if the type is wrong
-   */
-  const int& getType(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-  /// \brief Returns the type of myConstraint member
-  inline const int& getType() const
-  {
-    return myType;
-  }
-
-  /// \brief Returns list of attributes names in the correct order required by SolveSpace
-  inline const std::vector<std::string>& getAttributes() const
-  {
-    return myAttributesList;
-  }
-
- private:
-  std::shared_ptr<SketchPlugin_Constraint> myConstraint;
-  int myType;
-  std::vector<std::string> myAttributesList;
+  SketchSolver_Constraint() {}
+  SketchSolver_Constraint(ConstraintPtr theConstraint);
+
+public:
+  virtual ~SketchSolver_Constraint();
+
+  /// \brief Initializes the storage of SolveSpace constraints
+  void setStorage(StoragePtr theStorage);
+  /// \brief Initializes group ID for this constraint
+  void setGroup(SketchSolver_Group* theGroup);
+
+  /// \brief Update constraint
+  virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
+
+  /// \brief Tries to remove constraint
+  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+  /// \brief Update SketchPlugin attributes using the data obtained from SolveSpace entities
+  void refresh();
+
+  /// \brief Returns the type of constraint
+  virtual int getType() const = 0;
+
+  /// \brief Checks the constraint is used by current object
+  virtual bool hasConstraint(ConstraintPtr theConstraint) const
+  { return theConstraint == myBaseConstraint; }
+
+  /// \brief Return list of SketchPlugin constraints attached to this object
+  virtual std::list<ConstraintPtr> constraints() const;
+
+  /// \brief Return identifier of SolveSpace entity relating to the feature
+  Slvs_hEntity getId(FeaturePtr theFeature) const;
+  /// \brief Return identifier of SolveSpace entity relating to the attribute
+  Slvs_hEntity getId(AttributePtr theAttribute) const;
+
+  /// \brief Shows error message
+  const std::string& error() const
+  { return myErrorMsg; }
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process();
+
+  /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+  /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
+  /// \param[out] theAttributes list of attributes to be filled
+  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
+
+  /// \brief Create or change SlveSpace entity according to the given attribute
+  /// \param[in]  theAttribute  reference to the entity to be changed
+  /// \param[out] theType       type of created entity
+  /// \return identifier of created/updated entity
+  Slvs_hEntity changeEntity(AttributeRefAttrPtr theAttribute, int& theType);
+  /// \brief Create or change SlveSpace entity according to the given attribute
+  Slvs_hEntity changeEntity(AttributePtr theAttribute, int& theType);
+  /// \brief Create or change SlveSpace entity according to the given feature
+  Slvs_hEntity changeEntity(FeaturePtr theFeature, int& theType);
+
+  /// \brief Removes the links to unused entities
+  void cleanRemovedEntities();
+
+  /// \brief Removes last error
+  void cleanErrorMsg()
+  { myErrorMsg.clear(); }
+
+protected:
+  SketchSolver_Group* myGroup; ///< the group which contains current constraint
+  ConstraintPtr myBaseConstraint; ///< SketchPlugin constraint
+  std::vector<Slvs_hConstraint> mySlvsConstraints; ///< list of indices of SolveSpace constraints, together which equivalent to SketchPlugin constraint
+  std::map<FeaturePtr, Slvs_hEntity> myFeatureMap; ///< map feature to the entity it represents
+  std::map<AttributePtr, Slvs_hEntity> myAttributeMap; ///< map attribute to the corresponding entity
+  std::map<AttributePtr, Slvs_hParam> myValueMap; ///< list of attributes, which represents single value (e.g. distance) used in constraint
+  StoragePtr myStorage; ///< storage, which contains all information about entities and constraints in current group
+
+  std::string myErrorMsg; ///< error message
+};
+
+typedef std::shared_ptr<SketchSolver_Constraint> SolverConstraintPtr;
+
+
+
+/** \class   SketchSolver_ConstraintDistance
+ *  \ingroup Plugins
+ *  \brief   Convert distance constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintDistance : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintDistance(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_PT_PT_DISTANCE; }
+};
+
+
+/** \class   SketchSolver_ConstraintParallel
+ *  \ingroup Plugins
+ *  \brief   Convert Parallel constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintParallel : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintParallel(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_PARALLEL; }
+};
+
+
+/** \class   SketchSolver_ConstraintPerpendicular
+ *  \ingroup Plugins
+ *  \brief   Convert Perpendicular constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintPerpendicular : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintPerpendicular(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_PERPENDICULAR; }
+};
+
+
+/** \class   SketchSolver_ConstraintHorizontal
+ *  \ingroup Plugins
+ *  \brief   Convert Horizontal constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintHorizontal : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintHorizontal(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_HORIZONTAL; }
+};
+
+
+/** \class   SketchSolver_ConstraintVertical
+ *  \ingroup Plugins
+ *  \brief   Convert Vertical constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintVertical : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintVertical(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_VERTICAL; }
 };
 
 #endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp
new file mode 100644 (file)
index 0000000..a5b6001
--- /dev/null
@@ -0,0 +1,140 @@
+#include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchSolver_Error.h>
+#include <SketchSolver_Group.h>
+
+#include <map>
+
+bool SketchSolver_ConstraintCoincidence::hasConstraint(ConstraintPtr theConstraint) const
+{
+  if (myBaseConstraint == theConstraint)
+    return true;
+  std::map<ConstraintPtr, Slvs_hConstraint>::const_iterator anIt = myExtraCoincidence.begin();
+  for (; anIt != myExtraCoincidence.end(); anIt++)
+    if (anIt->first == theConstraint)
+      return true;
+  return false;
+}
+
+std::list<ConstraintPtr> SketchSolver_ConstraintCoincidence::constraints() const
+{
+  std::list<ConstraintPtr> aConstraints;
+  aConstraints.push_back(myBaseConstraint);
+  std::map<ConstraintPtr, Slvs_hConstraint>::const_iterator anIt = myExtraCoincidence.begin();
+  for (; anIt != myExtraCoincidence.end(); anIt++)
+    aConstraints.push_back(anIt->first);
+  return aConstraints;
+}
+
+bool SketchSolver_ConstraintCoincidence::isCoincide(
+    std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const
+{
+  std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFeatIter = myFeatureMap.begin();
+  for (; aFeatIter != myFeatureMap.end(); aFeatIter++)
+    if (theConstraint->myFeatureMap.find(aFeatIter->first) != theConstraint->myFeatureMap.end())
+      return true;
+  std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrIter = myAttributeMap.begin();
+  for (; anAttrIter != myAttributeMap.end(); anAttrIter++)
+    if (theConstraint->myAttributeMap.find(anAttrIter->first) != theConstraint->myAttributeMap.end())
+      return true;
+  return false;
+}
+
+void SketchSolver_ConstraintCoincidence::attach(
+    std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint)
+{
+  cleanErrorMsg();
+  Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
+  // Remove constraints from theConstraint
+  std::vector<Slvs_hConstraint>::iterator aCIter = theConstraint->mySlvsConstraints.begin();
+  for (; aCIter != theConstraint->mySlvsConstraints.end(); aCIter++)
+    theConstraint->myStorage->removeConstraint(*aCIter);
+
+  if (myStorage == theConstraint->myStorage) {
+    // Clean removed items
+    std::set<Slvs_hParam> aRemParams;
+    std::set<Slvs_hEntity> aRemEnts;
+    std::set<Slvs_hConstraint> aRemConstr;
+    theConstraint->myStorage->getRemoved(aRemParams, aRemEnts, aRemConstr);
+  }
+
+  // Copy data.
+  addConstraint(theConstraint->myBaseConstraint);
+  std::map<ConstraintPtr, Slvs_hConstraint>::iterator aConstrIter =
+      theConstraint->myExtraCoincidence.begin();
+  for (; aConstrIter != theConstraint->myExtraCoincidence.end(); aConstrIter++)
+    addConstraint(aConstrIter->first);
+  // Clear the lists to not remove the entities on destruction
+  theConstraint->mySlvsConstraints.clear();
+  theConstraint->myFeatureMap.clear();
+  theConstraint->myAttributeMap.clear();
+}
+
+Slvs_hConstraint SketchSolver_ConstraintCoincidence::addConstraint(
+    Slvs_hEntity thePoint1, Slvs_hEntity thePoint2)
+{
+  Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
+      SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(), 0.0, thePoint1, thePoint2, 
+      SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+  Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
+  mySlvsConstraints.push_back(aNewID);
+  return aNewID;
+}
+
+void SketchSolver_ConstraintCoincidence::addConstraint(ConstraintPtr theConstraint)
+{
+  std::list<AttributePtr> anAttrList =
+      theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
+  std::list<AttributePtr>::iterator anIter = anAttrList.begin();
+  std::vector<Slvs_hEntity> anEntities;
+  for (; anIter != anAttrList.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (!aRefAttr || aRefAttr->isObject() ||
+        myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end())
+      continue;
+    int aType;
+    Slvs_hEntity anEntityID = myGroup->getAttributeId(aRefAttr->attr());
+    if (anEntityID == SLVS_E_UNKNOWN)
+      anEntityID = changeEntity(aRefAttr->attr(), aType);
+    anEntities.push_back(anEntityID);
+  }
+
+  Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
+  Slvs_hConstraint aNewConstr = SLVS_E_UNKNOWN;
+  std::vector<Slvs_hEntity>::iterator anEntIter = anEntities.begin();
+  for (; anEntIter != anEntities.end(); anEntIter++)
+    aNewConstr = addConstraint(aBaseCoincidence.ptA, *anEntIter);
+  myExtraCoincidence[theConstraint] = aNewConstr;
+}
+
+bool SketchSolver_ConstraintCoincidence::remove(ConstraintPtr theConstraint)
+{
+  cleanErrorMsg();
+  ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
+  int aPos = -1; // position of constraint in the list (-1 for base constraint)
+  if (aConstraint != myBaseConstraint) {
+    std::map<ConstraintPtr, Slvs_hConstraint>::const_iterator anIt = myExtraCoincidence.begin();
+    for (aPos = 0; anIt != myExtraCoincidence.end(); anIt++, aPos++)
+      if (anIt->first == aConstraint)
+        break;
+    if (aPos >= (int)myExtraCoincidence.size())
+      return false; // there is no constraint, which is specified to remove
+  }
+
+  bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints[aPos+1]);
+  mySlvsConstraints.erase(mySlvsConstraints.begin() + (1+aPos));
+  cleanRemovedEntities();
+  if (aPos < 0 && !myExtraCoincidence.empty()) {
+    // Need to specify another base coincidence constraint
+    myBaseConstraint = myExtraCoincidence.begin()->first;
+    myExtraCoincidence.erase(myExtraCoincidence.begin());
+    std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+    Slvs_Constraint aBase = myStorage->getConstraint(*aCIter);
+    for (++aCIter; aCIter != mySlvsConstraints.end(); aCIter++) {
+      Slvs_Constraint aConstr = myStorage->getConstraint(*aCIter);
+      aConstr.ptA = aBase.ptA;
+      myStorage->updateConstraint(aConstr);
+    }
+  }
+  return true;
+}
+
diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.h b/src/SketchSolver/SketchSolver_ConstraintCoincidence.h
new file mode 100644 (file)
index 0000000..97c1c12
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_ConstraintCoincidence.h
+// Created: 29 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintCoincidence_H_
+#define SketchSolver_ConstraintCoincidence_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_Storage.h>
+
+/** \class   SketchSolver_ConstraintCoincidence
+ *  \ingroup Plugins
+ *  \brief   Convert coincidence constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintCoincidence : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_POINTS_COINCIDENT; }
+
+  /// \brief Tries to remove constraint
+  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+  /// \brief Checks the constraint is used by current object
+  virtual bool hasConstraint(ConstraintPtr theConstraint) const;
+
+  /// \brief Return list of SketchPlugin constraints attached to this object
+  virtual std::list<ConstraintPtr> constraints() const;
+
+  /// \brief Verifies the two Coincidence constraints are intersects (have shared point)
+  bool isCoincide(std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const;
+
+  /// \brief Append all data of coincidence constaint to the current
+  void attach(std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint);
+
+private:
+  /// \brief Creates new coincidence constraint
+  Slvs_hConstraint addConstraint(Slvs_hEntity thePoint1, Slvs_hEntity thePoint2);
+
+  /// \brief Create full SolveSpace structure according to given constraint
+  void addConstraint(ConstraintPtr theConstraint);
+
+private:
+  std::map<ConstraintPtr, Slvs_hConstraint> myExtraCoincidence; ///< multiple coincidence of points
+};
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp
deleted file mode 100644 (file)
index fcdcf36..0000000
+++ /dev/null
@@ -1,2347 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_ConstraintGroup.cpp
-// Created: 27 May 2014
-// Author:  Artem ZHIDKOV
-
-#include "SketchSolver_ConstraintGroup.h"
-
-#include <SketchSolver_Constraint.h>
-
-#include <Events_Error.h>
-#include <Events_Loop.h>
-#include <GeomAPI_XY.h>
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_Pnt2d.h>
-#include <GeomDataAPI_Dir.h>
-#include <GeomDataAPI_Point.h>
-#include <GeomDataAPI_Point2D.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_Document.h>
-#include <ModelAPI_Events.h>
-#include <ModelAPI_ResultConstruction.h>
-
-#include <SketchPlugin_Constraint.h>
-#include <SketchPlugin_ConstraintFillet.h>
-#include <SketchPlugin_ConstraintLength.h>
-#include <SketchPlugin_ConstraintCoincidence.h>
-#include <SketchPlugin_ConstraintMirror.h>
-#include <SketchPlugin_ConstraintRigid.h>
-
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Sketch.h>
-
-#include <math.h>
-#include <assert.h>
-
-/// Tolerance for value of parameters
-const double tolerance = 1.e-10;
-
-/**
- * Collects all sketch solver error' codes
- * as inline static functions
- */
- // TODO: Move this class into a separate file
-class SketchSolver_Error
-{
- public:
-  /// The value parameter for the constraint
-  inline static const std::string& CONSTRAINTS()
-  {
-    static const std::string MY_ERROR_VALUE("Conflicting constraints");
-    return MY_ERROR_VALUE;
-  }
-  /// The entities need to have shared point, but they have not
-  inline static const std::string& NO_COINCIDENT_POINTS()
-  {
-    static const std::string MY_ERROR_VALUE("Objects should have coincident point");
-    return MY_ERROR_VALUE;
-  }
-};
-
-/// This value is used to give unique index to the groups
-static Slvs_hGroup myGroupIndexer = 0;
-
-/** \brief Search the entity/parameter with specified ID in the list of elements
- *  \param[in] theEntityID unique ID of the element
- *  \param[in] theEntities list of elements
- *  \return position of the found element or -1 if the element is not found
- */
-template<typename T>
-static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
-
-// ========================================================
-// =========  SketchSolver_ConstraintGroup  ===============
-// ========================================================
-
-SketchSolver_ConstraintGroup::SketchSolver_ConstraintGroup(
-    std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
-    : myID(++myGroupIndexer),
-      myParamMaxID(0),
-      myEntityMaxID(0),
-      myConstrMaxID(0),
-      myConstraintMap(),
-      myNeedToSolve(false),
-      myConstrSolver()
-{
-  myParams.clear();
-  myEntities.clear();
-  myEntOfConstr.clear();
-  myConstraints.clear();
-
-  myTempConstraints.clear();
-  myTempPointWhereDragged.clear();
-  myTempPointWDrgdID = 0;
-
-  // Initialize workplane
-  myWorkplane.h = SLVS_E_UNKNOWN;
-#ifndef NDEBUG
-  assert(addWorkplane(theWorkplane));
-#else
-  addWorkplane(theWorkplane);
-#endif
-}
-
-SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
-{
-  myParams.clear();
-  myEntities.clear();
-  myEntOfConstr.clear();
-  myConstraints.clear();
-  myConstraintMap.clear();
-  myTempConstraints.clear();
-  myTempPointWhereDragged.clear();
-
-  // If the group with maximal identifier is deleted, decrease the indexer
-  if (myID == myGroupIndexer)
-    myGroupIndexer--;
-}
-
-// ============================================================================
-//  Function: isBaseWorkplane
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  verify the group is based on the given workplane
-// ============================================================================
-bool SketchSolver_ConstraintGroup::isBaseWorkplane(
-    std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane) const
-{
-  return theWorkplane == mySketch;
-}
-
-// ============================================================================
-//  Function: isInteract
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  verify are there any entities in the group used by given constraint
-// ============================================================================
-bool SketchSolver_ConstraintGroup::isInteract(
-    std::shared_ptr<SketchPlugin_Feature> theFeature) const
-{
-  // Check the group is empty
-  if (isEmpty())
-    return true;
-
-  // Check if the feature is already in the group
-  if (myEntityFeatMap.find(theFeature) != myEntityFeatMap.end())
-    return true;
-  std::shared_ptr<SketchPlugin_Constraint> aConstr =
-      std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
-  if (aConstr && myConstraintMap.find(aConstr) != myConstraintMap.end())
-    return true;
-
-  // Go through the attributes and verify if some of them already in the group
-  std::list<std::shared_ptr<ModelAPI_Attribute>> 
-      anAttrList = theFeature->data()->attributes(std::string());
-  std::list<std::shared_ptr<ModelAPI_Attribute>>::const_iterator
-      anAttrIter = anAttrList.begin();
-  for ( ; anAttrIter != anAttrList.end(); anAttrIter++) {
-    AttributeRefListPtr aCAttrRefList = 
-        std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrIter);
-    if (aCAttrRefList) {
-      std::list<ObjectPtr> anObjList = aCAttrRefList->list();
-      std::list<ObjectPtr>::iterator anIt = anObjList.begin();
-      for ( ; anIt != anObjList.end(); anIt++) {
-        FeaturePtr aFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(*anIt);
-        if (aFeature && myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
-          return true;
-      }
-      continue;
-    }
-    AttributeRefAttrPtr aCAttrRef =
-        std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
-    if (!aCAttrRef || !aCAttrRef->isObject()) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aCAttrRef ? aCAttrRef->attr() : *anAttrIter;
-      if (myEntityAttrMap.find(anAttr) != myEntityAttrMap.end())
-        return true;
-    } else {
-      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-          aCAttrRef->object());
-      if (!aRC)
-        continue;
-      std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-      FeaturePtr aFeature = aDoc->feature(aRC);
-      if (myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
-        return true;
-      // search attributes of a feature to be parameters of constraint
-      std::list<std::shared_ptr<ModelAPI_Attribute> > aFeatAttrList =
-          aFeature->data()->attributes(std::string());
-      std::list<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aFAIter = aFeatAttrList
-          .begin();
-      for (; aFAIter != aFeatAttrList.end(); aFAIter++)
-        if (myEntityAttrMap.find(*aFAIter) != myEntityAttrMap.end())
-          return true;
-    }
-  }
-
-  // Entities did not found
-  return false;
-}
-
-// ============================================================================
-//  Function: checkConstraintConsistence
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  verifies and changes parameters of the constraint
-// ============================================================================
-void SketchSolver_ConstraintGroup::checkConstraintConsistence(Slvs_Constraint& theConstraint)
-{
-  if (theConstraint.type == SLVS_C_PT_LINE_DISTANCE) {
-    // Get constraint parameters and check the sign of constraint value
-
-    // point coordinates
-    int aPtPos = Search(theConstraint.ptA, myEntities);
-    int aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
-    std::shared_ptr<GeomAPI_XY> aPoint(
-        new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
-
-    // line coordinates
-    int aLnPos = Search(theConstraint.entityA, myEntities);
-    aPtPos = Search(myEntities[aLnPos].point[0], myEntities);
-    aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
-    std::shared_ptr<GeomAPI_XY> aStart(
-        new GeomAPI_XY(-myParams[aPtParamPos].val, -myParams[aPtParamPos + 1].val));
-    aPtPos = Search(myEntities[aLnPos].point[1], myEntities);
-    aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
-    std::shared_ptr<GeomAPI_XY> aEnd(
-        new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
-
-    aEnd = aEnd->added(aStart);
-    aPoint = aPoint->added(aStart);
-    if (aPoint->cross(aEnd) * theConstraint.valA < 0.0)
-      theConstraint.valA *= -1.0;
-  }
-}
-
-// ============================================================================
-//  Function: changeConstraint
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeConstraint(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
-  // There is no workplane yet, something wrong
-  if (myWorkplane.h == SLVS_E_UNKNOWN)
-    return false;
-
-  if (theConstraint) {
-    if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID())
-      return changeRigidConstraint(theConstraint);
-    if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID())
-      return changeMirrorConstraint(theConstraint);
-    if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID())
-      return changeFilletConstraint(theConstraint);
-  }
-
-  // Search this constraint in the current group to update it
-  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
-  std::vector<Slvs_Constraint>::iterator aConstrIter;
-  if (aConstrMapIter != myConstraintMap.end()) {
-    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
-    aConstrIter = myConstraints.begin() + aConstrPos;
-  }
-
-  // Get constraint type and verify the constraint parameters are correct
-  SketchSolver_Constraint aConstraint(theConstraint);
-  int aConstrType = aConstraint.getType();
-  if (aConstrType == SLVS_C_UNKNOWN
-      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
-    return false;
-  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
-  // Create constraint parameters
-  double aDistance = 0.0;  // scalar value of the constraint
-  AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-      theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE()));
-  if (aDistAttr) {
-    aDistance = aDistAttr->value();
-    // Issue #196: checking the positivity of the distance constraint
-    if (aDistance < tolerance &&
-       (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE))
-      return false;
-    // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
-    if (aConstrType == SLVS_C_DIAMETER)
-      aDistance *= 2.0;
-    if (aConstrMapIter != myConstraintMap.end()
-        && fabs(aConstrIter->valA - aDistance) > tolerance) {
-      myNeedToSolve = true;
-      aConstrIter->valA = aDistance;
-    }
-  }
-
-  size_t aNbTmpConstraints = myTempConstraints.size();
-  Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE];  // parameters of the constraint
-  for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-    aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
-    std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
-        ModelAPI_AttributeRefAttr>(
-        theConstraint->data()->attribute(aConstraintAttributes[indAttr]));
-    if (!aConstrAttr)
-      continue;
-
-    // Convert the object of the attribute to the feature
-    FeaturePtr aFeature;
-    if (aConstrAttr->isObject() && aConstrAttr->object()) {
-      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-          aConstrAttr->object());
-      if (!aRC)
-        continue;
-      std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-      aFeature = aDoc->feature(aRC);
-    }
-
-    // For the length constraint the start and end points of the line should be added to the entities list instead of line
-    if (aConstrType == SLVS_C_PT_PT_DISTANCE
-        && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0) {
-      Slvs_hEntity aLineEnt = changeEntityFeature(aFeature);
-      int aEntPos = Search(aLineEnt, myEntities);
-      aConstrEnt[indAttr++] = myEntities[aEntPos].point[0];
-      aConstrEnt[indAttr++] = myEntities[aEntPos].point[1];
-      while (indAttr < CONSTRAINT_ATTR_SIZE)
-        aConstrEnt[indAttr++] = 0;
-      break;  // there should be no other entities
-    } else if (aConstrAttr->isObject())
-      aConstrEnt[indAttr] = changeEntityFeature(aFeature);
-    else
-      aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
-  }
-
-  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
-    // Several points may be coincident, it is not necessary to store all constraints between them.
-    // Try to find sequence of coincident points which connects the points of new constraint
-    if (aConstrType == SLVS_C_POINTS_COINCIDENT) {
-      if (aConstrEnt[0] == aConstrEnt[1])  // no need to add self coincidence
-        return false;
-      if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) {
-        myExtraCoincidence.insert(theConstraint);  // the constraint is stored for further purposes
-        return false;
-      }
-      if (aNbTmpConstraints < myTempConstraints.size()) {
-        // There was added temporary constraint. Check that there is no coincident points which already rigid.
-
-        // Get list of already fixed points
-        std::set<Slvs_hEntity> anAlreadyFixed;
-        std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
-        for (; aCIter != myConstraints.end(); aCIter++)
-          if (aCIter->type == SLVS_C_WHERE_DRAGGED) {
-            std::list<Slvs_hConstraint>::const_iterator aTmpIt = myTempConstraints.begin();
-            for (; aTmpIt != myTempConstraints.end(); aTmpIt++)
-              if (*aTmpIt == aCIter->h)
-                break;
-            if (aTmpIt == myTempConstraints.end())
-              anAlreadyFixed.insert(aCIter->ptA);
-          }
-
-        std::set<Slvs_hConstraint> aTmpConstrToDelete;
-        std::list<Slvs_hConstraint>::reverse_iterator aTmpIter = myTempConstraints.rbegin();
-        size_t aCurSize = myTempConstraints.size();
-        for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend();
-            aTmpIter++, aCurSize--) {
-          int aConstrPos = Search(*aTmpIter, myConstraints);
-          std::vector<std::set<Slvs_hEntity> >::const_iterator
-            aCoincIter = myCoincidentPoints.begin();
-          for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
-            if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) {
-              std::set<Slvs_hEntity>::const_iterator anIt;
-              for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++)
-                if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) {
-                  aTmpConstrToDelete.insert(*aTmpIter);
-                  break;
-                }
-              break;
-            }
-        }
-        if (!aTmpConstrToDelete.empty())
-          removeTemporaryConstraints(aTmpConstrToDelete);
-      }
-    }
-    // For the tangency constraints it is necessary to identify which points of entities are coincident
-    int aSlvsOtherFlag = 0;
-    int aSlvsOther2Flag = 0;
-    if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) {
-      // Search entities used by constraint
-      int anEnt1Pos = Search(aConstrEnt[2], myEntities);
-      int anEnt2Pos = Search(aConstrEnt[3], myEntities);
-      // Obtain start and end points of entities
-      Slvs_hEntity aPointsToFind[4];
-      aPointsToFind[0] = myEntities[anEnt1Pos].point[1];
-      aPointsToFind[1]= myEntities[anEnt1Pos].point[2];
-      bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT);
-      aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1];
-      aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2];
-      // Search coincident points
-      bool isPointFound[4];
-      std::vector<std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
-      for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) {
-        for (int i = 0; i < 4; i++)
-          isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end());
-        if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) {
-          // the arc is tangent by end point
-          if (isPointFound[1]) aSlvsOtherFlag = 1;
-          // the second item is an arc and it is tangent by end point too
-          if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1;
-          break;
-        }
-      }
-      if (aCPIter == myCoincidentPoints.end()) {
-        // There is no coincident points between tangential objects. Generate error message
-        Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
-        return false;
-      }
-    }
-
-    // Create SolveSpace constraint structure
-    Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
-                                                      myWorkplane.h, aDistance, aConstrEnt[0],
-                                                      aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
-    if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag;
-    if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag;
-    myConstraints.push_back(aSlvsConstr);
-    myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aSlvsConstr.h);
-    int aConstrPos = Search(aSlvsConstr.h, myConstraints);
-    aConstrIter = myConstraints.begin() + aConstrPos;
-    myNeedToSolve = true;
-  } else { // Attributes of constraint may be changed => update constraint
-    Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB,
-                                   &aConstrIter->entityA, &aConstrIter->entityB,
-                                   &aConstrIter->entityC, &aConstrIter->entityD};
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr])
-      {
-        *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr];
-        myNeedToSolve = true;
-      }
-    }
-  }
-
-  // Update flags of entities to be used by constraints
-  for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
-    if (aConstrEnt[indAttr] != 0) {
-      int aPos = Search(aConstrEnt[indAttr], myEntities);
-      myEntOfConstr[aPos] = true;
-      // Sub-entities should be used implcitly
-      Slvs_hEntity* aEntPtr = myEntities[aPos].point;
-      while (*aEntPtr != 0) {
-        aPos = Search(*aEntPtr, myEntities);
-        myEntOfConstr[aPos] = true;
-        aEntPtr++;
-      }
-    }
-
-  checkConstraintConsistence(*aConstrIter);
-  return true;
-}
-
-// ============================================================================
-//  Function: changeRigidConstraint
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the "Rigid" constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeRigidConstraint(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
-  // Search this constraint in the current group to update it
-  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
-  std::vector<Slvs_Constraint>::iterator aConstrIter;
-  if (aConstrMapIter != myConstraintMap.end()) {
-    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
-    aConstrIter = myConstraints.begin() + aConstrPos;
-  }
-
-  // Get constraint type and verify the constraint parameters are correct
-  SketchSolver_Constraint aConstraint(theConstraint);
-  int aConstrType = aConstraint.getType();
-  if (aConstrType == SLVS_C_UNKNOWN
-      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
-    return false;
-  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
-  Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN;
-  std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
-      ModelAPI_AttributeRefAttr>(
-      theConstraint->data()->attribute(aConstraintAttributes[0]));
-  if (!aConstrAttr)
-    return false;
-
-  // Convert the object of the attribute to the feature
-  FeaturePtr aFeature;
-  if (aConstrAttr->isObject() && aConstrAttr->object()) {
-    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-        aConstrAttr->object());
-    if (!aRC)
-      return false;
-    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-    aFeature = aDoc->feature(aRC);
-  }
-
-  aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr());
-
-  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
-    // Check the fixed entity is not a point.
-    std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
-        ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0]));
-    std::shared_ptr<GeomDataAPI_Point> aPoint =
-        std::dynamic_pointer_cast<GeomDataAPI_Point>(aConstrAttr->attr());
-    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aConstrAttr->attr());
-    if (aPoint || aPoint2D || aFeature->getKind() == SketchPlugin_Point::ID()) {
-      // Create SolveSpace constraint structure
-      Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-          ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
-          aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-      myConstraints.push_back(aConstraint);
-      myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aConstraint.h);
-      int aConstrPos = Search(aConstraint.h, myConstraints);
-      aConstrIter = myConstraints.begin() + aConstrPos;
-      myNeedToSolve = true;
-    } else {
-      myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
-
-      // To avoid SolveSpace problems:
-      // * if the circle is rigid, we will fix its center and radius;
-      // * if the arc is rigid, we will fix its start and end points and radius.
-      double aRadius = 0.0;
-      bool isArc = false;
-      bool isCircle = false;
-      if (aFeature) {
-        if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
-          std::shared_ptr<GeomDataAPI_Point2D> aCenter =
-              std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-              aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
-          std::shared_ptr<GeomDataAPI_Point2D> aStart =
-              std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-              aFeature->data()->attribute(SketchPlugin_Arc::START_ID()));
-          aRadius = aStart->pnt()->distance(aCenter->pnt());
-          isArc = true;
-        } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
-          aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-              aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
-          isCircle = true;
-        }
-      }
-
-      // Get list of already fixed points
-      std::set<Slvs_hEntity> anAlreadyFixed;
-      std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
-      for (; aCIter != myConstraints.end(); aCIter++)
-        if (aCIter->type == SLVS_C_WHERE_DRAGGED)
-          anAlreadyFixed.insert(aCIter->ptA);
-
-      // Create constraints to fix the parameters of the entity
-      int aEntPos = Search(aConstrEnt, myEntities);
-      Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point;
-      if (isArc) aPointsPtr++; // avoid to fix center of arc
-      while (*aPointsPtr != 0) {
-        // Avoid to create additional "Rigid" constraints for coincident points
-        bool isCoincAlreadyFixed = false;
-        if (!anAlreadyFixed.empty()) {
-          if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end())
-            isCoincAlreadyFixed = true;
-
-          std::vector<std::set<Slvs_hEntity> >::const_iterator aCoincIter =
-              myCoincidentPoints.begin();
-          for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) {
-            if (aCoincIter->find(*aPointsPtr) == aCoincIter->end())
-              continue;
-            std::set<Slvs_hEntity>::const_iterator anIter = anAlreadyFixed.begin();
-            for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++)
-              if (aCoincIter->find(*anIter) != aCoincIter->end())
-                isCoincAlreadyFixed = true;
-          }
-        }
-
-        if (!isCoincAlreadyFixed) {
-          Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-              ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
-              *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-          myConstraints.push_back(aConstraint);
-          myConstraintMap[theConstraint].push_back(aConstraint.h);
-        }
-        aPointsPtr++;
-      }
-
-      if (isArc || isCircle) { // add radius constraint
-        Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-            ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius,
-            SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN);
-        myConstraints.push_back(aConstraint);
-        myConstraintMap[theConstraint].push_back(aConstraint.h);
-      }
-
-      // The object is already rigid, so there is no constraints added
-      if (myConstraintMap[theConstraint].empty()) {
-        myConstraintMap.erase(theConstraint);
-        myNeedToSolve = false;
-      }
-      else
-        myNeedToSolve = true;
-    }
-  }
-  return true;
-}
-
-// ============================================================================
-//  Function: changeMirrorConstraint
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the "Mirror" constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeMirrorConstraint(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
-  DataPtr aConstrData = theConstraint->data();
-
-  // Search this constraint in the current group to update it
-  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
-  std::vector<Slvs_Constraint>::iterator aConstrIter;
-  bool isExists = false;
-  if (aConstrMapIter != myConstraintMap.end()) {
-    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
-    aConstrIter = myConstraints.begin() + aConstrPos;
-    isExists = true;
-  }
-
-  // Get constraint type and verify the constraint parameters are correct
-  SketchSolver_Constraint aConstraint(theConstraint);
-  int aConstrType = aConstraint.getType();
-  if (aConstrType == SLVS_C_UNKNOWN
-      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
-    return false;
-  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
-  Slvs_hEntity aMirrorLineEnt = SLVS_E_UNKNOWN;
-  AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-      aConstrData->attribute(aConstraintAttributes[0]));
-  if (!aConstrAttr)
-    return false;
-
-  // Convert the object of the attribute to the feature
-  FeaturePtr aMirrorLineFeat;
-  if (aConstrAttr->isObject() && aConstrAttr->object()) {
-    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-        aConstrAttr->object());
-    if (!aRC)
-      return false;
-    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-    aMirrorLineFeat = aDoc->feature(aRC);
-  }
-  aMirrorLineEnt = aConstrAttr->isObject() ?
-      changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr());
-
-  // Append symmetric constraint for each point of mirroring features
-  AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-    aConstrData->attribute(aConstraintAttributes[1]));
-  AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-    aConstrData->attribute(aConstraintAttributes[2]));
-  if (!aBaseRefList || !aMirroredRefList)
-    return false;
-
-  std::list<ObjectPtr> aBaseList = aBaseRefList->list();
-  std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
-  // remove all empty items
-  std::list<ObjectPtr>::iterator anIt = aBaseList.begin();
-  std::list<ObjectPtr>::iterator aTmpIt;
-  while (anIt != aBaseList.end()) {
-    aTmpIt = anIt;
-    anIt++;
-    if (!(*aTmpIt))
-      aBaseList.erase(aTmpIt);
-  }
-  anIt = aMirroredList.begin();
-  while (anIt != aMirroredList.end()) {
-    aTmpIt = anIt;
-    anIt++;
-    if (!(*aTmpIt))
-      aMirroredList.erase(aTmpIt);
-  }
-  if (aBaseList.empty() || aBaseList.size() != aMirroredList.size())
-    return false;
-
-  std::vector<Slvs_hConstraint> aNewConstraints;
-  // Fill the list of already mirrored points
-  std::vector<Slvs_Constraint> anOldConstraints;
-  std::map<Slvs_hEntity, Slvs_hEntity> aMirroredPoints;
-  if (isExists) {
-    std::vector<Slvs_hConstraint>::const_iterator aCIter = aConstrMapIter->second.begin();
-    for (; aCIter != aConstrMapIter->second.end(); aCIter++) {
-      int anInd = Search(*aCIter, myConstraints);
-      if (myConstraints[anInd].type != aConstrType)
-        continue;
-      aMirroredPoints[myConstraints[anInd].ptA] = myConstraints[anInd].ptB;
-      anOldConstraints.push_back(myConstraints[anInd]);
-    }
-  }
-
-  FeaturePtr aBaseFeature, aMirrorFeature;
-  ResultConstructionPtr aRC;
-  std::list<ObjectPtr>::iterator aBaseIter = aBaseList.begin();
-  std::list<ObjectPtr>::iterator aMirIter = aMirroredList.begin();
-  for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) {
-    aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
-    aBaseFeature = aRC ? aRC->document()->feature(aRC) :
-        std::dynamic_pointer_cast<ModelAPI_Feature>(*aBaseIter);
-    aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirIter);
-    aMirrorFeature = aRC ? aRC->document()->feature(aRC) :
-        std::dynamic_pointer_cast<ModelAPI_Feature>(*aMirIter);
-
-    if (!aBaseFeature || !aMirrorFeature || 
-        aBaseFeature->getKind() != aMirrorFeature->getKind())
-      return false;
-    Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature);
-    Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature);
-    // Make aMirrorEnt parameters to be symmetric with aBaseEnt
-    makeMirrorEntity(aBaseEnt, aMirrorEnt, aMirrorLineEnt);
-
-    if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) {
-      Slvs_hConstraint anID = changeMirrorPoints(aBaseEnt, aMirrorEnt,
-          aMirrorLineEnt, anOldConstraints, aMirroredPoints);
-      aNewConstraints.push_back(anID);
-    } else {
-      int aBasePos = Search(aBaseEnt, myEntities);
-      int aMirrorPos = Search(aMirrorEnt, myEntities);
-      if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) {
-        for (int ind = 0; ind < 2; ind++) {
-          Slvs_hConstraint anID = changeMirrorPoints(myEntities[aBasePos].point[ind],
-              myEntities[aMirrorPos].point[ind], aMirrorLineEnt, anOldConstraints, aMirroredPoints);
-          aNewConstraints.push_back(anID);
-        }
-      } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
-        Slvs_hConstraint anID = changeMirrorPoints(myEntities[aBasePos].point[0],
-            myEntities[aMirrorPos].point[0], aMirrorLineEnt, anOldConstraints, aMirroredPoints);
-        aNewConstraints.push_back(anID);
-        // Additional constraint for equal radii
-        Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
-            ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0,
-            SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt);
-        myConstraints.push_back(anEqRadConstr);
-        myConstraintMap[theConstraint].push_back(anEqRadConstr.h);
-      } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
-        // Workaround to avoid problems in SolveSpace.
-        // The symmetry of two arcs will be done using symmetry of three points on these arcs:
-        // start point, end point, and any other point on the arc
-        Slvs_hEntity aBaseArcPoints[3] = {
-            myEntities[aBasePos].point[1],
-            myEntities[aBasePos].point[2],
-            SLVS_E_UNKNOWN};
-        Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
-            myEntities[aMirrorPos].point[2],
-            myEntities[aMirrorPos].point[1],
-            SLVS_E_UNKNOWN};
-        Slvs_hEntity aBothArcs[2] = {aBaseEnt, aMirrorEnt};
-        Slvs_hEntity aBothMiddlePoints[2];
-        for (int i = 0; i < 2; i++) {
-          double x, y;
-          calculateMiddlePoint(aBothArcs[i], x, y);
-          std::vector<Slvs_Param>::iterator aParamIter = myParams.end();
-          Slvs_hParam u = changeParameter(x, aParamIter);
-          Slvs_hParam v = changeParameter(y, aParamIter);
-          Slvs_Entity aPoint = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, u, v);
-          myEntities.push_back(aPoint);
-          myEntOfConstr.push_back(true);
-          aBothMiddlePoints[i] = aPoint.h;
-          // additional constraint point-on-curve
-          Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
-              ++myConstrMaxID, myID, SLVS_C_PT_ON_CIRCLE, myWorkplane.h, 0.0,
-              aPoint.h, SLVS_E_UNKNOWN, aBothArcs[i], SLVS_E_UNKNOWN);
-          myConstraints.push_back(aPonCircConstr);
-          myConstraintMap[theConstraint].push_back(aPonCircConstr.h);
-          aNewConstraints.push_back(aPonCircConstr.h);
-        }
-
-        aBaseArcPoints[2] = aBothMiddlePoints[0];
-        aMirrorArcPoints[2] = aBothMiddlePoints[1];
-        for (int ind = 0; ind < 3; ind++) {
-          Slvs_hConstraint anID = changeMirrorPoints(aBaseArcPoints[ind], aMirrorArcPoints[ind],
-              aMirrorLineEnt, anOldConstraints, aMirroredPoints);
-          aNewConstraints.push_back(anID);
-        }
-      }
-    }
-  }
-
-  // Remove unused constraints
-  std::vector<Slvs_Constraint>::const_iterator anOldCIter = anOldConstraints.begin();
-  for (; anOldCIter != anOldConstraints.end(); anOldCIter++) {
-    int anInd = Search(anOldCIter->h, myConstraints);
-    myConstraints.erase(myConstraints.begin() + anInd);
-  }
-  myConstraintMap[theConstraint] = aNewConstraints;
-
-  if (!isExists) {
-    // Set the mirror line unchanged during constraint recalculation
-    int aMirrorLinePos = Search(aMirrorLineEnt, myEntities);
-    // firstly check the line is not fixed yet
-    bool isFixed[2] = {false, false};
-    std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-    for (; aConstrIter != myConstraints.end() && !(isFixed[0] && isFixed[1]); aConstrIter++)
-      if (aConstrIter->type == SLVS_C_WHERE_DRAGGED) {
-        if (aConstrIter->ptA == myEntities[aMirrorLinePos].point[0])
-          isFixed[0] = true;
-        else if (aConstrIter->ptA == myEntities[aMirrorLinePos].point[1])
-          isFixed[1] = true;
-      }
-    // add new rigid constraints
-    if (!isFixed[0]) {
-      Slvs_Constraint aRigidStart = Slvs_MakeConstraint(
-          ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
-          myEntities[aMirrorLinePos].point[0], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-      myConstraints.push_back(aRigidStart);
-      myConstraintMap[theConstraint].push_back(aRigidStart.h);
-    }
-    if (!isFixed[1]) {
-      Slvs_Constraint aRigidEnd = Slvs_MakeConstraint(
-          ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
-          myEntities[aMirrorLinePos].point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-      myConstraints.push_back(aRigidEnd);
-      myConstraintMap[theConstraint].push_back(aRigidEnd.h);
-    }
-
-    // Add temporary constraints for initial objects to be unchanged
-    for (aBaseIter = aBaseList.begin(); aBaseIter != aBaseList.end(); aBaseIter++) {
-      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
-      aBaseFeature = aRC ? aRC->document()->feature(aRC) :
-          std::dynamic_pointer_cast<ModelAPI_Feature>(*aBaseIter);
-      if (!aBaseFeature) continue;
-      std::list<AttributePtr> aPoints = aBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
-      if (aBaseFeature->getKind() != SketchPlugin_Arc::ID()) {
-        std::list<AttributePtr>::iterator anIt = aPoints.begin();
-        for ( ; anIt != aPoints.end(); anIt++) {
-          addTemporaryConstraintWhereDragged(*anIt);
-        }
-      } else {
-        // Arcs are fixed by center and start points only (to avoid solving errors in SolveSpace)
-        AttributePtr aCenterAttr = aBaseFeature->attribute(SketchPlugin_Arc::CENTER_ID());
-        std::map<AttributePtr, Slvs_hEntity>::iterator aFound = myEntityAttrMap.find(aCenterAttr);
-        Slvs_hEntity anArcPoints[3] = {aFound->second, 0, 0};
-        AttributePtr aStartAttr = aBaseFeature->attribute(SketchPlugin_Arc::START_ID());
-        aFound = myEntityAttrMap.find(aStartAttr);
-        anArcPoints[1] = aFound->second;
-        AttributePtr aEndAttr = aBaseFeature->attribute(SketchPlugin_Arc::END_ID());
-        aFound = myEntityAttrMap.find(aEndAttr);
-        anArcPoints[2] = aFound->second;
-
-        bool isFixed[3] = {false, false, false};
-        int aNbFixed = 0; // number of already fixed points on the arc
-        for (int i = 0; i < 3; i++) {
-          std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
-          for (; aCoPtIter != myCoincidentPoints.end() && !isFixed[i]; aCoPtIter++) {
-            if (aCoPtIter->find(anArcPoints[i]) == aCoPtIter->end())
-              continue;  // the entity was not found in current set
-
-            // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
-            std::vector<Slvs_Constraint>::iterator aConstrIter = myConstraints.begin();
-            for (; aConstrIter != myConstraints.end(); aConstrIter++)
-              if (aConstrIter->type == SLVS_C_WHERE_DRAGGED && 
-                  aCoPtIter->find(aConstrIter->ptA) != aCoPtIter->end()) {
-                isFixed[i] = true;
-                aNbFixed++;
-                break;  // the SLVS_C_WHERE_DRAGGED constraint already exists
-              }
-          }
-        }
-        if (aNbFixed < 2) { // append constraints
-          if (!isFixed[0])
-            addTemporaryConstraintWhereDragged(aCenterAttr);
-          if (!isFixed[1] && (isFixed[0] || aNbFixed == 0))
-            addTemporaryConstraintWhereDragged(aStartAttr);
-        }
-      }
-    }
-  }
-  return true;
-}
-
-// ============================================================================
-//  Function: changeFilletConstraint
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the "Fillet" constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeFilletConstraint(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
-  DataPtr aConstrData = theConstraint->data();
-
-  // Search this constraint in the current group to update it
-  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
-  std::vector<Slvs_Constraint>::iterator aConstrIter;
-  if (aConstrMapIter != myConstraintMap.end()) {
-    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
-    aConstrIter = myConstraints.begin() + aConstrPos;
-  }
-
-  // Get constraint type and verify the constraint parameters are correct
-  SketchSolver_Constraint aConstraint(theConstraint);
-  int aConstrType = aConstraint.getType();
-  if (aConstrType == SLVS_C_UNKNOWN)
-    return false;
-  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
-  // Obtain hEntity for basic objects of fillet
-  Slvs_hEntity aBaseObject[2];
-  FeaturePtr aBaseFeature[2];
-  for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
-    AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-        aConstrData->attribute(aConstraintAttributes[indAttr]));
-    if (!aConstrAttr)
-      return false;
-    if (aConstrAttr->isObject() && aConstrAttr->object()) {
-      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-          aConstrAttr->object());
-      if (!aRC)
-        return false;
-      std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-      aBaseFeature[indAttr] = aDoc->feature(aRC);
-    }
-    aBaseObject[indAttr] = aConstrAttr->isObject() ?
-        changeEntityFeature(aBaseFeature[indAttr]) : changeEntity(aConstrAttr->attr());
-  }
-  // Check the base entities have a coincident point
-  int aBaseObjInd[2] = {
-      Search(aBaseObject[0], myEntities),
-      Search(aBaseObject[1], myEntities)
-    };
-  int aShift[2] = { // shift for calculating correct start and end points for different types of objects
-      myEntities[aBaseObjInd[0]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
-      myEntities[aBaseObjInd[1]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
-    };
-  Slvs_hEntity aFirstObjPoints[2] = { // indices of start and end point of first object
-      myEntities[aBaseObjInd[0]].point[aShift[0]],
-      myEntities[aBaseObjInd[0]].point[1+aShift[0]]
-    };
-  Slvs_hEntity aSecondObjPoints[2] = { // indices of start and end point of second object
-      myEntities[aBaseObjInd[1]].point[aShift[1]],
-      myEntities[aBaseObjInd[1]].point[1+aShift[1]]
-    };
-  bool isCoincidentFound = false;
-  int aBaseCoincInd[2] = {0, 0}; // indices in aFirstObjPoint and aSecondObjPoint identifying coincident points
-  std::vector<std::set<Slvs_hEntity> >::iterator aCPIter = myCoincidentPoints.begin();
-  for ( ; aCPIter != myCoincidentPoints.end() && !isCoincidentFound; aCPIter++)
-    for (int ind1 = 0; ind1 < 2 && !isCoincidentFound; ind1++)
-      for (int ind2 = 0; ind2 < 2 && !isCoincidentFound; ind2++)
-        if (aCPIter->find(aFirstObjPoints[ind1]) != aCPIter->end() &&
-            aCPIter->find(aSecondObjPoints[ind2]) != aCPIter->end()) {
-          aBaseCoincInd[0] = ind1;
-          aBaseCoincInd[1] = ind2;
-          isCoincidentFound = true;
-        }
-  if (!isCoincidentFound) {
-    // There is no coincident points between objects. Generate error message
-    Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
-    return false;
-  }
-
-  // Create fillet entities
-  // - first object is placed on the first base 
-  // - second object is on the second base 
-  // - third object is a filleting arc
-  static const int aNbFilletEnt = 3;
-  Slvs_hEntity aFilletEnt[aNbFilletEnt];
-  int aFilletObjInd[aNbFilletEnt];
-  AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-      aConstrData->attribute(aConstraintAttributes[2]));
-  if (!aFilletRefList)
-    return false;
-  std::list<ObjectPtr> aFilletList = aFilletRefList->list();
-  if (aFilletList.size() < aNbFilletEnt)
-    return false;
-  FeaturePtr aFilletFeature;
-  ResultConstructionPtr aRC;
-  std::list<ObjectPtr>::iterator aFilIter = aFilletList.begin();
-  for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) {
-    aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aFilIter);
-    aFilletFeature = aRC ? aRC->document()->feature(aRC) :
-        std::dynamic_pointer_cast<ModelAPI_Feature>(*aFilIter);
-    if (!aFilletFeature)
-      return false;
-    aFilletEnt[indEnt] = changeEntityFeature(aFilletFeature);
-    if (aFilletEnt[indEnt] == SLVS_E_UNKNOWN)
-      return false; // not all attributes are initialized yet
-    aFilletObjInd[indEnt] = Search(aFilletEnt[indEnt], myEntities);
-  }
-  // At first time, for correct result, move floating points of fillet on the middle points of base objects
-  if (myConstraintMap.find(theConstraint) == myConstraintMap.end()) {
-    double anArcPoints[6];
-    for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
-      int anIndShift = myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
-      int aPointsPos[2] = {
-          Search(myEntities[aFilletObjInd[indEnt]].point[anIndShift], myEntities),
-          Search(myEntities[aFilletObjInd[indEnt]].point[1+anIndShift], myEntities)
-        };
-      int aParamPos[2] = {
-          Search(myEntities[aPointsPos[0]].param[0], myParams),
-          Search(myEntities[aPointsPos[1]].param[0], myParams)
-        };
-      int anIndex = aParamPos[aBaseCoincInd[indEnt]];
-      if (anIndShift == 0) {
-        myParams[anIndex].val =
-            0.5 * (myParams[aParamPos[0]].val + myParams[aParamPos[1]].val);
-        myParams[1 + anIndex].val =
-            0.5 * (myParams[1 + aParamPos[0]].val + myParams[1 + aParamPos[1]].val);
-      } else { // place the changed point on the arc
-        double x = 0, y = 0;
-        calculateMiddlePoint(aFilletEnt[indEnt], x, y);
-        myParams[anIndex].val = x;
-        myParams[1 + anIndex].val = y;
-      }
-      anArcPoints[indEnt*2+2] = myParams[anIndex].val;
-      anArcPoints[indEnt*2+3] = myParams[1 + anIndex].val;
-    }
-    anArcPoints[0] = 0.5 * (anArcPoints[2] + anArcPoints[4]);
-    anArcPoints[1] = 0.5 * (anArcPoints[3] + anArcPoints[5]);
-    for (int indArcPt = 0; indArcPt < 3; indArcPt++) {
-      int aPtPos = Search(myEntities[aFilletObjInd[2]].point[indArcPt], myEntities);
-      int aParamPos = Search(myEntities[aPtPos].param[0], myParams);
-      myParams[aParamPos].val = anArcPoints[indArcPt * 2];
-      myParams[aParamPos + 1].val = anArcPoints[indArcPt * 2 + 1];
-    }
-  }
-
-  // Create list of constraints to generate fillet
-  int aPtInd;
-  std::vector<Slvs_hConstraint> aConstrList;
-  bool isExists = myConstraintMap.find(theConstraint) != myConstraintMap.end(); // constraint already exists
-  std::vector<Slvs_hConstraint>::iterator aCMapIter =
-    isExists ? myConstraintMap[theConstraint].begin() : aConstrList.begin();
-  std::vector<Slvs_hConstraint>::iterator aCMapEnd =
-    isExists ? myConstraintMap[theConstraint].end() : aConstrList.end();
-  int aCurConstrPos = isExists ? Search(*aCMapIter, myConstraints) : 0;
-  for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
-    // one point of fillet object should be coincident with the point on base, non-coincident with another base object
-    aPtInd = 1-aBaseCoincInd[indEnt]+aShift[indEnt]; // (1-aBaseCoincInd[indEnt]) = index of non-coincident point, aShift is used to process all types of shapes
-    Slvs_hEntity aPtBase = myEntities[aBaseObjInd[indEnt]].point[aPtInd];
-    Slvs_hEntity aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
-    if (isExists) {
-      myConstraints[aCurConstrPos].ptA = aPtBase;
-      myConstraints[aCurConstrPos].ptB = aPtFillet;
-      aCMapIter++;
-      aCurConstrPos = Search(*aCMapIter, myConstraints);
-    } else if (addCoincidentPoints(aPtBase, aPtFillet)) { // the points are not connected by coincidence yet
-      Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
-          ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
-          0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-      myConstraints.push_back(aCoincConstr);
-      aConstrList.push_back(aCoincConstr.h);
-    }
-
-    // another point of fillet object should be placed on the base object
-    Slvs_Constraint aPonCurveConstr;
-    int aTangentType;
-    if (myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE) {
-      // centers of arcs should be coincident
-      aPtBase = myEntities[aBaseObjInd[indEnt]].point[0];
-      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[0];
-      if (isExists) {
-        myConstraints[aCurConstrPos].ptA = aPtBase;
-        myConstraints[aCurConstrPos].ptB = aPtFillet;
-        aCMapIter++;
-        if (aCMapIter != aCMapEnd)
-          aCurConstrPos = Search(*aCMapIter, myConstraints);
-      } else if (addCoincidentPoints(aPtBase, aPtFillet)) { // the points are not connected by coincidence yet
-        aPonCurveConstr = Slvs_MakeConstraint(
-            ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
-            0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-      }
-      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[1+aBaseCoincInd[indEnt]]; // !!! will be used below
-      aTangentType = SLVS_C_CURVE_CURVE_TANGENT;
-    } else {
-      aPtInd = aBaseCoincInd[indEnt];
-      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
-      if (isExists) {
-        myConstraints[aCurConstrPos].ptA = aPtFillet;
-        aCMapIter++;
-        if (aCMapIter != aCMapEnd)
-          aCurConstrPos = Search(*aCMapIter, myConstraints);
-      } else {
-        aPonCurveConstr = Slvs_MakeConstraint(
-            ++myConstrMaxID, myID, SLVS_C_PT_ON_LINE, myWorkplane.h,
-            0, aPtFillet, SLVS_E_UNKNOWN, aBaseObject[indEnt], SLVS_E_UNKNOWN);
-      }
-      aTangentType = SLVS_C_ARC_LINE_TANGENT;
-    }
-    if (!isExists) {
-      myConstraints.push_back(aPonCurveConstr);
-      aConstrList.push_back(aPonCurveConstr.h);
-    }
-  }
-
-  if (!isExists)
-    myConstraintMap[theConstraint] = aConstrList;
-
-  // Additional temporary constraints for base objects to be fixed
-  int aNbArcs = 0;
-  for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
-    if (!aBaseFeature[indAttr]) {
-      AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-          aConstrData->attribute(aConstraintAttributes[indAttr]));
-      addTemporaryConstraintWhereDragged(aConstrAttr->attr());
-      continue;
-    }
-    if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Line::ID()) {
-      addTemporaryConstraintWhereDragged(
-          aBaseFeature[indAttr]->attribute(SketchPlugin_Line::START_ID()));
-      addTemporaryConstraintWhereDragged(
-          aBaseFeature[indAttr]->attribute(SketchPlugin_Line::END_ID()));
-    } else if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Arc::ID()) {
-      // Arc should be fixed by its center only (to avoid "conflicting constraints" message)
-      // If the fillet is made on two arc, the shared point should be fixed too
-      aNbArcs++;
-      addTemporaryConstraintWhereDragged(
-          aBaseFeature[indAttr]->attribute(SketchPlugin_Arc::CENTER_ID()));
-    }
-  }
-  if (aNbArcs == 2) {
-      addTemporaryConstraintWhereDragged(aBaseCoincInd[0] == 0 ?
-          aBaseFeature[0]->attribute(SketchPlugin_Arc::START_ID()) : 
-          aBaseFeature[0]->attribute(SketchPlugin_Arc::END_ID()));
-  }
-  return true;
-}
-
-// ============================================================================
-//  Function: changeEntity
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the element affected by any constraint
-// ============================================================================
-Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
-    std::shared_ptr<ModelAPI_Attribute> theEntity)
-{
-  // If the entity is already in the group, try to find it
-  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
-      myEntityAttrMap.find(theEntity);
-  int aEntPos;
-  std::vector<Slvs_Param>::iterator aParamIter;  // looks at first parameter of already existent entity or at the end of vector otherwise
-  if (aEntIter == myEntityAttrMap.end())  // no such entity => should be created
-    aParamIter = myParams.end();
-  else {  // the entity already exists
-    aEntPos = Search(aEntIter->second, myEntities);
-    int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
-    aParamIter = myParams.begin() + aParamPos;
-  }
-  const bool isEntExists = (aEntIter != myEntityAttrMap.end());  // defines that the entity already exists
-  const bool isNeedToSolve = myNeedToSolve;
-  myNeedToSolve = false;
-
-  if (isEntExists) {
-    // Verify that the entity is not used by "Rigid" constraint.
-    // If it is used, the object should not move.
-    std::vector<std::set<Slvs_hEntity> >::iterator aCoincIter = myCoincidentPoints.begin();
-    for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
-      if (aCoincIter->find(aEntIter->second) != aCoincIter->end())
-        break;
-    std::set<Slvs_hEntity> aCoincident;
-    if (aCoincIter != myCoincidentPoints.end()) {
-      aCoincident = *aCoincIter;
-      aCoincident.erase(aEntIter->second);
-
-      std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-      for (; aConstrIter != myConstraints.end(); aConstrIter++)
-        if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
-            aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
-          myNeedToSolve = true;
-          return aEntIter->second;
-        }
-    }
-  }
-
-  // Look over supported types of entities
-  Slvs_Entity aNewEntity;
-  aNewEntity.h = SLVS_E_UNKNOWN;
-
-  // Point in 3D
-  std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
-      theEntity);
-  if (aPoint) {
-    Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
-    Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
-    Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
-    if (!isEntExists) // New entity
-      aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
-  } else {
-    // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
-    if (myWorkplane.h == SLVS_E_UNKNOWN)
-      return SLVS_E_UNKNOWN;
-
-    // Point in 2D
-    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
-    if (aPoint2D) {
-      Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
-      Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
-      if (!isEntExists) // New entity
-        aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
-    } else {
-      // Scalar value (used for the distance entities)
-      AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
-      if (aScalar) {
-        Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
-        if (!isEntExists) // New entity
-          aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
-      }
-    }
-  }
-  /// \todo Other types of entities
-
-  Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type
-
-  if (isEntExists) {
-    myNeedToSolve = myNeedToSolve || isNeedToSolve;
-    aResult = aEntIter->second;
-  } else if (aNewEntity.h != SLVS_E_UNKNOWN) {
-    myEntities.push_back(aNewEntity);
-    myEntOfConstr.push_back(false);
-    myEntityAttrMap[theEntity] = aNewEntity.h;
-    aResult = aNewEntity.h;
-  }
-
-  // If the attribute was changed by the user, we need to fix it before solving
-  if (myNeedToSolve && theEntity->isImmutable())
-    addTemporaryConstraintWhereDragged(theEntity, false);
-
-  return aResult;
-}
-
-// ============================================================================
-//  Function: changeEntity
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the element defined by the feature affected by any constraint
-// ============================================================================
-Slvs_hEntity SketchSolver_ConstraintGroup::changeEntityFeature(FeaturePtr theEntity)
-{
-  if (!theEntity->data()->isValid())
-    return SLVS_E_UNKNOWN;
-  // If the entity is already in the group, try to find it
-  std::map<FeaturePtr, Slvs_hEntity>::const_iterator aEntIter = myEntityFeatMap.find(theEntity);
-  // defines that the entity already exists
-  const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
-  
-  Slvs_Entity aNewEntity;
-  aNewEntity.h = SLVS_E_UNKNOWN;
-
-  // SketchPlugin features
-  std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
-      SketchPlugin_Feature>(theEntity);
-  if (aFeature) {  // Verify the feature by its kind
-    const std::string& aFeatureKind = aFeature->getKind();
-    AttributePtr anAttribute;
-
-    // Line
-    if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aStart = changeEntity(anAttribute);
-
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aEnd = changeEntity(anAttribute);
-
-      if (!isEntExists) // New entity
-        aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
-    }
-    // Circle
-    else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aCenter = changeEntity(anAttribute);
-
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aRadius = changeEntity(anAttribute);
-
-      if (!isEntExists) // New entity
-        aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter,
-                                     myWorkplane.normal, aRadius);
-    }
-    // Arc
-    else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aCenter = changeEntity(anAttribute);
-
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aStart = changeEntity(anAttribute);
-
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aEnd = changeEntity(anAttribute);
-
-      if (!isEntExists)
-        aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h,
-                                          myWorkplane.normal, aCenter, aStart, aEnd);
-    }
-    // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
-    else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) {
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aPoint = changeEntity(anAttribute);
-
-      if (isEntExists)
-        return aEntIter->second;
-
-      // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
-      myEntityFeatMap[theEntity] = aPoint;
-      myNeedToSolve = true;
-      return aPoint;
-    }
-  }
-  /// \todo Other types of features
-
-  if (isEntExists)
-    return aEntIter->second;
-
-  if (aNewEntity.h != SLVS_E_UNKNOWN) {
-    myEntities.push_back(aNewEntity);
-    myEntOfConstr.push_back(false);
-    myEntityFeatMap[theEntity] = aNewEntity.h;
-    myNeedToSolve = true;
-    return aNewEntity.h;
-  }
-
-  // Unsupported or wrong entity type
-  return SLVS_E_UNKNOWN;
-}
-
-// ============================================================================
-//  Function: changeNormal
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the normal of workplane
-// ============================================================================
-Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal(
-    std::shared_ptr<ModelAPI_Attribute> theDirX,
-    std::shared_ptr<ModelAPI_Attribute> theNorm)
-{
-  std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNorm);
-  std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
-  if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance))
-    return SLVS_E_UNKNOWN;
-  // calculate Y direction
-  std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
-
-  // quaternion parameters of normal vector
-  double qw, qx, qy, qz;
-  Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
-                      &qx, &qy, &qz);
-  double aNormCoord[4] = { qw, qx, qy, qz };
-
-  // Try to find existent normal
-  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
-      myEntityAttrMap.find(theNorm);
-  std::vector<Slvs_Param>::iterator aParamIter;  // looks to the first parameter of already existent entity or to the end of vector otherwise
-  if (aEntIter == myEntityAttrMap.end())  // no such entity => should be created
-    aParamIter = myParams.end();
-  else {  // the entity already exists, update it
-    int aEntPos = Search(aEntIter->second, myEntities);
-    int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
-    aParamIter = myParams.begin() + aParamPos;
-  }
-
-  // Change parameters of the normal
-  Slvs_hParam aNormParams[4];
-  for (int i = 0; i < 4; i++)
-    aNormParams[i] = changeParameter(aNormCoord[i], aParamIter);
-
-  if (aEntIter != myEntityAttrMap.end())  // the entity already exists
-    return aEntIter->second;
-
-  // Create a normal
-  Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, aNormParams[0], aNormParams[1],
-                                          aNormParams[2], aNormParams[3]);
-  myEntities.push_back(aNormal);
-  myEntOfConstr.push_back(false);
-  myEntityAttrMap[theNorm] = aNormal.h;
-  return aNormal.h;
-}
-
-// ============================================================================
-//  Function: addWorkplane
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create workplane for the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::addWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch)
-{
-  if (myWorkplane.h || theSketch->getKind().compare(SketchPlugin_Sketch::ID()) != 0)
-    return false;  // the workplane already exists or the function parameter is not Sketch
-
-  mySketch = theSketch;
-  updateWorkplane();
-  return true;
-}
-
-// ============================================================================
-//  Function: updateWorkplane
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  update parameters of workplane
-// ============================================================================
-bool SketchSolver_ConstraintGroup::updateWorkplane()
-{
-  if (!mySketch->data())
-    return false; // case sketch is deleted
-  // Get parameters of workplane
-  std::shared_ptr<ModelAPI_Attribute> aDirX = mySketch->data()->attribute(
-      SketchPlugin_Sketch::DIRX_ID());
-  std::shared_ptr<ModelAPI_Attribute> aNorm = mySketch->data()->attribute(
-      SketchPlugin_Sketch::NORM_ID());
-  std::shared_ptr<ModelAPI_Attribute> anOrigin = mySketch->data()->attribute(
-      SketchPlugin_Sketch::ORIGIN_ID());
-  // Transform them into SolveSpace format
-  Slvs_hEntity aNormalWP = changeNormal(aDirX, aNorm);
-  if (!aNormalWP)
-    return false;
-  Slvs_hEntity anOriginWP = changeEntity(anOrigin);
-  if (!anOriginWP)
-    return false;
-
-  if (!myWorkplane.h) {
-    // Create workplane
-    myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
-    // Workplane should be added to the list of entities
-    myEntities.push_back(myWorkplane);
-    myEntOfConstr.push_back(false);
-  }
-  return true;
-}
-
-// ============================================================================
-//  Function: changeParameter
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update value of parameter
-// ============================================================================
-Slvs_hParam SketchSolver_ConstraintGroup::changeParameter(
-    double theParam, std::vector<Slvs_Param>::iterator& thePrmIter)
-{
-  if (thePrmIter != myParams.end()) {  // Parameter should be updated
-    int aParamPos = thePrmIter - myParams.begin();
-    if (fabs(thePrmIter->val - theParam) > tolerance) {
-      myNeedToSolve = true;  // parameter is changed, need to resolve constraints
-      myParams[aParamPos].val = theParam;
-    }
-    thePrmIter++;
-    return myParams[aParamPos].h;
-  }
-
-  // Newly created parameter
-  Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
-  myParams.push_back(aParam);
-  myNeedToSolve = true;
-  // The list of parameters is changed, move iterator to the end of the list to avoid problems
-  thePrmIter = myParams.end();
-  return aParam.h;
-}
-
-// ============================================================================
-//  Function: resolveConstraints
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  solve the set of constraints for the current group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::resolveConstraints()
-{
-  if (!myNeedToSolve)
-    return false;
-
-  myConstrSolver.setGroupID(myID);
-  myConstrSolver.setParameters(myParams);
-  myConstrSolver.setEntities(myEntities);
-  myConstrSolver.setConstraints(myConstraints);
-  myConstrSolver.setDraggedParameters(myTempPointWhereDragged);
-
-  int aResult = myConstrSolver.solve();
-  if (aResult == SLVS_RESULT_OKAY) {  // solution succeeded, store results into correspondent attributes
-                                      // Obtain result into the same list of parameters
-    if (!myConstrSolver.getResult(myParams))
-      return true;
-
-    // We should go through the attributes map, because only attributes have valued parameters
-    std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntIter =
-        myEntityAttrMap.begin();
-    for (; anEntIter != myEntityAttrMap.end(); anEntIter++) {
-      if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
-        anEntIter->first->owner()->data()->blockSendAttributeUpdated(true);
-      if (updateAttribute(anEntIter->first, anEntIter->second))
-        updateRelatedConstraints(anEntIter->first);
-    }
-    updateFilletConstraints();
-    // unblock all features then
-    for (anEntIter = myEntityAttrMap.begin(); anEntIter != myEntityAttrMap.end(); anEntIter++) {
-      if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
-        anEntIter->first->owner()->data()->blockSendAttributeUpdated(false);
-    }
-  } else if (!myConstraints.empty())
-    Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
-
-  removeTemporaryConstraints();
-  myNeedToSolve = false;
-  return true;
-}
-
-// ============================================================================
-//  Function: mergeGroups
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  append specified group to the current group
-// ============================================================================
-void SketchSolver_ConstraintGroup::mergeGroups(const SketchSolver_ConstraintGroup& theGroup)
-{
-  // If specified group is empty, no need to merge
-  if (theGroup.myConstraintMap.empty())
-    return;
-
-  // Map between old and new indexes of SolveSpace constraints
-  std::map<Slvs_hConstraint, Slvs_hConstraint> aConstrMap;
-
-  // Add all constraints from theGroup to the current group
-  ConstraintMap::const_iterator aConstrIter = theGroup.myConstraintMap.begin();
-  for (; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++)
-    if (changeConstraint(aConstrIter->first))
-      aConstrMap[aConstrIter->second.back()] = myConstrMaxID;  // the constraint was added => store its ID
-
-  // Add temporary constraints from theGroup
-  std::list<Slvs_hConstraint>::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin();
-  for (; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++) {
-    std::map<Slvs_hConstraint, Slvs_hConstraint>::iterator aFind = aConstrMap.find(
-        *aTempConstrIter);
-    if (aFind != aConstrMap.end())
-      myTempConstraints.push_back(aFind->second);
-  }
-
-  if (myTempPointWhereDragged.empty())
-    myTempPointWhereDragged = theGroup.myTempPointWhereDragged;
-  else if (!theGroup.myTempPointWhereDragged.empty()) {  // Need to create additional transient constraint
-    std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aFeatureIter =
-        theGroup.myEntityAttrMap.begin();
-    for (; aFeatureIter != theGroup.myEntityAttrMap.end(); aFeatureIter++)
-      if (aFeatureIter->second == myTempPointWDrgdID) {
-        addTemporaryConstraintWhereDragged(aFeatureIter->first);
-        break;
-      }
-  }
-
-  myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve;
-}
-
-// ============================================================================
-//  Function: splitGroup
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  divide the group into several subgroups
-// ============================================================================
-void SketchSolver_ConstraintGroup::splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts)
-{
-  // Divide constraints and entities into several groups
-  std::vector<std::set<Slvs_hEntity> > aGroupsEntities;
-  std::vector<std::set<Slvs_hConstraint> > aGroupsConstr;
-  int aMaxNbEntities = 0;  // index of the group with maximal nuber of elements (this group will be left in the current)
-  std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-  for (; aConstrIter != myConstraints.end(); aConstrIter++) {
-    Slvs_hEntity aConstrEnt[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA,
-        aConstrIter->entityB };
-    std::vector<int> anIndexes;
-    // Go through the groupped entities and find even one of entities of current constraint
-    std::vector<std::set<Slvs_hEntity> >::iterator aGrEntIter;
-    for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++) {
-      bool isFound = false;
-      for (int i = 0; i < 4 && !isFound; i++)
-        if (aConstrEnt[i] != 0) {
-          isFound = (aGrEntIter->find(aConstrEnt[i]) != aGrEntIter->end());
-          // Also we need to check sub-entities
-          int aEntPos = Search(aConstrEnt[i], myEntities);
-          if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
-            Slvs_hEntity* aSub = myEntities[aEntPos].point;
-            for (int j = 0; *aSub != 0 && j < 4 && !isFound; aSub++, j++)
-              isFound = (aGrEntIter->find(*aSub) != aGrEntIter->end());
-          }
-        }
-      if (isFound)
-        anIndexes.push_back(aGrEntIter - aGroupsEntities.begin());
-    }
-    // Add new group if no one is found
-    if (anIndexes.empty()) {
-      std::set<Slvs_hEntity> aNewGrEnt;
-      for (int i = 0; i < 4; i++)
-        if (aConstrEnt[i] != 0) {
-          aNewGrEnt.insert(aConstrEnt[i]);
-          int aEntPos = Search(aConstrEnt[i], myEntities);
-          if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
-            Slvs_hEntity* aSub = myEntities[aEntPos].point;
-            for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
-              aNewGrEnt.insert(*aSub);
-          }
-        }
-      std::set<Slvs_hConstraint> aNewGrConstr;
-      aNewGrConstr.insert(aConstrIter->h);
-
-      aGroupsEntities.push_back(aNewGrEnt);
-      aGroupsConstr.push_back(aNewGrConstr);
-      if (aNewGrEnt.size() > aGroupsEntities[aMaxNbEntities].size())
-        aMaxNbEntities = aGroupsEntities.size() - 1;
-    } else {  // Add entities indexes into the found group
-      aGrEntIter = aGroupsEntities.begin() + anIndexes.front();
-      for (int i = 0; i < 4; i++)
-        if (aConstrEnt[i] != 0) {
-          aGrEntIter->insert(aConstrEnt[i]);
-          int aEntPos = Search(aConstrEnt[i], myEntities);
-          if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
-            Slvs_hEntity* aSub = myEntities[aEntPos].point;
-            for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
-              aGrEntIter->insert(*aSub);
-          }
-        }
-      aGroupsConstr[anIndexes.front()].insert(aConstrIter->h);
-      if (aGrEntIter->size() > aGroupsEntities[aMaxNbEntities].size())
-        aMaxNbEntities = aGrEntIter - aGroupsEntities.begin();
-      if (anIndexes.size() > 1) {  // There are found several connected groups, merge them
-        std::vector<std::set<Slvs_hEntity> >::iterator aFirstGroup = aGroupsEntities.begin()
-            + anIndexes.front();
-        std::vector<std::set<Slvs_hConstraint> >::iterator aFirstConstr = aGroupsConstr.begin()
-            + anIndexes.front();
-        std::vector<int>::iterator anInd = anIndexes.begin();
-        for (++anInd; anInd != anIndexes.end(); anInd++) {
-          aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end());
-          aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end());
-        }
-        if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size())
-          aMaxNbEntities = anIndexes.front();
-        // Remove merged groups
-        for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--) {
-          aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd));
-          aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd));
-        }
-      }
-    }
-  }
-
-  if (aGroupsEntities.size() <= 1)
-    return;
-
-  // Remove the group with maximum elements as it will be left in the current group
-  aGroupsEntities.erase(aGroupsEntities.begin() + aMaxNbEntities);
-  aGroupsConstr.erase(aGroupsConstr.begin() + aMaxNbEntities);
-
-  // Add new groups of constraints and divide current group
-  std::vector<SketchSolver_ConstraintGroup*> aNewGroups;
-  for (int i = aGroupsEntities.size(); i > 0; i--) {
-    SketchSolver_ConstraintGroup* aG = new SketchSolver_ConstraintGroup(mySketch);
-    aNewGroups.push_back(aG);
-  }
-  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.begin();
-  int aConstrMapPos = 0;  // position of iterator in the map (used to restore iterator after removing constraint)
-  while (aConstrMapIter != myConstraintMap.end()) {
-    std::vector<std::set<Slvs_hConstraint> >::const_iterator aGIter = aGroupsConstr.begin();
-    std::vector<SketchSolver_ConstraintGroup*>::iterator aGroup = aNewGroups.begin();
-    for (; aGIter != aGroupsConstr.end(); aGIter++, aGroup++)
-      if (aGIter->find(aConstrMapIter->second.front()) != aGIter->end()) {
-        (*aGroup)->changeConstraint(aConstrMapIter->first);
-        removeConstraint(aConstrMapIter->first);
-        // restore iterator
-        aConstrMapIter = myConstraintMap.begin();
-        for (int i = 0; i < aConstrMapPos; i++)
-          aConstrMapIter++;
-        break;
-      }
-    if (aGIter == aGroupsConstr.end()) {
-      aConstrMapIter++;
-      aConstrMapPos++;
-    }
-  }
-
-  theCuts.insert(theCuts.end(), aNewGroups.begin(), aNewGroups.end());
-}
-
-// ============================================================================
-//  Function: updateGroup
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  search removed entities and constraints
-// ============================================================================
-bool SketchSolver_ConstraintGroup::updateGroup()
-{
-  ConstraintMap::reverse_iterator aConstrIter = myConstraintMap.rbegin();
-  bool isAllValid = true;
-  bool isCCRemoved = false;  // indicates that at least one of coincidence constraints was removed
-  int aConstrIndex = 0;
-  while (/*isAllValid && */aConstrIter != myConstraintMap.rend()) {
-    if (!aConstrIter->first->data() || !aConstrIter->first->data()->isValid()) {
-      if (aConstrIter->first->getKind().compare(SketchPlugin_ConstraintCoincidence::ID()) == 0)
-        isCCRemoved = true;
-      removeConstraint(aConstrIter->first);
-      isAllValid = false;
-      // Get back the correct position of iterator after the "remove" operation
-      aConstrIter = myConstraintMap.rbegin();
-      for (int i = 0; i < aConstrIndex && aConstrIter != myConstraintMap.rend(); i++)
-        aConstrIter++;
-    } else {
-      aConstrIter++;
-      aConstrIndex++;
-    }
-  }
-
-  // Check if some entities are invalid too
-  std::set<Slvs_hEntity> anEntToRemove;
-  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
-      anAttrIter = myEntityAttrMap.begin();
-  while (anAttrIter != myEntityAttrMap.end()) {
-    if (!anAttrIter->first->owner() || !anAttrIter->first->owner()->data() ||
-        !anAttrIter->first->owner()->data()->isValid()) {
-      anEntToRemove.insert(anAttrIter->second);
-      std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
-          aRemovedIter = anAttrIter;
-      anAttrIter++;
-      myEntityAttrMap.erase(aRemovedIter);
-    } else
-      anAttrIter++;
-  }
-  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myEntityFeatMap.begin();
-  while (aFeatIter != myEntityFeatMap.end()) {
-    if (!aFeatIter->first || !aFeatIter->first->data() ||
-        !aFeatIter->first->data()->isValid()) {
-      anEntToRemove.insert(aFeatIter->second);
-      std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = aFeatIter;
-      aFeatIter++;
-      myEntityFeatMap.erase(aRemovedIter);
-    } else
-      aFeatIter++;
-  }
-  removeEntitiesById(anEntToRemove);
-
-  // Probably, need to update coincidence constraints
-  if (isCCRemoved && !myExtraCoincidence.empty()) {
-    // Make a copy, because the new list of unused constrtaints will be generated
-    std::set<std::shared_ptr<SketchPlugin_Constraint> > anExtraCopy = myExtraCoincidence;
-    myExtraCoincidence.clear();
-
-    std::set<std::shared_ptr<SketchPlugin_Constraint> >::iterator aCIter = anExtraCopy.begin();
-    for (; aCIter != anExtraCopy.end(); aCIter++)
-      if ((*aCIter)->data() && (*aCIter)->data()->isValid())
-        changeConstraint(*aCIter);
-  }
-
-  return !isAllValid;
-}
-
-// ============================================================================
-//  Function: updateAttribute
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  update features of sketch after resolving constraints
-// ============================================================================
-bool SketchSolver_ConstraintGroup::updateAttribute(
-    std::shared_ptr<ModelAPI_Attribute> theAttribute, const Slvs_hEntity& theEntityID)
-{
-  // Search the position of the first parameter of the entity
-  int anEntPos = Search(theEntityID, myEntities);
-  int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
-
-  // Look over supported types of entities
-
-  // Point in 3D
-  std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
-      theAttribute);
-  if (aPoint) {
-    if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance
-        || fabs(aPoint->y() - myParams[aFirstParamPos + 1].val) > tolerance
-        || fabs(aPoint->z() - myParams[aFirstParamPos + 2].val) > tolerance) {
-      aPoint->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val,
-                       myParams[aFirstParamPos + 2].val);
-      return true;
-    }
-    return false;
-  }
-
-  // Point in 2D
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
-  if (aPoint2D) {
-    if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance
-        || fabs(aPoint2D->y() - myParams[aFirstParamPos + 1].val) > tolerance) {
-      aPoint2D->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val);
-      return true;
-    }
-    return false;
-  }
-
-  // Scalar value
-  AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
-  if (aScalar) {
-    if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance) {
-      aScalar->setValue(myParams[aFirstParamPos].val);
-      return true;
-    }
-    return false;
-  }
-
-  /// \todo Support other types of entities
-  return false;
-}
-
-// ============================================================================
-//  Function: updateEntityIfPossible
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  search the entity in this group and update it
-// ============================================================================
-void SketchSolver_ConstraintGroup::updateEntityIfPossible(
-    std::shared_ptr<ModelAPI_Attribute> theEntity)
-{
-  if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) {
-    // If the attribute is a point and it is changed (the group needs to rebuild),
-    // probably user has dragged this point into this position,
-    // so it is necessary to add constraint which will guarantee the point will not change
-
-    // Store myNeedToSolve flag to verify the entity is really changed
-    bool aNeedToSolveCopy = myNeedToSolve;
-    myNeedToSolve = false;
-
-    changeEntity(theEntity);
-
-    if (myNeedToSolve)  // the entity is changed
-    {
-      // Verify the entity is a point and add temporary constraint of permanency
-      std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
-          theEntity);
-      std::shared_ptr<GeomDataAPI_Point2D> aPoint2D = std::dynamic_pointer_cast<
-          GeomDataAPI_Point2D>(theEntity);
-      if (aPoint || aPoint2D)
-        addTemporaryConstraintWhereDragged(theEntity);
-    }
-
-    // Restore flag of changes
-    myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
-
-    if (myNeedToSolve)
-      updateRelatedConstraints(theEntity);
-  }
-}
-
-// ============================================================================
-//  Function: addTemporaryConstraintWhereDragged
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  add transient constraint SLVS_C_WHERE_DRAGGED for the entity, 
-//            which was moved by user
-// ============================================================================
-void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged(
-    std::shared_ptr<ModelAPI_Attribute> theEntity,
-    bool theAllowToFit)
-{
-  // Find identifier of the entity
-  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
-      myEntityAttrMap.find(theEntity);
-  if (anEntIter == myEntityAttrMap.end())
-    return;
-
-  // Get identifiers of all dragged points
-  std::set<Slvs_hEntity> aDraggedPntID;
-  aDraggedPntID.insert(myTempPointWDrgdID);
-  std::list<Slvs_hConstraint>::const_iterator aTmpCoIter = myTempConstraints.begin();
-  for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) {
-    unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
-    if (aConstrPos < myConstraints.size())
-      aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
-  }
-  std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-  for (; aConstrIter != myConstraints.end(); aConstrIter++)
-    if (aConstrIter->type == SLVS_C_WHERE_DRAGGED)
-      aDraggedPntID.insert(aConstrIter->ptA);
-  // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
-  std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
-  for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) {
-    if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
-      continue;  // the entity was not found in current set
-
-    // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
-    std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
-    for (; aDrgIter != aDraggedPntID.end(); aDrgIter++)
-      if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
-        return;  // the SLVS_C_WHERE_DRAGGED constraint already exists
-  }
-  if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end())
-    return;
-
-  // If this is a first dragged point, its parameters should be placed 
-  // into Slvs_System::dragged field to avoid system inconsistense
-  if (myTempPointWhereDragged.empty() && theAllowToFit) {
-    int anEntPos = Search(anEntIter->second, myEntities);
-    Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
-    for (int i = 0; i < 4; i++, aDraggedParam++)
-      if (*aDraggedParam != 0)
-        myTempPointWhereDragged.push_back(*aDraggedParam);
-    myTempPointWDrgdID = myEntities[anEntPos].h;
-    return;
-  }
-
-  // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
-  Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
-                                                  myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
-  myConstraints.push_back(aWDConstr);
-  myTempConstraints.push_back(aWDConstr.h);
-}
-
-// ============================================================================
-//  Function: removeTemporaryConstraints
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  remove all transient SLVS_C_WHERE_DRAGGED constraints after
-//            resolving the set of constraints
-// ============================================================================
-void SketchSolver_ConstraintGroup::removeTemporaryConstraints(
-    const std::set<Slvs_hConstraint>& theRemoved)
-{
-  std::list<Slvs_hConstraint>::reverse_iterator aTmpConstrIter;
-  for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend();
-      aTmpConstrIter++) {
-    if (!theRemoved.empty() && theRemoved.find(*aTmpConstrIter) == theRemoved.end())
-      continue;
-    unsigned int aConstrPos = Search(*aTmpConstrIter, myConstraints);
-    if (aConstrPos >= myConstraints.size())
-      continue;
-    myConstraints.erase(myConstraints.begin() + aConstrPos);
-
-    // If the removing constraint has higher index, decrease the indexer
-    if (*aTmpConstrIter == myConstrMaxID)
-      myConstrMaxID--;
-  }
-  myTempConstraints.clear();
-
-  // Clear basic dragged point
-  myTempPointWhereDragged.clear();
-  myTempPointWDrgdID = SLVS_E_UNKNOWN;
-}
-
-// ============================================================================
-//  Function: removeConstraint
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  remove constraint and all unused entities
-// ============================================================================
-void SketchSolver_ConstraintGroup::removeConstraint(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
-  ConstraintMap::iterator anIterToRemove = myConstraintMap.find(theConstraint);
-  if (anIterToRemove == myConstraintMap.end())
-    return;
-
-  std::vector<Slvs_hConstraint> aCnstrToRemove = anIterToRemove->second;
-  // Remove constraint from the map
-  myConstraintMap.erase(anIterToRemove);
-
-  std::set<Slvs_hEntity> anEntToRemove;
-  
-  // Find unused entities
-  std::vector<Slvs_hConstraint>::iterator aCnstrToRemoveIter = aCnstrToRemove.begin();
-  for (; aCnstrToRemoveIter != aCnstrToRemove.end(); aCnstrToRemoveIter++) {
-    int aConstrPos = Search(*aCnstrToRemoveIter, myConstraints);
-    Slvs_hEntity aCnstEnt[] = { myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB,
-        myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB };
-    for (int i = 0; i < 4; i++)
-      if (aCnstEnt[i] != 0)
-        anEntToRemove.insert(aCnstEnt[i]);
-    myConstraints.erase(myConstraints.begin() + aConstrPos);
-    if (*aCnstrToRemoveIter == myConstrMaxID)
-      myConstrMaxID--;
-  }
-
-  // Find all entities which are based on these unused
-  std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
-  for ( ; anEntIter != myEntities.end(); anEntIter++)
-    if (anEntIter->type == SLVS_E_LINE_SEGMENT || anEntIter->type == SLVS_E_CIRCLE ||
-        anEntIter->type == SLVS_E_ARC_OF_CIRCLE) {
-      for (int i = 0; i < 4; i++)
-        if (anEntToRemove.find(anEntIter->point[i]) != anEntToRemove.end()) {
-          anEntToRemove.insert(anEntIter->h);
-          for (int j = 0; j < 4; j++)
-            if (anEntIter->point[j] != 0)
-              anEntToRemove.insert(anEntIter->point[j]);
-          break;
-        }
-    }
-
-  // Find entities used by remaining constraints and remove them from the list to delete
-  std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-  for (; aConstrIter != myConstraints.end(); aConstrIter++) {
-    Slvs_hEntity aEnts[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA, aConstrIter
-        ->entityB };
-    for (int i = 0; i < 4; i++)
-      if (aEnts[i] != 0 && anEntToRemove.find(aEnts[i]) != anEntToRemove.end()) {
-        anEntToRemove.erase(aEnts[i]);
-        // remove from the list all points of current entity
-        int aEntPos = Search(aEnts[i], myEntities);
-        for (int j = 0; j < 4; j++)
-          if (myEntities[aEntPos].point[j] != 0)
-            anEntToRemove.erase(myEntities[aEntPos].point[j]);
-      }
-  }
-
-  if (anEntToRemove.empty())
-    return;
-
-  // Remove unused entities
-  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntAttrIter =
-      myEntityAttrMap.begin();
-  while (anEntAttrIter != myEntityAttrMap.end()) {
-    if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end()) {
-      std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator aRemovedIter =
-          anEntAttrIter;
-      anEntAttrIter++;
-      myEntityAttrMap.erase(aRemovedIter);
-    } else
-      anEntAttrIter++;
-  }
-  std::map<FeaturePtr, Slvs_hEntity>::iterator anEntFeatIter = myEntityFeatMap.begin();
-  while (anEntFeatIter != myEntityFeatMap.end()) {
-    if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end()) {
-      std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = anEntFeatIter;
-      anEntFeatIter++;
-      myEntityFeatMap.erase(aRemovedIter);
-    } else
-      anEntFeatIter++;
-  }
-
-  removeEntitiesById(anEntToRemove);
-
-  if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty())
-    myCoincidentPoints.clear();
-}
-
-// ============================================================================
-//  Function: removeEntitiesById
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  Removes specified entities and their parameters
-// ============================================================================
-void SketchSolver_ConstraintGroup::removeEntitiesById(const std::set<Slvs_hEntity>& theEntities)
-{
-  std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = theEntities.rbegin();
-  for (; aRemIter != theEntities.rend(); aRemIter++) {
-    unsigned int anEntPos = Search(*aRemIter, myEntities);
-    if (anEntPos >= myEntities.size())
-      continue;
-    if (myEntities[anEntPos].param[0] != 0) {
-      unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
-      if (aParamPos >= myParams.size())
-        continue;
-      int aNbParams = 0;
-      while (myEntities[anEntPos].param[aNbParams] != 0)
-        aNbParams++;
-      if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID)
-        myParamMaxID -= aNbParams;
-      myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
-      if (*aRemIter == myEntityMaxID)
-        myEntityMaxID--;
-    }
-    myEntities.erase(myEntities.begin() + anEntPos);
-    myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos);
-
-    // Remove entity's ID from the lists of conincident points
-    std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
-    for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
-      aCoPtIter->erase(*aRemIter);
-  }
-}
-
-// ============================================================================
-//  Function: addCoincidentPoints
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  add coincident point the appropriate list of such points
-// ============================================================================
-bool SketchSolver_ConstraintGroup::addCoincidentPoints(const Slvs_hEntity& thePoint1,
-                                                       const Slvs_hEntity& thePoint2)
-{
-  std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
-  std::vector<std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
-  while (aCoPtIter != myCoincidentPoints.end()) {
-    bool isFound[2] = {  // indicate which point ID was already in coincidence constraint
-        aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2)
-            != aCoPtIter->end(), };
-    if (isFound[0] && isFound[1])  // points are already connected by coincidence constraints => no need additional one
-      return false;
-    if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) {
-      if (aFirstFound != myCoincidentPoints.end()) {  // there are two groups of coincident points connected by created constraint => merge them
-        int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
-        int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
-        aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
-        myCoincidentPoints.erase(aCoPtIter);
-        aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
-        aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
-        continue;
-      } else {
-        aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
-        aFirstFound = aCoPtIter;
-      }
-    }
-    aCoPtIter++;
-  }
-  // No points were found, need to create new set
-  if (aFirstFound == myCoincidentPoints.end()) {
-    std::set<Slvs_hEntity> aNewSet;
-    aNewSet.insert(thePoint1);
-    aNewSet.insert(thePoint2);
-    myCoincidentPoints.push_back(aNewSet);
-  }
-
-  return true;
-}
-
-// ============================================================================
-//  Function: updateRelatedConstraints
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  emit the signal to update constraints
-// ============================================================================
-void SketchSolver_ConstraintGroup::updateRelatedConstraints(
-    std::shared_ptr<ModelAPI_Attribute> theEntity) const
-{
-  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
-  for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
-    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
-        ->attributes(std::string());
-
-    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
-    for (; anAttrIter != anAttributes.end(); anAttrIter++) {
-      bool isUpd = (*anAttrIter == theEntity);
-      std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
-          ModelAPI_AttributeRefAttr>(*anAttrIter);
-      if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
-        isUpd = true;
-
-      if (isUpd) {
-        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
-        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
-        break;
-      }
-    }
-  }
-}
-
-void SketchSolver_ConstraintGroup::updateRelatedConstraintsFeature(
-    std::shared_ptr<ModelAPI_Feature> theFeature) const
-{
-  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
-  for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
-    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
-        ->attributes(std::string());
-
-    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
-    for (; anAttrIter != anAttributes.end(); anAttrIter++) {
-      std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
-          ModelAPI_AttributeRefAttr>(*anAttrIter);
-      if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature) {
-        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
-        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
-        break;
-      }
-    }
-  }
-}
-
-// ============================================================================
-//  Function: updateFilletConstraints
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  change fillet arc to be less than 180 degree
-// ============================================================================
-void SketchSolver_ConstraintGroup::updateFilletConstraints()
-{
-  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
-  for (; aConstrIter != myConstraintMap.end(); aConstrIter++)
-    if (aConstrIter->first->getKind() == SketchPlugin_ConstraintFillet::ID()) {
-      AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-          aConstrIter->first->data()->attribute(SketchPlugin_ConstraintFillet::ENTITY_C()));
-      if (!aFilletRefList)
-        return;
-      ObjectPtr anArcObj = aFilletRefList->object(2);
-      std::shared_ptr<GeomDataAPI_Point2D> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          anArcObj->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
-      std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          anArcObj->data()->attribute(SketchPlugin_Arc::START_ID()));
-      std::shared_ptr<GeomDataAPI_Point2D> aEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          anArcObj->data()->attribute(SketchPlugin_Arc::END_ID()));
-      double aCosA = aStart->x() - aCenter->x();
-      double aSinA = aStart->y() - aCenter->y();
-      double aCosB = aEnd->x() - aCenter->x();
-      double aSinB = aEnd->y() - aCenter->y();
-      if (aCosA * aSinB - aSinA * aCosB <= 0.0) {
-        anArcObj->data()->blockSendAttributeUpdated(true);
-        double x = aStart->x();
-        double y = aStart->y();
-        aStart->setValue(aEnd->x(), aEnd->y());
-        aEnd->setValue(x, y);
-        // Update constraint data
-        changeFilletConstraint(aConstrIter->first);
-        anArcObj->data()->blockSendAttributeUpdated(false);
-      }
-    }
-}
-
-// ============================================================================
-//  Function: makeMirrorEntity
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  change entities parameters to make them symmetric relating to the mirror line
-// ============================================================================
-void SketchSolver_ConstraintGroup::makeMirrorEntity(const Slvs_hEntity& theBase,
-                                                    const Slvs_hEntity& theMirror,
-                                                    const Slvs_hEntity& theMirrorLine)
-{
-  Slvs_Entity aBase = myEntities[Search(theBase, myEntities)];
-  Slvs_Entity aMirror = myEntities[Search(theMirror, myEntities)];
-  int i = 0;
-  if (aBase.type != SLVS_E_ARC_OF_CIRCLE) {
-    while (aBase.point[i] != 0 && aMirror.point[i] != 0) {
-      makeMirrorEntity(aBase.point[i], aMirror.point[i], theMirrorLine);
-      i++;
-    }
-  } else {
-    // swap mirroring first and last points of an arc
-    makeMirrorEntity(aBase.point[0], aMirror.point[0], theMirrorLine);
-    makeMirrorEntity(aBase.point[1], aMirror.point[2], theMirrorLine);
-    makeMirrorEntity(aBase.point[2], aMirror.point[1], theMirrorLine);
-  }
-  if (aBase.param[0] != 0 && aMirror.param[0] != 0) { // this is a point, copy it
-    Slvs_Entity aMirrorLine = myEntities[Search(theMirrorLine, myEntities)];
-    std::shared_ptr<GeomAPI_XY> aLinePoints[2];
-    for (i = 0; i < 2; i++) {
-      Slvs_Entity aPoint = myEntities[Search(aMirrorLine.point[i], myEntities)];
-      int aParamPos = Search(aPoint.param[0], myParams);
-      aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
-          new GeomAPI_XY(myParams[aParamPos].val, myParams[1+aParamPos].val));
-    }
-    int aBaseParamPos = Search(aBase.param[0], myParams);
-    int aMirrorParamPos = Search(aMirror.param[0], myParams);
-    std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(
-        new GeomAPI_XY(myParams[aBaseParamPos].val, myParams[1+aBaseParamPos].val));
-
-    // direction of a mirror line
-    std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
-        new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
-    // orthogonal direction
-    aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
-
-    std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
-        new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
-    double aDist = aVec->dot(aDir->xy());
-    std::shared_ptr<GeomAPI_XY> aMirrorPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
-
-    myParams[aMirrorParamPos].val = aMirrorPoint->x();
-    myParams[1+aMirrorParamPos].val = aMirrorPoint->y();
-  }
-}
-
-// ============================================================================
-//  Function: changeMirrorPoints
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  creates/updates mirror constraint for two points
-// ============================================================================
-Slvs_hConstraint SketchSolver_ConstraintGroup::changeMirrorPoints(
-    const Slvs_hEntity& theBasePoint,
-    const Slvs_hEntity& theMirrorPoint,
-    const Slvs_hEntity& theMirrorLine,
-    std::vector<Slvs_Constraint>&  thePrevConstr,
-    std::map<Slvs_hEntity, Slvs_hEntity>& thePrevMirror)
-{
-  std::map<Slvs_hEntity, Slvs_hEntity>::iterator aMapIter = thePrevMirror.find(theBasePoint);
-  if (aMapIter != thePrevMirror.end()) {
-    thePrevMirror.erase(aMapIter);
-    std::vector<Slvs_Constraint>::iterator anIter = thePrevConstr.begin();
-    for (; anIter != thePrevConstr.end(); anIter++)
-      if (anIter->ptA == theBasePoint) {
-        if (anIter->ptB != theMirrorPoint) {
-          int aConstrInd = Search(anIter->h, myConstraints);
-          myConstraints[aConstrInd].ptB = theMirrorPoint;
-          myConstraints[aConstrInd].entityA = theMirrorLine;
-        }
-        Slvs_hConstraint aResult = anIter->h;
-        thePrevConstr.erase(anIter);
-        return aResult;
-      }
-  }
-
-  // Newly created constraint
-  Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-      ++myConstrMaxID, myID, SLVS_C_SYMMETRIC_LINE, myWorkplane.h, 0.0,
-      theBasePoint, theMirrorPoint, theMirrorLine, SLVS_E_UNKNOWN);
-  myConstraints.push_back(aConstraint);
-  return aConstraint.h;
-}
-
-
-// ============================================================================
-//  Function: calculateMiddlePoint
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  calculates middle point on line or arc
-// ============================================================================
-void SketchSolver_ConstraintGroup::calculateMiddlePoint(
-    const Slvs_hEntity& theEntity,
-    double& theX,
-    double& theY) const
-{
-  int anInd = Search(theEntity, myEntities);
-  if (myEntities[anInd].type == SLVS_E_LINE_SEGMENT) {
-    int aLineParams[2];
-    for (int i = 0; i < 2; i++) {
-      int aPtPos = Search(myEntities[anInd].point[i], myEntities);
-      aLineParams[i] = Search(myEntities[aPtPos].param[0], myParams);
-    }
-    theX = 0.5 * (myParams[aLineParams[0]].val + myParams[aLineParams[1]].val);
-    theY = 0.5 * (myParams[1 + aLineParams[0]].val + myParams[1 + aLineParams[1]].val);
-  } else if (myEntities[anInd].type == SLVS_E_ARC_OF_CIRCLE) {
-    double anArcPoint[3][2];
-    for (int i = 0; i < 3; i++) {
-      int aPtPos = Search(myEntities[anInd].point[i], myEntities);
-      int anArcParam = Search(myEntities[aPtPos].param[0], myParams);
-      anArcPoint[i][0] = myParams[anArcParam].val;
-      anArcPoint[i][1] = myParams[1 + anArcParam].val;
-    }
-    // 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] = anArcPoint[0][0] + x * aRad / aNorm;
-      anArcPoint[2][1] = anArcPoint[0][1] + y * aRad / aNorm;
-    }
-
-    x = anArcPoint[1][0] + anArcPoint[2][0] - 2.0 * anArcPoint[0][0];
-    y = anArcPoint[1][1] + anArcPoint[2][1] - 2.0 * anArcPoint[0][1];
-    aNorm = sqrt(x*x + y*y);
-    if (aNorm >= tolerance) {
-      x *= aRad / aNorm;
-      y *= aRad / aNorm;
-    } else { // obtain orthogonal direction
-      x = 0.5 * (anArcPoint[2][1] - anArcPoint[1][1]);
-      y = -0.5 * (anArcPoint[2][0] - anArcPoint[1][0]);
-    }
-    theX = anArcPoint[0][0] + x;
-    theY = anArcPoint[0][1] + y;
-  }
-}
-
-
-// ========================================================
-// =========      Auxiliary functions       ===============
-// ========================================================
-
-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();
-  while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
-    aResIndex--;
-  while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
-    aResIndex++;
-  if (aResIndex == -1)
-    aResIndex = aVecSize;
-  return aResIndex;
-}
diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.h b/src/SketchSolver/SketchSolver_ConstraintGroup.h
deleted file mode 100644 (file)
index 8ec2685..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_ConstraintGroup.h
-// Created: 27 May 2014
-// Author:  Artem ZHIDKOV
-
-#ifndef SketchSolver_ConstraintGroup_H_
-#define SketchSolver_ConstraintGroup_H_
-
-#include "SketchSolver.h"
-#include <SketchSolver_Solver.h>
-
-#include <SketchPlugin_Constraint.h>
-#include <ModelAPI_Data.h>
-#include <ModelAPI_Feature.h>
-
-
-#include <memory>
-#include <list>
-#include <map>
-#include <vector>
-#include <set>
-
-typedef std::map< std::shared_ptr<SketchPlugin_Constraint>, std::vector<Slvs_hConstraint> >
-  ConstraintMap;
-
-/** \class   SketchSolver_ConstraintGroup
- *  \ingroup Plugins
- *  \brief   Keeps the group of constraints which based on the same entities
- */
-class SketchSolver_ConstraintGroup
-{
- public:
-  /** \brief New group based on specified workplane.
-   *         Throws an exception if theWorkplane is not an object of SketchPlugin_Sketch type
-   *  \remark Type of theSketch is not verified inside
-   */
-  SketchSolver_ConstraintGroup(std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane);
-
-  ~SketchSolver_ConstraintGroup();
-
-  /// \brief Returns group's unique identifier
-  inline const Slvs_hGroup& getId() const
-  {
-    return myID;
-  }
-
-  /// \brief Returns true if the group has no constraints yet
-  inline bool isEmpty() const
-  {
-    return myConstraints.empty();
-  }
-
-  /// \brief Check for valid sketch data
-  inline bool isWorkplaneValid() const
-  {
-    return mySketch->data() && mySketch->data()->isValid();
-  }
-
-  /** \brief Adds or updates a constraint in the group
-   *  \param[in] theConstraint constraint to be changed
-   *  \return \c true if the constraint added or updated successfully
-   */
-  bool changeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-  /** \brief Adds or updates a rigid constraint in the group
-   *  \param[in] theConstraint constraint to be changed
-   *  \return \c true if the constraint added or updated successfully
-   */
-  bool changeRigidConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-  /** \brief Adds or updates a mirror constraint in the group
-   *  \param[in] theConstraint constraint to be changed
-   *  \return \c true if the constraint added or updated successfully
-   */
-  bool changeMirrorConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-  /** \brief Adds or updates a fillet constraint in the group
-   *  \param[in] theConstraint constraint to be changed
-   *  \return \c true if the constraint added or updated successfully
-   */
-  bool changeFilletConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
-  /** \brief Verifies the feature attributes are used in this group
-   *  \param[in] theFeature constraint or any other object for verification of interaction
-   *  \return \c true if some of attributes are used in current group
-   */
-  bool isInteract(std::shared_ptr<SketchPlugin_Feature> theFeature) const;
-
-  /** \brief Verifies the specified feature is equal to the base workplane for this group
-   *  \param[in] theWorkplane the feature to be compared with base workplane
-   *  \return \c true if workplanes are the same
-   */
-  bool isBaseWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane) const;
-
-  /// Returns the current workplane
-  std::shared_ptr<ModelAPI_CompositeFeature> getWorkplane() const
-  {
-    return mySketch;
-  }
-
-  /** \brief Update parameters of workplane. Should be called when Update event is coming.
-   *  \return \c true if workplane updated successfully, \c false if workplane parameters are not consistent
-   */
-  bool updateWorkplane();
-
-  /** \brief If the entity is in this group it will updated
-   *  \param[in] theEntity attribute, which values should update SolveSpace entity
-   */
-  void updateEntityIfPossible(std::shared_ptr<ModelAPI_Attribute> theEntity);
-
-  /** \brief Searches invalid features and constraints in the group and avoids them
-   *  \return \c true if the group several constraints were removed
-   */
-  bool updateGroup();
-
-  /** \brief Add specified group to this one
-   *  \param[in] theGroup group of constraint to be added
-   */
-  void mergeGroups(const SketchSolver_ConstraintGroup& theGroup);
-
-  /** \brief Cut from the group several subgroups, which are not connected to the current one by any constraint
-   *  \param[out] theCuts enlarge this list by newly created groups
-   */
-  void splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts);
-
-  /** \brief Start solution procedure if necessary and update attributes of features
-   *  \return \c false when no need to solve constraints
-   */
-  bool resolveConstraints();
-
-  /** \brief Searches the constraints built on the entity and emit the signal to update them
-   *  \param[in] theEntity attribute of the constraint
-   */
-  void updateRelatedConstraints(std::shared_ptr<ModelAPI_Attribute> theEntity) const;
-  /** \brief Searches the constraints built on the entity and emit the signal to update them
-   *  \param[in] theFeature feature of the constraint
-   */
-  void updateRelatedConstraintsFeature(std::shared_ptr<ModelAPI_Feature> theFeature) const;
-
-  /** \brief Adds or updates an entity in the group
-   *
-   *  The parameters of entity will be parsed and added to the list of SolveSpace parameters.
-   *  Parameters of certain entity will be placed sequentially in the list.
-   *
-   *  \param[in] theEntity the object of constraint
-   *  \return identifier of changed entity or 0 if entity could not be changed
-   */
-  Slvs_hEntity changeEntity(std::shared_ptr<ModelAPI_Attribute> theEntity);
-  Slvs_hEntity changeEntityFeature(std::shared_ptr<ModelAPI_Feature> theEntity);
-
-protected:
-  /** \brief Adds or updates a normal in the group
-   *
-   *  Normal is a special entity in SolveSpace, which defines a direction in 3D and
-   *  a rotation about this direction. So, SolveSpace represents normals as unit quaternions.
-   *
-   *  To define a normal there should be specified two coordinate axis
-   *  on the plane transversed to created normal.
-   *
-   *  \param[in] theDirX first coordinate axis of the plane
-   *  \param[in] theNorm attribute for the normal (used to identify newly created entity)
-   *  \return identifier of created or updated normal
-   */
-  Slvs_hEntity changeNormal(std::shared_ptr<ModelAPI_Attribute> theDirX,
-                            std::shared_ptr<ModelAPI_Attribute> theNorm);
-
-  /** \brief Adds or updates a parameter in the group
-   *  \param[in] theParam   the value of parameter
-   *  \param[in] thePrmIter the cell in the list of parameters which should be changed
-   *                        (the iterator will be increased if it does not reach the end of the list)
-   *  \return identifier of changed parameter; when the parameter cannot be created, returned ID is 0
-   */
-  Slvs_hParam changeParameter(double theParam,
-                              std::vector<Slvs_Param>::iterator& thePrmIter);
-
-  /** \brief Removes specified entities and their parameters
-   *  \param[in] theEntities  list of IDs of the entities to be removed
-   */
-  void removeEntitiesById(const std::set<Slvs_hEntity>& theEntities);
-
-  /** \brief Removes constraints from the group
-   *  \param[in] theConstraint constraint to be removed
-   */
-  void removeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
-  /** \brief Change values of attribute by parameters received from SolveSpace solver
-   *  \param[in,out] theAttribute pointer to the attribute to be changed
-   *  \param[in]     theEntityID  identifier of SolveSpace entity, which contains updated data
-   *  \return \c true if the attribute's value has changed
-   */
-  bool updateAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute,
-                       const Slvs_hEntity& theEntityID);
-
-  /// \brief Update arc of fillet to be less than 180 degree
-  void updateFilletConstraints();
-
-  /** \brief Adds a constraint for a point which should not be changed during computations
-   *  \param[in] theEntity     the base for the constraint
-   *  \param[in] theAllowToFit this flag shows that the entity may be placed into 
-   *                           the 'dragged' field of SolveSpace solver, so this entity 
-   *                           may be changed a little during solution
-   */
-  void addTemporaryConstraintWhereDragged(std::shared_ptr<ModelAPI_Attribute> theEntity,
-                                          bool theAllowToFit = true);
-
-  /** \brief Remove all temporary constraint after computation finished
-   *  \param[in] theRemoved  indexes of constraints to be removed. If empty, all temporary constraints should be deleted
-   */
-  void removeTemporaryConstraints(const std::set<Slvs_hConstraint>& theRemoved =
-                                                                 std::set<Slvs_hConstraint>());
-
- private:
-  /** \brief Creates a workplane from the sketch parameters
-   *  \param[in] theSketch parameters of workplane are the attributes of this sketch
-   *  \return \c true if success, \c false if workplane parameters are not consistent
-   */
-  bool addWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch);
-
-  /** \brief Add the entities of constraint for points coincidence into the appropriate list
-   *  \param[in] thePoint1 identifier of the first point
-   *  \param[in] thePoint2 identifier of the second point
-   *  \return \c true if the points are added successfully, and 
-   *          \c false if the constraint is the extra one (should not be created in SolveSpace)
-   */
-  bool addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2);
-
-  /** \brief Verifies and changes parameters of constriant, 
-   *         e.g. sign of the distance between line and point
-   *  \param[in,out] theConstraint SolveSpace constraint to be verified
-   */
-  void checkConstraintConsistence(Slvs_Constraint& theConstraint);
-
-  /** \brief Change entities parameters to make them symmetric relating to the mirror line
-   *  \param[in] theBase        entity to be mirrored
-   *  \param[in] theMirror      a mirrored object
-   *  \param[in] theMirrorLine  a mirror line
-   */
-  void makeMirrorEntity(const Slvs_hEntity& theBase,
-                        const Slvs_hEntity& theMirror,
-                        const Slvs_hEntity& theMirrorLine);
-
-  /** \brief Creates/updates mirror constraint for two points
-   *  \param[in]     theBasePoint   ID of initial point
-   *  \param[in]     theMirrorPoint ID of the mirroring point
-   *  \param[in]     theMirrorLine  ID of the mirror line
-   *  \param[in]     thePrevConstr  list of previous constraints (the items will be deleted from the list if they are updated)
-   *  \param[in,out] thePrevMirror  list of previously mirrored points (the items will be deleted from the list if they are updated)
-   *  \return ID of created/updated constraint
-   */
-  Slvs_hConstraint changeMirrorPoints(const Slvs_hEntity& theBasePoint,
-                                      const Slvs_hEntity& theMirrorPoint,
-                                      const Slvs_hEntity& theMirrorLine,
-                                      std::vector<Slvs_Constraint>&  thePrevConstr,
-                                      std::map<Slvs_hEntity, Slvs_hEntity>& thePrevMirror);
-
-  /** \brief Calculates middle point on line or arc
-   *  \param[in]  theEntity  identifier of line or arc
-   *  \param[out] theX       X value of middle point
-   *  \param[out] theY       Y value of middle point
-   */
-  void calculateMiddlePoint(const Slvs_hEntity& theEntity,
-                            double& theX, double& theY) const;
-
- private:
-  // SolveSpace entities
-  Slvs_hGroup myID;            ///< the index of the group
-  Slvs_Entity myWorkplane;     ///< Workplane for the current group
-  std::vector<Slvs_Param> myParams;        ///< List of parameters of the constraints
-  Slvs_hParam myParamMaxID;    ///< Actual maximal ID of parameters (not equal to myParams size)
-  std::vector<Slvs_Entity> myEntities;      ///< List of entities of the constaints
-  std::vector<bool> myEntOfConstr; ///< Flags show that certain entity used in constraints
-  Slvs_hEntity myEntityMaxID;   ///< Actual maximal ID of entities (not equal to myEntities size)
-  std::vector<Slvs_Constraint> myConstraints;   ///< List of constraints in SolveSpace format
-  Slvs_hConstraint myConstrMaxID;  ///< Actual maximal ID of constraints (not equal to myConstraints size)
-  bool myNeedToSolve;  ///< Indicator that something changed in the group and constraint system need to be rebuilt
-
-  SketchSolver_Solver myConstrSolver;  ///< Solver for set of equations obtained by constraints
-
-  std::vector<Slvs_hParam> myTempPointWhereDragged;  ///< Parameters of one of the points which is moved by user
-  Slvs_hEntity myTempPointWDrgdID;      ///< Identifier of such point
-  std::list<Slvs_hConstraint> myTempConstraints;  ///< The list of identifiers of temporary constraints (SLVS_C_WHERE_DRAGGED) applied for all other points moved by user
-
-  // SketchPlugin entities
-  std::shared_ptr<ModelAPI_CompositeFeature> mySketch;        ///< Equivalent to workplane
-  ConstraintMap myConstraintMap;  ///< The map between SketchPlugin and SolveSpace constraints
-  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity> myEntityAttrMap;  ///< The map between "attribute" parameters of constraints and their equivalent SolveSpace entities
-  std::map<FeaturePtr, Slvs_hEntity> myEntityFeatMap;  ///< The map between "feature" parameters of constraints and their equivalent SolveSpace entities
-
-  // Conincident items
-  std::vector<std::set<Slvs_hEntity> > myCoincidentPoints;  ///< Stores the lists of identifiers of coincident points (to avoid unnecessary coincidence constraints)
-  std::set<std::shared_ptr<SketchPlugin_Constraint> > myExtraCoincidence;  ///< Additional coincidence constraints which are not necessary (coincidence between points already done
-                                                                             ///< by other constraints) but created by GUI tools. Useful when some coincidence constraints were removed
-};
-
-#endif
index bd346fb35fe35fac2343b7ff27b2600dae9c9544..1e80079c96c2406ff039fb43bd82f1306ebdd3a2 100644 (file)
@@ -5,7 +5,6 @@
 // Author:  Artem ZHIDKOV
 
 #include "SketchSolver_ConstraintManager.h"
-#include <SketchSolver_ConstraintGroup.h>
 
 #include <Events_Loop.h>
 #include <ModelAPI_AttributeDouble.h>
@@ -88,7 +87,7 @@ void SketchSolver_ConstraintManager::processEvent(
         std::shared_ptr<SketchPlugin_Feature> aSFeature = 
             std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
         if (aSFeature)
-          updateEntity(aSFeature);
+          moveEntity(aSFeature);
       }
     } else {
       std::set<ObjectPtr>::iterator aFeatIter;
@@ -138,8 +137,8 @@ void SketchSolver_ConstraintManager::processEvent(
         break;
 
     if (aFGrIter != aFeatureGroups.end()) {
-      std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
-      std::vector<SketchSolver_ConstraintGroup*> aSeparatedGroups;
+      std::vector<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
+      std::vector<SketchSolver_Group*> aSeparatedGroups;
       while (aGroupIter != myGroups.end()) {
         if (!(*aGroupIter)->isWorkplaneValid()) {  // the group should be removed
           delete *aGroupIter;
@@ -148,7 +147,7 @@ void SketchSolver_ConstraintManager::processEvent(
           aGroupIter = myGroups.begin() + aShift;
           continue;
         }
-        if ((*aGroupIter)->updateGroup()) {  // some constraints were removed, try to split the group
+        if (!(*aGroupIter)->isConsistent()) {  // some constraints were removed, try to split the group
           (*aGroupIter)->splitGroup(aSeparatedGroups);
         }
         aGroupIter++;
@@ -164,13 +163,12 @@ void SketchSolver_ConstraintManager::processEvent(
 //  Class:    SketchSolver_Session
 //  Purpose:  update workplane by given parameters of the sketch
 // ============================================================================
-bool SketchSolver_ConstraintManager::changeWorkplane(
-    std::shared_ptr<ModelAPI_CompositeFeature> theSketch)
+bool SketchSolver_ConstraintManager::changeWorkplane(CompositeFeaturePtr theSketch)
 {
   bool aResult = true;  // changed when a workplane wrongly updated
   bool isUpdated = false;
   // Try to update specified workplane in all groups
-  std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+  std::vector<SketchSolver_Group*>::iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
     if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
       isUpdated = true;
@@ -179,7 +177,7 @@ bool SketchSolver_ConstraintManager::changeWorkplane(
     }
   // If the workplane is not updated, so this is a new workplane
   if (!isUpdated) {
-    SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch);
+    SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch);
     // Verify that the group is created successfully
     if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) {
       delete aNewGroup;
@@ -213,7 +211,7 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
     std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(aConstraint);
     if (!aWP)
       return false;
-    SketchSolver_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP);
+    SketchSolver_Group* aGroup = new SketchSolver_Group(aWP);
     if (!aGroup->changeConstraint(aConstraint)) {
       delete aGroup;
       return false;
@@ -222,19 +220,19 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
     return true;
   } else if (aGroups.size() == 1) {  // Only one group => add feature into it
     Slvs_hGroup aGroupId = *(aGroups.begin());
-    std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+    std::vector<SketchSolver_Group*>::iterator aGroupIter;
     for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
       if ((*aGroupIter)->getId() == aGroupId) {
         // If the group is empty, the feature is not added (the constraint only)
-        if (!aConstraint && !(*aGroupIter)->isEmpty())
-          return (*aGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
+////        if (!aConstraint && !(*aGroupIter)->isEmpty())
+////          return (*aGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
         return (*aGroupIter)->changeConstraint(aConstraint);
       }
   } else if (aGroups.size() > 1) {  // Several groups applicable for this feature => need to merge them
     std::set<Slvs_hGroup>::const_iterator aGroupsIter = aGroups.begin();
 
     // Search first group
-    std::vector<SketchSolver_ConstraintGroup*>::iterator aFirstGroupIter;
+    std::vector<SketchSolver_Group*>::iterator aFirstGroupIter;
     for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
       if ((*aFirstGroupIter)->getId() == *aGroupsIter)
         break;
@@ -242,7 +240,7 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
       return false;
 
     // Append other groups to the first one
-    std::vector<SketchSolver_ConstraintGroup*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
+    std::vector<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
     for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
       for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
         if ((*anOtherGroupIter)->getId() == *aGroupsIter)
@@ -263,7 +261,7 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
 
     if (aConstraint)
       return (*aFirstGroupIter)->changeConstraint(aConstraint);
-    return (*aFirstGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
+////    return (*aFirstGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
   }
 
   // Something goes wrong
@@ -271,54 +269,59 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
 }
 
 // ============================================================================
-//  Function: updateEntity
+//  Function: moveEntity
 //  Class:    SketchSolver_Session
-//  Purpose:  update any element on the sketch, which is used by constraints
+//  Purpose:  update element moved on the sketch, which is used by constraints
 // ============================================================================
-void SketchSolver_ConstraintManager::updateEntity(
+void SketchSolver_ConstraintManager::moveEntity(
     std::shared_ptr<SketchPlugin_Feature> theFeature)
 {
-  // Create list of attributes depending on type of the feature
-  std::vector<std::string> anAttrList;
-  const std::string& aFeatureKind = theFeature->getKind();
-  // Point
-  if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0)
-    anAttrList.push_back(SketchPlugin_Point::COORD_ID());
-  // Line
-  else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
-    anAttrList.push_back(SketchPlugin_Line::START_ID());
-    anAttrList.push_back(SketchPlugin_Line::END_ID());
-  }
-  // Circle
-  else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
-    anAttrList.push_back(SketchPlugin_Circle::CENTER_ID());
-    anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID());
-  }
-  // Arc
-  else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
-    anAttrList.push_back(SketchPlugin_Arc::CENTER_ID());
-    anAttrList.push_back(SketchPlugin_Arc::START_ID());
-    anAttrList.push_back(SketchPlugin_Arc::END_ID());
-  }
-  /// \todo Other types of features should be implemented
-
-  // Check changing of feature's attributes (go through the groups and search usage of the attributes)
-  std::vector<std::string>::const_iterator anAttrIter;
-  for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++) {
-    std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
-    for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
-      if ((*aGroupIter)->isEmpty())
-        continue;
-      std::shared_ptr<ModelAPI_Attribute> anAttribute = std::dynamic_pointer_cast<
-          ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
-      (*aGroupIter)->updateEntityIfPossible(anAttribute);
-    }
-  }
-
-  std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
-  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
-    if (!(*aGroupIter)->isEmpty())
-      (*aGroupIter)->updateRelatedConstraintsFeature(theFeature);
+  std::vector<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
+  for (; aGroupIt != myGroups.end(); aGroupIt++)
+    if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature))
+      (*aGroupIt)->moveFeature(theFeature);
+
+////  // Create list of attributes depending on type of the feature
+////  std::vector<std::string> anAttrList;
+////  const std::string& aFeatureKind = theFeature->getKind();
+////  // Point
+////  if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0)
+////    anAttrList.push_back(SketchPlugin_Point::COORD_ID());
+////  // Line
+////  else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
+////    anAttrList.push_back(SketchPlugin_Line::START_ID());
+////    anAttrList.push_back(SketchPlugin_Line::END_ID());
+////  }
+////  // Circle
+////  else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
+////    anAttrList.push_back(SketchPlugin_Circle::CENTER_ID());
+////    anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID());
+////  }
+////  // Arc
+////  else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
+////    anAttrList.push_back(SketchPlugin_Arc::CENTER_ID());
+////    anAttrList.push_back(SketchPlugin_Arc::START_ID());
+////    anAttrList.push_back(SketchPlugin_Arc::END_ID());
+////  }
+////  /// \todo Other types of features should be implemented
+////
+////  // Check changing of feature's attributes (go through the groups and search usage of the attributes)
+////  std::vector<std::string>::const_iterator anAttrIter;
+////  for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++) {
+////    std::vector<SketchSolver_Group*>::iterator aGroupIter;
+////    for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
+////      if ((*aGroupIter)->isEmpty())
+////        continue;
+////      std::shared_ptr<ModelAPI_Attribute> anAttribute = std::dynamic_pointer_cast<
+////          ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
+////      (*aGroupIter)->updateEntityIfPossible(anAttribute);
+////    }
+////  }
+////
+////  std::vector<SketchSolver_Group*>::iterator aGroupIter;
+////  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+////    if (!(*aGroupIter)->isEmpty())
+////      (*aGroupIter)->updateRelatedConstraintsFeature(theFeature);
 }
 
 // ============================================================================
@@ -332,8 +335,8 @@ void SketchSolver_ConstraintManager::findGroups(
 {
   std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(theFeature);
 
-  SketchSolver_ConstraintGroup* anEmptyGroup = 0;  // appropriate empty group for specified constraint
-  std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
+  SketchSolver_Group* anEmptyGroup = 0;  // appropriate empty group for specified constraint
+  std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
     if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) {
       if (!(*aGroupIter)->isEmpty())
@@ -358,7 +361,7 @@ std::shared_ptr<ModelAPI_CompositeFeature> SketchSolver_ConstraintManager
   // Already verified workplanes
   std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
 
-  std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
+  std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
     std::shared_ptr<ModelAPI_CompositeFeature> aWP = (*aGroupIter)->getWorkplane();
     if (aVerified.find(aWP) != aVerified.end())
@@ -396,7 +399,7 @@ void SketchSolver_ConstraintManager::resolveConstraints(const bool theForceUpdat
     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
   }
 
-  std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+  std::vector<SketchSolver_Group*>::iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
     if ((*aGroupIter)->resolveConstraints())
       needToUpdate = true;
index f5e148362bd448bb8e6020c258de1e6980c824d3..a2d7ffaffe580a08ca944a71938b56dfae64092d 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "SketchSolver.h"
 #include <SketchSolver_Solver.h>
-#include <SketchSolver_ConstraintGroup.h>
+#include <SketchSolver_Group.h>
 
 #include <Events_Listener.h>
 #include <SketchPlugin_Constraint.h>
@@ -67,7 +67,7 @@ class SketchSolver_ConstraintManager : public Events_Listener
    *  \return \c true if the workplane changed successfully
    *  \remark Type of theSketch is not verified inside
    */
-  bool changeWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch);
+  bool changeWorkplane(CompositeFeaturePtr theSketch);
 
   /** \brief Removes a workplane from the manager.
    *         All groups based on such workplane will be removed too.
@@ -76,10 +76,10 @@ class SketchSolver_ConstraintManager : public Events_Listener
    */
   bool removeWorkplane(std::shared_ptr<SketchPlugin_Sketch> theSketch);
 
-  /** \brief Updates entity which is neither workplane nor constraint
+  /** \brief Updates entity which is moved in GUI
    *  \param[in] theFeature entity to be updated
    */
-  void updateEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
+  void moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
 
   /** \brief Goes through the list of groups and solve the constraints
    *  \param theForceUpdate flushes the update event in any case: something changed or not
@@ -103,7 +103,7 @@ class SketchSolver_ConstraintManager : public Events_Listener
 
  private:
   static SketchSolver_ConstraintManager* _self;  ///< Self pointer to implement singleton functionality
-  std::vector<SketchSolver_ConstraintGroup*> myGroups;  ///< Groups of constraints
+  std::vector<SketchSolver_Group*> myGroups;  ///< Groups of constraints
   /// true if computation is performed and all "updates" are generated by this algo
   /// and needs no recomputation
   bool myIsComputed;
diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.cpp b/src/SketchSolver/SketchSolver_ConstraintRigid.cpp
new file mode 100644 (file)
index 0000000..02ba819
--- /dev/null
@@ -0,0 +1,102 @@
+#include <SketchSolver_ConstraintRigid.h>
+#include <SketchSolver_Error.h>
+#include <SketchSolver_Group.h>
+
+#include <SketchPlugin_ConstraintRigid.h>
+
+SketchSolver_ConstraintRigid::SketchSolver_ConstraintRigid(FeaturePtr theFeature)
+  : SketchSolver_Constraint(),
+    myBaseFeature(theFeature)
+{
+  process();
+}
+
+void SketchSolver_ConstraintRigid::process()
+{
+  cleanErrorMsg();
+  if ((!myBaseConstraint && !myBaseFeature) || !myStorage || myGroup == 0) {
+    /// TODO: Put error message here
+    return;
+  }
+  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+    update(myBaseConstraint);
+
+  double aValue;
+  std::vector<Slvs_hEntity> anEntities;
+  getAttributes(aValue, anEntities);
+
+  Slvs_Constraint aConstraint;
+  std::vector<Slvs_hConstraint>::iterator aConstrIter = mySlvsConstraints.begin();
+  bool isEmpty = aConstrIter == mySlvsConstraints.end();
+  std::vector<Slvs_hEntity>::const_iterator anEntIter = anEntities.begin();
+  for (; anEntIter != anEntities.end(); anEntIter++) {
+    if (isEmpty) { // create new constraint
+      aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
+          aValue, *anEntIter, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+      aConstraint.h = myStorage->addConstraint(aConstraint);
+      mySlvsConstraints.push_back(aConstraint.h);
+      if (!myBaseConstraint)
+        myStorage->addTemporaryConstraint(aConstraint.h);
+    } else { // update already existent constraint
+      aConstraint = myStorage->getConstraint(*aConstrIter);
+      aConstraint.ptA = *anEntIter;
+      myStorage->addConstraint(aConstraint);
+      aConstrIter++;
+      isEmpty = aConstrIter == mySlvsConstraints.end();
+    }
+  }
+}
+
+
+void SketchSolver_ConstraintRigid::getAttributes(
+    double& theValue,
+    std::vector<Slvs_hEntity>& theAttributes)
+{
+  theValue = 0.0;
+  int aType = SLVS_E_UNKNOWN; // type of created entity
+  Slvs_hEntity anEntityID = SLVS_E_UNKNOWN;
+  if (myBaseConstraint) {
+    // Get the attribute of constraint
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
+    if (!aRefAttr) {
+      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+      return;
+    }
+    anEntityID = myGroup->getAttributeId(aRefAttr);
+    if (anEntityID == SLVS_E_UNKNOWN)
+      anEntityID = changeEntity(aRefAttr, aType);
+  } else {
+    anEntityID = myGroup->getFeatureId(myBaseFeature);
+    if (anEntityID == SLVS_E_UNKNOWN)
+      anEntityID = changeEntity(myBaseFeature, aType);
+  }
+
+  // Check the entity is complex
+  Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
+  if (anEntity.point[0] != SLVS_E_UNKNOWN) {
+    for (int i = 0; i < 4 && anEntity.point[i]; i++)
+      theAttributes.push_back(anEntity.point[i]);
+  } else // simple entity
+    theAttributes.push_back(anEntityID);
+}
+
+bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint)
+{
+  cleanErrorMsg();
+  if (theConstraint && theConstraint != myBaseConstraint)
+    return false;
+  bool isFullyRemoved = true;
+  std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+  for (; aCIter != mySlvsConstraints.end(); aCIter++)
+    isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
+
+  if (isFullyRemoved) {
+    myFeatureMap.clear();
+    myAttributeMap.clear();
+    myValueMap.clear();
+  } else
+    cleanRemovedEntities();
+  return true;
+}
+
diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.h b/src/SketchSolver/SketchSolver_ConstraintRigid.h
new file mode 100644 (file)
index 0000000..66f5816
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_ConstraintRigid.h
+// Created: 30 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintRigid_H_
+#define SketchSolver_ConstraintRigid_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class   SketchSolver_ConstraintRigid
+ *  \ingroup Plugins
+ *  \brief   Stores data of Rigid (Fixed) constraint
+ *
+ *  Rigid constraint may have NULL basic SketchPlugin constraint,
+ *  because the Rigid constraint may be temporary for correct moving of objects
+ */
+class SketchSolver_ConstraintRigid : public SketchSolver_Constraint
+{
+public:
+  /// Creates constraint to manage the given constraint from plugin
+  SketchSolver_ConstraintRigid(ConstraintPtr theConstraint)
+    : SketchSolver_Constraint(theConstraint)
+  {}
+  /// Creates temporary constraint based on feature
+  SketchSolver_ConstraintRigid(FeaturePtr theFeature);
+
+  /// \brief Tries to remove constraint
+  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+  /// \brief Returns the type of constraint
+  virtual int getType() const
+  { return SLVS_C_WHERE_DRAGGED; }
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process();
+
+  /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+  /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
+  /// \param[out] theAttributes list of attributes to be filled
+  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
+
+protected:
+  FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL)
+};
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_Error.h b/src/SketchSolver/SketchSolver_Error.h
new file mode 100644 (file)
index 0000000..0ef0147
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Error.h
+// Created: 29 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_Error_H_
+#define SketchSolver_Error_H_
+
+#include <string>
+
+/** \class SketchSolver_Error
+ *  \ingroup Plugins
+ *  \brief Collects all sketch solver error' codes
+ *         as inline static functions
+ */
+class SketchSolver_Error
+{
+ public:
+  /// The value parameter for the constraint
+  inline static const std::string& CONSTRAINTS()
+  {
+    static const std::string MY_ERROR_VALUE("Conflicting constraints");
+    return MY_ERROR_VALUE;
+  }
+  /// The entities need to have shared point, but they have not
+  inline static const std::string& NO_COINCIDENT_POINTS()
+  {
+    static const std::string MY_ERROR_VALUE("Objects should have coincident point");
+    return MY_ERROR_VALUE;
+  }
+  /// Attribute of a feature is not initialized
+  inline static const std::string& NOT_INITIALIZED()
+  {
+    static const std::string MY_ERROR_VALUE("Attribute is not initialized");
+    return MY_ERROR_VALUE;
+  }
+};
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_FeatureStorage.cpp b/src/SketchSolver/SketchSolver_FeatureStorage.cpp
new file mode 100644 (file)
index 0000000..9b8f133
--- /dev/null
@@ -0,0 +1,372 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_FeatureStorage.cpp
+// Created: 23 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#include <SketchSolver_FeatureStorage.h>
+
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_ResultConstruction.h>
+
+void SketchSolver_FeatureStorage::changeConstraint(ConstraintPtr theConstraint)
+{
+  std::list<AttributePtr> anAttributes = theConstraint->data()->attributes(std::string());
+  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+  for (; anIter != anAttributes.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (aRefAttr) {
+      if (!aRefAttr->isObject()) {
+        changeAttribute(aRefAttr->attr(), theConstraint);
+        continue;
+      }
+      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+          aRefAttr->object());
+      FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+          std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
+      if (aFeature)
+        changeFeature(aFeature, theConstraint);
+      continue;
+    }
+    AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+    if (aRefList) {
+      std::list<ObjectPtr> aList = aRefList->list();
+      std::list<ObjectPtr>::iterator aListIter = aList.begin();
+      for (; aListIter != aList.end(); aListIter++) {
+        ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+            *aListIter);
+        FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+            std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
+        if (aFeature)
+          changeFeature(aFeature, theConstraint);
+      }
+      continue;
+    }
+    changeAttribute(*anIter, theConstraint);
+  }
+  myConstraints.insert(theConstraint);
+}
+
+void SketchSolver_FeatureStorage::removeConstraint(ConstraintPtr theConstraint)
+{
+  DataPtr aData = theConstraint->data();
+  if (aData) { // Constraint has data. Iterate through its attributes and remove them
+    std::list<AttributePtr> anAttributes = aData->attributes(std::string());
+    std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+    for (; anIter != anAttributes.end(); anIter++) {
+      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+      if (aRefAttr) {
+        if (!aRefAttr->isObject()) {
+          removeAttribute(aRefAttr->attr(), theConstraint);
+          continue;
+        }
+        ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+            aRefAttr->object());
+        FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+            std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
+        if (aFeature)
+          removeFeature(aFeature, theConstraint);
+        continue;
+      }
+      AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+      if (aRefList) {
+        std::list<ObjectPtr> aList = aRefList->list();
+        std::list<ObjectPtr>::iterator aListIter = aList.begin();
+        for (; aListIter != aList.end(); aListIter++) {
+          ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+              *aListIter);
+          FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+              std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
+          if (aFeature)
+            removeFeature(aFeature, theConstraint);
+        }
+        continue;
+      }
+      removeAttribute(*anIter, theConstraint);
+    }
+  } else { // Constraint has no data. Search the links on it in the lists of back references for features and attributes
+    std::set<ConstraintPtr>::iterator aCIter;
+    MapFeatureConstraint::iterator aFeatIter = myFeatures.begin();
+    while (aFeatIter != myFeatures.end()) {
+      aCIter = aFeatIter->second.find(theConstraint);
+      if (aCIter != aFeatIter->second.end()) {
+        aFeatIter->second.erase(aCIter);
+        if (aFeatIter->second.empty()) {
+          MapFeatureConstraint::iterator aTmpIter = aFeatIter; // stores iterator for the next element, while the current is deleting
+          aTmpIter++;
+          myFeatures.erase(aFeatIter);
+          aFeatIter = aTmpIter;
+          continue;
+        }
+      }
+      aFeatIter++;
+    }
+    std::set<FeaturePtr>::iterator aFIter;
+    MapAttributeFeature::iterator anAttrIter = myAttributes.begin();
+    while (anAttrIter != myAttributes.end()) {
+      aFIter = anAttrIter->second.find(theConstraint);
+      if (aFIter != anAttrIter->second.end()) {
+        anAttrIter->second.erase(aFIter);
+        if (anAttrIter->second.empty()) {
+          MapAttributeFeature::iterator aTmpIter = anAttrIter; // stores iterator for the next element, while the current is deleting
+          aTmpIter++;
+          myAttributes.erase(anAttrIter);
+          anAttrIter = aTmpIter;
+          continue;
+        }
+      }
+      anAttrIter++;
+    }
+  }
+  myConstraints.erase(theConstraint);
+}
+
+bool SketchSolver_FeatureStorage::isInteract(ConstraintPtr theConstraint) const
+{
+  if (myConstraints.empty() || myConstraints.find(theConstraint) != myConstraints.end())
+    return true;
+
+  DataPtr aData = theConstraint->data();
+  if (!aData)
+    return false;
+
+  std::list<AttributePtr> anAttributes = aData->attributes(std::string());
+  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+  for (; anIter != anAttributes.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (aRefAttr) {
+      if (!aRefAttr->isObject()) {
+        if (isInteract(aRefAttr->attr()))
+          return true;
+        continue;
+      }
+      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+          aRefAttr->object());
+      FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+          std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
+      if (aFeature)
+        if (isInteract(aFeature))
+          return true;
+      continue;
+    }
+    AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+    if (aRefList) {
+      std::list<ObjectPtr> aList = aRefList->list();
+      std::list<ObjectPtr>::iterator aListIter = aList.begin();
+      for (; aListIter != aList.end(); aListIter++) {
+        ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+            *aListIter);
+        FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+            std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
+        if (aFeature)
+          if (isInteract(aFeature))
+            return true;
+      }
+      continue;
+    }
+    if (isInteract(*anIter))
+      return true;
+  }
+  return false;
+}
+
+
+void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature)
+{
+  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+  for (; anIter != anAttributes.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (aRefAttr) {
+      if (!aRefAttr->isObject())
+        changeAttribute(aRefAttr->attr(), theFeature);
+      continue;
+    }
+    changeAttribute(*anIter, theFeature);
+  }
+  if (myFeatures.find(theFeature) == myFeatures.end())
+    myFeatures[theFeature] = std::set<ConstraintPtr>();
+}
+
+void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint)
+{
+  // Change all attributes of the feature
+  changeFeature(theFeature);
+  // Add back reference feature to constraint
+  myFeatures[theFeature].insert(theConstraint);
+}
+
+void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature)
+{
+  MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature);
+  if (aFeatIter != myFeatures.end())
+    return; // no such feature
+
+  std::set<ConstraintPtr> aConstraints = aFeatIter->second;
+  std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
+  for (; aCIter != aConstraints.end(); aCIter++)
+    removeFeature(theFeature, *aCIter);
+}
+
+void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint)
+{
+  MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature);
+  if (aFeatIter != myFeatures.end())
+    return; // no such feature
+
+  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+  for (; anIter != anAttributes.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (aRefAttr) {
+      if (!aRefAttr->isObject())
+        removeAttribute(aRefAttr->attr(), theFeature);
+      continue;
+    }
+    removeAttribute(*anIter, theFeature);
+  }
+
+  aFeatIter->second.erase(theConstraint);
+  if (aFeatIter->second.empty())
+    myFeatures.erase(aFeatIter);
+}
+
+bool SketchSolver_FeatureStorage::isInteract(FeaturePtr theFeature) const
+{
+  if (myFeatures.find(theFeature) != myFeatures.end())
+    return true;
+
+  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+  for (; anIter != anAttributes.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (aRefAttr) {
+      if (!aRefAttr->isObject())
+        if (isInteract(aRefAttr->attr()))
+          return true;
+      continue;
+    }
+    if (isInteract(*anIter))
+      return true;
+  }
+  return false;
+}
+
+
+void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute)
+{
+  if (myAttributes.find(theAttribute) == myAttributes.end())
+    myAttributes[theAttribute] = std::set<FeaturePtr>();
+}
+
+void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature)
+{
+  MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
+  if (anAttrIter == myAttributes.end()) {
+    std::set<FeaturePtr> aFeatures;
+    aFeatures.insert(theFeature);
+    myAttributes[theAttribute] = aFeatures;
+    return;
+  }
+  anAttrIter->second.insert(theFeature);
+}
+
+void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute)
+{
+  MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
+  if (anAttrIter == myAttributes.end())
+    return;
+
+  std::set<FeaturePtr> aFeatures = anAttrIter->second;
+  std::set<FeaturePtr>::iterator aFeatIter = aFeatures.begin();
+  for (; aFeatIter != aFeatures.end(); aFeatIter++)
+    removeAttribute(theAttribute, *aFeatIter);
+}
+
+void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature)
+{
+  MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
+  if (anAttrIter != myAttributes.end())
+    return; // no such attribute
+
+  anAttrIter->second.erase(theFeature);
+  if (anAttrIter->second.empty())
+    myAttributes.erase(anAttrIter);
+}
+
+bool SketchSolver_FeatureStorage::isInteract(AttributePtr theAttribute) const
+{
+  return myAttributes.find(theAttribute) != myAttributes.end();
+}
+
+
+bool SketchSolver_FeatureStorage::isConsistent() const
+{
+  // Check the constraints are valid
+  std::set<ConstraintPtr>::const_iterator aCIter = myConstraints.begin();
+  for (; aCIter != myConstraints.end(); aCIter++)
+    if (!(*aCIter)->data() || !(*aCIter)->data()->isValid())
+      return false;
+  // Check the features are valid
+  MapFeatureConstraint::const_iterator aFIter = myFeatures.begin();
+  for (; aFIter != myFeatures.end(); aFIter++)
+    if (!aFIter->first->data() || !aFIter->first->data()->isValid())
+      return false;
+  // Check the attributes are valid
+  MapAttributeFeature::const_iterator aTIter = myAttributes.begin();
+  for (; aTIter != myAttributes.end(); aTIter++)
+    if (!aTIter->first->isInitialized())
+      return false;
+  return true;
+}
+
+std::set<ConstraintPtr> SketchSolver_FeatureStorage::getConstraints(FeaturePtr theFeature) const
+{
+  std::set<ConstraintPtr> aResult;
+  MapFeatureConstraint::const_iterator aFeatIter = myFeatures.find(theFeature);
+  if (aFeatIter != myFeatures.end())
+    aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
+
+  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+  std::list<AttributePtr>::const_iterator anAttrIter = anAttributes.begin();
+  for (; anAttrIter != anAttributes.end(); anAttrIter++) {
+    MapAttributeFeature::const_iterator anIt = myAttributes.find(*anAttrIter);
+    if (anIt == myAttributes.end())
+      continue;
+    std::set<FeaturePtr>::const_iterator aFIter = anIt->second.begin();
+    for (; aFIter != anIt->second.end(); aFIter++) {
+      aFeatIter = myFeatures.find(*aFIter);
+      if (aFeatIter != myFeatures.end())
+        aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
+      else {
+        ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFIter);
+        if (aConstraint)
+          aResult.insert(aConstraint);
+      }
+    }
+  }
+  return aResult;
+}
+
+std::set<ConstraintPtr> SketchSolver_FeatureStorage::getConstraints(AttributePtr theAttribute) const
+{
+  std::set<ConstraintPtr> aResult;
+  MapAttributeFeature::const_iterator anIt = myAttributes.find(theAttribute);
+  if (anIt == myAttributes.end())
+    return aResult;
+  std::set<FeaturePtr>::const_iterator aFIter = anIt->second.begin();
+  MapFeatureConstraint::const_iterator aFeatIter;
+  for (; aFIter != anIt->second.end(); aFIter++) {
+    aFeatIter = myFeatures.find(*aFIter);
+    if (aFeatIter != myFeatures.end())
+      aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
+    else {
+      ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFIter);
+      if (aConstraint)
+        aResult.insert(aConstraint);
+    }
+  }
+  return aResult;
+}
+
diff --git a/src/SketchSolver/SketchSolver_FeatureStorage.h b/src/SketchSolver/SketchSolver_FeatureStorage.h
new file mode 100644 (file)
index 0000000..287be5a
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_FeatureStorage.h
+// Created: 23 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_FeatureStorage_H_
+#define SketchSolver_FeatureStorage_H_
+
+#include <SketchSolver.h>
+#include <SketchPlugin_Feature.h>
+#include <SketchPlugin_Constraint.h>
+
+#include <set>
+#include <map>
+
+typedef std::map<FeaturePtr, std::set<ConstraintPtr> > MapFeatureConstraint;
+typedef std::map<AttributePtr, std::set<FeaturePtr> >  MapAttributeFeature;
+
+/** \class   SketchSolver_FeatureStorage
+ *  \ingroup Plugins
+ *  \brief   Collects information about SketchPlugin constraints used in specific group
+ */
+class SketchSolver_FeatureStorage
+{
+public:
+  SketchSolver_FeatureStorage() {}
+
+  /// \brief Adds or changes a constraint and all features it uses in the storage
+  void changeConstraint(ConstraintPtr theConstraint);
+  /// \brief Removes a constraint and all its features not used by other constraints
+  void removeConstraint(ConstraintPtr theConstraint);
+  /// \brief Verifies a constraint is used in the current storage
+  bool isInteract(ConstraintPtr theConstraint) const;
+
+  /// \brief Adds or changes a feature in the storage
+  void changeFeature(FeaturePtr theFeature);
+  /// \brief Adds or changes a feature in the storage. The feature is used in specified constraint
+  void changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint);
+  /// \brief Removes a feature
+  void removeFeature(FeaturePtr theFeature);
+  /// \brief Removes a feature according to a given constraint
+  void removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint);
+  /// \brief Verifies a feature is used in the current storage
+  bool isInteract(FeaturePtr theFeature) const;
+
+  /// \brief Adds or changes an attribute in the storage
+  void changeAttribute(AttributePtr theAttribute);
+  /// \brief Adds or changes a attribute in the storage.
+  ///        The attribute is used in specified feature or constraint (theFeature)
+  void changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature);
+  /// \brief Removes an attribute
+  void removeAttribute(AttributePtr theAttribute);
+  /// \brief Removes an attribute according to a given feature
+  void removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature);
+  /// \brief Verifies an attribute is used in the current storage
+  bool isInteract(AttributePtr theAttribute) const;
+
+  /// \brief Check the features is not removed
+  bool isConsistent() const;
+
+  /// \brief Prepares list of constraints, which using specified feature or its attributes
+  std::set<ConstraintPtr> getConstraints(FeaturePtr theFeature) const;
+  /// \brief Prepares list of constraints, which using specified attribute
+  std::set<ConstraintPtr> getConstraints(AttributePtr theAttribute) const;
+
+private:
+  std::set<ConstraintPtr> myConstraints; ///< list of SketchPlugin constraints used in the current group
+  MapFeatureConstraint myFeatures; ///< list of features used in the group and corresponding constraints which use the feature
+  MapAttributeFeature myAttributes; ///< list of attributes used in the group and corresponding features which are based on the attribute
+};
+
+typedef std::shared_ptr<SketchSolver_FeatureStorage> FeatureStoragePtr;
+
+#endif // SketchSolver_FeatureStorage_H_
diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp
new file mode 100644 (file)
index 0000000..f5b0ee3
--- /dev/null
@@ -0,0 +1,2028 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Group.cpp
+// Created: 27 May 2014
+// Author:  Artem ZHIDKOV
+
+#include "SketchSolver_Group.h"
+
+#include <SketchSolver_Builder.h>
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchSolver_Error.h>
+
+#include <Events_Error.h>
+#include <Events_Loop.h>
+#include <GeomAPI_XY.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_Document.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_ResultConstruction.h>
+
+#include <SketchPlugin_Constraint.h>
+#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintRigid.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <math.h>
+#include <assert.h>
+
+
+/// \brief This class is used to give unique index to the groups
+class GroupIndexer
+{
+public:
+  /// \brief Return vacant index
+  static Slvs_hGroup NEW_GROUP() { return ++myGroupIndex; }
+  /// \brief Removes the index
+  static void REMOVE_GROUP(const Slvs_hGroup& theIndex) {
+    if (myGroupIndex == theIndex)
+      myGroupIndex--;
+  }
+
+private:
+  GroupIndexer() {};
+
+  static Slvs_hGroup myGroupIndex; ///< index of the group
+};
+
+Slvs_hGroup GroupIndexer::myGroupIndex = 0;
+
+
+/** \brief Search the entity/parameter with specified ID in the list of elements
+ *  \param[in] theEntityID unique ID of the element
+ *  \param[in] theEntities list of elements
+ *  \return position of the found element or -1 if the element is not found
+ */
+template<typename T>
+static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
+
+// ========================================================
+// =========  SketchSolver_Group  ===============
+// ========================================================
+
+SketchSolver_Group::SketchSolver_Group(
+    std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
+    : myID(GroupIndexer::NEW_GROUP())
+{
+  // Initialize workplane
+  myWorkplaneID = SLVS_E_UNKNOWN;
+#ifndef NDEBUG
+  assert(addWorkplane(theWorkplane));
+#else
+  addWorkplane(theWorkplane);
+#endif
+}
+
+SketchSolver_Group::~SketchSolver_Group()
+{
+  myConstraints.clear();
+  GroupIndexer::REMOVE_GROUP(myID);
+}
+
+// ============================================================================
+//  Function: isBaseWorkplane
+//  Class:    SketchSolver_Group
+//  Purpose:  verify the group is based on the given workplane
+// ============================================================================
+bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const
+{
+  return theWorkplane == mySketch;
+}
+
+// ============================================================================
+//  Function: isInteract
+//  Class:    SketchSolver_Group
+//  Purpose:  verify are there any entities in the group used by given constraint
+// ============================================================================
+bool SketchSolver_Group::isInteract(
+    std::shared_ptr<SketchPlugin_Feature> theFeature) const
+{
+  // Empty group interacts with everything
+  if (isEmpty()) return true;
+  ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
+  if (aConstraint)
+    return myFeatureStorage->isInteract(aConstraint);
+  return myFeatureStorage->isInteract(theFeature);
+}
+
+// ============================================================================
+//  Function: getFeatureId
+//  Class:    SketchSolver_Group
+//  Purpose:  Find the identifier of the feature, if it already exists in the group
+// ============================================================================
+Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const
+{
+  if (!myFeatureStorage)
+    return SLVS_E_UNKNOWN;
+  std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theFeature);
+  if (aConstraints.empty())
+    return SLVS_E_UNKNOWN;
+  ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstraints.begin());
+  if (aCIter == myConstraints.end())
+    return SLVS_E_UNKNOWN;
+  return aCIter->second->getId(theFeature);
+}
+
+// ============================================================================
+//  Function: getAttributeId
+//  Class:    SketchSolver_Group
+//  Purpose:  Find the identifier of the attribute, if it already exists in the group
+// ============================================================================
+Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const
+{
+  if (!myFeatureStorage)
+    return SLVS_E_UNKNOWN;
+  std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theAttribute);
+  if (aConstraints.empty())
+    return SLVS_E_UNKNOWN;
+  ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstraints.begin());
+  if (aCIter == myConstraints.end())
+    return SLVS_E_UNKNOWN;
+  return aCIter->second->getId(theAttribute);
+}
+
+
+////// ============================================================================
+//////  Function: checkConstraintConsistence
+//////  Class:    SketchSolver_Group
+//////  Purpose:  verifies and changes parameters of the constraint
+////// ============================================================================
+////void SketchSolver_Group::checkConstraintConsistence(Slvs_Constraint& theConstraint)
+////{
+////  if (theConstraint.type == SLVS_C_PT_LINE_DISTANCE) {
+////    // Get constraint parameters and check the sign of constraint value
+////
+////    // point coordinates
+////    int aPtPos = Search(theConstraint.ptA, myEntities);
+////    int aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
+////    std::shared_ptr<GeomAPI_XY> aPoint(
+////        new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
+////
+////    // line coordinates
+////    int aLnPos = Search(theConstraint.entityA, myEntities);
+////    aPtPos = Search(myEntities[aLnPos].point[0], myEntities);
+////    aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
+////    std::shared_ptr<GeomAPI_XY> aStart(
+////        new GeomAPI_XY(-myParams[aPtParamPos].val, -myParams[aPtParamPos + 1].val));
+////    aPtPos = Search(myEntities[aLnPos].point[1], myEntities);
+////    aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
+////    std::shared_ptr<GeomAPI_XY> aEnd(
+////        new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
+////
+////    aEnd = aEnd->added(aStart);
+////    aPoint = aPoint->added(aStart);
+////    if (aPoint->cross(aEnd) * theConstraint.valA < 0.0)
+////      theConstraint.valA *= -1.0;
+////  }
+////}
+
+// ============================================================================
+//  Function: changeConstraint
+//  Class:    SketchSolver_Group
+//  Purpose:  create/update the constraint in the group
+// ============================================================================
+bool SketchSolver_Group::changeConstraint(
+    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+{
+  // There is no workplane yet, something wrong
+  if (myWorkplaneID == SLVS_E_UNKNOWN)
+    return false;
+
+  if (!theConstraint)
+    return false;
+
+  if (myConstraints.find(theConstraint) == myConstraints.end()) {
+    // Add constraint to the current group
+    SolverConstraintPtr aConstraint =
+        SketchSolver_Builder::getInstance()->createConstraint(theConstraint);
+    if (!aConstraint)
+      return false;
+    aConstraint->setGroup(this);
+    aConstraint->setStorage(myStorage);
+    if (!aConstraint->error().empty()) {
+      if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
+        return false; // some attribute are not initialized yet, don't show message
+      Events_Error::send(aConstraint->error(), this);
+    }
+
+    // Additional verification of coincidence of several points
+    if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+      ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+      for (; aCIter != myConstraints.end(); aCIter++) {
+        std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoincidence =
+          std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aCIter->second);
+        if (!aCoincidence)
+          continue;
+        std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoinc2 =
+          std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aConstraint);
+        if (aCoincidence != aCoinc2 && aCoincidence->isCoincide(aCoinc2)) {
+          aCoincidence->attach(aCoinc2);
+          aConstraint = aCoincidence;
+        }
+      }
+    }
+    myConstraints[theConstraint] = aConstraint;
+  }
+  else
+    myConstraints[theConstraint]->update();
+
+  if (!myFeatureStorage)
+    myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
+  myFeatureStorage->changeConstraint(theConstraint);
+
+////  if (theConstraint) {
+////    if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID())
+////      return changeRigidConstraint(theConstraint);
+////    if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID())
+////      return changeMirrorConstraint(theConstraint);
+////    if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID())
+////      return changeFilletConstraint(theConstraint);
+////  }
+////
+////  // Search this constraint in the current group to update it
+////  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
+////  std::vector<Slvs_Constraint>::iterator aConstrIter;
+////  if (aConstrMapIter != myConstraintMap.end()) {
+////    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
+////    aConstrIter = myConstraints.begin() + aConstrPos;
+////  }
+////
+////  // Get constraint type and verify the constraint parameters are correct
+////  SketchSolver_Constraint aConstraint(theConstraint);
+////  int aConstrType = aConstraint.getType();
+////  if (aConstrType == SLVS_C_UNKNOWN
+////      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
+////    return false;
+////  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
+////
+////  // Create constraint parameters
+////  double aDistance = 0.0;  // scalar value of the constraint
+////  AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+////      theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE()));
+////  if (aDistAttr) {
+////    aDistance = aDistAttr->value();
+////    // Issue #196: checking the positivity of the distance constraint
+////    if (aDistance < tolerance &&
+////       (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE))
+////      return false;
+////    // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
+////    if (aConstrType == SLVS_C_DIAMETER)
+////      aDistance *= 2.0;
+////    if (aConstrMapIter != myConstraintMap.end()
+////        && fabs(aConstrIter->valA - aDistance) > tolerance) {
+////      myNeedToSolve = true;
+////      aConstrIter->valA = aDistance;
+////    }
+////  }
+////
+////  size_t aNbTmpConstraints = myTempConstraints.size();
+////  Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE];  // parameters of the constraint
+////  for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
+////    aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
+////    std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
+////        ModelAPI_AttributeRefAttr>(
+////        theConstraint->data()->attribute(aConstraintAttributes[indAttr]));
+////    if (!aConstrAttr)
+////      continue;
+////
+////    // Convert the object of the attribute to the feature
+////    FeaturePtr aFeature;
+////    if (aConstrAttr->isObject() && aConstrAttr->object()) {
+////      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+////          aConstrAttr->object());
+////      if (!aRC)
+////        continue;
+////      std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
+////      aFeature = aDoc->feature(aRC);
+////    }
+////
+////    // For the length constraint the start and end points of the line should be added to the entities list instead of line
+////    if (aConstrType == SLVS_C_PT_PT_DISTANCE
+////        && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0) {
+////      Slvs_hEntity aLineEnt = changeEntityFeature(aFeature);
+////      int aEntPos = Search(aLineEnt, myEntities);
+////      aConstrEnt[indAttr++] = myEntities[aEntPos].point[0];
+////      aConstrEnt[indAttr++] = myEntities[aEntPos].point[1];
+////      while (indAttr < CONSTRAINT_ATTR_SIZE)
+////        aConstrEnt[indAttr++] = 0;
+////      break;  // there should be no other entities
+////    } else if (aConstrAttr->isObject())
+////      aConstrEnt[indAttr] = changeEntityFeature(aFeature);
+////    else
+////      aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
+////  }
+////
+////  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
+////    // Several points may be coincident, it is not necessary to store all constraints between them.
+////    // Try to find sequence of coincident points which connects the points of new constraint
+////    if (aConstrType == SLVS_C_POINTS_COINCIDENT) {
+////      if (aConstrEnt[0] == aConstrEnt[1])  // no need to add self coincidence
+////        return false;
+////      if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) {
+////        myExtraCoincidence.insert(theConstraint);  // the constraint is stored for further purposes
+////        return false;
+////      }
+////      if (aNbTmpConstraints < myTempConstraints.size()) {
+////        // There was added temporary constraint. Check that there is no coincident points which already rigid.
+////
+////        // Get list of already fixed points
+////        std::set<Slvs_hEntity> anAlreadyFixed;
+////        std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
+////        for (; aCIter != myConstraints.end(); aCIter++)
+////          if (aCIter->type == SLVS_C_WHERE_DRAGGED) {
+////            std::list<Slvs_hConstraint>::const_iterator aTmpIt = myTempConstraints.begin();
+////            for (; aTmpIt != myTempConstraints.end(); aTmpIt++)
+////              if (*aTmpIt == aCIter->h)
+////                break;
+////            if (aTmpIt == myTempConstraints.end())
+////              anAlreadyFixed.insert(aCIter->ptA);
+////          }
+////
+////        std::set<Slvs_hConstraint> aTmpConstrToDelete;
+////        std::list<Slvs_hConstraint>::reverse_iterator aTmpIter = myTempConstraints.rbegin();
+////        size_t aCurSize = myTempConstraints.size();
+////        for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend();
+////            aTmpIter++, aCurSize--) {
+////          int aConstrPos = Search(*aTmpIter, myConstraints);
+////          std::vector<std::set<Slvs_hEntity> >::const_iterator
+////            aCoincIter = myCoincidentPoints.begin();
+////          for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
+////            if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) {
+////              std::set<Slvs_hEntity>::const_iterator anIt;
+////              for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++)
+////                if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) {
+////                  aTmpConstrToDelete.insert(*aTmpIter);
+////                  break;
+////                }
+////              break;
+////            }
+////        }
+////        if (!aTmpConstrToDelete.empty())
+////          removeTemporaryConstraints(aTmpConstrToDelete);
+////      }
+////    }
+////    // For the tangency constraints it is necessary to identify which points of entities are coincident
+////    int aSlvsOtherFlag = 0;
+////    int aSlvsOther2Flag = 0;
+////    if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) {
+////      // Search entities used by constraint
+////      int anEnt1Pos = Search(aConstrEnt[2], myEntities);
+////      int anEnt2Pos = Search(aConstrEnt[3], myEntities);
+////      // Obtain start and end points of entities
+////      Slvs_hEntity aPointsToFind[4];
+////      aPointsToFind[0] = myEntities[anEnt1Pos].point[1];
+////      aPointsToFind[1]= myEntities[anEnt1Pos].point[2];
+////      bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT);
+////      aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1];
+////      aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2];
+////      // Search coincident points
+////      bool isPointFound[4];
+////      std::vector<std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
+////      for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) {
+////        for (int i = 0; i < 4; i++)
+////          isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end());
+////        if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) {
+////          // the arc is tangent by end point
+////          if (isPointFound[1]) aSlvsOtherFlag = 1;
+////          // the second item is an arc and it is tangent by end point too
+////          if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1;
+////          break;
+////        }
+////      }
+////      if (aCPIter == myCoincidentPoints.end()) {
+////        // There is no coincident points between tangential objects. Generate error message
+////        Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
+////        return false;
+////      }
+////    }
+////
+////    // Create SolveSpace constraint structure
+////    Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
+////                                                      myWorkplane.h, aDistance, aConstrEnt[0],
+////                                                      aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
+////    if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag;
+////    if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag;
+////    myConstraints.push_back(aSlvsConstr);
+////    myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aSlvsConstr.h);
+////    int aConstrPos = Search(aSlvsConstr.h, myConstraints);
+////    aConstrIter = myConstraints.begin() + aConstrPos;
+////    myNeedToSolve = true;
+////  } else { // Attributes of constraint may be changed => update constraint
+////    Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB,
+////                                   &aConstrIter->entityA, &aConstrIter->entityB,
+////                                   &aConstrIter->entityC, &aConstrIter->entityD};
+////    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
+////      if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr])
+////      {
+////        *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr];
+////        myNeedToSolve = true;
+////      }
+////    }
+////  }
+////
+////  // Update flags of entities to be used by constraints
+////  for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
+////    if (aConstrEnt[indAttr] != 0) {
+////      int aPos = Search(aConstrEnt[indAttr], myEntities);
+////      myEntOfConstr[aPos] = true;
+////      // Sub-entities should be used implcitly
+////      Slvs_hEntity* aEntPtr = myEntities[aPos].point;
+////      while (*aEntPtr != 0) {
+////        aPos = Search(*aEntPtr, myEntities);
+////        myEntOfConstr[aPos] = true;
+////        aEntPtr++;
+////      }
+////    }
+////
+////  checkConstraintConsistence(*aConstrIter);
+  return true;
+}
+
+void SketchSolver_Group::moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
+{
+  std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theFeature);
+  std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
+  for (; aCIter != aConstraints.end(); aCIter++) {
+    ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter);
+    aSolConIter->second->update();
+  }
+
+  // Temporary rigid constraint
+  SolverConstraintPtr aConstraint =
+      SketchSolver_Builder::getInstance()->createRigidConstraint(theFeature);
+  if (!aConstraint)
+    return;
+  aConstraint->setGroup(this);
+  aConstraint->setStorage(myStorage);
+  myTempConstraints.insert(aConstraint);
+}
+
+////// ============================================================================
+//////  Function: changeRigidConstraint
+//////  Class:    SketchSolver_Group
+//////  Purpose:  create/update the "Rigid" constraint in the group
+////// ============================================================================
+////bool SketchSolver_Group::changeRigidConstraint(
+////    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+////{
+////  // Search this constraint in the current group to update it
+////  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
+////  std::vector<Slvs_Constraint>::iterator aConstrIter;
+////  if (aConstrMapIter != myConstraintMap.end()) {
+////    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
+////    aConstrIter = myConstraints.begin() + aConstrPos;
+////  }
+////
+////  // Get constraint type and verify the constraint parameters are correct
+////  SketchSolver_Constraint aConstraint(theConstraint);
+////  int aConstrType = aConstraint.getType();
+////  if (aConstrType == SLVS_C_UNKNOWN
+////      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
+////    return false;
+////  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
+////
+////  Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN;
+////  std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
+////      ModelAPI_AttributeRefAttr>(
+////      theConstraint->data()->attribute(aConstraintAttributes[0]));
+////  if (!aConstrAttr)
+////    return false;
+////
+////  // Convert the object of the attribute to the feature
+////  FeaturePtr aFeature;
+////  if (aConstrAttr->isObject() && aConstrAttr->object()) {
+////    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+////        aConstrAttr->object());
+////    if (!aRC)
+////      return false;
+////    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
+////    aFeature = aDoc->feature(aRC);
+////  }
+////
+////  aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr());
+////
+////  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
+////    // Check the fixed entity is not a point.
+////    std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
+////        ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0]));
+////    std::shared_ptr<GeomDataAPI_Point> aPoint =
+////        std::dynamic_pointer_cast<GeomDataAPI_Point>(aConstrAttr->attr());
+////    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aConstrAttr->attr());
+////    if (aPoint || aPoint2D) {
+////      // Create SolveSpace constraint structure
+////      Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+////          ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
+////          aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+////      myConstraints.push_back(aConstraint);
+////      myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aConstraint.h);
+////      int aConstrPos = Search(aConstraint.h, myConstraints);
+////      aConstrIter = myConstraints.begin() + aConstrPos;
+////      myNeedToSolve = true;
+////    } else {
+////      myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
+////
+////      // To avoid SolveSpace problems:
+////      // * if the circle is rigid, we will fix its center and radius;
+////      // * if the arc is rigid, we will fix its start and end points and radius.
+////      double aRadius = 0.0;
+////      bool isArc = false;
+////      bool isCircle = false;
+////      if (aFeature) {
+////        if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
+////          std::shared_ptr<GeomDataAPI_Point2D> aCenter =
+////              std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+////              aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
+////          std::shared_ptr<GeomDataAPI_Point2D> aStart =
+////              std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+////              aFeature->data()->attribute(SketchPlugin_Arc::START_ID()));
+////          aRadius = aStart->pnt()->distance(aCenter->pnt());
+////          isArc = true;
+////        } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
+////          aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+////              aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
+////          isCircle = true;
+////        }
+////      }
+////
+////      // Get list of already fixed points
+////      std::set<Slvs_hEntity> anAlreadyFixed;
+////      std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
+////      for (; aCIter != myConstraints.end(); aCIter++)
+////        if (aCIter->type == SLVS_C_WHERE_DRAGGED)
+////          anAlreadyFixed.insert(aCIter->ptA);
+////
+////      // Create constraints to fix the parameters of the entity
+////      int aEntPos = Search(aConstrEnt, myEntities);
+////      Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point;
+////      if (isArc) aPointsPtr++; // avoid to fix center of arc
+////      while (*aPointsPtr != 0) {
+////        // Avoid to create additional "Rigid" constraints for coincident points
+////        bool isCoincAlreadyFixed = false;
+////        if (!anAlreadyFixed.empty()) {
+////          if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end())
+////            isCoincAlreadyFixed = true;
+////
+////          std::vector<std::set<Slvs_hEntity> >::const_iterator aCoincIter =
+////              myCoincidentPoints.begin();
+////          for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) {
+////            if (aCoincIter->find(*aPointsPtr) == aCoincIter->end())
+////              continue;
+////            std::set<Slvs_hEntity>::const_iterator anIter = anAlreadyFixed.begin();
+////            for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++)
+////              if (aCoincIter->find(*anIter) != aCoincIter->end())
+////                isCoincAlreadyFixed = true;
+////          }
+////        }
+////
+////        if (!isCoincAlreadyFixed) {
+////          Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+////              ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
+////              *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+////          myConstraints.push_back(aConstraint);
+////          myConstraintMap[theConstraint].push_back(aConstraint.h);
+////        }
+////        aPointsPtr++;
+////      }
+////
+////      if (isArc || isCircle) { // add radius constraint
+////        Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+////            ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius,
+////            SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN);
+////        myConstraints.push_back(aConstraint);
+////        myConstraintMap[theConstraint].push_back(aConstraint.h);
+////      }
+////
+////      // The object is already rigid, so there is no constraints added
+////      if (myConstraintMap[theConstraint].empty()) {
+////        myConstraintMap.erase(theConstraint);
+////        myNeedToSolve = false;
+////      }
+////      else
+////        myNeedToSolve = true;
+////    }
+////  }
+////  return true;
+////}
+////
+////// ============================================================================
+//////  Function: changeMirrorConstraint
+//////  Class:    SketchSolver_Group
+//////  Purpose:  create/update the "Mirror" constraint in the group
+////// ============================================================================
+////bool SketchSolver_Group::changeMirrorConstraint(
+////    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+////{
+////  DataPtr aConstrData = theConstraint->data();
+////
+////  // Search this constraint in the current group to update it
+////  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
+////  std::vector<Slvs_Constraint>::iterator aConstrIter;
+////  if (aConstrMapIter != myConstraintMap.end()) {
+////    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
+////    aConstrIter = myConstraints.begin() + aConstrPos;
+////  }
+////
+////  // Get constraint type and verify the constraint parameters are correct
+////  SketchSolver_Constraint aConstraint(theConstraint);
+////  int aConstrType = aConstraint.getType();
+////  if (aConstrType == SLVS_C_UNKNOWN
+////      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
+////    return false;
+////  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
+////
+////  Slvs_hEntity aMirrorLineEnt = SLVS_E_UNKNOWN;
+////  AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+////      aConstrData->attribute(aConstraintAttributes[0]));
+////  if (!aConstrAttr)
+////    return false;
+////
+////  // Convert the object of the attribute to the feature
+////  FeaturePtr aMirrorLineFeat;
+////  if (aConstrAttr->isObject() && aConstrAttr->object()) {
+////    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+////        aConstrAttr->object());
+////    if (!aRC)
+////      return false;
+////    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
+////    aMirrorLineFeat = aDoc->feature(aRC);
+////  }
+////  aMirrorLineEnt = aConstrAttr->isObject() ?
+////      changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr());
+////
+////  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
+////    // Append symmetric constraint for each point of mirroring features
+////    AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+////        aConstrData->attribute(aConstraintAttributes[1]));
+////    AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+////        aConstrData->attribute(aConstraintAttributes[2]));
+////    if (!aBaseRefList || !aMirroredRefList)
+////      return false;
+////
+////    std::list<ObjectPtr> aBaseList = aBaseRefList->list();
+////    std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
+////    if (aBaseList.size() != aMirroredList.size())
+////      return false;
+////
+////    myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
+////
+////    FeaturePtr aBaseFeature, aMirrorFeature;
+////    ResultConstructionPtr aRC;
+////    std::list<ObjectPtr>::iterator aBaseIter = aBaseList.begin();
+////    std::list<ObjectPtr>::iterator aMirIter = aMirroredList.begin();
+////    for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) {
+////      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
+////      aBaseFeature = aRC ? aRC->document()->feature(aRC) :
+////          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aBaseIter);
+////      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirIter);
+////      aMirrorFeature = aRC ? aRC->document()->feature(aRC) :
+////          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aMirIter);
+////
+////      if (!aBaseFeature || !aMirrorFeature || 
+////          aBaseFeature->getKind() != aMirrorFeature->getKind())
+////        return false;
+////      Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature);
+////      Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature);
+////      // Make aMirrorEnt parameters to be symmetric with aBaseEnt
+////      makeMirrorEntity(aBaseEnt, aMirrorEnt, aMirrorLineEnt);
+////
+////      if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) {
+////        Slvs_Constraint aConstraint = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
+////            myWorkplane.h, 0.0, aBaseEnt, aMirrorEnt, aMirrorLineEnt, SLVS_E_UNKNOWN);
+////        myConstraints.push_back(aConstraint);
+////        myConstraintMap[theConstraint].push_back(aConstraint.h);
+////      } else {
+////        int aBasePos = Search(aBaseEnt, myEntities);
+////        int aMirrorPos = Search(aMirrorEnt, myEntities);
+////        if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) {
+////          for (int ind = 0; ind < 2; ind++) {
+////            Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+////                ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
+////                myEntities[aBasePos].point[ind], myEntities[aMirrorPos].point[ind],
+////                aMirrorLineEnt, SLVS_E_UNKNOWN);
+////            myConstraints.push_back(aConstraint);
+////            myConstraintMap[theConstraint].push_back(aConstraint.h);
+////          }
+////        } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
+////          Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+////              ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
+////              myEntities[aBasePos].point[0], myEntities[aMirrorPos].point[0],
+////              aMirrorLineEnt, SLVS_E_UNKNOWN);
+////          myConstraints.push_back(aConstraint);
+////          myConstraintMap[theConstraint].push_back(aConstraint.h);
+////          // Additional constraint for equal radii
+////          Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
+////              ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0,
+////              SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt);
+////          myConstraints.push_back(anEqRadConstr);
+////          myConstraintMap[theConstraint].push_back(anEqRadConstr.h);
+////        } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
+////          // Workaround to avoid problems in SolveSpace.
+////          // The symmetry of two arcs will be done using symmetry of three points on these arcs:
+////          // start point, end point, and any other point on the arc
+////          Slvs_hEntity aBaseArcPoints[3] = {
+////              myEntities[aBasePos].point[1],
+////              myEntities[aBasePos].point[2],
+////              SLVS_E_UNKNOWN};
+////          Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
+////              myEntities[aMirrorPos].point[2],
+////              myEntities[aMirrorPos].point[1],
+////              SLVS_E_UNKNOWN};
+////          Slvs_hEntity aBothArcs[2] = {aBaseEnt, aMirrorEnt};
+////          Slvs_hEntity aBothMiddlePoints[2];
+////          for (int i = 0; i < 2; i++) {
+////            double x, y;
+////            calculateMiddlePoint(aBothArcs[i], x, y);
+////            std::vector<Slvs_Param>::iterator aParamIter = myParams.end();
+////            Slvs_hParam u = changeParameter(x, aParamIter);
+////            Slvs_hParam v = changeParameter(y, aParamIter);
+////            Slvs_Entity aPoint = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, u, v);
+////            myEntities.push_back(aPoint);
+////            aBothMiddlePoints[i] = aPoint.h;
+////            // additional constraint point-on-curve
+////            Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
+////                ++myConstrMaxID, myID, SLVS_C_PT_ON_CIRCLE, myWorkplane.h, 0.0,
+////                aPoint.h, SLVS_E_UNKNOWN, aBothArcs[i], SLVS_E_UNKNOWN);
+////            myConstraints.push_back(aPonCircConstr);
+////            myConstraintMap[theConstraint].push_back(aPonCircConstr.h);
+////          }
+////
+////          aBaseArcPoints[2] = aBothMiddlePoints[0];
+////          aMirrorArcPoints[2] = aBothMiddlePoints[1];
+////          for (int ind = 0; ind < 3; ind++) {
+////            Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+////                ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
+////                aBaseArcPoints[ind], aMirrorArcPoints[ind], aMirrorLineEnt, SLVS_E_UNKNOWN);
+////            myConstraints.push_back(aConstraint);
+////            myConstraintMap[theConstraint].push_back(aConstraint.h);
+////          }
+////        }
+////      }
+////    }
+////
+////    // Set the mirror line unchanged during constraint recalculation
+////    int aMirrorLinePos = Search(aMirrorLineEnt, myEntities);
+////    Slvs_Constraint aRigidStart = Slvs_MakeConstraint(
+////        ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
+////        myEntities[aMirrorLinePos].point[0], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+////    myConstraints.push_back(aRigidStart);
+////    myConstraintMap[theConstraint].push_back(aRigidStart.h);
+////    Slvs_Constraint aRigidEnd = Slvs_MakeConstraint(
+////        ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
+////        myEntities[aMirrorLinePos].point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+////    myConstraints.push_back(aRigidEnd);
+////    myConstraintMap[theConstraint].push_back(aRigidEnd.h);
+////
+////    // Add temporary constraints for initial objects to be unchanged
+////    for (aBaseIter = aBaseList.begin(); aBaseIter != aBaseList.end(); aBaseIter++) {
+////      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
+////      aBaseFeature = aRC ? aRC->document()->feature(aRC) :
+////          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aBaseIter);
+////      if (!aBaseFeature) continue;
+////      std::list<AttributePtr> aPoints = aBaseFeature->data()->attributes(GeomDataAPI_Point2D::type());
+////      std::list<AttributePtr>::iterator anIt = aPoints.begin();
+////      for ( ; anIt != aPoints.end(); anIt++) {
+////        // Arcs are fixed by center and start points only (to avoid solving errors in SolveSpace)
+////        if (aBaseFeature->getKind() == SketchPlugin_Arc::ID() &&
+////            (*anIt)->id() == SketchPlugin_Arc::END_ID())
+////          continue;
+////        addTemporaryConstraintWhereDragged(*anIt);
+////      }
+////    }
+////  }
+////  return true;
+////}
+////
+////// ============================================================================
+//////  Function: changeFilletConstraint
+//////  Class:    SketchSolver_Group
+//////  Purpose:  create/update the "Fillet" constraint in the group
+////// ============================================================================
+////bool SketchSolver_Group::changeFilletConstraint(
+////    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+////{
+////  DataPtr aConstrData = theConstraint->data();
+////
+////  // Search this constraint in the current group to update it
+////  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
+////  std::vector<Slvs_Constraint>::iterator aConstrIter;
+////  if (aConstrMapIter != myConstraintMap.end()) {
+////    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
+////    aConstrIter = myConstraints.begin() + aConstrPos;
+////  }
+////
+////  // Get constraint type and verify the constraint parameters are correct
+////  SketchSolver_Constraint aConstraint(theConstraint);
+////  int aConstrType = aConstraint.getType();
+////  if (aConstrType == SLVS_C_UNKNOWN)
+////    return false;
+////  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
+////
+////  // Obtain hEntity for basic objects of fillet
+////  Slvs_hEntity aBaseObject[2];
+////  FeaturePtr aBaseFeature[2];
+////  for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
+////    AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+////        aConstrData->attribute(aConstraintAttributes[indAttr]));
+////    if (!aConstrAttr)
+////      return false;
+////    if (aConstrAttr->isObject() && aConstrAttr->object()) {
+////      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+////          aConstrAttr->object());
+////      if (!aRC)
+////        return false;
+////      std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
+////      aBaseFeature[indAttr] = aDoc->feature(aRC);
+////    }
+////    aBaseObject[indAttr] = aConstrAttr->isObject() ?
+////        changeEntityFeature(aBaseFeature[indAttr]) : changeEntity(aConstrAttr->attr());
+////  }
+////  // Check the base entities have a coincident point
+////  int aBaseObjInd[2] = {
+////      Search(aBaseObject[0], myEntities),
+////      Search(aBaseObject[1], myEntities)
+////    };
+////  int aShift[2] = { // shift for calculating correct start and end points for different types of objects
+////      myEntities[aBaseObjInd[0]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
+////      myEntities[aBaseObjInd[1]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
+////    };
+////  Slvs_hEntity aFirstObjPoints[2] = { // indices of start and end point of first object
+////      myEntities[aBaseObjInd[0]].point[aShift[0]],
+////      myEntities[aBaseObjInd[0]].point[1+aShift[0]]
+////    };
+////  Slvs_hEntity aSecondObjPoints[2] = { // indices of start and end point of second object
+////      myEntities[aBaseObjInd[1]].point[aShift[1]],
+////      myEntities[aBaseObjInd[1]].point[1+aShift[1]]
+////    };
+////  bool isCoincidentFound = false;
+////  int aBaseCoincInd[2] = {0, 0}; // indices in aFirstObjPoint and aSecondObjPoint identifying coincident points
+////  std::vector<std::set<Slvs_hEntity> >::iterator aCPIter = myCoincidentPoints.begin();
+////  for ( ; aCPIter != myCoincidentPoints.end() && !isCoincidentFound; aCPIter++)
+////    for (int ind1 = 0; ind1 < 2 && !isCoincidentFound; ind1++)
+////      for (int ind2 = 0; ind2 < 2 && !isCoincidentFound; ind2++)
+////        if (aCPIter->find(aFirstObjPoints[ind1]) != aCPIter->end() &&
+////            aCPIter->find(aSecondObjPoints[ind2]) != aCPIter->end()) {
+////          aBaseCoincInd[0] = ind1;
+////          aBaseCoincInd[1] = ind2;
+////          isCoincidentFound = true;
+////        }
+////  if (!isCoincidentFound) {
+////    // There is no coincident points between objects. Generate error message
+////    Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
+////    return false;
+////  }
+////
+////  // Create fillet entities
+////  // - first object is placed on the first base 
+////  // - second object is on the second base 
+////  // - third object is a filleting arc
+////  static const int aNbFilletEnt = 3;
+////  Slvs_hEntity aFilletEnt[aNbFilletEnt];
+////  int aFilletObjInd[aNbFilletEnt];
+////  AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+////      aConstrData->attribute(aConstraintAttributes[2]));
+////  if (!aFilletRefList)
+////    return false;
+////  std::list<ObjectPtr> aFilletList = aFilletRefList->list();
+////  if (aFilletList.size() < aNbFilletEnt)
+////    return false;
+////  FeaturePtr aFilletFeature;
+////  ResultConstructionPtr aRC;
+////  std::list<ObjectPtr>::iterator aFilIter = aFilletList.begin();
+////  for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) {
+////    aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aFilIter);
+////    aFilletFeature = aRC ? aRC->document()->feature(aRC) :
+////        std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFilIter);
+////    if (!aFilletFeature)
+////      return false;
+////    aFilletEnt[indEnt] = changeEntityFeature(aFilletFeature);
+////    aFilletObjInd[indEnt] = Search(aFilletEnt[indEnt], myEntities);
+////  }
+////  // At first time, for correct result, move floating points of fillet on the middle points of base objects
+////  if (myConstraintMap.find(theConstraint) == myConstraintMap.end()) {
+////    double anArcPoints[6];
+////    for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
+////      int anIndShift = myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
+////      int aPointsPos[2] = {
+////          Search(myEntities[aFilletObjInd[indEnt]].point[anIndShift], myEntities),
+////          Search(myEntities[aFilletObjInd[indEnt]].point[1+anIndShift], myEntities)
+////        };
+////      int aParamPos[2] = {
+////          Search(myEntities[aPointsPos[0]].param[0], myParams),
+////          Search(myEntities[aPointsPos[1]].param[0], myParams)
+////        };
+////      int anIndex = aParamPos[aBaseCoincInd[indEnt]];
+////      if (anIndShift == 0) {
+////        myParams[anIndex].val =
+////            0.5 * (myParams[aParamPos[0]].val + myParams[aParamPos[1]].val);
+////        myParams[1 + anIndex].val =
+////            0.5 * (myParams[1 + aParamPos[0]].val + myParams[1 + aParamPos[1]].val);
+////      } else { // place the changed point on the arc
+////        double x = 0, y = 0;
+////        calculateMiddlePoint(aFilletEnt[indEnt], x, y);
+////        myParams[anIndex].val = x;
+////        myParams[1 + anIndex].val = y;
+////      }
+////      anArcPoints[indEnt*2+2] = myParams[anIndex].val;
+////      anArcPoints[indEnt*2+3] = myParams[1 + anIndex].val;
+////    }
+////    anArcPoints[0] = 0.5 * (anArcPoints[2] + anArcPoints[4]);
+////    anArcPoints[1] = 0.5 * (anArcPoints[3] + anArcPoints[5]);
+////    for (int indArcPt = 0; indArcPt < 3; indArcPt++) {
+////      int aPtPos = Search(myEntities[aFilletObjInd[2]].point[indArcPt], myEntities);
+////      int aParamPos = Search(myEntities[aPtPos].param[0], myParams);
+////      myParams[aParamPos].val = anArcPoints[indArcPt * 2];
+////      myParams[aParamPos + 1].val = anArcPoints[indArcPt * 2 + 1];
+////    }
+////  }
+////
+////  // Check the fillet arc which point to be connected to
+////  bool isArcInversed = false; // indicates that start and end points of arc should be connected to second and first object respectively
+////  Slvs_hEntity hEnt = myEntities[aFilletObjInd[2]].point[1];
+////  int aPos = Search(hEnt, myEntities);
+////  Slvs_hParam anArcStartPoint = myEntities[aPos].param[0];
+////  aPos = Search(anArcStartPoint, myParams);
+////  double anArcPtCoord[2] = {myParams[aPos].val, myParams[aPos+1].val};
+////  double aSqDistances[2];
+////  int aPtInd;
+////  for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
+////    aPtInd = aBaseCoincInd[indEnt]+aShift[indEnt];
+////    hEnt = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
+////    aPos = Search(hEnt, myEntities);
+////    Slvs_hParam anObjectPoint = myEntities[aPos].param[0];
+////    aPos = Search(anObjectPoint, myParams);
+////    double aPtCoord[2] = {myParams[aPos].val, myParams[aPos+1].val};
+////    aSqDistances[indEnt] = 
+////        (anArcPtCoord[0] - aPtCoord[0]) * (anArcPtCoord[0] - aPtCoord[0]) +
+////        (anArcPtCoord[1] - aPtCoord[1]) * (anArcPtCoord[1] - aPtCoord[1]);
+////  }
+////  if (aSqDistances[1] < aSqDistances[0])
+////    isArcInversed = true;
+////
+////  // Create list of constraints to generate fillet
+////  std::vector<Slvs_hConstraint> aConstrList;
+////  bool isExists = myConstraintMap.find(theConstraint) != myConstraintMap.end(); // constraint already exists
+////  std::vector<Slvs_hConstraint>::iterator aCMapIter =
+////    isExists ? myConstraintMap[theConstraint].begin() : aConstrList.begin();
+////  int aCurConstrPos = isExists ? Search(*aCMapIter, myConstraints) : 0;
+////  for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
+////    // one point of fillet object should be coincident with the point on base, non-coincident with another base object
+////    aPtInd = 1-aBaseCoincInd[indEnt]+aShift[indEnt]; // (1-aBaseCoincInd[indEnt]) = index of non-coincident point, aShift is used to process all types of shapes
+////    Slvs_hEntity aPtBase = myEntities[aBaseObjInd[indEnt]].point[aPtInd];
+////    Slvs_hEntity aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
+////    if (isExists) {
+////      myConstraints[aCurConstrPos].ptA = aPtBase;
+////      myConstraints[aCurConstrPos].ptB = aPtFillet;
+////      aCMapIter++;
+////      aCurConstrPos = Search(*aCMapIter, myConstraints);
+////    } else {
+////      Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
+////          ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
+////          0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+////      myConstraints.push_back(aCoincConstr);
+////      aConstrList.push_back(aCoincConstr.h);
+////    }
+////
+////    // another point of fillet object should be placed on the base object
+////    Slvs_Constraint aPonCurveConstr;
+////    int aTangentType;
+////    if (myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE) {
+////      // centers of arcs should be coincident
+////      aPtBase = myEntities[aBaseObjInd[indEnt]].point[0];
+////      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[0];
+////      if (isExists) {
+////        myConstraints[aCurConstrPos].ptA = aPtBase;
+////        myConstraints[aCurConstrPos].ptB = aPtFillet;
+////        aCMapIter++;
+////        aCurConstrPos = Search(*aCMapIter, myConstraints);
+////      } else {
+////        aPonCurveConstr = Slvs_MakeConstraint(
+////            ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
+////            0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+////      }
+////      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[1+aBaseCoincInd[indEnt]]; // !!! will be used below
+////      aTangentType = SLVS_C_CURVE_CURVE_TANGENT;
+////    } else {
+////      aPtInd = aBaseCoincInd[indEnt];
+////      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
+////      if (isExists) {
+////        myConstraints[aCurConstrPos].ptA = aPtFillet;
+////        aCMapIter++;
+////        aCurConstrPos = Search(*aCMapIter, myConstraints);
+////      } else {
+////        aPonCurveConstr = Slvs_MakeConstraint(
+////            ++myConstrMaxID, myID, SLVS_C_PT_ON_LINE, myWorkplane.h,
+////            0, aPtFillet, SLVS_E_UNKNOWN, aBaseObject[indEnt], SLVS_E_UNKNOWN);
+////      }
+////      aTangentType = SLVS_C_ARC_LINE_TANGENT;
+////    }
+////    if (!isExists) {
+////      myConstraints.push_back(aPonCurveConstr);
+////      aConstrList.push_back(aPonCurveConstr.h);
+////    }
+////
+////    // Bound point of fillet arc should be tangently coincident with a bound point of fillet object
+////    aPtInd = 1 + (isArcInversed ? 1-indEnt : indEnt);
+////    Slvs_hEntity aPtArc = myEntities[aFilletObjInd[2]].point[aPtInd];
+////    if (isExists) {
+////      myConstraints[aCurConstrPos].ptA = aPtArc;
+////      myConstraints[aCurConstrPos].ptB = aPtFillet;
+////      aCMapIter++;
+////      aCurConstrPos = Search(*aCMapIter, myConstraints);
+////      myConstraints[aCurConstrPos].entityA = aFilletEnt[2];
+////      myConstraints[aCurConstrPos].entityB = aFilletEnt[indEnt];
+////      myConstraints[aCurConstrPos].other = (isArcInversed ? 1-indEnt : indEnt);
+////      aCMapIter++;
+////      aCurConstrPos = Search(*aCMapIter, myConstraints);
+////    } else {
+////      Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
+////          ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
+////          0, aPtArc, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+////      myConstraints.push_back(aCoincConstr);
+////      aConstrList.push_back(aCoincConstr.h);
+////      Slvs_Constraint aTangency = Slvs_MakeConstraint(
+////          ++myConstrMaxID, myID, aTangentType, myWorkplane.h,
+////          0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aFilletEnt[2], aFilletEnt[indEnt]);
+////      aTangency.other = (isArcInversed ? 1-indEnt : indEnt);
+////      aTangency.other2 = aTangentType == SLVS_C_CURVE_CURVE_TANGENT ? aBaseCoincInd[indEnt] : 0;
+////      myConstraints.push_back(aTangency);
+////      aConstrList.push_back(aTangency.h);
+////    }
+////  }
+////
+////  // Additional constraint for fillet diameter
+////  double aRadius = 0.0;  // scalar value of the constraint
+////  AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+////      aConstrData->attribute(SketchPlugin_Constraint::VALUE()));
+////  aRadius = aDistAttr->value();
+////  if (isExists) {
+////    myConstraints[aCurConstrPos].entityA = aFilletEnt[2];
+////    myConstraints[aCurConstrPos].valA = aRadius * 2.0;
+////    aCMapIter++;
+////  } else {
+////    Slvs_Constraint aDiamConstr = Slvs_MakeConstraint(
+////        ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, aRadius * 2.0,
+////        SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aFilletEnt[2], SLVS_E_UNKNOWN);
+////    myConstraints.push_back(aDiamConstr);
+////    aConstrList.push_back(aDiamConstr.h);
+////
+////    myConstraintMap[theConstraint] = aConstrList;
+////  }
+////
+////  // Additional temporary constraints for base objects to be fixed
+////  for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
+////    if (!aBaseFeature[indAttr]) {
+////      AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+////          aConstrData->attribute(aConstraintAttributes[indAttr]));
+////      addTemporaryConstraintWhereDragged(aConstrAttr->attr());
+////      continue;
+////    }
+////    std::list<AttributePtr> anAttributes =
+////        aBaseFeature[indAttr]->data()->attributes(GeomDataAPI_Point2D::type());
+////    std::list<AttributePtr>::iterator anIt = anAttributes.begin();
+////    for ( ; anIt != anAttributes.end(); anIt++) {
+////      // Arc should be fixed by center and start points only (to avoid "conflicting constraints" message)
+////      if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Arc::ID() &&
+////          (*anIt)->id() == SketchPlugin_Arc::END_ID())
+////        continue;
+////      addTemporaryConstraintWhereDragged(*anIt);
+////    }
+////  }
+////  return true;
+////}
+////
+////// ============================================================================
+//////  Function: changeEntity
+//////  Class:    SketchSolver_Group
+//////  Purpose:  create/update the element affected by any constraint
+////// ============================================================================
+////Slvs_hEntity SketchSolver_Group::changeEntity(
+////    std::shared_ptr<ModelAPI_Attribute> theEntity)
+////{
+////  // If the entity is already in the group, try to find it
+////  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
+////      myEntityAttrMap.find(theEntity);
+////  int aEntPos;
+////  std::vector<Slvs_Param>::const_iterator aParamIter;  // looks at first parameter of already existent entity or at the end of vector otherwise
+////  if (aEntIter == myEntityAttrMap.end())  // no such entity => should be created
+////    aParamIter = myParams.end();
+////  else {  // the entity already exists
+////    aEntPos = Search(aEntIter->second, myEntities);
+////    int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
+////    aParamIter = myParams.begin() + aParamPos;
+////  }
+////  const bool isEntExists = (aEntIter != myEntityAttrMap.end());  // defines that the entity already exists
+////  const bool isNeedToSolve = myNeedToSolve;
+////  myNeedToSolve = false;
+////
+////  if (isEntExists) {
+////    // Verify that the entity is not used by "Rigid" constraint.
+////    // If it is used, the object should not move.
+////    std::vector<std::set<Slvs_hEntity> >::iterator aCoincIter = myCoincidentPoints.begin();
+////    for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
+////      if (aCoincIter->find(aEntIter->second) != aCoincIter->end())
+////        break;
+////    std::set<Slvs_hEntity> aCoincident;
+////    if (aCoincIter != myCoincidentPoints.end()) {
+////      aCoincident = *aCoincIter;
+////      aCoincident.erase(aEntIter->second);
+////
+////      std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+////      for (; aConstrIter != myConstraints.end(); aConstrIter++)
+////        if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
+////            aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
+////          myNeedToSolve = true;
+////          return aEntIter->second;
+////        }
+////    }
+////  }
+////
+////  // Look over supported types of entities
+////  Slvs_Entity aNewEntity;
+////  aNewEntity.h = SLVS_E_UNKNOWN;
+////
+////  // Point in 3D
+////  std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
+////      theEntity);
+////  if (aPoint) {
+////    Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
+////    Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
+////    Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
+////    if (!isEntExists) // New entity
+////      aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
+////  } else {
+////    // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
+////    if (myWorkplane.h == SLVS_E_UNKNOWN)
+////      return SLVS_E_UNKNOWN;
+////
+////    // Point in 2D
+////    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
+////    if (aPoint2D) {
+////      Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
+////      Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
+////      if (!isEntExists) // New entity
+////        aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
+////    } else {
+////      // Scalar value (used for the distance entities)
+////      AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
+////      if (aScalar) {
+////        Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
+////        if (!isEntExists) // New entity
+////          aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
+////      }
+////    }
+////  }
+////  /// \todo Other types of entities
+////
+////  Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type
+////
+////  if (isEntExists) {
+////    myNeedToSolve = myNeedToSolve || isNeedToSolve;
+////    aResult = aEntIter->second;
+////  } else if (aNewEntity.h != SLVS_E_UNKNOWN) {
+////    myEntities.push_back(aNewEntity);
+////    myEntOfConstr.push_back(false);
+////    myEntityAttrMap[theEntity] = aNewEntity.h;
+////    aResult = aNewEntity.h;
+////  }
+////
+////  // If the attribute was changed by the user, we need to fix it before solving
+////  if (myNeedToSolve && theEntity->isImmutable())
+////    addTemporaryConstraintWhereDragged(theEntity, false);
+////
+////  return aResult;
+////}
+////
+////// ============================================================================
+//////  Function: changeEntity
+//////  Class:    SketchSolver_Group
+//////  Purpose:  create/update the element defined by the feature affected by any constraint
+////// ============================================================================
+////Slvs_hEntity SketchSolver_Group::changeEntityFeature(FeaturePtr theEntity)
+////{
+////  if (!theEntity->data()->isValid())
+////    return SLVS_E_UNKNOWN;
+////  // If the entity is already in the group, try to find it
+////  std::map<FeaturePtr, Slvs_hEntity>::const_iterator aEntIter = myEntityFeatMap.find(theEntity);
+////  // defines that the entity already exists
+////  const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
+////  
+////  Slvs_Entity aNewEntity;
+////  aNewEntity.h = SLVS_E_UNKNOWN;
+////
+////  // SketchPlugin features
+////  std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
+////      SketchPlugin_Feature>(theEntity);
+////  if (aFeature) {  // Verify the feature by its kind
+////    const std::string& aFeatureKind = aFeature->getKind();
+////    AttributePtr anAttribute;
+////
+////    // Line
+////    if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
+////      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
+////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+////      Slvs_hEntity aStart = changeEntity(anAttribute);
+////
+////      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
+////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+////      Slvs_hEntity aEnd = changeEntity(anAttribute);
+////
+////      if (!isEntExists) // New entity
+////        aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
+////    }
+////    // Circle
+////    else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
+////      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
+////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+////      Slvs_hEntity aCenter = changeEntity(anAttribute);
+////
+////      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
+////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+////      Slvs_hEntity aRadius = changeEntity(anAttribute);
+////
+////      if (!isEntExists) // New entity
+////        aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter,
+////                                     myWorkplane.normal, aRadius);
+////    }
+////    // Arc
+////    else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
+////      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
+////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+////      Slvs_hEntity aCenter = changeEntity(anAttribute);
+////
+////      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
+////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+////      Slvs_hEntity aStart = changeEntity(anAttribute);
+////
+////      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
+////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+////      Slvs_hEntity aEnd = changeEntity(anAttribute);
+////
+////      if (!isEntExists)
+////        aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h,
+////                                          myWorkplane.normal, aCenter, aStart, aEnd);
+////    }
+////    // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
+////    else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) {
+////      anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
+////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+////      Slvs_hEntity aPoint = changeEntity(anAttribute);
+////
+////      if (isEntExists)
+////        return aEntIter->second;
+////
+////      // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
+////      myEntityFeatMap[theEntity] = aPoint;
+////      myNeedToSolve = true;
+////      return aPoint;
+////    }
+////  }
+////  /// \todo Other types of features
+////
+////  if (isEntExists)
+////    return aEntIter->second;
+////
+////  if (aNewEntity.h != SLVS_E_UNKNOWN) {
+////    myEntities.push_back(aNewEntity);
+////    myEntOfConstr.push_back(false);
+////    myEntityFeatMap[theEntity] = aNewEntity.h;
+////    myNeedToSolve = true;
+////    return aNewEntity.h;
+////  }
+////
+////  // Unsupported or wrong entity type
+////  return SLVS_E_UNKNOWN;
+////}
+
+// ============================================================================
+//  Function: addWorkplane
+//  Class:    SketchSolver_Group
+//  Purpose:  create workplane for the group
+// ============================================================================
+bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch)
+{
+  if (myWorkplaneID != SLVS_E_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID())
+    return false;  // the workplane already exists or the function parameter is not Sketch
+
+  mySketch = theSketch;
+  updateWorkplane();
+  return true;
+}
+
+// ============================================================================
+//  Function: updateWorkplane
+//  Class:    SketchSolver_Group
+//  Purpose:  update parameters of workplane
+// ============================================================================
+bool SketchSolver_Group::updateWorkplane()
+{
+  if (!myStorage) // Create storage if not exists
+    myStorage = StoragePtr(new SketchSolver_Storage);
+  SketchSolver_Builder* aBuilder = SketchSolver_Builder::getInstance();
+
+  std::vector<Slvs_Entity> anEntities;
+  std::vector<Slvs_Param> aParams;
+  if (!aBuilder->createWorkplane(mySketch, anEntities, aParams))
+    return false;
+
+  if (myWorkplaneID == SLVS_E_UNKNOWN) {
+    myWorkplaneID = anEntities.back().h;
+    // Add new workplane elements
+    std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
+    for (; aParIter != aParams.end(); aParIter++) {
+      aParIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
+      aParIter->group = myID;
+      aParIter->h = myStorage->addParameter(*aParIter);
+    }
+    std::vector<Slvs_Entity>::iterator anEntIter = anEntities.begin();
+    for (; anEntIter != anEntities.end(); anEntIter++) {
+      anEntIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
+      anEntIter->group = myID;
+      anEntIter->wrkpl = myWorkplaneID;
+      for (int i = 0; i < 4; i++)
+        if (anEntIter->param[i] != SLVS_E_UNKNOWN)
+          anEntIter->param[i] = aParams[anEntIter->param[i]-1].h;
+      for (int i = 0; i < 4; i++)
+        if (anEntIter->point[i] != SLVS_E_UNKNOWN)
+          anEntIter->point[i] = anEntities[anEntIter->point[i]-1].h;
+      anEntIter->h = myStorage->addEntity(*anEntIter);
+    }
+  } else {
+    // Update existent workplane
+    const Slvs_Entity& aWP = myStorage->getEntity(myWorkplaneID);
+    const Slvs_Entity& anOrigin = myStorage->getEntity(aWP.point[0]);
+    const Slvs_Entity& aNormal = myStorage->getEntity(aWP.normal);
+    // Get parameters and update them
+    Slvs_hParam aWPParams[7] = {
+        anOrigin.param[0], anOrigin.param[1], anOrigin.param[2],
+        aNormal.param[0], aNormal.param[1], aNormal.param[2], aNormal.param[3]
+      };
+    std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
+    for (int i = 0; aParIter != aParams.end(); aParIter++, i++) {
+      Slvs_Param aParam = myStorage->getParameter(aWPParams[i]);
+      aParam.val = aParIter->val;
+      myStorage->updateParameter(aParam);
+    }
+  }
+  return myWorkplaneID > 0;
+}
+
+////// ============================================================================
+//////  Function: changeParameter
+//////  Class:    SketchSolver_Group
+//////  Purpose:  create/update value of parameter
+////// ============================================================================
+////Slvs_hParam SketchSolver_Group::changeParameter(
+////    const double& theParam, std::vector<Slvs_Param>::const_iterator& thePrmIter)
+////{
+////  if (thePrmIter != myParams.end()) {  // Parameter should be updated
+////    int aParamPos = thePrmIter - myParams.begin();
+////    if (fabs(thePrmIter->val - theParam) > tolerance) {
+////      myNeedToSolve = true;  // parameter is changed, need to resolve constraints
+////      myParams[aParamPos].val = theParam;
+////    }
+////    thePrmIter++;
+////    return myParams[aParamPos].h;
+////  }
+////
+////  // Newly created parameter
+////  Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
+////  myParams.push_back(aParam);
+////  myNeedToSolve = true;
+////  // The list of parameters is changed, move iterator to the end of the list to avoid problems
+////  thePrmIter = myParams.end();
+////  return aParam.h;
+////}
+
+// ============================================================================
+//  Function: resolveConstraints
+//  Class:    SketchSolver_Group
+//  Purpose:  solve the set of constraints for the current group
+// ============================================================================
+bool SketchSolver_Group::resolveConstraints()
+{
+  if (!myStorage->isNeedToResolve() || isEmpty())
+    return false;
+
+  myConstrSolver.setGroupID(myID);
+  myStorage->initializeSolver(myConstrSolver);
+
+////  theSolver.setDraggedParameters(myTempPointWhereDragged);
+////
+  int aResult = myConstrSolver.solve();
+  if (aResult == SLVS_RESULT_OKAY) {  // solution succeeded, store results into correspondent attributes
+    ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
+    for (; aConstrIter != myConstraints.end(); aConstrIter++)
+      aConstrIter->second->refresh();
+
+////                                      // Obtain result into the same list of parameters
+////    if (!myConstrSolver.getResult(myParams))
+////      return true;
+////
+////    // We should go through the attributes map, because only attributes have valued parameters
+////    std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntIter =
+////        myEntityAttrMap.begin();
+////    for (; anEntIter != myEntityAttrMap.end(); anEntIter++) {
+////      if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
+////        anEntIter->first->owner()->data()->blockSendAttributeUpdated(true);
+////      if (updateAttribute(anEntIter->first, anEntIter->second))
+////        updateRelatedConstraints(anEntIter->first);
+////    }
+////    updateFilletConstraints();
+////    // unblock all features then
+////    for (anEntIter = myEntityAttrMap.begin(); anEntIter != myEntityAttrMap.end(); anEntIter++) {
+////      if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
+////        anEntIter->first->owner()->data()->blockSendAttributeUpdated(false);
+////    }
+  } else if (!myConstraints.empty())
+    Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
+
+  removeTemporaryConstraints();
+////  myNeedToSolve = false;
+  myStorage->setNeedToResolve(false);
+  return true;
+}
+
+// ============================================================================
+//  Function: mergeGroups
+//  Class:    SketchSolver_Group
+//  Purpose:  append specified group to the current group
+// ============================================================================
+void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
+{
+  // If specified group is empty, no need to merge
+  if (theGroup.isEmpty())
+    return;
+  if (!myFeatureStorage)
+    myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
+
+  ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
+  for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++)
+    changeConstraint(aConstrIter->first);
+}
+
+// ============================================================================
+//  Function: splitGroup
+//  Class:    SketchSolver_Group
+//  Purpose:  divide the group into several subgroups
+// ============================================================================
+void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
+{
+  // Obtain constraints, which should be separated
+  FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage);
+  std::vector<ConstraintPtr> anUnusedConstraints;
+  ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+  for ( ; aCIter != myConstraints.end(); aCIter++) {
+    std::list<ConstraintPtr> aBaseConstraints = aCIter->second->constraints();
+    std::list<ConstraintPtr>::iterator anIter = aBaseConstraints.begin();
+    for (; anIter != aBaseConstraints.end(); anIter++)
+      if (aNewFeatStorage->isInteract(*anIter)) {
+        aNewFeatStorage->changeConstraint(*anIter);
+      } else
+        anUnusedConstraints.push_back(*anIter);
+  }
+
+  std::vector<SketchSolver_Group*>::iterator aCutsIter;
+  std::vector<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
+  for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) {
+    // Remove unused constraints
+    removeConstraint(*aUnuseIt);
+    // Try to append constraint to already existent group
+    for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); aCutsIter++)
+      if ((*aCutsIter)->isInteract(*aUnuseIt)) {
+        (*aCutsIter)->changeConstraint(*aUnuseIt);
+        break;
+      }
+    if (aCutsIter == theCuts.end()) {
+      // Add new group
+      SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch);
+      aGroup->changeConstraint(*aUnuseIt);
+      theCuts.push_back(aGroup);
+    }
+  }
+}
+
+// ============================================================================
+//  Function: isConsistent
+//  Class:    SketchSolver_Group
+//  Purpose:  search removed entities and constraints
+// ============================================================================
+bool SketchSolver_Group::isConsistent()
+{
+  if (!myFeatureStorage) // no one constraint is initialized yet
+    return true;
+
+  bool aResult = myFeatureStorage->isConsistent();
+  if (!aResult) {
+    // remove invalid entities
+    ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+    while (aCIter != myConstraints.end()) {
+      std::list<ConstraintPtr> aConstraints = aCIter->second->constraints();
+      std::list<ConstraintPtr>::iterator anIt = aConstraints.begin();
+      for (; anIt != aConstraints.end(); anIt++)
+        if (!(*anIt)->data() || !(*anIt)->data()->isValid())
+          if (aCIter->second->remove(*anIt)) {
+            // the constraint is fully removed, detach it from the list
+            ConstraintConstraintMap::iterator aTmpIt = aCIter++;
+            myFeatureStorage->removeConstraint(aTmpIt->first);
+            myConstraints.erase(aTmpIt);
+            break;
+          }
+      if (anIt == aConstraints.end())
+        aCIter++;
+    }
+  }
+  return aResult;
+}
+
+////// ============================================================================
+//////  Function: updateAttribute
+//////  Class:    SketchSolver_Group
+//////  Purpose:  update features of sketch after resolving constraints
+////// ============================================================================
+////bool SketchSolver_Group::updateAttribute(
+////    std::shared_ptr<ModelAPI_Attribute> theAttribute, const Slvs_hEntity& theEntityID)
+////{
+////  // Search the position of the first parameter of the entity
+////  int anEntPos = Search(theEntityID, myEntities);
+////  int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
+////
+////  // Look over supported types of entities
+////
+////  // Point in 3D
+////  std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
+////      theAttribute);
+////  if (aPoint) {
+////    if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance
+////        || fabs(aPoint->y() - myParams[aFirstParamPos + 1].val) > tolerance
+////        || fabs(aPoint->z() - myParams[aFirstParamPos + 2].val) > tolerance) {
+////      aPoint->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val,
+////                       myParams[aFirstParamPos + 2].val);
+////      return true;
+////    }
+////    return false;
+////  }
+////
+////  // Point in 2D
+////  std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+////      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+////  if (aPoint2D) {
+////    if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance
+////        || fabs(aPoint2D->y() - myParams[aFirstParamPos + 1].val) > tolerance) {
+////      aPoint2D->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val);
+////      return true;
+////    }
+////    return false;
+////  }
+////
+////  // Scalar value
+////  AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+////  if (aScalar) {
+////    if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance) {
+////      aScalar->setValue(myParams[aFirstParamPos].val);
+////      return true;
+////    }
+////    return false;
+////  }
+////
+////  /// \todo Support other types of entities
+////  return false;
+////}
+////
+////// ============================================================================
+//////  Function: updateEntityIfPossible
+//////  Class:    SketchSolver_Group
+//////  Purpose:  search the entity in this group and update it
+////// ============================================================================
+////void SketchSolver_Group::updateEntityIfPossible(
+////    std::shared_ptr<ModelAPI_Attribute> theEntity)
+////{
+////  if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) {
+////    // If the attribute is a point and it is changed (the group needs to rebuild),
+////    // probably user has dragged this point into this position,
+////    // so it is necessary to add constraint which will guarantee the point will not change
+////
+////    // Store myNeedToSolve flag to verify the entity is really changed
+////    bool aNeedToSolveCopy = myNeedToSolve;
+////    myNeedToSolve = false;
+////
+////    changeEntity(theEntity);
+////
+////    if (myNeedToSolve)  // the entity is changed
+////    {
+////      // Verify the entity is a point and add temporary constraint of permanency
+////      std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
+////          theEntity);
+////      std::shared_ptr<GeomDataAPI_Point2D> aPoint2D = std::dynamic_pointer_cast<
+////          GeomDataAPI_Point2D>(theEntity);
+////      if (aPoint || aPoint2D)
+////        addTemporaryConstraintWhereDragged(theEntity);
+////    }
+////
+////    // Restore flag of changes
+////    myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
+////
+////    if (myNeedToSolve)
+////      updateRelatedConstraints(theEntity);
+////  }
+////}
+////
+////// ============================================================================
+//////  Function: addTemporaryConstraintWhereDragged
+//////  Class:    SketchSolver_Group
+//////  Purpose:  add transient constraint SLVS_C_WHERE_DRAGGED for the entity, 
+//////            which was moved by user
+////// ============================================================================
+////void SketchSolver_Group::addTemporaryConstraintWhereDragged(
+////    std::shared_ptr<ModelAPI_Attribute> theEntity,
+////    bool theAllowToFit)
+////{
+////  // Find identifier of the entity
+////  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
+////      myEntityAttrMap.find(theEntity);
+////  if (anEntIter == myEntityAttrMap.end())
+////    return;
+////
+////  // Get identifiers of all dragged points
+////  std::set<Slvs_hEntity> aDraggedPntID;
+////  aDraggedPntID.insert(myTempPointWDrgdID);
+////  std::list<Slvs_hConstraint>::const_iterator aTmpCoIter = myTempConstraints.begin();
+////  for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) {
+////    unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
+////    if (aConstrPos < myConstraints.size())
+////      aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
+////  }
+////  std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+////  for (; aConstrIter != myConstraints.end(); aConstrIter++)
+////    if (aConstrIter->type == SLVS_C_WHERE_DRAGGED)
+////      aDraggedPntID.insert(aConstrIter->ptA);
+////  // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
+////  std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
+////  for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) {
+////    if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
+////      continue;  // the entity was not found in current set
+////
+////    // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
+////    std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
+////    for (; aDrgIter != aDraggedPntID.end(); aDrgIter++)
+////      if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
+////        return;  // the SLVS_C_WHERE_DRAGGED constraint already exists
+////  }
+////  if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end())
+////    return;
+////
+////  // If this is a first dragged point, its parameters should be placed 
+////  // into Slvs_System::dragged field to avoid system inconsistense
+////  if (myTempPointWhereDragged.empty() && theAllowToFit) {
+////    int anEntPos = Search(anEntIter->second, myEntities);
+////    Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
+////    for (int i = 0; i < 4; i++, aDraggedParam++)
+////      if (*aDraggedParam != 0)
+////        myTempPointWhereDragged.push_back(*aDraggedParam);
+////    myTempPointWDrgdID = myEntities[anEntPos].h;
+////    return;
+////  }
+////
+////  // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
+////  Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
+////                                                  myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
+////  myConstraints.push_back(aWDConstr);
+////  myTempConstraints.push_back(aWDConstr.h);
+////}
+
+// ============================================================================
+//  Function: removeTemporaryConstraints
+//  Class:    SketchSolver_Group
+//  Purpose:  remove all transient SLVS_C_WHERE_DRAGGED constraints after
+//            resolving the set of constraints
+// ============================================================================
+void SketchSolver_Group::removeTemporaryConstraints()
+{
+  myTempConstraints.clear();
+  // Clean lists of removed entities in the storage
+  std::set<Slvs_hParam> aRemPar;
+  std::set<Slvs_hEntity> aRemEnt;
+  std::set<Slvs_hConstraint> aRemCon;
+  myStorage->getRemoved(aRemPar, aRemEnt, aRemCon);
+}
+
+// ============================================================================
+//  Function: removeConstraint
+//  Class:    SketchSolver_Group
+//  Purpose:  remove constraint and all unused entities
+// ============================================================================
+void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
+{
+  myFeatureStorage->removeConstraint(theConstraint);
+  ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+  for (; aCIter != myConstraints.end(); aCIter++)
+    if (aCIter->second->hasConstraint(theConstraint)) {
+      if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed
+        aCIter = myConstraints.end();
+      break;
+    }
+  if (aCIter != myConstraints.end())
+    myConstraints.erase(aCIter);
+}
+
+////// ============================================================================
+//////  Function: removeEntitiesById
+//////  Class:    SketchSolver_Group
+//////  Purpose:  Removes specified entities and their parameters
+////// ============================================================================
+////void SketchSolver_Group::removeEntitiesById(const std::set<Slvs_hEntity>& theEntities)
+////{
+////  std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = theEntities.rbegin();
+////  for (; aRemIter != theEntities.rend(); aRemIter++) {
+////    unsigned int anEntPos = Search(*aRemIter, myEntities);
+////    if (anEntPos >= myEntities.size())
+////      continue;
+////    if (myEntities[anEntPos].param[0] != 0) {
+////      unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
+////      if (aParamPos >= myParams.size())
+////        continue;
+////      int aNbParams = 0;
+////      while (myEntities[anEntPos].param[aNbParams] != 0)
+////        aNbParams++;
+////      if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID)
+////        myParamMaxID -= aNbParams;
+////      myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
+////      if (*aRemIter == myEntityMaxID)
+////        myEntityMaxID--;
+////    }
+////    myEntities.erase(myEntities.begin() + anEntPos);
+////    myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos);
+////
+////    // Remove entity's ID from the lists of conincident points
+////    std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
+////    for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
+////      aCoPtIter->erase(*aRemIter);
+////  }
+////}
+////
+////// ============================================================================
+//////  Function: addCoincidentPoints
+//////  Class:    SketchSolver_Group
+//////  Purpose:  add coincident point the appropriate list of such points
+////// ============================================================================
+////bool SketchSolver_Group::addCoincidentPoints(const Slvs_hEntity& thePoint1,
+////                                                       const Slvs_hEntity& thePoint2)
+////{
+////  std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
+////  std::vector<std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
+////  while (aCoPtIter != myCoincidentPoints.end()) {
+////    bool isFound[2] = {  // indicate which point ID was already in coincidence constraint
+////        aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2)
+////            != aCoPtIter->end(), };
+////    if (isFound[0] && isFound[1])  // points are already connected by coincidence constraints => no need additional one
+////      return false;
+////    if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) {
+////      if (aFirstFound != myCoincidentPoints.end()) {  // there are two groups of coincident points connected by created constraint => merge them
+////        int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
+////        int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
+////        aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
+////        myCoincidentPoints.erase(aCoPtIter);
+////        aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
+////        aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
+////        continue;
+////      } else {
+////        aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
+////        aFirstFound = aCoPtIter;
+////      }
+////    }
+////    aCoPtIter++;
+////  }
+////  // No points were found, need to create new set
+////  if (aFirstFound == myCoincidentPoints.end()) {
+////    std::set<Slvs_hEntity> aNewSet;
+////    aNewSet.insert(thePoint1);
+////    aNewSet.insert(thePoint2);
+////    myCoincidentPoints.push_back(aNewSet);
+////  }
+////
+////  return true;
+////}
+////
+////// ============================================================================
+//////  Function: updateRelatedConstraints
+//////  Class:    SketchSolver_Group
+//////  Purpose:  emit the signal to update constraints
+////// ============================================================================
+////void SketchSolver_Group::updateRelatedConstraints(
+////    std::shared_ptr<ModelAPI_Attribute> theEntity) const
+////{
+////  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
+////  for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
+////    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
+////        ->attributes(std::string());
+////
+////    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
+////    for (; anAttrIter != anAttributes.end(); anAttrIter++) {
+////      bool isUpd = (*anAttrIter == theEntity);
+////      std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
+////          ModelAPI_AttributeRefAttr>(*anAttrIter);
+////      if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
+////        isUpd = true;
+////
+////      if (isUpd) {
+////        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+////        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
+////        break;
+////      }
+////    }
+////  }
+////}
+////
+////void SketchSolver_Group::updateRelatedConstraintsFeature(
+////    std::shared_ptr<ModelAPI_Feature> theFeature) const
+////{
+////  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
+////  for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
+////    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
+////        ->attributes(std::string());
+////
+////    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
+////    for (; anAttrIter != anAttributes.end(); anAttrIter++) {
+////      std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
+////          ModelAPI_AttributeRefAttr>(*anAttrIter);
+////      if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature) {
+////        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+////        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
+////        break;
+////      }
+////    }
+////  }
+////}
+////
+////// ============================================================================
+//////  Function: updateFilletConstraints
+//////  Class:    SketchSolver_Group
+//////  Purpose:  change fillet arc to be less than 180 degree
+////// ============================================================================
+////void SketchSolver_Group::updateFilletConstraints()
+////{
+////  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
+////  for (; aConstrIter != myConstraintMap.end(); aConstrIter++)
+////    if (aConstrIter->first->getKind() == SketchPlugin_ConstraintFillet::ID()) {
+////      AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+////          aConstrIter->first->data()->attribute(SketchPlugin_ConstraintFillet::ENTITY_C()));
+////      if (!aFilletRefList)
+////        return;
+////      ObjectPtr anArcObj = aFilletRefList->object(2);
+////      std::shared_ptr<GeomDataAPI_Point2D> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+////          anArcObj->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
+////      std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+////          anArcObj->data()->attribute(SketchPlugin_Arc::START_ID()));
+////      std::shared_ptr<GeomDataAPI_Point2D> aEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+////          anArcObj->data()->attribute(SketchPlugin_Arc::END_ID()));
+////      double aCosA = aStart->x() - aCenter->x();
+////      double aSinA = aStart->y() - aCenter->y();
+////      double aCosB = aEnd->x() - aCenter->x();
+////      double aSinB = aEnd->y() - aCenter->y();
+////      if (aCosA * aSinB - aSinA * aCosB <= 0.0) {
+////        anArcObj->data()->blockSendAttributeUpdated(true);
+////        double x = aStart->x();
+////        double y = aStart->y();
+////        aStart->setValue(aEnd->x(), aEnd->y());
+////        aEnd->setValue(x, y);
+////        // Update constraint data
+////        changeFilletConstraint(aConstrIter->first);
+////        anArcObj->data()->blockSendAttributeUpdated(false);
+////      }
+////    }
+////}
+////
+////// ============================================================================
+//////  Function: makeMirrorEntity
+//////  Class:    SketchSolver_Group
+//////  Purpose:  change entities parameters to make them symmetric relating to the mirror line
+////// ============================================================================
+////void SketchSolver_Group::makeMirrorEntity(const Slvs_hEntity& theBase,
+////                                                    const Slvs_hEntity& theMirror,
+////                                                    const Slvs_hEntity& theMirrorLine)
+////{
+////  Slvs_Entity aBase = myEntities[Search(theBase, myEntities)];
+////  Slvs_Entity aMirror = myEntities[Search(theMirror, myEntities)];
+////  int i = 0;
+////  while (aBase.point[i] != 0 && aMirror.point[i] != 0) {
+////    makeMirrorEntity(aBase.point[i], aMirror.point[i], theMirrorLine);
+////    i++;
+////  }
+////  if (aBase.param[0] != 0 && aMirror.param[0] != 0) { // this is a point, copy it
+////    Slvs_Entity aMirrorLine = myEntities[Search(theMirrorLine, myEntities)];
+////    std::shared_ptr<GeomAPI_XY> aLinePoints[2];
+////    for (i = 0; i < 2; i++) {
+////      Slvs_Entity aPoint = myEntities[Search(aMirrorLine.point[i], myEntities)];
+////      int aParamPos = Search(aPoint.param[0], myParams);
+////      aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
+////          new GeomAPI_XY(myParams[aParamPos].val, myParams[1+aParamPos].val));
+////    }
+////    int aBaseParamPos = Search(aBase.param[0], myParams);
+////    int aMirrorParamPos = Search(aMirror.param[0], myParams);
+////    std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(
+////        new GeomAPI_XY(myParams[aBaseParamPos].val, myParams[1+aBaseParamPos].val));
+////
+////    // direction of a mirror line
+////    std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
+////        new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
+////    // orthogonal direction
+////    aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
+////
+////    std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
+////        new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
+////    double aDist = aVec->dot(aDir->xy());
+////    std::shared_ptr<GeomAPI_XY> aMirrorPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
+////
+////    myParams[aMirrorParamPos].val = aMirrorPoint->x();
+////    myParams[1+aMirrorParamPos].val = aMirrorPoint->y();
+////  }
+////}
+////
+////// ============================================================================
+//////  Function: calculateMiddlePoint
+//////  Class:    SketchSolver_Group
+//////  Purpose:  calculates middle point on line or arc
+////// ============================================================================
+////void SketchSolver_Group::calculateMiddlePoint(
+////    const Slvs_hEntity& theEntity,
+////    double& theX,
+////    double& theY) const
+////{
+////  int anInd = Search(theEntity, myEntities);
+////  if (myEntities[anInd].type == SLVS_E_LINE_SEGMENT) {
+////    int aLineParams[2];
+////    for (int i = 0; i < 2; i++) {
+////      int aPtPos = Search(myEntities[anInd].point[i], myEntities);
+////      aLineParams[i] = Search(myEntities[aPtPos].param[0], myParams);
+////    }
+////    theX = 0.5 * (myParams[aLineParams[0]].val + myParams[aLineParams[1]].val);
+////    theY = 0.5 * (myParams[1 + aLineParams[0]].val + myParams[1 + aLineParams[1]].val);
+////  } else if (myEntities[anInd].type == SLVS_E_ARC_OF_CIRCLE) {
+////    double anArcPoint[3][2];
+////    for (int i = 0; i < 3; i++) {
+////      int aPtPos = Search(myEntities[anInd].point[i], myEntities);
+////      int anArcParam = Search(myEntities[aPtPos].param[0], myParams);
+////      anArcPoint[i][0] = myParams[anArcParam].val;
+////      anArcPoint[i][1] = myParams[1 + anArcParam].val;
+////    }
+////    // 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] = anArcPoint[0][0] + x * aRad / aNorm;
+////      anArcPoint[2][1] = anArcPoint[0][1] + y * aRad / aNorm;
+////    }
+////
+////    x = anArcPoint[1][0] + anArcPoint[2][0] - 2.0 * anArcPoint[0][0];
+////    y = anArcPoint[1][1] + anArcPoint[2][1] - 2.0 * anArcPoint[0][1];
+////    aNorm = sqrt(x*x + y*y);
+////    if (aNorm >= tolerance) {
+////      x *= aRad / aNorm;
+////      y *= aRad / aNorm;
+////    } else { // obtain orthogonal direction
+////      x = 0.5 * (anArcPoint[2][1] - anArcPoint[1][1]);
+////      y = -0.5 * (anArcPoint[2][0] - anArcPoint[1][0]);
+////    }
+////    theX = anArcPoint[0][0] + x;
+////    theY = anArcPoint[0][1] + y;
+////  }
+////}
+
+
+// ========================================================
+// =========      Auxiliary functions       ===============
+// ========================================================
+
+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();
+  while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
+    aResIndex--;
+  while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
+    aResIndex++;
+  if (aResIndex == -1)
+    aResIndex = aVecSize;
+  return aResIndex;
+}
diff --git a/src/SketchSolver/SketchSolver_Group.h b/src/SketchSolver/SketchSolver_Group.h
new file mode 100644 (file)
index 0000000..68317fd
--- /dev/null
@@ -0,0 +1,309 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Group.h
+// Created: 27 May 2014
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_Group_H_
+#define SketchSolver_Group_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_Storage.h>
+#include <SketchSolver_FeatureStorage.h>
+#include <SketchSolver_Solver.h>
+
+#include <SketchPlugin_Constraint.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Feature.h>
+
+
+#include <memory>
+#include <list>
+#include <map>
+#include <vector>
+#include <set>
+
+typedef std::map<ConstraintPtr, SolverConstraintPtr> ConstraintConstraintMap;
+
+/** \class   SketchSolver_Group
+ *  \ingroup Plugins
+ *  \brief   Keeps the group of constraints which based on the same entities
+ */
+class SketchSolver_Group
+{
+ public:
+  /** \brief New group based on specified workplane.
+   *         Throws an exception if theWorkplane is not an object of SketchPlugin_Sketch type
+   *  \remark Type of theSketch is not verified inside
+   */
+  SketchSolver_Group(std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane);
+
+  ~SketchSolver_Group();
+
+  /// \brief Returns group's unique identifier
+  inline const Slvs_hGroup& getId() const
+  {
+    return myID;
+  }
+
+  /// \brief Returns identifier of the workplane
+  inline const Slvs_hEntity& getWorkplaneId() const
+  {
+    return myWorkplaneID;
+  }
+
+  /// \brief Find the identifier of the feature, if it already exists in the group
+  Slvs_hEntity getFeatureId(FeaturePtr theFeature) const;
+  /// \brief Find the identifier of the attribute, if it already exists in the group
+  Slvs_hEntity getAttributeId(AttributePtr theAttribute) const;
+
+  /// \brief Returns true if the group has no constraints yet
+  inline bool isEmpty() const
+  {
+    return myConstraints.empty();
+  }
+
+  /// \brief Check for valid sketch data
+  inline bool isWorkplaneValid() const
+  {
+    return mySketch->data() && mySketch->data()->isValid();
+  }
+
+  /** \brief Adds or updates a constraint in the group
+   *  \param[in] theConstraint constraint to be changed
+   *  \return \c true if the constraint added or updated successfully
+   */
+  bool changeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
+////  /** \brief Adds or updates a rigid constraint in the group
+////   *  \param[in] theConstraint constraint to be changed
+////   *  \return \c true if the constraint added or updated successfully
+////   */
+////  bool changeRigidConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
+////  /** \brief Adds or updates a mirror constraint in the group
+////   *  \param[in] theConstraint constraint to be changed
+////   *  \return \c true if the constraint added or updated successfully
+////   */
+////  bool changeMirrorConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
+////  /** \brief Adds or updates a fillet constraint in the group
+////   *  \param[in] theConstraint constraint to be changed
+////   *  \return \c true if the constraint added or updated successfully
+////   */
+////  bool changeFilletConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
+
+  /** \brief Updates the data corresponding the specified feature moved in GUI.
+   *         Additional Fixed constraints are created.
+   *  \param[in] theFeature the feature to be updated
+   */
+  void moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature);
+
+  /** \brief Verifies the feature attributes are used in this group
+   *  \param[in] theFeature constraint or any other object for verification of interaction
+   *  \return \c true if some of attributes are used in current group
+   */
+  bool isInteract(std::shared_ptr<SketchPlugin_Feature> theFeature) const;
+
+  /** \brief Verifies the specified feature is equal to the base workplane for this group
+   *  \param[in] theWorkplane the feature to be compared with base workplane
+   *  \return \c true if workplanes are the same
+   */
+  bool isBaseWorkplane(CompositeFeaturePtr theWorkplane) const;
+
+  /// Returns the current workplane
+  std::shared_ptr<ModelAPI_CompositeFeature> getWorkplane() const
+  {
+    return mySketch;
+  }
+
+  /** \brief Update parameters of workplane. Should be called when Update event is coming.
+   *  \return \c true if workplane updated successfully, \c false if workplane parameters are not consistent
+   */
+  bool updateWorkplane();
+////
+////  /** \brief If the entity is in this group it will updated
+////   *  \param[in] theEntity attribute, which values should update SolveSpace entity
+////   */
+////  void updateEntityIfPossible(std::shared_ptr<ModelAPI_Attribute> theEntity);
+
+  /** \brief Searches invalid features and constraints in the group and removes them
+   *  \return \c false if the group several constraints were removed
+   */
+  bool isConsistent();
+
+  /** \brief Add specified group to this one
+   *  \param[in] theGroup group of constraint to be added
+   */
+  void mergeGroups(const SketchSolver_Group& theGroup);
+
+  /** \brief Cut from the group several subgroups, which are not connected to the current one by any constraint
+   *  \param[out] theCuts enlarge this list by newly created groups
+   */
+  void splitGroup(std::vector<SketchSolver_Group*>& theCuts);
+
+  /** \brief Start solution procedure if necessary and update attributes of features
+   *  \return \c false when no need to solve constraints
+   */
+  bool resolveConstraints();
+////
+////  /** \brief Searches the constraints built on the entity and emit the signal to update them
+////   *  \param[in] theEntity attribute of the constraint
+////   */
+////  void updateRelatedConstraints(std::shared_ptr<ModelAPI_Attribute> theEntity) const;
+////  /** \brief Searches the constraints built on the entity and emit the signal to update them
+////   *  \param[in] theFeature feature of the constraint
+////   */
+////  void updateRelatedConstraintsFeature(std::shared_ptr<ModelAPI_Feature> theFeature) const;
+////
+////  /** \brief Adds or updates an entity in the group
+////   *
+////   *  The parameters of entity will be parsed and added to the list of SolveSpace parameters.
+////   *  Parameters of certain entity will be placed sequentially in the list.
+////   *
+////   *  \param[in] theEntity the object of constraint
+////   *  \return identifier of changed entity or 0 if entity could not be changed
+////   */
+////  Slvs_hEntity changeEntity(std::shared_ptr<ModelAPI_Attribute> theEntity);
+////  Slvs_hEntity changeEntityFeature(std::shared_ptr<ModelAPI_Feature> theEntity);
+
+protected:
+////  /** \brief Adds or updates a normal in the group
+////   *
+////   *  Normal is a special entity in SolveSpace, which defines a direction in 3D and
+////   *  a rotation about this direction. So, SolveSpace represents normals as unit quaternions.
+////   *
+////   *  To define a normal there should be specified two coordinate axis
+////   *  on the plane transversed to created normal.
+////   *
+////   *  \param[in] theDirX first coordinate axis of the plane
+////   *  \param[in] theNorm attribute for the normal (used to identify newly created entity)
+////   *  \return identifier of created or updated normal
+////   */
+////  Slvs_hEntity changeNormal(std::shared_ptr<ModelAPI_Attribute> theDirX,
+////                            std::shared_ptr<ModelAPI_Attribute> theNorm);
+////
+////  /** \brief Adds or updates a parameter in the group
+////   *  \param[in] theParam   the value of parameter
+////   *  \param[in] thePrmIter the cell in the list of parameters which should be changed
+////   *                        (the iterator will be increased if it does not reach the end of the list)
+////   *  \return identifier of changed parameter; when the parameter cannot be created, returned ID is 0
+////   */
+////  Slvs_hParam changeParameter(const double& theParam,
+////                              std::vector<Slvs_Param>::const_iterator& thePrmIter);
+////
+////  /** \brief Removes specified entities and their parameters
+////   *  \param[in] theEntities  list of IDs of the entities to be removed
+////   */
+////  void removeEntitiesById(const std::set<Slvs_hEntity>& theEntities);
+
+  /** \brief Removes constraints from the group
+   *  \param[in] theConstraint constraint to be removed
+   */
+  void removeConstraint(ConstraintPtr theConstraint);
+////
+////  /** \brief Change values of attribute by parameters received from SolveSpace solver
+////   *  \param[in,out] theAttribute pointer to the attribute to be changed
+////   *  \param[in]     theEntityID  identifier of SolveSpace entity, which contains updated data
+////   *  \return \c true if the attribute's value has changed
+////   */
+////  bool updateAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute,
+////                       const Slvs_hEntity& theEntityID);
+////
+////  /// \brief Update arc of fillet to be less than 180 degree
+////  void updateFilletConstraints();
+////
+////  /** \brief Adds a constraint for a point which should not be changed during computations
+////   *  \param[in] theEntity     the base for the constraint
+////   *  \param[in] theAllowToFit this flag shows that the entity may be placed into 
+////   *                           the 'dragged' field of SolveSpace solver, so this entity 
+////   *                           may be changed a little during solution
+////   */
+////  void addTemporaryConstraintWhereDragged(std::shared_ptr<ModelAPI_Attribute> theEntity,
+////                                          bool theAllowToFit = true);
+
+  /** \brief Remove all temporary constraint after computation finished
+   *  \param[in] theRemoved  indexes of constraints to be removed. If empty, all temporary constraints should be deleted
+   */
+  void removeTemporaryConstraints();
+
+private:
+  /** \brief Creates a workplane from the sketch parameters
+   *  \param[in] theSketch parameters of workplane are the attributes of this sketch
+   *  \return \c true if success, \c false if workplane parameters are not consistent
+   */
+  bool addWorkplane(CompositeFeaturePtr theSketch);
+////
+////  /** \brief Add the entities of constraint for points coincidence into the appropriate list
+////   *  \param[in] thePoint1 identifier of the first point
+////   *  \param[in] thePoint2 identifier of the second point
+////   *  \return \c true if the points are added successfully, and 
+////   *          \c false if the constraint is the extra one (should not be created in SolveSpace)
+////   */
+////  bool addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2);
+////
+////  /** \brief Verifies and changes parameters of constriant, 
+////   *         e.g. sign of the distance between line and point
+////   *  \param[in,out] theConstraint SolveSpace constraint to be verified
+////   */
+////  void checkConstraintConsistence(Slvs_Constraint& theConstraint);
+////
+////  /** \brief Change entities parameters to make them symmetric relating to the mirror line
+////   *  \param[in] theBase        entity to be mirrored
+////   *  \param[in] theMirror      a mirrored object
+////   *  \param[in] theMirrorLine  a mirror line
+////   */
+////  void makeMirrorEntity(const Slvs_hEntity& theBase,
+////                        const Slvs_hEntity& theMirror,
+////                        const Slvs_hEntity& theMirrorLine);
+////
+////  /** \brief Calculates middle point on line or arc
+////   *  \param[in]  theEntity  identifier of line or arc
+////   *  \param[out] theX       X value of middle point
+////   *  \param[out] theY       Y value of middle point
+////   */
+////  void calculateMiddlePoint(const Slvs_hEntity& theEntity,
+////                            double& theX, double& theY) const;
+////
+//// private:
+////  // SolveSpace entities
+////  Slvs_hGroup myID;            ///< the index of the group
+////  Slvs_Entity myWorkplane;     ///< Workplane for the current group
+////  std::vector<Slvs_Param> myParams;        ///< List of parameters of the constraints
+////  Slvs_hParam myParamMaxID;    ///< Actual maximal ID of parameters (not equal to myParams size)
+////  std::vector<Slvs_Entity> myEntities;      ///< List of entities of the constaints
+////  std::vector<bool> myEntOfConstr; ///< Flags show that certain entity used in constraints
+////  Slvs_hEntity myEntityMaxID;   ///< Actual maximal ID of entities (not equal to myEntities size)
+////  std::vector<Slvs_Constraint> myConstraints;   ///< List of constraints in SolveSpace format
+////  Slvs_hConstraint myConstrMaxID;  ///< Actual maximal ID of constraints (not equal to myConstraints size)
+////  bool myNeedToSolve;  ///< Indicator that something changed in the group and constraint system need to be rebuilt
+////
+////  SketchSolver_Solver myConstrSolver;  ///< Solver for set of equations obtained by constraints
+////
+////  std::vector<Slvs_hParam> myTempPointWhereDragged;  ///< Parameters of one of the points which is moved by user
+////  Slvs_hEntity myTempPointWDrgdID;      ///< Identifier of such point
+////  std::list<Slvs_hConstraint> myTempConstraints;  ///< The list of identifiers of temporary constraints (SLVS_C_WHERE_DRAGGED) applied for all other points moved by user
+////
+////  // SketchPlugin entities
+////  std::shared_ptr<ModelAPI_CompositeFeature> mySketch;        ///< Equivalent to workplane
+////  ConstraintMap myConstraintMap;  ///< The map between SketchPlugin and SolveSpace constraints
+////  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity> myEntityAttrMap;  ///< The map between "attribute" parameters of constraints and their equivalent SolveSpace entities
+////  std::map<FeaturePtr, Slvs_hEntity> myEntityFeatMap;  ///< The map between "feature" parameters of constraints and their equivalent SolveSpace entities
+////
+////  // Conincident items
+////  std::vector<std::set<Slvs_hEntity> > myCoincidentPoints;  ///< Stores the lists of identifiers of coincident points (to avoid unnecessary coincidence constraints)
+////  std::set<std::shared_ptr<SketchPlugin_Constraint> > myExtraCoincidence;  ///< Additional coincidence constraints which are not necessary (coincidence between points already done
+////                                                                             ///< by other constraints) but created by GUI tools. Useful when some coincidence constraints were removed
+
+private:
+  Slvs_hGroup myID; ///< Index of the group
+  Slvs_hEntity myWorkplaneID; ///< Index of workplane, the group is based on
+  CompositeFeaturePtr mySketch; ///< Sketch is equivalent to workplane
+  ConstraintConstraintMap myConstraints; ///< List of constraints
+  std::set<SolverConstraintPtr> myTempConstraints; ///< List of temporary constraints
+
+  StoragePtr myStorage; ///< Container for the set of SolveSpace constraints and their entities
+  FeatureStoragePtr myFeatureStorage; ///< Container for the set of SketchPlugin features and their dependencies
+
+  SketchSolver_Solver myConstrSolver;  ///< Solver for set of equations obtained by constraints
+};
+
+#endif
index 7e3a33de2891d609d769b2505179b7a2f46f91b4..650e11c2d79b12c9a261e355c45500c1358acd5d 100644 (file)
@@ -31,83 +31,36 @@ SketchSolver_Solver::SketchSolver_Solver()
 
 SketchSolver_Solver::~SketchSolver_Solver()
 {
-  if (myEquationsSystem.param)
-    delete[] myEquationsSystem.param;
-  if (myEquationsSystem.entity)
-    delete[] myEquationsSystem.entity;
-  if (myEquationsSystem.constraint)
-    delete[] myEquationsSystem.constraint;
   if (myEquationsSystem.failed)
     delete[] myEquationsSystem.failed;
 }
 
-void SketchSolver_Solver::setParameters(const std::vector<Slvs_Param>& theParameters)
+void SketchSolver_Solver::setParameters(Slvs_Param* theParameters, int theSize)
 {
-  if (theParameters.size() != myEquationsSystem.params)  // number of parameters was changed => reallocate the memory
-      {
-    if (myEquationsSystem.param)
-      delete[] myEquationsSystem.param;
-    myEquationsSystem.params = theParameters.size();
-    myEquationsSystem.param = new Slvs_Param[theParameters.size()];
-  }
-
-  // Copy data
-  std::vector<Slvs_Param>::const_iterator aParamIter = theParameters.begin();
-  for (int i = 0; i < myEquationsSystem.params; i++, aParamIter++)
-    myEquationsSystem.param[i] = *aParamIter;
+  myEquationsSystem.param = theParameters;
+  myEquationsSystem.params = theSize;
 }
 
-void SketchSolver_Solver::setDraggedParameters(const std::vector<Slvs_hParam>& theDragged)
+
+void SketchSolver_Solver::setDraggedParameters(const Slvs_hParam* theDragged)
 {
-  if (theDragged.size() == 0) {
-    myEquationsSystem.dragged[0] = 0;
-    myEquationsSystem.dragged[1] = 0;
-    myEquationsSystem.dragged[2] = 0;
-    myEquationsSystem.dragged[3] = 0;
-    return;
-  }
-  for (unsigned int i = 0; i < theDragged.size(); i++)
+  for (unsigned int i = 0; i < 4; i++)
     myEquationsSystem.dragged[i] = theDragged[i];
 }
 
-void SketchSolver_Solver::setEntities(const std::vector<Slvs_Entity>& theEntities)
+void SketchSolver_Solver::setEntities(Slvs_Entity* theEntities, int theSize)
 {
-  if (theEntities.size() != myEquationsSystem.entities)  // number of entities was changed => reallocate the memory
-      {
-    if (myEquationsSystem.entity)
-      delete[] myEquationsSystem.entity;
-    myEquationsSystem.entities = theEntities.size();
-    myEquationsSystem.entity = new Slvs_Entity[theEntities.size()];
-  }
-
-  // Copy data
-  std::vector<Slvs_Entity>::const_iterator aEntIter = theEntities.begin();
-  for (int i = 0; i < myEquationsSystem.entities; i++, aEntIter++)
-    myEquationsSystem.entity[i] = *aEntIter;
+  myEquationsSystem.entity = theEntities;
+  myEquationsSystem.entities = theSize;
 }
 
-void SketchSolver_Solver::setConstraints(const std::vector<Slvs_Constraint>& theConstraints)
+void SketchSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize)
 {
-  if (theConstraints.size() != myEquationsSystem.constraints)  // number of constraints was changed => reallocate the memory
-      {
-    if (myEquationsSystem.constraint)
-      delete[] myEquationsSystem.constraint;
-    myEquationsSystem.constraints = theConstraints.size();
-    myEquationsSystem.constraint = new Slvs_Constraint[theConstraints.size()];
-
-    // Assign the memory for the failed constraints
-    if (myEquationsSystem.failed)
-      delete[] myEquationsSystem.failed;
-    myEquationsSystem.failed = new Slvs_hConstraint[theConstraints.size()];
-    myEquationsSystem.faileds = theConstraints.size();
-  }
-
-  // Copy data
-  std::vector<Slvs_Constraint>::const_iterator aConstrIter = theConstraints.begin();
-  for (int i = 0; i < myEquationsSystem.constraints; i++, aConstrIter++)
-    myEquationsSystem.constraint[i] = *aConstrIter;
+  myEquationsSystem.constraint = theConstraints;
+  myEquationsSystem.constraints = theSize;
 }
 
+
 int SketchSolver_Solver::solve()
 {
   if (myEquationsSystem.constraints <= 0)
index 4a45b525343b64936823d677135795b90b243009..bdc23ce288182adff99c5752d3f0befc5d06e60f 100644 (file)
@@ -28,6 +28,8 @@ typedef unsigned int UINT32;
 #define SLVS_C_FILLET 100100
 // Unknown entity
 #define SLVS_E_UNKNOWN 0
+// Unknown group
+#define SLVS_G_UNKNOWN 0
 
 /**
  * The main class that performs the high-level operations for connection to the SolveSpace.
@@ -46,25 +48,28 @@ class SketchSolver_Solver
   }
 
   /** \brief Change array of parameters
-   *  \param[in] theParameters vector of parameters
+   *  \param[in] theParameters pointer to the array of parameters
+   *  \param[in] theSize       size of this array
    */
-  void setParameters(const std::vector<Slvs_Param>& theParameters);
+  void setParameters(Slvs_Param* theParameters, int theSize);
 
   /** \brief Change array of entities
-   *  \param[in] theEntities vector of entities
+   *  \param[in] theEntities pointer to the array of entities
+   *  \param[in] theSize     size of this array
    */
-  void setEntities(const std::vector<Slvs_Entity>& theEntities);
+  void setEntities(Slvs_Entity* theEntities, int theSize);
 
   /** \brief Change array of constraints
-   *  \param[in] theConstraints vector of constraints
+   *  \param[in] theConstraints pointer to the array of constraints
+   *  \param[in] theSize        size of this array
    */
-  void setConstraints(const std::vector<Slvs_Constraint>& theConstraints);
+  void setConstraints(Slvs_Constraint* theConstraints, int theSize);
 
   /** \brief Store the parameters of the point which was moved by user.
    *         The solver will watch this items to be constant
    *  \param[in] theDragged list of parameters (not more than 4) which should not be changed during solving
    */
-  void setDraggedParameters(const std::vector<Slvs_hParam>& theDragged);
+  void setDraggedParameters(const Slvs_hParam* theDragged);
 
   /** \brief Solve the set of equations
    *  \return identifier whether solution succeeded
diff --git a/src/SketchSolver/SketchSolver_Storage.cpp b/src/SketchSolver/SketchSolver_Storage.cpp
new file mode 100644 (file)
index 0000000..d56d98d
--- /dev/null
@@ -0,0 +1,343 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Storage.cpp
+// Created: 18 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#include <SketchSolver_Storage.h>
+
+/** \brief Search the entity/parameter with specified ID in the list of elements
+ *  \param[in] theEntityID unique ID of the element
+ *  \param[in] theEntities list of elements
+ *  \return position of the found element or -1 if the element is not found
+ */
+template<typename T>
+static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
+
+/// \brief Compare two parameters to be different
+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 constriants to be different
+static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2);
+
+
+SketchSolver_Storage::SketchSolver_Storage()
+  : myParamMaxID(SLVS_E_UNKNOWN),
+    myEntityMaxID(SLVS_E_UNKNOWN),
+    myConstrMaxID(SLVS_C_UNKNOWN),
+    myNeedToResolve(false)
+{
+}
+
+Slvs_hParam SketchSolver_Storage::addParameter(const Slvs_Param& theParam)
+{
+  if (theParam.h > 0 && theParam.h <= myParamMaxID) {
+    // parameter is already used, rewrite it
+    return updateParameter(theParam);
+  }
+
+  Slvs_Param aParam = theParam;
+  if (aParam.h > myParamMaxID)
+    myParamMaxID = aParam.h;
+  else
+    aParam.h = ++myParamMaxID;
+  myParameters.push_back(aParam);
+  myNeedToResolve = true;
+  return aParam.h;
+}
+
+Slvs_hParam SketchSolver_Storage::updateParameter(const Slvs_Param& theParam)
+{
+  if (theParam.h > 0 && theParam.h <= myParamMaxID) {
+    // parameter already used, rewrite it
+    int aPos = Search(theParam.h, myParameters);
+    if (aPos >= 0 && aPos < (int)myParameters.size()) {
+      myNeedToResolve = myNeedToResolve || IsNotEqual(myParameters[aPos], theParam);
+      myParameters[aPos] = theParam;
+      return theParam.h;
+    }
+  }
+
+  // Parameter is not found, add new one
+  Slvs_Param aParam = theParam;
+  aParam.h = 0;
+  return addParameter(aParam);
+}
+
+bool SketchSolver_Storage::removeParameter(const Slvs_hParam& theParamID)
+{
+  int aPos = Search(theParamID, myParameters);
+  if (aPos >= 0 && aPos < (int)myParameters.size()) {
+    // Firstly, search the parametes is not used elsewhere
+    std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+    for (; anEntIter != myEntities.end(); anEntIter++) {
+      for (int i = 0; i < 4; i++)
+        if (anEntIter->param[i] == theParamID)
+          return false;
+    }
+    // Remove parameter
+    myParameters.erase(myParameters.begin() + aPos);
+    myNeedToResolve = true;
+    myRemovedParameters.insert(theParamID);
+    return true;
+  }
+  return false;
+}
+
+const Slvs_Param& SketchSolver_Storage::getParameter(const Slvs_hParam& theParamID) const
+{
+  int aPos = Search(theParamID, myParameters);
+  if (aPos >= 0 && aPos < (int)myParameters.size())
+    return myParameters[aPos];
+
+  // Parameter is not found, return empty object
+  static Slvs_Param aDummy;
+  aDummy.h = 0;
+  return aDummy;
+}
+
+
+Slvs_hEntity SketchSolver_Storage::addEntity(const Slvs_Entity& theEntity)
+{
+  if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
+    // Entity is already used, rewrite it
+    return updateEntity(theEntity);
+  }
+
+  Slvs_Entity aEntity = theEntity;
+  if (aEntity.h > myEntityMaxID)
+    myEntityMaxID = aEntity.h;
+  else
+    aEntity.h = ++myEntityMaxID;
+  myEntities.push_back(aEntity);
+  myNeedToResolve = true;
+  return aEntity.h;
+}
+
+Slvs_hEntity SketchSolver_Storage::updateEntity(const Slvs_Entity& theEntity)
+{
+  if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
+    // Entity already used, rewrite it
+    int aPos = Search(theEntity.h, myEntities);
+    if (aPos >= 0 && aPos < (int)myEntities.size()) {
+      myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity);
+      myEntities[aPos] = theEntity;
+      return theEntity.h;
+    }
+  }
+
+  // Entity is not found, add new one
+  Slvs_Entity aEntity = theEntity;
+  aEntity.h = 0;
+  return addEntity(aEntity);
+}
+
+bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
+{
+  bool aResult = true;
+  int aPos = Search(theEntityID, myEntities);
+  if (aPos >= 0 && aPos < (int)myEntities.size()) {
+    // Firstly, check the entity is not used elsewhere
+    std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+    for (; anEntIter != myEntities.end(); anEntIter++) {
+      for (int i = 0; i < 4; i++)
+        if (anEntIter->point[i] == theEntityID)
+          return false;
+      if (anEntIter->distance == theEntityID)
+        return false;
+    }
+    std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+    for (; aConstrIter != myConstraints.end(); aConstrIter++) {
+      Slvs_hEntity anEntIDs[6] = {aConstrIter->ptA, aConstrIter->ptB,
+          aConstrIter->entityA, aConstrIter->entityB,
+          aConstrIter->entityC, aConstrIter->entityD};
+      for (int i = 0; i < 6; i++)
+        if (anEntIDs[i] == theEntityID)
+          return false;
+    }
+    // The entity is not used, remove it and its parameters
+    Slvs_Entity anEntity = myEntities[aPos];
+    myEntities.erase(myEntities.begin() + aPos);
+    if (anEntity.distance != SLVS_E_UNKNOWN)
+      aResult = aResult && removeParameter(anEntity.distance);
+    for (int i = 0; i < 4; i++)
+      if (anEntity.param[i] != SLVS_E_UNKNOWN)
+        aResult = removeParameter(anEntity.param[i]) && aResult;
+    for (int i = 0; i < 4; i++)
+      if (anEntity.point[i] != SLVS_E_UNKNOWN)
+        aResult = removeEntity(anEntity.point[i]) && aResult;
+    myNeedToResolve = true;
+    myRemovedEntities.insert(theEntityID);
+  }
+  return aResult;
+}
+
+const Slvs_Entity& SketchSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const
+{
+  int aPos = Search(theEntityID, myEntities);
+  if (aPos >= 0 && aPos < (int)myEntities.size())
+    return myEntities[aPos];
+
+  // Entity is not found, return empty object
+  static Slvs_Entity aDummy;
+  aDummy.h = 0;
+  return aDummy;
+}
+
+
+Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
+{
+  if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
+    // Constraint is already used, rewrite it
+    return updateConstraint(theConstraint);
+  }
+
+  Slvs_Constraint aConstraint = theConstraint;
+  if (aConstraint.h > myConstrMaxID)
+    myConstrMaxID = aConstraint.h;
+  else
+    aConstraint.h = ++myConstrMaxID;
+  myConstraints.push_back(aConstraint);
+  myNeedToResolve = true;
+  return aConstraint.h;
+}
+
+Slvs_hConstraint SketchSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint)
+{
+  if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
+    // Constraint already used, rewrite it
+    int aPos = Search(theConstraint.h, myConstraints);
+    if (aPos >= 0 && aPos < (int)myConstraints.size()) {
+      myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint);
+      myConstraints[aPos] = theConstraint;
+      return theConstraint.h;
+    }
+  }
+
+  // Constraint is not found, add new one
+  Slvs_Constraint aConstraint = theConstraint;
+  aConstraint.h = 0;
+  return addConstraint(aConstraint);
+}
+
+bool SketchSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID)
+{
+  bool aResult = true;
+  int aPos = Search(theConstraintID, myConstraints);
+  if (aPos >= 0 && aPos < (int)myConstraints.size()) {
+    Slvs_Constraint aConstraint = myConstraints[aPos];
+    myConstraints.erase(myConstraints.begin() + aPos);
+    myNeedToResolve = true;
+    myRemovedConstraints.insert(theConstraintID);
+    // Remove all entities
+    Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB,
+        aConstraint.entityA, aConstraint.entityB,
+        aConstraint.entityC, aConstraint.entityD};
+    for (int i = 0; i < 6; i++)
+      if (anEntities[i] != SLVS_E_UNKNOWN) {
+        aResult = removeEntity(anEntities[i]) && aResult;
+        // remove temporary fixed points, if exists
+        std::vector<Slvs_hEntity>::iterator aFPIt = myFixedPoints.begin();
+        for (; aFPIt != myFixedPoints.end(); aFPIt++)
+          if (*aFPIt == anEntities[i]) {
+            myFixedPoints.erase(aFPIt);
+            break;
+          }
+      }
+  }
+  return aResult;
+}
+
+const Slvs_Constraint& SketchSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const
+{
+  int aPos = Search(theConstraintID, myConstraints);
+  if (aPos >= 0 && aPos < (int)myConstraints.size())
+    return myConstraints[aPos];
+
+  // Constraint is not found, return empty object
+  static Slvs_Constraint aDummy;
+  aDummy.h = 0;
+  return aDummy;
+}
+
+void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
+{
+  int aPos = Search(theConstraintID, myConstraints);
+  myFixedPoints.push_back(myConstraints[aPos].ptA);
+}
+
+void SketchSolver_Storage::getRemoved(
+    std::set<Slvs_hParam>& theParameters,
+    std::set<Slvs_hEntity>& theEntities,
+    std::set<Slvs_hConstraint>& theConstraints)
+{
+  theParameters = myRemovedParameters;
+  theEntities = myRemovedEntities;
+  theConstraints = myRemovedConstraints;
+
+  myRemovedParameters.clear();
+  myRemovedEntities.clear();
+  myRemovedConstraints.clear();
+}
+
+void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver)
+{
+  theSolver.setParameters(myParameters.data(), (int)myParameters.size());
+  theSolver.setEntities(myEntities.data(), (int)myEntities.size());
+  theSolver.setConstraints(myConstraints.data(), (int)myConstraints.size());
+
+  // initialize fixed points
+  if (!myFixedPoints.empty()) {
+    int aPos = Search(myFixedPoints.front(), myEntities);
+    theSolver.setDraggedParameters(myEntities[aPos].param);
+  }
+}
+
+
+// ========================================================
+// =========      Auxiliary functions       ===============
+// ========================================================
+
+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();
+  while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
+    aResIndex--;
+  while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
+    aResIndex++;
+  if (aResIndex == -1)
+    aResIndex = aVecSize;
+  return aResIndex;
+}
+
+bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2)
+{
+  return fabs(theParam1.val - theParam2.val) > tolerance;
+}
+
+bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2)
+{
+  int i = 0;
+  for (; theEntity1.param[i] != 0 && i < 4; i++)
+    if (theEntity1.param[i] != theEntity2.param[i])
+      return true;
+  i = 0;
+  for (; theEntity1.point[i] != 0 && i < 4; i++)
+    if (theEntity1.point[i] != theEntity2.point[i])
+      return true;
+  return false;
+}
+
+bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2)
+{
+  return theConstraint1.ptA != theConstraint2.ptA ||
+         theConstraint1.ptB != theConstraint2.ptB ||
+         theConstraint1.entityA != theConstraint2.entityA ||
+         theConstraint1.entityB != theConstraint2.entityB ||
+         theConstraint1.entityC != theConstraint2.entityC ||
+         theConstraint1.entityD != theConstraint2.entityD ||
+         fabs(theConstraint1.valA - theConstraint2.valA) > tolerance;
+}
diff --git a/src/SketchSolver/SketchSolver_Storage.h b/src/SketchSolver/SketchSolver_Storage.h
new file mode 100644 (file)
index 0000000..0317f93
--- /dev/null
@@ -0,0 +1,121 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Storage.h
+// Created: 18 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_Storage_H_
+#define SketchSolver_Storage_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Solver.h>
+
+#include <memory>
+#include <set>
+#include <vector>
+
+/** \class   SketchSolver_Storage
+ *  \ingroup Plugins
+ *  \brief   Contains all necessary data in SolveSpace format to solve a single group of constraints
+ */
+class SketchSolver_Storage
+{
+public:
+  SketchSolver_Storage();
+
+  /** \brief Add new parameter to the current group
+   *  \param[in] theParam  SolveSpace parameter
+   *  \return the ID of added parameter
+   */
+  Slvs_hParam addParameter(const Slvs_Param& theParam);
+  /** \brief Updates parameter in the current group. If the ID of parameter is zero, the new item will be added
+   *  \param[in] theParam  SolveSpace parameter
+   *  \return the ID of updated/added parameter
+   */
+  Slvs_hParam updateParameter(const Slvs_Param& theParam);
+  /** \brief Removes the parameter by its ID
+   *  \param[in] theParamID  index of parameter to be removed
+   *  \return \c true if the parameter was successfully removed
+   */
+  bool removeParameter(const Slvs_hParam& theParamID);
+  /// \brief Returns the parameter by its ID
+  const Slvs_Param& getParameter(const Slvs_hParam& theParamID) const;
+
+  /** \brief Add new entity to the current group
+   *  \param[in] theEntity  SolveSpace entity
+   *  \return the ID of added entity
+   */
+  Slvs_hEntity addEntity(const Slvs_Entity& theEntity);
+  /** \brief Updates entity in the current group. If the ID of entity is zero, the new item will be added
+   *  \param[in] theEntity  SolveSpace entity
+   *  \return the ID of updated/added entity
+   */
+  Slvs_hEntity updateEntity(const Slvs_Entity& theEntity);
+  /** \brief Removes the entity by its ID. All parameters used in this entity,
+   *         and not used in other constraints, will be removed too.
+   *  \param[in] theEntityID  index of entity to be removed
+   *  \return \c true if the entity was successfully removed
+   */
+  bool removeEntity(const Slvs_hEntity& theEntityID);
+  /// \brief Returns the entity by its ID
+  const Slvs_Entity& getEntity(const Slvs_hEntity& theEntityID) const;
+
+  /** \brief Add new constraint to the current group
+   *  \param[in] theConstraint  SolveSpace constraint
+   *  \return the ID of added constraint
+   */
+  Slvs_hConstraint addConstraint(const Slvs_Constraint& theConstraint);
+  /** \brief Updates constraint in the current group.
+   *         If the ID of constraint is zero, the new item will be added
+   *  \param[in] theConstraint  SolveSpace constraint
+   *  \return the ID of updated/added constraint
+   */
+  Slvs_hConstraint updateConstraint(const Slvs_Constraint& theConstraint);
+  /** \brief Removes the constraint by its ID. All entities and parameters depending on this
+   *         constraint, which are not used in other constraints, will be removed too.
+   *  \param[in] theConstraintID  index of constraint to be removed
+   *  \return \c true if the constraint was successfully removed
+   */
+  bool removeConstraint(const Slvs_hConstraint& theConstraintID);
+  /// \brief Returns the constraint by its ID
+  const Slvs_Constraint& getConstraint(const Slvs_hConstraint& theConstraintID) const;
+
+  /// \brief Attach temporary constraint to this storage. It need to make precise calculations
+  void addTemporaryConstraint(const Slvs_hConstraint& theConstraintID);
+
+  /// \brief Shows the sketch should be resolved
+  bool isNeedToResolve() const
+  { return myNeedToResolve; }
+
+  /// \brief Changes the flag of group to be resolved
+  void setNeedToResolve(bool theFlag)
+  { myNeedToResolve = theFlag; }
+
+  /// \brief Returns lists of removed elements
+  void getRemoved(std::set<Slvs_hParam>& theParameters,
+                  std::set<Slvs_hEntity>& theEntities,
+                  std::set<Slvs_hConstraint>& theConstraints);
+
+  /// \brief Initialize constraint solver by the entities collected by current storage
+  void initializeSolver(SketchSolver_Solver& theSolver);
+
+private:
+  Slvs_hParam myParamMaxID; ///< current parameter index (may differs with the number of parameters)
+  std::vector<Slvs_Param> myParameters; ///< list of parameters used in the current group of constraints
+  Slvs_hEntity myEntityMaxID; ///< current entity index (may differs with the number of entities)
+  std::vector<Slvs_Entity> myEntities; ///< list of entities used in the current group of constraints
+  Slvs_hConstraint myConstrMaxID; ///< current constraint index (may differs with the number of constraints)
+  std::vector<Slvs_Constraint> myConstraints; ///< list of constraints used in the current group
+
+  std::vector<Slvs_hEntity> myFixedPoints; ///< identifiers of entities which relate to temporary constraints
+
+  bool myNeedToResolve; ///< parameters are changed and group needs to be resolved
+
+  std::set<Slvs_hParam> myRemovedParameters; ///< list of just removed parameters (cleared when returning to applicant)
+  std::set<Slvs_hEntity> myRemovedEntities; ///< list of just removed entities (cleared when returning to applicant)
+  std::set<Slvs_hConstraint> myRemovedConstraints; ///< list of just removed constraints (cleared when returning to applicant)
+};
+
+typedef std::shared_ptr<SketchSolver_Storage> StoragePtr;
+
+#endif