]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Second phase of SketchSolver refactoring
authorazv <azv@opencascade.com>
Wed, 16 Dec 2015 05:18:01 +0000 (08:18 +0300)
committerazv <azv@opencascade.com>
Tue, 22 Dec 2015 08:13:48 +0000 (11:13 +0300)
2. Implementation of PlaneGCS solver connection.
3. Update test cases according new behavior.

29 files changed:
src/Config/plugins.xml
src/GeomAPI/GeomAPI_Edge.cpp
src/GeomAPI/GeomAPI_Edge.h
src/SketchPlugin/Test/TestConstraintLength.py
src/SketchPlugin/Test/TestConstraintRigid.py
src/SketchPlugin/Test/TestConstraintTangent.py
src/SketchSolver/PlaneGCSSolver/CMakeLists.txt [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.cpp [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.h [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.cpp [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.h [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Defs.h [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.cpp [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.h [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.cpp [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.h [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.cpp [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.h [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.cpp [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.h [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h [new file with mode: 0644]
src/SketchSolver/SketchSolver.h
src/SketchSolver/SketchSolver_IEntityWrapper.h
src/SketchSolver/SketchSolver_Storage.h

index 90a80b50b6be903570f9339620c5fa11b6fac8ac..9b0e0cf5fec33838f6d323452f434708b8b4f9fa 100644 (file)
@@ -11,7 +11,8 @@
   <plugin script="addons_Features" configuration="addons_Features.xml"/>
   <plugin script="ConnectorPlugin" configuration="plugin-Connector.xml" dependency="Geometry"/>
   <plugin library="ParametersPlugin" configuration="plugin-Parameters.xml"/>
-  <plugin library="SolveSpaceSolver"/>
+<!--  <plugin library="SolveSpaceSolver"/> -->
+  <plugin library="PlaneGCSSolver"/>
   <plugin library="GeomValidators"/>
   <plugin library="DFBrowser" internal="true"/>
 </plugins>
index b5736f4b618d70b52ad2e8c786c8db1ba4d20ff6..2edd787d94d9333de94d9ede8eaa99081c756b36 100644 (file)
@@ -166,3 +166,9 @@ bool GeomAPI_Edge::isEqual(const std::shared_ptr<GeomAPI_Shape> theEdge) const
 
   return true;
 }
+
+void GeomAPI_Edge::getRange(double& theFirst, double& theLast) const
+{
+  const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
+  Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, theFirst, theLast);
+}
index c5c62a9e9f689c54a7a5867c471d1cd8a21427aa..4c929aa2a86379615e2523e983dc0f0801707ec5 100644 (file)
@@ -60,6 +60,10 @@ public:
   /// Returns true if the current edge is geometrically equal to the given edge
   GEOMAPI_EXPORT 
   bool isEqual(const std::shared_ptr<GeomAPI_Shape> theEdge) const;
+
+  /// Returns range of parameter on the curve
+  GEOMAPI_EXPORT 
+  void getRange(double& theFirst, double& theLast) const;
 };
 
 #endif
index 87a388a65021fb5eaf48bd593810e67ceafbe5ab..88f9292b61e4f436799dae44bb3a415005a30abc 100644 (file)
@@ -11,6 +11,7 @@
 """
 from GeomDataAPI import *
 from ModelAPI import *
+import math
 #=========================================================================
 # Initialization of the test
 #=========================================================================
@@ -76,7 +77,7 @@ aSession.finishOperation()
 assert (aLineAStartPoint.y() == 25)
 assert (aLineAEndPoint.y() == 25)
 # length of the line is the same
-assert (aLineAEndPoint.x() - aLineAStartPoint.x() == 100)
+assert (math.fabs(aLineAEndPoint.x() - aLineAStartPoint.x() - 100) < 1.e-10)
 #=========================================================================
 # Change the length value of the constraint
 #=========================================================================
@@ -84,7 +85,7 @@ aSession.startOperation()
 aLength.setValue(140.)
 aLengthConstraint.execute()
 aSession.finishOperation()
-assert (aLineAEndPoint.x() - aLineAStartPoint.x() == 140)
+assert (math.fabs(aLineAEndPoint.x() - aLineAStartPoint.x() - 140) < 1.e-10)
 #=========================================================================
 # TODO: improve test
 # 1. remove constraint, move line's start point to
index b40ffcd420b48f806b20694300e10dc2d3a7e33a..2fe43e55756e8d6458fa82df145107020771f593 100644 (file)
@@ -105,12 +105,9 @@ eachRefattr.setObject(aResult)
 aSession.finishOperation()
 
 # Check that constarints doesn't affected lines' values
-assert (kLineAStart == (aLineAStartPoint.x(), aLineAStartPoint.y()))
-assert (kLineAEnd == (aLineAEndPoint.x(),   aLineAEndPoint.y()))
-assert (kLineBStart == (aLineBStartPoint.x(), aLineBStartPoint.y()))
-assert (kLineBEnd == (aLineBEndPoint.x(),   aLineBEndPoint.y()))
-assert (kLineCStart == (aLineCStartPoint.x(), aLineCStartPoint.y()))
-assert (kLineCEnd == (aLineCEndPoint.x(),   aLineCEndPoint.y()))
+assert ((aLineAStartPoint.x(), aLineAStartPoint.y()) == (aLineCEndPoint.x(), aLineCEndPoint.y()))
+assert ((aLineBStartPoint.x(), aLineBStartPoint.y()) == (aLineAEndPoint.x(), aLineAEndPoint.y()))
+assert ((aLineCStartPoint.x(), aLineCStartPoint.y()) == (aLineBEndPoint.x(), aLineBEndPoint.y()))
 #=========================================================================
 # Check that moving line A does not affect lines
 #=========================================================================
@@ -118,12 +115,9 @@ aSession.startOperation()
 aLineAEndPoint.setValue(90., 0.)
 aSession.finishOperation()
 # Check that constarint keep features' values
-assert (kLineAStart == (aLineAStartPoint.x(), aLineAStartPoint.y()))
-assert (kLineAEnd == (aLineAEndPoint.x(),   aLineAEndPoint.y()))
-assert (kLineBStart == (aLineBStartPoint.x(), aLineBStartPoint.y()))
-assert (kLineBEnd == (aLineBEndPoint.x(),   aLineBEndPoint.y()))
-assert (kLineCStart == (aLineCStartPoint.x(), aLineCStartPoint.y()))
-assert (kLineCEnd == (aLineCEndPoint.x(),   aLineCEndPoint.y()))
+assert ((aLineAStartPoint.x(), aLineAStartPoint.y()) == (aLineCEndPoint.x(), aLineCEndPoint.y()))
+assert ((aLineBStartPoint.x(), aLineBStartPoint.y()) == (aLineAEndPoint.x(), aLineAEndPoint.y()))
+assert ((aLineCStartPoint.x(), aLineCStartPoint.y()) == (aLineBEndPoint.x(), aLineBEndPoint.y()))
 #=========================================================================
 # Check that moving line B does not affect lines
 #=========================================================================
@@ -131,12 +125,9 @@ aSession.startOperation()
 aLineBEndPoint.setValue(90., 150.)
 aSession.finishOperation()
 # Check that constarint keep features' values
-assert (kLineAStart == (aLineAStartPoint.x(), aLineAStartPoint.y()))
-assert (kLineAEnd == (aLineAEndPoint.x(),   aLineAEndPoint.y()))
-assert (kLineBStart == (aLineBStartPoint.x(), aLineBStartPoint.y()))
-assert (kLineBEnd != (aLineBEndPoint.x(),   aLineBEndPoint.y()))
-assert (kLineCStart != (aLineCStartPoint.x(), aLineCStartPoint.y()))
-assert (kLineCEnd == (aLineCEndPoint.x(),   aLineCEndPoint.y()))
+assert ((aLineAStartPoint.x(), aLineAStartPoint.y()) == (aLineCEndPoint.x(), aLineCEndPoint.y()))
+assert ((aLineBStartPoint.x(), aLineBStartPoint.y()) == (aLineAEndPoint.x(), aLineAEndPoint.y()))
+assert ((aLineCStartPoint.x(), aLineCStartPoint.y()) == (aLineBEndPoint.x(), aLineBEndPoint.y()))
 #=========================================================================
 # TODO: improve test
 # 1. remove constraint, move line to check that constraint are not applied
index 225447d3e308b50644dc17e06804fae0d1d38537..e83d85716529d7f66b30a8c4bb8105fcf00321ac 100644 (file)
@@ -100,10 +100,12 @@ aTangency.execute()
 aSession.finishOperation()
 anArcVecX = anArcStartPoint.x() - anArcCentr.x()
 anArcVecY = anArcStartPoint.y() - anArcCentr.y()
+aLen = math.sqrt(anArcVecX**2 + anArcVecY**2)
 aLineVecX = aLine1EndPoint.x() - aLine1StartPoint.x()
 aLineVecY = aLine1EndPoint.y() - aLine1StartPoint.y()
+aLen = aLen * math.sqrt(aLineVecX**2 + aLineVecY**2)
 aDot = anArcVecX * aLineVecX + anArcVecY * aLineVecY
-assert(math.fabs(aDot) <= 1.e-12)
+assert math.fabs(aDot) <= 2.e-6 * aLen, "Observed dot product: {0}".format(aDot)
 #=========================================================================
 # Add tangency constraint for arc and second line and check correctness
 #=========================================================================
@@ -121,10 +123,12 @@ aTangency.execute()
 aSession.finishOperation()
 anArcVecX = anArcEndPoint.x() - anArcCentr.x()
 anArcVecY = anArcEndPoint.y() - anArcCentr.y()
+aLen = math.sqrt(anArcVecX**2 + anArcVecY**2)
 aLineVecX = aLine2EndPoint.x() - aLine2StartPoint.x()
 aLineVecY = aLine2EndPoint.y() - aLine2StartPoint.y()
+aLen = aLen * math.sqrt(aLineVecX**2 + aLineVecY**2)
 aDot = anArcVecX * aLineVecX + anArcVecY * aLineVecY
-assert(math.fabs(aDot) <= 1.e-12)
+assert math.fabs(aDot) <= 2.e-6 * aLen, "Observed dot product: {0}".format(aDot)
 
 #=========================================================================
 # TEST 2. Arc-arc tangency
@@ -179,10 +183,12 @@ aTangency.execute()
 aSession.finishOperation()
 anArc1VecX = anArc1EndPoint.x() - anArc1Centr.x()
 anArc1VecY = anArc1EndPoint.y() - anArc1Centr.y()
+aLen = math.sqrt(anArc1VecX**2 + anArc1VecY**2)
 anArc2VecX = anArc2StartPoint.x() - anArc2Centr.x()
 anArc2VecY = anArc2StartPoint.y() - anArc2Centr.y()
+aLen = aLen * math.sqrt(anArc2VecX**2 + anArc2VecY**2)
 aCross = anArc1VecX * anArc2VecY - anArc1VecY * anArc2VecX
-assert(math.fabs(aCross) <= 1.e-12)
+assert math.fabs(aCross) <= 2.e-6 * aLen, "Observed cross product: {0}".format(aCross)
 
 #=========================================================================
 # TEST 3. Tangency between non-connected objects should be wrong
diff --git a/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt b/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt
new file mode 100644 (file)
index 0000000..73c890e
--- /dev/null
@@ -0,0 +1,51 @@
+## Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+FIND_PACKAGE(PlaneGCS REQUIRED)
+
+SET(PROJECT_HEADERS
+    PlaneGCSSolver_Defs.h
+    PlaneGCSSolver_Solver.h
+    PlaneGCSSolver_Builder.h
+    PlaneGCSSolver_Storage.h
+    PlaneGCSSolver_ConstraintWrapper.h
+    PlaneGCSSolver_EntityWrapper.h
+    PlaneGCSSolver_PointWrapper.h
+    PlaneGCSSolver_ScalarWrapper.h
+    PlaneGCSSolver_ParameterWrapper.h
+    PlaneGCSSolver_AngleWrapper.h
+)
+
+SET(PROJECT_SOURCES
+    PlaneGCSSolver_Solver.cpp
+    PlaneGCSSolver_Builder.cpp
+    PlaneGCSSolver_Storage.cpp
+    PlaneGCSSolver_ConstraintWrapper.cpp
+    PlaneGCSSolver_EntityWrapper.cpp
+    PlaneGCSSolver_PointWrapper.cpp
+    PlaneGCSSolver_ScalarWrapper.cpp
+    PlaneGCSSolver_ParameterWrapper.cpp
+    PlaneGCSSolver_AngleWrapper.cpp
+)
+
+SET(PROJECT_LIBRARIES
+    ${PLANEGCS_LIBRARIES}
+    SketchSolver
+    ModelAPI
+    GeomAPI
+)
+
+INCLUDE_DIRECTORIES(
+    ${Boost_INCLUDE_DIRS}
+    ${EIGEN3_INCLUDE_DIR}
+    ${PLANEGCS_INCLUDE_DIRS}
+    ${PROJECT_SOURCE_DIR}/src/SketchSolver
+    ${PROJECT_SOURCE_DIR}/src/SketchPlugin
+    ${PROJECT_SOURCE_DIR}/src/ModelAPI
+    ${PROJECT_SOURCE_DIR}/src/GeomAPI
+    ${PROJECT_SOURCE_DIR}/src/GeomDataAPI
+)
+
+
+ADD_LIBRARY(PlaneGCSSolver MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS})
+TARGET_LINK_LIBRARIES(PlaneGCSSolver ${PROJECT_LIBRARIES})
+INSTALL(TARGETS PlaneGCSSolver DESTINATION plugins)
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.cpp
new file mode 100644 (file)
index 0000000..2bcf426
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_AngleWrapper.cpp
+// Created: 18 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#include <PlaneGCSSolver_AngleWrapper.h>
+
+#include <math.h>
+
+static double deg2rad(double theDegrees)
+{
+  return theDegrees * M_PI / 180.0;
+}
+
+static double rad2deg(double theRadians)
+{
+  return theRadians * 180.0 / M_PI;
+}
+
+PlaneGCSSolver_AngleWrapper::PlaneGCSSolver_AngleWrapper(double *const theParam)
+  : PlaneGCSSolver_ParameterWrapper(theParam)
+{
+  setValue(*myValue);
+}
+
+void PlaneGCSSolver_AngleWrapper::setValue(double theValue)
+{
+  *(myValue) = deg2rad(theValue);
+}
+
+double PlaneGCSSolver_AngleWrapper::value() const
+{
+  return rad2deg(*myValue);
+}
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.h
new file mode 100644 (file)
index 0000000..0eb1f6c
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_AngleWrapper.h
+// Created: 18 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef PlaneGCSSolver_AngleWrapper_H_
+#define PlaneGCSSolver_AngleWrapper_H_
+
+#include <PlaneGCSSolver_ParameterWrapper.h>
+
+/**
+ *  Wrapper providing operations with angular parameters in PlaneGCS.
+ */
+class PlaneGCSSolver_AngleWrapper : public PlaneGCSSolver_ParameterWrapper
+{
+public:
+  PlaneGCSSolver_AngleWrapper(double *const theParam);
+  ~PlaneGCSSolver_AngleWrapper() {}
+
+  /// \brief Change value of parameter
+  virtual void setValue(double theValue);
+  /// \brief Return value of parameter
+  virtual double value() const;
+};
+
+#endif
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp
new file mode 100644 (file)
index 0000000..f74db8d
--- /dev/null
@@ -0,0 +1,1256 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_Builder.cpp
+// Created: 14 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#include <PlaneGCSSolver_Builder.h>
+#include <PlaneGCSSolver_Solver.h>
+#include <PlaneGCSSolver_Storage.h>
+#include <PlaneGCSSolver_ParameterWrapper.h>
+#include <PlaneGCSSolver_AngleWrapper.h>
+#include <PlaneGCSSolver_EntityWrapper.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_ConstraintWrapper.h>
+
+#include <SketchSolver_Manager.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_Attribute.h>
+#include <ModelAPI_AttributeRefAttr.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_ConstraintAngle.h>
+
+#include <math.h>
+
+
+#define GCS_ENTITY_WRAPPER(x) std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(x)
+#define GCS_POINT_WRAPPER(x) std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(x)
+#define GCS_PARAMETER_WRAPPER(x) std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(x)
+
+
+/// \brief Converts a value to SolveSpace parameter
+/// \param theGroup [in]  group to store parameter
+/// \param theValue [in]  value of parameter
+/// \param theExpr  [in]  shows the parameter is given by expression
+/// \return Created parameter's wrapper
+static ParameterWrapperPtr createParameter(const GroupID& theGroup,
+                                           const double theValue = 0.0,
+                                           const bool theExpr = false);
+
+static ParameterWrapperPtr createParamAngle(const GroupID& theGroup,
+                                            const double& theValue = 0.0);
+
+static std::shared_ptr<PlaneGCSSolver_ScalarWrapper>
+    createScalar(const GroupID& theGroupID,
+                 AttributeDoublePtr theDoubleAttr = AttributeDoublePtr());
+
+static EntityWrapperPtr createLine(FeaturePtr theFeature,
+                                   const std::list<EntityWrapperPtr>& theAttributes,
+                                   const GroupID& theGroupID);
+static EntityWrapperPtr createCircle(FeaturePtr theFeature,
+                                     const std::list<EntityWrapperPtr>& theAttributes,
+                                     const GroupID& theGroupID);
+static EntityWrapperPtr createArc(FeaturePtr theFeature,
+                                  const std::list<EntityWrapperPtr>& theAttributes,
+                                  const GroupID& theGroupID);
+
+
+static ConstraintWrapperPtr
+  createConstraintCoincidence(ConstraintPtr theConstraint, 
+                              const GroupID& theGroupID,
+                              std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
+                              std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2);
+static ConstraintWrapperPtr
+  createConstraintPointOnEntity(ConstraintPtr theConstraint, 
+                                const GroupID& theGroupID,
+                                const SketchSolver_ConstraintType& theType,
+                                std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
+                                std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity);
+static ConstraintWrapperPtr
+  createConstraintDistancePointPoint(ConstraintPtr theConstraint,
+                                     const GroupID& theGroupID,
+                                     std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
+                                     std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
+                                     std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2);
+static ConstraintWrapperPtr
+  createConstraintDistancePointLine(ConstraintPtr theConstraint,
+                                    const GroupID& theGroupID,
+                                    std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
+                                    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
+                                    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity);
+static ConstraintWrapperPtr
+  createConstraintRadius(ConstraintPtr theConstraint,
+                         const GroupID& theGroupID,
+                         std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
+                         std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity);
+static ConstraintWrapperPtr
+  createConstraintAngle(ConstraintPtr theConstraint,
+                        const GroupID& theGroupID,
+                        std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
+                        std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+                        std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
+static ConstraintWrapperPtr
+  createConstraintHorizVert(ConstraintPtr theConstraint,
+                            const GroupID& theGroupID,
+                            const SketchSolver_ConstraintType& theType,
+                            std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity);
+static ConstraintWrapperPtr
+  createConstraintParallel(ConstraintPtr theConstraint,
+                           const GroupID& theGroupID,
+                           std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+                           std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
+static ConstraintWrapperPtr
+  createConstraintPerpendicular(ConstraintPtr theConstraint,
+                                const GroupID& theGroupID,
+                                std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+                                std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
+static ConstraintWrapperPtr
+  createConstraintEqual(ConstraintPtr theConstraint,
+                        const GroupID& theGroupID,
+                        const SketchSolver_ConstraintType& theType,
+                        std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+                        std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2,
+                        std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theIntermed);
+static ConstraintWrapperPtr
+  createConstraintTangent(ConstraintPtr theConstraint,
+                          const GroupID& theGroupID,
+                          const SketchSolver_ConstraintType& theType,
+                          std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+                          std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
+
+
+
+/// \brief Set flags for angle constraint
+static void adjustAngle(ConstraintWrapperPtr theConstraint);
+/// \brief Update mirror points
+static void adjustMirror(ConstraintWrapperPtr theConstraint);
+/// \brief Update positions of rotated features
+static void adjustMultiRotation(ConstraintWrapperPtr theConstraint);
+/// \brief Update positions of translated features
+static void adjustMultiTranslation(ConstraintWrapperPtr theConstraint);
+
+/// \brief Transform points to be symmetric regarding to the mirror line
+static void makeMirrorPoints(EntityWrapperPtr theOriginal,
+                             EntityWrapperPtr theMirrored,
+                             EntityWrapperPtr theMirrorLine);
+
+
+
+// Initialization of constraint builder self pointer
+BuilderPtr PlaneGCSSolver_Builder::mySelf = PlaneGCSSolver_Builder::getInstance();
+
+BuilderPtr PlaneGCSSolver_Builder::getInstance()
+{
+  if (!mySelf) {
+    mySelf = BuilderPtr(new PlaneGCSSolver_Builder);
+    SketchSolver_Manager::instance()->setBuilder(mySelf);
+  }
+  return mySelf;
+}
+
+StoragePtr PlaneGCSSolver_Builder::createStorage(const GroupID& theGroup) const
+{
+  return StoragePtr(new PlaneGCSSolver_Storage(theGroup));
+}
+
+SolverPtr PlaneGCSSolver_Builder::createSolver() const
+{
+  return SolverPtr(new PlaneGCSSolver_Solver);
+}
+
+
+std::list<ConstraintWrapperPtr> PlaneGCSSolver_Builder::createConstraint(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    const EntityID& theSketchID,
+    const SketchSolver_ConstraintType& theType,
+    const double& theValue,
+    const EntityWrapperPtr& thePoint1,
+    const EntityWrapperPtr& thePoint2,
+    const EntityWrapperPtr& theEntity1,
+    const EntityWrapperPtr& theEntity2) const
+{
+  ConstraintWrapperPtr aResult;
+  ParameterWrapperPtr anIntermediate;
+  switch (theType) {
+  case CONSTRAINT_PT_PT_COINCIDENT:
+    aResult = createConstraintCoincidence(theConstraint, theGroupID,
+                  GCS_POINT_WRAPPER(thePoint1), GCS_POINT_WRAPPER(thePoint2));
+    break;
+  case CONSTRAINT_PT_ON_LINE:
+  case CONSTRAINT_PT_ON_CIRCLE:
+    aResult = createConstraintPointOnEntity(theConstraint, theGroupID, theType,
+                  GCS_POINT_WRAPPER(thePoint1), GCS_ENTITY_WRAPPER(theEntity1));
+    break;
+  case CONSTRAINT_PT_PT_DISTANCE:
+    aResult = createConstraintDistancePointPoint(theConstraint, theGroupID,
+                  GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)),
+                  GCS_POINT_WRAPPER(thePoint1), GCS_POINT_WRAPPER(thePoint2));
+    break;
+  case CONSTRAINT_PT_LINE_DISTANCE:
+    aResult = createConstraintDistancePointLine(theConstraint, theGroupID,
+                  GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)),
+                  GCS_POINT_WRAPPER(thePoint1), GCS_ENTITY_WRAPPER(theEntity1));
+    break;
+  case CONSTRAINT_RADIUS:
+    aResult = createConstraintRadius(theConstraint, theGroupID,
+                  GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)),
+                  GCS_ENTITY_WRAPPER(theEntity1));
+    break;
+  case CONSTRAINT_ANGLE:
+    aResult = createConstraintAngle(theConstraint, theGroupID,
+                  GCS_PARAMETER_WRAPPER(createParamAngle(GID_OUTOFGROUP, theValue)),
+                  GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
+    break;
+  case CONSTRAINT_FIXED:
+    break;
+  case CONSTRAINT_HORIZONTAL:
+  case CONSTRAINT_VERTICAL:
+    aResult = createConstraintHorizVert(theConstraint, theGroupID, theType,
+                  GCS_ENTITY_WRAPPER(theEntity1));
+    break;
+  case CONSTRAINT_PARALLEL:
+    aResult = createConstraintParallel(theConstraint, theGroupID,
+                  GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
+    break;
+  case CONSTRAINT_PERPENDICULAR:
+    aResult = createConstraintPerpendicular(theConstraint, theGroupID,
+                  GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
+    break;
+  case CONSTRAINT_EQUAL_LINES:
+    anIntermediate = createParameter(theGroupID);
+  case CONSTRAINT_EQUAL_LINE_ARC:
+  case CONSTRAINT_EQUAL_RADIUS:
+    aResult = createConstraintEqual(theConstraint, theGroupID, theType,
+                  GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2),
+                  GCS_PARAMETER_WRAPPER(anIntermediate));
+    break;
+  case CONSTRAINT_TANGENT_ARC_LINE:
+  case CONSTRAINT_TANGENT_ARC_ARC:
+    aResult = createConstraintTangent(theConstraint, theGroupID, theType,
+                  GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
+    break;
+  case CONSTRAINT_MULTI_TRANSLATION:
+  case CONSTRAINT_MULTI_ROTATION:
+    break;
+  case CONSTRAINT_SYMMETRIC:
+    return createMirror(theConstraint, theGroupID, theSketchID,
+                        thePoint1, thePoint2, theEntity1);
+  default:
+    break;
+  }
+
+  if (!aResult)
+    return std::list<ConstraintWrapperPtr>();
+  adjustConstraint(aResult);
+  return std::list<ConstraintWrapperPtr>(1, aResult);
+}
+
+std::list<ConstraintWrapperPtr> PlaneGCSSolver_Builder::createConstraint(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    const EntityID& theSketchID,
+    const SketchSolver_ConstraintType& theType,
+    const double& theValue,
+    const EntityWrapperPtr& thePoint1,
+    const EntityWrapperPtr& thePoint2,
+    const std::list<EntityWrapperPtr>& theTrsfEnt) const
+{
+  ParameterWrapperPtr anAngleParam;
+  if (theType == CONSTRAINT_MULTI_ROTATION)
+    anAngleParam = createParamAngle(theGroupID, theValue);
+  else if (theType != CONSTRAINT_MULTI_TRANSLATION)
+    return std::list<ConstraintWrapperPtr>();
+
+  std::list<EntityWrapperPtr> aConstrAttrList = theTrsfEnt;
+  if (thePoint2)
+    aConstrAttrList.push_front(thePoint2);
+  aConstrAttrList.push_front(thePoint1);
+
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
+      new PlaneGCSSolver_ConstraintWrapper(theConstraint, std::list<GCSConstraintPtr>(), theType));
+  aResult->setGroup(theGroupID);
+  aResult->setEntities(aConstrAttrList);
+  if (anAngleParam)
+    aResult->setValueParameter(anAngleParam);
+  return std::list<ConstraintWrapperPtr>(1, aResult);
+}
+
+
+std::list<ConstraintWrapperPtr> PlaneGCSSolver_Builder::createMirror(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    const EntityID& theSketchID,
+    const EntityWrapperPtr& theEntity1,
+    const EntityWrapperPtr& theEntity2,
+    const EntityWrapperPtr& theMirrorLine) const
+{
+  std::list<ConstraintWrapperPtr> aResult;
+  std::list<EntityWrapperPtr> aConstrAttrList;
+  if (theEntity1->type() == ENTITY_POINT) {
+    if (theEntity2->group() == theGroupID) // theEntity2 is not fixed
+      makeMirrorPoints(theEntity1, theEntity2, theMirrorLine);
+
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint1 = 
+        std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity1);
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint2 = 
+        std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity2);
+
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> aMirrorLine = 
+        std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theMirrorLine);
+    std::shared_ptr<GCS::Line> aLine =
+        std::dynamic_pointer_cast<GCS::Line>(aMirrorLine->entity());
+
+    std::list<GCSConstraintPtr> aConstrList;
+    aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintPerpendicular(
+        *(aPoint1->point()), *(aPoint2->point()), aLine->p1, aLine->p2)));
+    aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintMidpointOnLine(
+        *(aPoint1->point()), *(aPoint2->point()), aLine->p1, aLine->p2)));
+
+    ConstraintWrapperPtr aSubResult(new PlaneGCSSolver_ConstraintWrapper(
+        theConstraint, aConstrList, CONSTRAINT_SYMMETRIC));
+    aSubResult->setGroup(theGroupID);
+    std::list<EntityWrapperPtr> aSubs(1, theEntity1);
+    aSubs.push_back(theEntity2);
+    aSubs.push_back(theMirrorLine);
+    aSubResult->setEntities(aSubs);
+    aResult.push_back(aSubResult);
+  }
+  else if (theEntity1->type() == ENTITY_LINE) {
+    const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
+    const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
+    std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
+    std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
+    for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) {
+      std::list<ConstraintWrapperPtr> aMrrList =
+          createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
+      aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
+    }
+  }
+  else if (theEntity1->type() == ENTITY_CIRCLE) {
+    const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
+    std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
+    for (; anIt1 != aPoints1.end(); ++anIt1)
+      if ((*anIt1)->type() == ENTITY_POINT)
+        break;
+    const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
+    std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
+    for (; anIt2 != aPoints2.end(); ++anIt2)
+      if ((*anIt2)->type() == ENTITY_POINT)
+        break;
+
+    std::list<ConstraintWrapperPtr> aMrrList =
+        createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
+    aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
+
+    // Additional constraint for equal radii
+    aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS,
+        0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2);
+    aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
+  }
+  else if (theEntity1->type() == ENTITY_ARC) {
+    // Do not allow mirrored arc recalculate its position until coordinated of all points recalculated
+    FeaturePtr aMirrArc = theEntity2->baseFeature();
+    aMirrArc->data()->blockSendAttributeUpdated(true);
+
+    // Make mirror for center and start point of original arc
+    std::list<ConstraintWrapperPtr> aMrrList;
+    std::list<EntityWrapperPtr>::const_iterator anIt1 = theEntity1->subEntities().begin();
+    std::list<EntityWrapperPtr>::const_iterator anIt2 = theEntity2->subEntities().begin();
+    aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
+    aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
+
+    ++anIt1;
+    ++anIt2; ++anIt2;
+    aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
+    aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
+
+    // make symmetric last point of original arc and first point of mirrored arc without additional constraint
+    ++anIt1;
+    --anIt2;
+    makeMirrorPoints(*anIt1, *anIt2, theMirrorLine);
+
+    // Additionally, make equal radii...
+    aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS,
+        0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2);
+    aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
+    // ... and make parametric length of arcs the same
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> anArcEnt1 = 
+        std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theEntity1);
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> anArcEnt2 = 
+        std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theEntity2);
+    std::shared_ptr<GCS::Arc> anArc1 = std::dynamic_pointer_cast<GCS::Arc>(anArcEnt1->entity());
+    std::shared_ptr<GCS::Arc> anArc2 = std::dynamic_pointer_cast<GCS::Arc>(anArcEnt2->entity());
+    std::shared_ptr<PlaneGCSSolver_ParameterWrapper> anIntermed =
+        std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(
+        createParameter(theGroupID, *(anArc1->endAngle) - *(anArc1->startAngle)));
+    // By the way, recalculate start and end angles of mirrored arc
+    std::shared_ptr<GeomAPI_Dir2d> anOX(new GeomAPI_Dir2d(1.0, 0.0));
+    std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(
+        *(anArc2->start.x) - *(anArc2->center.x), *(anArc2->start.y) - *(anArc2->center.y)));
+    std::shared_ptr<GeomAPI_Dir2d> aEndDir(new GeomAPI_Dir2d(
+        *(anArc2->end.x) - *(anArc2->center.x), *(anArc2->end.y) - *(anArc2->center.y)));
+    *anArc2->startAngle = anOX->angle(aStartDir);
+    *anArc2->endAngle = anOX->angle(aEndDir);
+
+    std::list<GCSConstraintPtr> aConstrList;
+    aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintDifference(
+        anArc1->endAngle, anArc1->startAngle, anIntermed->parameter())));
+    aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintDifference(
+        anArc2->endAngle, anArc2->startAngle, anIntermed->parameter())));
+
+    std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aSubResult(
+        new PlaneGCSSolver_ConstraintWrapper(theConstraint, aConstrList, CONSTRAINT_SYMMETRIC));
+    aSubResult->setGroup(theGroupID);
+    std::list<EntityWrapperPtr> aSubs(1, theEntity1);
+    aSubs.push_back(theEntity2);
+    aSubs.push_back(theMirrorLine);
+    aSubResult->setEntities(aSubs);
+    aSubResult->setValueParameter(anIntermed);
+    aResult.push_back(aSubResult);
+
+    // Restore event sending
+    aMirrArc->data()->blockSendAttributeUpdated(false);
+  }
+  return aResult;
+}
+
+void PlaneGCSSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const
+{
+  SketchSolver_ConstraintType aType = theConstraint->type();
+  // Update flags and parameters in constraints
+  if (aType == CONSTRAINT_ANGLE)
+    adjustAngle(theConstraint);
+////  else if (aType == CONSTRAINT_SYMMETRIC)
+////    adjustMirror(theConstraint);
+  else if (aType == CONSTRAINT_MULTI_ROTATION)
+    adjustMultiRotation(theConstraint);
+  else if (aType == CONSTRAINT_MULTI_TRANSLATION)
+    adjustMultiTranslation(theConstraint);
+}
+
+EntityWrapperPtr PlaneGCSSolver_Builder::createFeature(
+    FeaturePtr theFeature,
+    const std::list<EntityWrapperPtr>& theAttributes,
+    const GroupID& theGroupID,
+    const EntityID& /*theSketchID*/) const
+{
+  static EntityWrapperPtr aDummy;
+  if (!theFeature->data()->isValid())
+    return aDummy;
+
+  // Sketch
+  CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
+  if (aSketch)
+    return createSketchEntity(aSketch, theGroupID);
+
+  // SketchPlugin features
+  std::shared_ptr<SketchPlugin_Feature> aFeature =
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
+  if (!aFeature)
+    return aDummy;
+
+  // Verify the feature by its kind
+  const std::string& aFeatureKind = aFeature->getKind();
+  // Line
+  if (aFeatureKind == SketchPlugin_Line::ID())
+    return createLine(theFeature, theAttributes, theGroupID);
+  // Circle
+  else if (aFeatureKind == SketchPlugin_Circle::ID())
+    return createCircle(theFeature, theAttributes, theGroupID);
+  // Arc
+  else if (aFeatureKind == SketchPlugin_Arc::ID())
+    return createArc(theFeature, theAttributes, theGroupID);
+  // 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 = theFeature->attribute(SketchPlugin_Point::COORD_ID());
+    if (!aPoint->isInitialized())
+      return aDummy;
+    EntityWrapperPtr aSub = createAttribute(aPoint, theGroupID);
+    if (!aSub)
+      return aDummy;
+
+    GCSPointPtr aSubEnt =
+        std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(aSub)->point();
+    EntityWrapperPtr aNewEntity(new PlaneGCSSolver_EntityWrapper(theFeature));
+    aNewEntity->setSubEntities(std::list<EntityWrapperPtr>(1, aSub));
+    return aNewEntity;
+  }
+
+  // wrong entity
+  return aDummy;
+}
+
+EntityWrapperPtr PlaneGCSSolver_Builder::createAttribute(
+    AttributePtr theAttribute,
+    const GroupID& theGroupID,
+    const EntityID& theSketchID) const
+{
+  AttributePtr anAttribute = theAttribute;
+  AttributeRefAttrPtr aRefAttr =
+      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
+  if (aRefAttr) {
+    if (aRefAttr->isObject()) {
+      // do not create features here
+      return EntityWrapperPtr();
+    } else
+      anAttribute = aRefAttr->attr();
+  }
+
+  std::list<ParameterWrapperPtr> aParameters;
+  EntityWrapperPtr aResult;
+
+  // Point in 2D
+  std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+  if (aPoint2D) {
+    aParameters.push_back(::createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty()));
+    aParameters.push_back(::createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty()));
+    GCSPointPtr aGCSPoint(new GCS::Point);
+    aGCSPoint->x = std::dynamic_pointer_cast<
+      PlaneGCSSolver_ParameterWrapper>(aParameters.front())->parameter();
+    aGCSPoint->y = std::dynamic_pointer_cast<
+      PlaneGCSSolver_ParameterWrapper>(aParameters.back())->parameter();
+    // Create entity (parameters are not filled)
+    aResult = EntityWrapperPtr(new PlaneGCSSolver_PointWrapper(theAttribute, aGCSPoint));
+  } else {
+    // Scalar value (used for the distance entities)
+    AttributeDoublePtr aScalar =
+      std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+    if (aScalar)
+      return createScalar(theGroupID, aScalar);
+  }
+
+  if (!aResult) {
+    // unknown attribute type
+    return EntityWrapperPtr();
+  }
+
+  aResult->setGroup(theGroupID);
+  aResult->setParameters(aParameters);
+  return aResult;
+}
+
+ParameterWrapperPtr PlaneGCSSolver_Builder::createParameter(
+    const GroupID& theGroupID, double theValue) const
+{
+  return ::createParameter(theGroupID, theValue);
+}
+
+
+EntityWrapperPtr PlaneGCSSolver_Builder::createSketchEntity(
+    CompositeFeaturePtr theSketch,
+    const GroupID& theGroupID) const
+{
+  DataPtr aSketchData = theSketch->data();
+  if (!aSketchData || !aSketchData->isValid())
+    return EntityWrapperPtr(); // the sketch is incorrect
+
+  // Create dummy wrapper representing workplane
+  std::shared_ptr<PlaneGCSSolver_EntityWrapper> aSketchEnt(
+      new PlaneGCSSolver_EntityWrapper(FeaturePtr(theSketch)));
+  aSketchEnt->setGroup(theGroupID);
+  aSketchEnt->setId(EID_SKETCH);
+  return aSketchEnt;
+}
+
+
+
+////EntityWrapperPtr PlaneGCSSolver_Builder::createNormal(
+////    AttributePtr theNormal,
+////    AttributePtr theDirX,
+////    const GroupID& theGroupID) const
+////{
+////  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 || !aNorm ||
+////      (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) || 
+////      !aNorm->isInitialized())
+////    return EntityWrapperPtr();
+////  // 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
+////  std::list<ParameterWrapperPtr> aParameters;
+////  for (int i = 0; i < 4; i++)
+////    aParameters.push_back(createParameter(theGroupID, aNormCoord[i]));
+////
+////  // Create a normal with empty parameters
+////  Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+////      SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+////  EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt));
+////  aNormal->setParameters(aParameters);
+////  return aNormal;
+////}
+
+
+
+
+
+// ================   Auxiliary functions   ==========================
+ParameterWrapperPtr createParameter(
+    const GroupID& theGroup, const double theValue, const bool theExpr)
+{
+  double* aParam = new double(theValue);
+  ParameterWrapperPtr aWrapper(new PlaneGCSSolver_ParameterWrapper(aParam));
+  aWrapper->setGroup(theGroup);
+  aWrapper->setIsParametric(theExpr);
+  return aWrapper;
+}
+
+ParameterWrapperPtr createParamAngle(const GroupID& theGroup, const double& theValue)
+{
+  double* aParam = new double(theValue);
+  ParameterWrapperPtr aWrapper(new PlaneGCSSolver_AngleWrapper(aParam));
+  aWrapper->setGroup(theGroup);
+  return aWrapper;
+}
+
+std::shared_ptr<PlaneGCSSolver_ScalarWrapper> createScalar(
+    const GroupID& theGroupID,
+    AttributeDoublePtr theDoubleAttr)
+{
+  ParameterWrapperPtr aParam = createParameter(theGroupID, theDoubleAttr ? theDoubleAttr->value() : 0.0);
+  return std::shared_ptr<PlaneGCSSolver_ScalarWrapper>(
+      new PlaneGCSSolver_ScalarWrapper(theDoubleAttr, aParam));
+}
+
+EntityWrapperPtr createLine(FeaturePtr theFeature,
+                            const std::list<EntityWrapperPtr>& theAttributes,
+                            const GroupID& theGroupID)
+{
+  EntityWrapperPtr aNewEntity;
+  std::list<EntityWrapperPtr> aSubs;
+
+  AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID());
+  AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID());
+  if (!aStart->isInitialized() || !aEnd->isInitialized())
+    return aNewEntity;
+
+  std::shared_ptr<PlaneGCSSolver_PointWrapper> aStartEnt, aEndEnt;
+  std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
+  for (; anIt != theAttributes.end(); ++anIt) {
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> aWrapper = 
+        std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(*anIt);
+    if (!aWrapper)
+      continue;
+    if (aWrapper->isBase(aStart))
+      aStartEnt = aWrapper;
+    else if (aWrapper->isBase(aEnd))
+      aEndEnt = aWrapper;
+  }
+  if (!aStartEnt || !aEndEnt)
+    return aNewEntity;
+
+  aSubs.push_back(aStartEnt);
+  aSubs.push_back(aEndEnt);
+
+  std::shared_ptr<GCS::Line> aLine(new GCS::Line);
+  aLine->p1 = *(aStartEnt->point());
+  aLine->p2 = *(aEndEnt->point());
+
+  aNewEntity = EntityWrapperPtr(new PlaneGCSSolver_EntityWrapper(theFeature, aLine));
+  aNewEntity->setGroup(theGroupID); // sub-entities should not change their groups, therefore they are added later
+  aNewEntity->setSubEntities(aSubs);
+  return aNewEntity;
+}
+
+EntityWrapperPtr createCircle(FeaturePtr theFeature,
+                              const std::list<EntityWrapperPtr>& theAttributes,
+                              const GroupID& theGroupID)
+{
+  EntityWrapperPtr aNewEntity;
+  std::list<EntityWrapperPtr> aSubs;
+
+  AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID());
+  AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
+  if (!aCenter->isInitialized() || !aRadius->isInitialized())
+    return aNewEntity;
+
+  std::shared_ptr<PlaneGCSSolver_PointWrapper> aCenterEnt;
+  std::shared_ptr<PlaneGCSSolver_ScalarWrapper> aRadiusEnt;
+  std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
+  for (; anIt != theAttributes.end(); ++anIt) {
+    if ((*anIt)->isBase(aCenter))
+      aCenterEnt = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(*anIt);
+    else if ((*anIt)->isBase(aRadius))
+      aRadiusEnt = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*anIt);
+  }
+  if (!aCenterEnt || !aRadiusEnt)
+    return aNewEntity;
+
+  aSubs.push_back(aCenterEnt);
+  aSubs.push_back(aRadiusEnt);
+
+  std::shared_ptr<GCS::Circle> aCircle(new GCS::Circle);
+  aCircle->center = *(aCenterEnt->point());
+  aCircle->rad = aRadiusEnt->scalar();
+
+  aNewEntity = EntityWrapperPtr(new PlaneGCSSolver_EntityWrapper(theFeature, aCircle));
+  aNewEntity->setGroup(theGroupID); // sub-entities should not change their groups, therefore they are added later
+  aNewEntity->setSubEntities(aSubs);
+  return aNewEntity;
+}
+
+EntityWrapperPtr createArc(FeaturePtr theFeature,
+                           const std::list<EntityWrapperPtr>& theAttributes,
+                           const GroupID& theGroupID)
+{
+  EntityWrapperPtr aNewEntity;
+  std::list<EntityWrapperPtr> aSubs;
+
+  AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID());
+  AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID());
+  AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID());
+  if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
+    return aNewEntity;
+
+  std::shared_ptr<PlaneGCSSolver_PointWrapper> aCenterEnt, aStartEnt, aEndEnt;
+  std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
+  for (; anIt != theAttributes.end(); ++anIt) {
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> aWrapper = 
+        std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(*anIt);
+    if (!aWrapper)
+      continue;
+    if (aWrapper->isBase(aCenter))
+      aCenterEnt = aWrapper;
+    else if (aWrapper->isBase(aStart))
+      aStartEnt = aWrapper;
+    else if (aWrapper->isBase(aEnd))
+      aEndEnt = aWrapper;
+  }
+  if (!aCenterEnt || !aStartEnt || !aEndEnt)
+    return aNewEntity;
+
+  std::shared_ptr<PlaneGCSSolver_ScalarWrapper> aStartAng, aEndAng, aRadius;
+  aStartAng = createScalar(theGroupID);
+  aEndAng   = createScalar(theGroupID);
+  aRadius   = createScalar(theGroupID);
+
+  aSubs.push_back(aCenterEnt);
+  aSubs.push_back(aStartEnt);
+  aSubs.push_back(aEndEnt);
+  aSubs.push_back(aStartAng);
+  aSubs.push_back(aEndAng);
+  aSubs.push_back(aRadius);
+
+  std::shared_ptr<GCS::Arc> anArc(new GCS::Arc);
+  anArc->center     = *(aCenterEnt->point());
+  anArc->start      = *(aStartEnt->point());
+  anArc->end        = *(aEndEnt->point());
+  anArc->startAngle = aStartAng->scalar();
+  anArc->endAngle   = aEndAng->scalar();
+  anArc->rad        = aRadius->scalar();
+
+  aNewEntity = EntityWrapperPtr(new PlaneGCSSolver_EntityWrapper(theFeature, anArc));
+  aNewEntity->setGroup(theGroupID); // sub-entities should not change their groups, therefore they are added later
+  aNewEntity->setSubEntities(aSubs);
+  return aNewEntity;
+}
+
+
+
+ConstraintWrapperPtr createConstraintCoincidence(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2)
+{
+  // Create equality constraint for corresponding attributes of the points
+  std::list<GCSConstraintPtr> aConstrList;
+  std::list<ParameterWrapperPtr>::const_iterator anIt1 = thePoint1->parameters().begin();
+  std::list<ParameterWrapperPtr>::const_iterator anIt2 = thePoint2->parameters().begin();
+  for (; anIt1 != thePoint1->parameters().end(); ++anIt1, ++anIt2) {
+    if (*anIt1 == *anIt2)
+      continue; // points use same parameters, no need additional constraints
+    std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam1 =
+        std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(*anIt1);
+    std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam2 =
+        std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(*anIt2);
+    aConstrList.push_back(
+        GCSConstraintPtr(new GCS::ConstraintEqual(aParam1->parameter(), aParam2->parameter())));
+  }
+
+  ConstraintWrapperPtr aResult(new PlaneGCSSolver_ConstraintWrapper(
+      theConstraint, aConstrList, CONSTRAINT_PT_PT_COINCIDENT));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, thePoint1);
+  aSubs.push_back(thePoint2);
+  aResult->setEntities(aSubs);
+  return aResult;
+}
+
+ConstraintWrapperPtr createConstraintPointOnEntity(
+    ConstraintPtr theConstraint, 
+    const GroupID& theGroupID,
+    const SketchSolver_ConstraintType& theType,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity)
+{
+  GCSConstraintPtr aNewConstr;
+
+  switch (theEntity->type()) {
+  case ENTITY_LINE: {
+    std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity->entity());
+    aNewConstr = GCSConstraintPtr(new GCS::ConstraintPointOnLine(*(thePoint->point()), *aLine));
+    break;
+    }
+  case ENTITY_ARC:
+  case ENTITY_CIRCLE: {
+    std::shared_ptr<GCS::Circle> aCirc = std::dynamic_pointer_cast<GCS::Circle>(theEntity->entity());
+    aNewConstr = GCSConstraintPtr(
+        new GCS::ConstraintP2PDistance(*(thePoint->point()), aCirc->center, aCirc->rad));
+    break;
+    }
+  default:
+    return ConstraintWrapperPtr();
+  }
+
+  ConstraintWrapperPtr aResult(new PlaneGCSSolver_ConstraintWrapper(
+      theConstraint, aNewConstr, theType));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, thePoint);
+  aSubs.push_back(theEntity);
+  aResult->setEntities(aSubs);
+  return aResult;
+}
+
+ConstraintWrapperPtr createConstraintDistancePointPoint(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2)
+{
+  GCSConstraintPtr aNewConstr(new GCS::ConstraintP2PDistance(
+      *(thePoint1->point()), *(thePoint2->point()), theValue->parameter()));
+
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
+      new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_PT_PT_DISTANCE));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, thePoint1);
+  aSubs.push_back(thePoint2);
+  aResult->setEntities(aSubs);
+  aResult->setValueParameter(theValue);
+  return aResult;
+}
+
+ConstraintWrapperPtr createConstraintDistancePointLine(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity)
+{
+  std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity->entity());
+  GCSConstraintPtr aNewConstr(new GCS::ConstraintP2LDistance(
+      *(thePoint->point()), *(aLine), theValue->parameter()));
+
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
+      new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_PT_LINE_DISTANCE));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, thePoint);
+  aSubs.push_back(theEntity);
+  aResult->setEntities(aSubs);
+  aResult->setValueParameter(theValue);
+  return aResult;
+}
+
+ConstraintWrapperPtr createConstraintRadius(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity)
+{
+  std::shared_ptr<GCS::Circle> aCircle = std::dynamic_pointer_cast<GCS::Circle>(theEntity->entity());
+  GCSConstraintPtr aNewConstr(new GCS::ConstraintEqual(aCircle->rad, theValue->parameter()));
+
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
+      new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_RADIUS));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, theEntity);
+  aResult->setEntities(aSubs);
+  aResult->setValueParameter(theValue);
+  return aResult;
+}
+
+ConstraintWrapperPtr createConstraintAngle(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theValue,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
+{
+  std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
+  std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
+  GCSConstraintPtr aNewConstr(new GCS::ConstraintL2LAngle(
+      *(aLine1), *(aLine2), theValue->parameter()));
+
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
+      new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_ANGLE));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, theEntity1);
+  aSubs.push_back(theEntity2);
+  aResult->setEntities(aSubs);
+  aResult->setValueParameter(theValue);
+  return aResult;
+}
+
+ConstraintWrapperPtr createConstraintHorizVert(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    const SketchSolver_ConstraintType& theType,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity)
+{
+  std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity->entity());
+  GCSConstraintPtr aNewConstr;
+  if (theType == CONSTRAINT_HORIZONTAL)
+    aNewConstr = GCSConstraintPtr(new GCS::ConstraintEqual(aLine->p1.y, aLine->p2.y));
+  else
+    aNewConstr = GCSConstraintPtr(new GCS::ConstraintEqual(aLine->p1.x, aLine->p2.x));
+
+  ConstraintWrapperPtr aResult(new PlaneGCSSolver_ConstraintWrapper(
+      theConstraint, aNewConstr, theType));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, theEntity);
+  aResult->setEntities(aSubs);
+  return aResult;
+}
+
+ConstraintWrapperPtr createConstraintParallel(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
+{
+  std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
+  std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
+  GCSConstraintPtr aNewConstr(new GCS::ConstraintParallel(*(aLine1), *(aLine2)));
+
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
+      new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_PARALLEL));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, theEntity1);
+  aSubs.push_back(theEntity2);
+  aResult->setEntities(aSubs);
+  return aResult;
+}
+
+ConstraintWrapperPtr createConstraintPerpendicular(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
+{
+  std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
+  std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
+  GCSConstraintPtr aNewConstr(new GCS::ConstraintPerpendicular(*(aLine1), *(aLine2)));
+
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
+      new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_PERPENDICULAR));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, theEntity1);
+  aSubs.push_back(theEntity2);
+  aResult->setEntities(aSubs);
+  return aResult;
+}
+
+ConstraintWrapperPtr createConstraintEqual(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    const SketchSolver_ConstraintType& theType,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2,
+    std::shared_ptr<PlaneGCSSolver_ParameterWrapper> theIntermed)
+{
+  if (theType == CONSTRAINT_EQUAL_LINE_ARC)
+    return ConstraintWrapperPtr(); // line-arc equivalence is not supported yet
+
+  std::list<GCSConstraintPtr> aConstrList;
+  if (theType == CONSTRAINT_EQUAL_LINES) {
+    std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
+    std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
+
+    aConstrList.push_back(GCSConstraintPtr(
+        new GCS::ConstraintP2PDistance(aLine1->p1, aLine1->p2, theIntermed->parameter())));
+    aConstrList.push_back(GCSConstraintPtr(
+        new GCS::ConstraintP2PDistance(aLine2->p1, aLine2->p2, theIntermed->parameter())));
+  } else {
+    std::shared_ptr<GCS::Circle> aCirc1 =
+        std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
+    std::shared_ptr<GCS::Circle> aCirc2 =
+        std::dynamic_pointer_cast<GCS::Circle>(theEntity2->entity());
+
+    aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(aCirc1->rad, aCirc2->rad)));
+  }
+
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
+      new PlaneGCSSolver_ConstraintWrapper(theConstraint, aConstrList, theType));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, theEntity1);
+  aSubs.push_back(theEntity2);
+  aResult->setEntities(aSubs);
+  if (theIntermed)
+    aResult->setValueParameter(theIntermed);
+  return aResult;
+}
+
+ConstraintWrapperPtr createConstraintTangent(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    const SketchSolver_ConstraintType& theType,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
+{
+  GCSConstraintPtr aNewConstr;
+  if (theType == CONSTRAINT_TANGENT_ARC_LINE) {
+    std::shared_ptr<GCS::Circle> aCirc = std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
+    std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
+
+    aNewConstr = GCSConstraintPtr(new GCS::ConstraintP2LDistance(aCirc->center, *aLine, aCirc->rad));
+  } else {
+    std::shared_ptr<GCS::Circle> aCirc1 = std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
+    std::shared_ptr<GCS::Circle> aCirc2 = std::dynamic_pointer_cast<GCS::Circle>(theEntity2->entity());
+
+    double aDX = *(aCirc1->center.x) - *(aCirc2->center.x);
+    double aDY = *(aCirc1->center.y) - *(aCirc2->center.y);
+    double aDist = sqrt(aDX * aDX + aDY * aDY);
+    aNewConstr = GCSConstraintPtr(new GCS::ConstraintTangentCircumf(aCirc1->center, aCirc2->center,
+        aCirc1->rad, aCirc2->rad, (aDist < *(aCirc1->rad) || aDist < *(aCirc2->rad))));
+  }
+
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
+      new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, theType));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, theEntity1);
+  aSubs.push_back(theEntity2);
+  aResult->setEntities(aSubs);
+  return aResult;
+}
+
+
+
+
+
+void adjustAngle(ConstraintWrapperPtr theConstraint)
+{
+  BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
+
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
+    std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
+
+  std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
+  const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
+  std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
+  for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
+    const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
+    std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
+    for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt)
+      aPoints[i][j] = aBuilder->point(*aLPIt);
+  }
+
+  std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
+    std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
+    std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
+  };
+  std::shared_ptr<GeomAPI_Pnt2d> anIntersection = aLine[0]->intersect(aLine[1]);
+  if (!anIntersection)
+    return;
+  double aDist[2][2];
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      aDist[i][j] = anIntersection->distance(aPoints[i][j]);
+      if (fabs(aDist[i][j]) <= tolerance)
+        aDist[i][j] = 0.0;
+    }
+    if (aDist[i][0] > tolerance && aDist[i][1] > tolerance &&
+        aDist[i][0] + aDist[i][1] < aPoints[i][0]->distance(aPoints[i][1]) + 2.0 * tolerance) {
+      // the intersection point is an inner point of the line,
+      // we change the sign of distance till start point to calculate correct coordinates
+      // after rotation
+      aDist[i][0] *= -1.0;
+    }
+  }
+  std::shared_ptr<GeomAPI_Dir2d> aDir[2];
+  for (int i = 0; i < 2; i++) {
+    if (aDist[i][1] > fabs(aDist[i][0]))
+      aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
+          aPoints[i][1]->xy()->decreased(anIntersection->xy())));
+    else {
+      aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
+          aPoints[i][0]->xy()->decreased(anIntersection->xy())));
+      // main direction is opposite => change signs
+      if (aDist[i][0] < 0.0) {
+        aDist[i][0] *= -1.0;
+        aDist[i][1] *= -1.0;
+      }
+    }
+  }
+
+  bool isChange = false;
+  for (int i = 0; i < 2; i++)
+    if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
+      isChange = !isChange;
+  if (isChange)
+    aConstraint->setValue(180.0 - aConstraint->value());
+}
+
+////void adjustMirror(ConstraintWrapperPtr theConstraint)
+////{
+////  std::vector<EntityWrapperPtr> aPoints;
+////  EntityWrapperPtr aMirrorLine;
+////
+////  const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
+////  std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
+////  for (; anIt != aSubs.end(); ++anIt) {
+////    if ((*anIt)->type() == ENTITY_POINT)
+////      aPoints.push_back(*anIt);
+////    else if ((*anIt)->type() == ENTITY_LINE)
+////      aMirrorLine = *anIt;
+////  }
+////
+////  makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
+////}
+
+void makeMirrorPoints(EntityWrapperPtr theOriginal,
+                      EntityWrapperPtr theMirrored,
+                      EntityWrapperPtr theMirrorLine)
+{
+  BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
+
+  std::shared_ptr<GeomAPI_Lin2d> aMirrorLine = aBuilder->line(theMirrorLine);
+  std::shared_ptr<GeomAPI_Dir2d> aMLDir = aMirrorLine->direction();
+  // orthogonal direction
+  aMLDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x()));
+
+  std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(theOriginal);
+  std::shared_ptr<GeomAPI_XY> aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy());
+  double aDist = aVec->dot(aMLDir->xy());
+  aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist));
+  double aCoord[2] = {aVec->x(), aVec->y()};
+  std::list<ParameterWrapperPtr>::const_iterator aMIt = theMirrored->parameters().begin();
+  for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i)
+    (*aMIt)->setValue(aCoord[i]);
+
+  // update corresponding attribute
+  AttributePtr anAttr = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theMirrored)->baseAttribute();
+  if (anAttr) {
+    std::shared_ptr<GeomDataAPI_Point2D> aMirroredPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
+    aMirroredPnt->setValue(aCoord[0], aCoord[1]);
+  }
+}
+
+static void rotate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
+                   std::shared_ptr<GeomAPI_Pnt2d> theCenter,
+                   double theSin, double theCos)
+{
+  if (theSource->type() == ENTITY_POINT) {
+    // Rotate single point
+    std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theSource->baseAttribute());
+    std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theDest->baseAttribute());
+    if (aSrcAttr && aDstAttr) {
+      std::shared_ptr<GeomAPI_XY> aVec = aSrcAttr->pnt()->xy()->decreased(theCenter->xy());
+      double aNewX = aVec->x() * theCos - aVec->y() * theSin;
+      double aNewY = aVec->x() * theSin + aVec->y() * theCos;
+      aDstAttr->setValue(theCenter->x() + aNewX, theCenter->y() + aNewY);
+    }
+    return;
+  }
+
+  FeaturePtr aDestFeature = theDest->baseFeature();
+  if (aDestFeature)
+    aDestFeature->data()->blockSendAttributeUpdated(true);
+
+  // Rotate points of the feature
+  const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
+  const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
+  std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
+  for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
+       aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
+    rotate(*aSrcIt, *aDstIt, theCenter, theSin, theCos);
+
+  if (aDestFeature)
+    aDestFeature->data()->blockSendAttributeUpdated(false);
+}
+
+static void translate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
+                      std::shared_ptr<GeomAPI_XY> theDelta)
+{
+  if (theSource->type() == ENTITY_POINT) {
+    // Translate single point
+    std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theSource->baseAttribute());
+    std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theDest->baseAttribute());
+    if (aSrcAttr && aDstAttr)
+      aDstAttr->setValue(aSrcAttr->x() + theDelta->x(), aSrcAttr->y() + theDelta->y());
+    return;
+  }
+
+  FeaturePtr aDestFeature = theDest->baseFeature();
+  if (aDestFeature)
+    aDestFeature->data()->blockSendAttributeUpdated(true);
+
+  // Translate points of the feature
+  const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
+  const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
+  std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
+  for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
+       aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
+    translate(*aSrcIt, *aDstIt, theDelta);
+
+  if (aDestFeature)
+    aDestFeature->data()->blockSendAttributeUpdated(false);
+}
+
+void adjustMultiRotation(ConstraintWrapperPtr theConstraint)
+{
+  BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
+
+  double anAngleRad = theConstraint->value() * PI / 180.0;
+  double aSin = sin(anAngleRad);
+  double aCos = cos(anAngleRad);
+
+  const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
+  std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+
+  std::shared_ptr<GeomAPI_Pnt2d> aCenter = aBuilder->point(*aSIt++);
+  std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
+  for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
+    rotate(*aPrevIt, *aSIt, aCenter, aSin, aCos);
+}
+
+void adjustMultiTranslation(ConstraintWrapperPtr theConstraint)
+{
+  BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
+
+  const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
+  std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+
+  std::shared_ptr<GeomAPI_Pnt2d> aStartPnt = aBuilder->point(*aSIt++);
+  std::shared_ptr<GeomAPI_Pnt2d> aEndPnt = aBuilder->point(*aSIt++);
+  std::shared_ptr<GeomAPI_XY> aDelta = aEndPnt->xy()->decreased(aStartPnt->xy());
+
+  std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
+  for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
+    translate(*aPrevIt, *aSIt, aDelta);
+}
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h
new file mode 100644 (file)
index 0000000..ef511e3
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_Builder.h
+// Created: 14 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef PlaneGCSSolver_Builder_H_
+#define PlaneGCSSolver_Builder_H_
+
+#include <PlaneGCSSolver_Defs.h>
+
+#include <SketchSolver_Builder.h>
+#include <SketchSolver_Constraint.h>
+
+#include <SketchPlugin_Constraint.h>
+
+#include <ModelAPI_CompositeFeature.h>
+
+/** \class   PlaneGCSSolver_Builder
+ *  \ingroup Plugins
+ *  \brief   Create bridges between SketchPlugin constraints and PlaneGCS constraints
+ */
+class PlaneGCSSolver_Builder : public SketchSolver_Builder
+{
+private:
+  /// Default constructor
+  PlaneGCSSolver_Builder() {}
+
+public:
+  /// \brief Returns single instance of builder
+  static BuilderPtr getInstance();
+
+  /// \brief Creates a storage specific for used solver
+  virtual StoragePtr createStorage(const GroupID& theGroup) const;
+  /// \brief Creates specific solver
+  virtual SolverPtr createSolver() const;
+
+  /// \brief Creates new constraint(s) using given parameters
+  /// \param theConstraint [in]  original constraint
+  /// \param theGroupID    [in]  group the constraint belongs to
+  /// \param theSketchID   [in]  sketch the constraint belongs to
+  /// \param theType       [in]  type of constraint
+  /// \param theValue      [in]  numeric characteristic of constraint (e.g. distance or radius) if applicable
+  /// \param theEntity1    [in]  first attribute of constraint
+  /// \param theEntity2    [in]  second attribute of constraint
+  /// \param theEntity3    [in]  third attribute of constraint
+  /// \param theEntity4    [in]  fourth attribute of constraint
+  /// \return Created list of wrappers of constraints applicable for specific solver.
+  ///         Most of constraint types lead to single constraint, but there are some kind of
+  ///         constraints (e.g. mirror), which may produce couple of constraints.
+  virtual std::list<ConstraintWrapperPtr>
+    createConstraint(ConstraintPtr theConstraint,
+                     const GroupID& theGroupID,
+                     const EntityID& theSketchID,
+                     const SketchSolver_ConstraintType& theType,
+                     const double& theValue,
+                     const EntityWrapperPtr& theEntity1,
+                     const EntityWrapperPtr& theEntity2 = EntityWrapperPtr(),
+                     const EntityWrapperPtr& theEntity3 = EntityWrapperPtr(),
+                     const EntityWrapperPtr& theEntity4 = EntityWrapperPtr()) const;
+
+  /// \brief Creates new multi-translation or multi-rotation constraint
+  /// \param theConstraint [in]  original constraint
+  /// \param theGroupID    [in]  group the constraint belongs to
+  /// \param theSketchID   [in]  sketch the constraint belongs to
+  /// \param theType       [in]  type of constraint
+  /// \param theValue      [in]  numeric characteristic of constraint (angle for multi-rotation) if applicable
+  /// \param thePoint1     [in]  center for multi-rotation or start point for multi-translation
+  /// \param thePoint2     [in]  end point for multi-translation (empty for multi-rotation)
+  /// \param theTrsfEnt    [in]  list of transformed entities
+  virtual std::list<ConstraintWrapperPtr>
+    createConstraint(ConstraintPtr theConstraint,
+                     const GroupID& theGroupID,
+                     const EntityID& theSketchID,
+                     const SketchSolver_ConstraintType& theType,
+                     const double& theValue,
+                     const EntityWrapperPtr& thePoint1,
+                     const EntityWrapperPtr& thePoint2,
+                     const std::list<EntityWrapperPtr>& theTrsfEnt) const;
+
+  /// \brief Update flags for several kinds of constraints
+  virtual void adjustConstraint(ConstraintWrapperPtr theConstraint) const;
+
+  /// \brief Creates a feature using list of already created attributes
+  /// \param theFeature    [in]  feature to create
+  /// \param theAttributes [in]  attributes of the feature
+  /// \param theGroupID    [in]  group the feature belongs to
+  /// \param theSketchID   [in]  sketch the feature belongs to
+  /// \return Created wrapper of the feature applicable for specific solver
+  virtual EntityWrapperPtr createFeature(FeaturePtr theFeature,
+                                         const std::list<EntityWrapperPtr>& theAttributes,
+                                         const GroupID& theGroupID,
+                                         const EntityID& theSketchID = EID_UNKNOWN) const;
+
+  /// \brief Creates an attribute
+  /// \param theAttribute [in]  attribute to create
+  /// \param theGroup     [in]  group the attribute belongs to
+  /// \param theSketchID  [in]  sketch the attribute belongs to
+  /// \return Created wrapper of the attribute applicable for specific solver
+  virtual EntityWrapperPtr createAttribute(AttributePtr theAttribute,
+                                           const GroupID& theGroup,
+                                           const EntityID& theSketchID = EID_UNKNOWN) const;
+
+  /// \brief Create a parameter
+  /// \param theGroupID [in]  group the parameter belongs to
+  /// \param theValue   [in]  value of the parameter
+  /// \return Created wrapper for parameter
+  ParameterWrapperPtr createParameter(const GroupID& theGroupID, double theValue = 0.0) const;
+
+private:
+  /// \brief Create necessary constraints to make two object symmetric relatively a given line
+  std::list<ConstraintWrapperPtr> createMirror(ConstraintPtr theConstraint,
+                                               const GroupID& theGroupID,
+                                               const EntityID& theSketchID,
+                                               const EntityWrapperPtr& theEntity1,
+                                               const EntityWrapperPtr& theEntity2,
+                                               const EntityWrapperPtr& theMirrorLine) const;
+
+  /// \brief Converts sketch parameters to the entity applicable for the solver.
+  /// \param theSketch  [in]  the element to be converted
+  /// \param theGroupID [in]  group where the sketch should be created
+  /// \return Entity respective the sketch or empty pointer, it the sketch has incorrect attributes
+  EntityWrapperPtr createSketchEntity(CompositeFeaturePtr theSketch,
+                                      const GroupID& theGroupID) const;
+
+////  /// \brief Converts two axes of sketch's trihedron to the normal entity
+////  /// \param theNormal  [in]  direction of the normal of the sketch
+////  /// \param theDirX    [in]  direction of the X axis of the sketch
+////  /// \param theGroupID [in]  group, the normal belongs to
+////  /// \return Created entity or empty pointer, if there are incorrect attributes
+////  EntityWrapperPtr createNormal(AttributePtr theNormal,
+////                                AttributePtr theDirX,
+////                                const GroupID& theGroupID) const;
+
+private:
+  static BuilderPtr mySelf;
+};
+
+#endif
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.cpp
new file mode 100644 (file)
index 0000000..db932e8
--- /dev/null
@@ -0,0 +1,128 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_ConstraintWrapper.cpp
+// Created: 14 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#include <PlaneGCSSolver_ConstraintWrapper.h>
+
+#include <math.h>
+
+PlaneGCSSolver_ConstraintWrapper::PlaneGCSSolver_ConstraintWrapper(
+    const ConstraintPtr& theOriginal,
+    const GCSConstraintPtr& theConstraint,
+    const SketchSolver_ConstraintType& theType)
+  : myGCSConstraints(1, theConstraint),
+    myType(theType),
+    myID(CID_UNKNOWN)
+{
+  myBaseConstraint = theOriginal;
+  myValue = 0.0;
+}
+
+PlaneGCSSolver_ConstraintWrapper::PlaneGCSSolver_ConstraintWrapper(
+    const ConstraintPtr& theOriginal,
+    const std::list<GCSConstraintPtr>& theConstraints,
+    const SketchSolver_ConstraintType& theType)
+  : myGCSConstraints(theConstraints),
+    myType(theType),
+    myID(CID_UNKNOWN)
+{
+  myBaseConstraint = theOriginal;
+  myValue = 0.0;
+}
+
+void PlaneGCSSolver_ConstraintWrapper::setValueParameter(const ParameterWrapperPtr& theValue)
+{
+  myValueParam = theValue;
+  myValue = myValueParam->value();
+}
+
+void PlaneGCSSolver_ConstraintWrapper::setValue(const double& theValue)
+{
+  myValue = theValue;
+  myValueParam->setValue(theValue);
+}
+
+
+void PlaneGCSSolver_ConstraintWrapper::setGroup(const GroupID& theGroup)
+{
+  myGroup = theGroup;
+  std::list<EntityWrapperPtr>::iterator aSubsIt = myConstrained.begin();
+  for (; aSubsIt != myConstrained.end(); ++aSubsIt)
+    (*aSubsIt)->setGroup(theGroup);
+}
+
+bool PlaneGCSSolver_ConstraintWrapper::isUsed(FeaturePtr theFeature) const
+{
+  std::list<EntityWrapperPtr>::const_iterator anIt = myConstrained.begin();
+  for (; anIt != myConstrained.end(); ++anIt)
+    if ((*anIt)->isUsed(theFeature))
+      return true;
+  return false;
+}
+
+bool PlaneGCSSolver_ConstraintWrapper::isUsed(AttributePtr theAttribute) const
+{
+  std::list<EntityWrapperPtr>::const_iterator anIt = myConstrained.begin();
+  for (; anIt != myConstrained.end(); ++anIt)
+    if ((*anIt)->isUsed(theAttribute))
+      return true;
+  return false;
+}
+
+bool PlaneGCSSolver_ConstraintWrapper::isEqual(const ConstraintWrapperPtr& theOther)
+{
+  if (type() != theOther->type())
+    return false;
+////  const Slvs_Constraint anOtherConstraint = 
+////    std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theOther)->constraint();
+////  if (mySlvsConstraint.type != anOtherConstraint.type)
+////    return false;
+////
+////  // Verify SolveSpace entities. If they are equal, no need additional checking of parameters.
+////  if (mySlvsConstraint.group   == anOtherConstraint.group   &&
+////      mySlvsConstraint.ptA     == anOtherConstraint.ptA     &&
+////      mySlvsConstraint.ptB     == anOtherConstraint.ptB     &&
+////      mySlvsConstraint.entityA == anOtherConstraint.entityA &&
+////      mySlvsConstraint.entityB == anOtherConstraint.entityB &&
+////      mySlvsConstraint.entityC == anOtherConstraint.entityC &&
+////      mySlvsConstraint.entityD == anOtherConstraint.entityD &&
+////      fabs(mySlvsConstraint.valA - anOtherConstraint.valA) < tolerance) {
+////    return true;
+////  }
+
+  // Verify equality of values
+  if (fabs(myValue - theOther->value()) > tolerance)
+    return false;
+
+  // Verify equality of entities
+  const std::list<EntityWrapperPtr>& anOtherSubs = theOther->entities();
+  if (myConstrained.size() != anOtherSubs.size())
+    return false;
+  std::list<EntityWrapperPtr>::const_iterator aMySubsIt = myConstrained.begin();
+  std::list<EntityWrapperPtr>::const_iterator anOtherSubsIt = anOtherSubs.begin();
+  for (; aMySubsIt != myConstrained.end(); ++aMySubsIt, ++anOtherSubsIt)
+    if (!(*aMySubsIt)->isEqual(*anOtherSubsIt))
+      return false;
+  return true;
+}
+
+bool PlaneGCSSolver_ConstraintWrapper::update(const ConstraintWrapperPtr& theOther)
+{
+  bool isUpdated = false;
+
+  std::list<EntityWrapperPtr> aMySubs = entities();
+  std::list<EntityWrapperPtr> anOtherSubs = theOther->entities();
+  std::list<EntityWrapperPtr>::const_iterator aMySubsIt = aMySubs.begin();
+  std::list<EntityWrapperPtr>::const_iterator anOtherSubsIt = anOtherSubs.begin();
+  for (; aMySubsIt != aMySubs.end() && anOtherSubsIt != anOtherSubs.end();
+       ++aMySubsIt, ++anOtherSubsIt)
+     isUpdated = (*aMySubsIt)->update(*anOtherSubsIt) || isUpdated;
+
+  if (fabs(value() - theOther->value()) > tolerance) {
+    myValue = theOther->value();
+    isUpdated = true;
+  }
+  return isUpdated;
+}
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.h
new file mode 100644 (file)
index 0000000..74341b5
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_ConstraintWrapper.h
+// Created: 14 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef PlaneGCSSolver_ConstraintWrapper_H_
+#define PlaneGCSSolver_ConstraintWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <PlaneGCSSolver_Solver.h>
+#include <SketchSolver_IConstraintWrapper.h>
+
+
+/**
+ *  Wrapper providing operations with SovleSpace constraints.
+ */
+class PlaneGCSSolver_ConstraintWrapper : public SketchSolver_IConstraintWrapper
+{
+public:
+  PlaneGCSSolver_ConstraintWrapper(const ConstraintPtr& theOriginal,
+                                   const GCSConstraintPtr& theConstraint,
+                                   const SketchSolver_ConstraintType& theType);
+  PlaneGCSSolver_ConstraintWrapper(const ConstraintPtr& theOriginal,
+                                   const std::list<GCSConstraintPtr>& theConstraints,
+                                   const SketchSolver_ConstraintType& theType);
+
+  /// \brief Return list of constraints
+  const std::list<GCSConstraintPtr>& constraints() const
+  { return myGCSConstraints; }
+////  /// \brief Return SolveSpace constraint to change
+////  GCSConstraintPtr& changeConstraint()
+////  { return myGCSConstraint; }
+
+  /// \brief Return ID of current entity
+  virtual ConstraintID id() const
+  { return myID; }
+
+  /// \brief Change group for the constraint
+  virtual void setGroup(const GroupID& theGroup);
+  /// \brief Return identifier of the group the constraint belongs to
+  virtual GroupID group() const
+  { return myGroup; }
+
+  /// \brief Return type of current entity
+  virtual SketchSolver_ConstraintType type() const
+  { return myType; }
+
+  /// \brief Assign numeric parameter of constraint
+  virtual void setValue(const double& theValue);
+
+  /// \brief Change parameter representing the value of constraint
+  void setValueParameter(const ParameterWrapperPtr& theValue);
+  /// \brief Return parametric representation of constraint value
+  const ParameterWrapperPtr& valueParameter() const
+  { return myValueParam; }
+
+  /// \brief Verify the feature is used in the constraint
+  virtual bool isUsed(FeaturePtr theFeature) const;
+  /// \brief Verify the attribute is used in the constraint
+  virtual bool isUsed(AttributePtr theAttribute) const;
+
+  /// \brief Compare current constraint with other
+  virtual bool isEqual(const ConstraintWrapperPtr& theOther);
+
+  /// \brief Update values of parameters of this constraint by the parameters of given one
+  /// \return \c true if some parameters change their values
+  virtual bool update(const std::shared_ptr<SketchSolver_IConstraintWrapper>& theOther);
+
+private:
+  ConstraintID     myID;
+  GroupID          myGroup;
+  SketchSolver_ConstraintType myType;
+  ParameterWrapperPtr myValueParam;
+  std::list<GCSConstraintPtr> myGCSConstraints;
+};
+
+#endif
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Defs.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Defs.h
new file mode 100644 (file)
index 0000000..5a22cde
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_Defs.h
+// Created: 14 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef PlaneGCSSolver_Defs_H_
+#define PlaneGCSSolver_Defs_H_
+
+#include <SketchSolver.h>
+
+#include <Constraints.h>
+#include <Geo.h>
+#include <memory>
+
+typedef std::shared_ptr<GCS::Point>       GCSPointPtr;
+typedef std::shared_ptr<GCS::Curve>       GCSCurvePtr;
+typedef std::shared_ptr<GCS::Constraint>  GCSConstraintPtr;
+
+#endif
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.cpp
new file mode 100644 (file)
index 0000000..45bee0e
--- /dev/null
@@ -0,0 +1,118 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_EntityWrapper.cpp
+// Created: 14 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#include <PlaneGCSSolver_EntityWrapper.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Sketch.h>
+
+PlaneGCSSolver_EntityWrapper::PlaneGCSSolver_EntityWrapper(
+    const FeaturePtr theFeature, const GCSCurvePtr theEntity)
+  : myEntity(theEntity),
+    myID(EID_UNKNOWN)
+{
+  myBaseFeature = theFeature;
+
+  std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(myEntity);
+  if (aLine) myType = ENTITY_LINE;
+  else {
+    std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(myEntity);
+    if (anArc) myType = ENTITY_ARC;
+    else {
+      std::shared_ptr<GCS::Circle> aCircle = std::dynamic_pointer_cast<GCS::Circle>(myEntity);
+      if (aCircle) myType = ENTITY_CIRCLE;
+    }
+  }
+
+  // empty entity, probably this is a SketchPlugin_Point or SketchPlugin_Sketch
+  if (theFeature->getKind() == SketchPlugin_Point::ID())
+    myType = ENTITY_POINT;
+  else if (theFeature->getKind() == SketchPlugin_Sketch::ID())
+    myType = ENTITY_SKETCH;
+}
+
+void PlaneGCSSolver_EntityWrapper::setGroup(const GroupID& theGroup)
+{
+  myGroup = theGroup;
+  std::list<EntityWrapperPtr>::iterator aSubsIt = mySubEntities.begin();
+  for (; aSubsIt != mySubEntities.end(); ++aSubsIt)
+    (*aSubsIt)->setGroup(theGroup);
+  std::list<ParameterWrapperPtr>::iterator aPIt = myParameters.begin();
+  for (; aPIt != myParameters.end(); ++aPIt)
+    (*aPIt)->setGroup(theGroup);
+}
+
+bool PlaneGCSSolver_EntityWrapper::isUsed(FeaturePtr theFeature) const
+{
+  if (isBase(theFeature))
+    return true;
+
+  std::list<EntityWrapperPtr>::const_iterator anIt = mySubEntities.begin();
+  for (; anIt != mySubEntities.end(); ++anIt)
+    if ((*anIt)->isUsed(theFeature))
+      return true;
+  return false;
+}
+
+bool PlaneGCSSolver_EntityWrapper::isUsed(AttributePtr theAttribute) const
+{
+  if (isBase(theAttribute))
+    return true;
+
+  std::list<EntityWrapperPtr>::const_iterator anIt = mySubEntities.begin();
+  for (; anIt != mySubEntities.end(); ++anIt)
+    if ((*anIt)->isUsed(theAttribute))
+      return true;
+  return false;
+}
+
+bool PlaneGCSSolver_EntityWrapper::isEqual(const EntityWrapperPtr& theOther)
+{
+  if (type() != theOther->type())
+    return false;
+
+  // Verify Equality of sub-entities
+  const std::list<EntityWrapperPtr>& anOtherSubs = theOther->subEntities();
+  if (mySubEntities.size() != anOtherSubs.size())
+    return false;
+  std::list<EntityWrapperPtr>::const_iterator aMySubsIt = mySubEntities.begin();
+  std::list<EntityWrapperPtr>::const_iterator anOtherSubsIt = anOtherSubs.begin();
+  for (; aMySubsIt != mySubEntities.end(); ++aMySubsIt, ++anOtherSubsIt)
+    if (!(*aMySubsIt)->isEqual(*anOtherSubsIt))
+      return false;
+
+  // Verify equality of parameters
+  const std::list<ParameterWrapperPtr>& anOtherParams = theOther->parameters();
+  if (myParameters.size() != anOtherParams.size())
+    return false;
+  std::list<ParameterWrapperPtr>::const_iterator aMyIt = myParameters.begin();
+  std::list<ParameterWrapperPtr>::const_iterator anOtherIt = anOtherParams.begin();
+  for (; aMyIt != myParameters.end(); ++aMyIt, ++anOtherIt)
+    if (!(*aMyIt)->isEqual(*anOtherIt))
+      return false;
+  return true;
+}
+
+bool PlaneGCSSolver_EntityWrapper::update(const EntityWrapperPtr& theOther)
+{
+  bool isUpdated = false;
+
+  std::list<EntityWrapperPtr> aMySubs = subEntities();
+  std::list<EntityWrapperPtr> anOtherSubs = theOther->subEntities();
+  std::list<EntityWrapperPtr>::const_iterator aMySubsIt = aMySubs.begin();
+  std::list<EntityWrapperPtr>::const_iterator anOtherSubsIt = anOtherSubs.begin();
+  for (; aMySubsIt != aMySubs.end() && anOtherSubsIt != anOtherSubs.end();
+       ++aMySubsIt, ++anOtherSubsIt)
+     isUpdated = (*aMySubsIt)->update(*anOtherSubsIt) || isUpdated;
+
+  std::list<ParameterWrapperPtr> aMyParams = parameters();
+  std::list<ParameterWrapperPtr> anOtherParams = theOther->parameters();
+  std::list<ParameterWrapperPtr>::const_iterator aMyParIt = aMyParams.begin();
+  std::list<ParameterWrapperPtr>::const_iterator anOtherParIt = anOtherParams.begin();
+  for (; aMyParIt != aMyParams.end() && anOtherParIt != anOtherParams.end();
+      ++aMyParIt, ++anOtherParIt)
+    isUpdated = (*aMyParIt)->update(*anOtherParIt);
+  return isUpdated;
+}
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.h
new file mode 100644 (file)
index 0000000..cb107b7
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_EntityWrapper.h
+// Created: 14 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef PlaneGCSSolver_EntityWrapper_H_
+#define PlaneGCSSolver_EntityWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <SketchSolver_IEntityWrapper.h>
+
+/**
+ *  Wrapper providing operations with PlaneGCS entities.
+ */
+class PlaneGCSSolver_EntityWrapper : public SketchSolver_IEntityWrapper
+{
+public:
+  PlaneGCSSolver_EntityWrapper(const FeaturePtr theFeature, const GCSCurvePtr theEntity = GCSCurvePtr());
+
+  /// \brief Return PlaneGCS geometric entity
+  const GCSCurvePtr& entity() const
+  { return myEntity; }
+  /// \brief Return PlaneGCS geometric entity to change
+  GCSCurvePtr& changeEntity()
+  { return myEntity; }
+
+  /// \brief Return ID of current entity
+  virtual EntityID id() const
+  { return myID; }
+  /// \brief Change ID of the entity
+  void setId(EntityID theID)
+  { myID = theID; }
+
+  /// \brief Change group for the entity
+  virtual void setGroup(const GroupID& theGroup);
+  /// \brief Return identifier of the group the entity belongs to
+  virtual GroupID group() const
+  { return myGroup; }
+
+  /// \brief Return type of current entity
+  virtual SketchSolver_EntityType type() const
+  { return myType; }
+
+  /// \brief Verify the feature is used in the entity
+  virtual bool isUsed(FeaturePtr theFeature) const;
+  /// \brief Verify the attribute is used in the entity
+  virtual bool isUsed(AttributePtr theAttribute) const;
+
+  /// \brief Compare current entity with other
+  virtual bool isEqual(const EntityWrapperPtr& theOther);
+
+  /// \brief Update values of parameters of this entity by the parameters of given one
+  /// \return \c true if some parameters change their values
+  virtual bool update(const EntityWrapperPtr& theOther);
+
+private:
+  EntityID    myID;
+  GroupID     myGroup;
+  SketchSolver_EntityType myType;
+  GCSCurvePtr myEntity;
+};
+
+#endif
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.cpp
new file mode 100644 (file)
index 0000000..0a271ff
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_ParameterWrapper.cpp
+// Created: 14 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#include <PlaneGCSSolver_ParameterWrapper.h>
+
+#include <math.h>
+
+PlaneGCSSolver_ParameterWrapper::PlaneGCSSolver_ParameterWrapper(double *const theParam)
+  : myValue(theParam),
+    myProcessing(false)
+{
+}
+
+PlaneGCSSolver_ParameterWrapper::~PlaneGCSSolver_ParameterWrapper()
+{
+  delete myValue;
+}
+
+void PlaneGCSSolver_ParameterWrapper::setValue(double theValue)
+{
+  *(myValue) = theValue;
+}
+
+double PlaneGCSSolver_ParameterWrapper::value() const
+{
+  return *(myValue);
+}
+
+bool PlaneGCSSolver_ParameterWrapper::isEqual(const ParameterWrapperPtr& theOther)
+{
+  return fabs(value() - theOther->value()) < tolerance;
+}
+
+bool PlaneGCSSolver_ParameterWrapper::update(const ParameterWrapperPtr& theOther)
+{
+  if (fabs(value() - theOther->value()) < tolerance)
+    return false;
+  setValue(theOther->value());
+  myIsParametric = theOther->isParametric();
+  return true;
+}
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.h
new file mode 100644 (file)
index 0000000..757728e
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_ParameterWrapper.h
+// Created: 14 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef PlaneGCSSolver_ParameterWrapper_H_
+#define PlaneGCSSolver_ParameterWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <SketchSolver_IParameterWrapper.h>
+
+/**
+ *  Wrapper providing operations with parameters in PlaneGCS.
+ */
+class PlaneGCSSolver_ParameterWrapper : public SketchSolver_IParameterWrapper
+{
+public:
+  PlaneGCSSolver_ParameterWrapper(double *const theParam);
+  virtual ~PlaneGCSSolver_ParameterWrapper();
+
+  /// \brief Return ID of current parameter
+  virtual ParameterID id() const
+  { return myID; }
+
+  double* parameter() const
+  { return myValue; }
+
+  /// \brief Change group for the parameter
+  virtual void setGroup(const GroupID& theGroup)
+  { myGroup = theGroup; }
+
+  /// \brief Return identifier of the group the parameter belongs to
+  virtual GroupID group() const
+  { return myGroup; }
+
+  /// \brief Change value of parameter
+  virtual void setValue(double theValue);
+  /// \brief Return value of parameter
+  virtual double value() const;
+
+  /// \brief Compare current parameter with other
+  virtual bool isEqual(const ParameterWrapperPtr& theOther);
+
+  /// \brief Update value of parameter by the given one
+  /// \return \c true if the value of parameter is changed
+  virtual bool update(const ParameterWrapperPtr& theOther);
+
+  /// \brief Shows the parameter is added to full list of parameters
+  bool isProcessed() const
+  { return myProcessing; }
+  /// \brief Set the flag that parameter is under processing
+  void setProcessed(bool isProc)
+  { myProcessing = isProc; }
+
+protected:
+  ParameterID myID;
+  GroupID     myGroup;
+  double*     myValue;
+  bool        myProcessing; ///< identify that the parameter is already in the list of parameters
+};
+
+#endif
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.cpp
new file mode 100644 (file)
index 0000000..a1e66e5
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_PointWrapper.cpp
+// Created: 14 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#include <PlaneGCSSolver_PointWrapper.h>
+
+PlaneGCSSolver_PointWrapper::PlaneGCSSolver_PointWrapper(
+    const AttributePtr theAttribute, const GCSPointPtr thePoint)
+  : myPoint(thePoint),
+    myID(EID_UNKNOWN)
+{
+  myBaseAttribute = theAttribute;
+}
+
+void PlaneGCSSolver_PointWrapper::setGroup(const GroupID& theGroup)
+{
+  myGroup = theGroup;
+  std::list<EntityWrapperPtr>::iterator aSubsIt = mySubEntities.begin();
+  for (; aSubsIt != mySubEntities.end(); ++aSubsIt)
+    (*aSubsIt)->setGroup(theGroup);
+  std::list<ParameterWrapperPtr>::iterator aPIt = myParameters.begin();
+  for (; aPIt != myParameters.end(); ++aPIt)
+    (*aPIt)->setGroup(theGroup);
+}
+
+bool PlaneGCSSolver_PointWrapper::isUsed(AttributePtr theAttribute) const
+{
+  return isBase(theAttribute);
+}
+
+bool PlaneGCSSolver_PointWrapper::isEqual(const EntityWrapperPtr& theOther)
+{
+  if (type() != theOther->type())
+    return false;
+
+  // Verify equality of parameters
+  const std::list<ParameterWrapperPtr>& anOtherParams = theOther->parameters();
+  if (myParameters.size() != anOtherParams.size())
+    return false;
+  std::list<ParameterWrapperPtr>::const_iterator aMyIt = myParameters.begin();
+  std::list<ParameterWrapperPtr>::const_iterator anOtherIt = anOtherParams.begin();
+  for (; aMyIt != myParameters.end(); ++aMyIt, ++anOtherIt)
+    if (!(*aMyIt)->isEqual(*anOtherIt))
+      return false;
+  return true;
+}
+
+bool PlaneGCSSolver_PointWrapper::update(const EntityWrapperPtr& theOther)
+{
+  bool isUpdated = false;
+  std::list<ParameterWrapperPtr> aMyParams = parameters();
+  std::list<ParameterWrapperPtr> anOtherParams = theOther->parameters();
+  std::list<ParameterWrapperPtr>::const_iterator aMyParIt = aMyParams.begin();
+  std::list<ParameterWrapperPtr>::const_iterator anOtherParIt = anOtherParams.begin();
+  for (; aMyParIt != aMyParams.end() && anOtherParIt != anOtherParams.end();
+      ++aMyParIt, ++anOtherParIt)
+    isUpdated = (*aMyParIt)->update(*anOtherParIt);
+  return isUpdated;
+}
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.h
new file mode 100644 (file)
index 0000000..dc276d4
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_PointWrapper.h
+// Created: 16 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef PlaneGCSSolver_PointWrapper_H_
+#define PlaneGCSSolver_PointWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <SketchSolver_IEntityWrapper.h>
+
+/**
+ *  Wrapper providing operations with PlaneGCS points.
+ */
+class PlaneGCSSolver_PointWrapper : public SketchSolver_IEntityWrapper
+{
+public:
+  PlaneGCSSolver_PointWrapper(const AttributePtr theAttribute, const GCSPointPtr thePoint);
+
+  /// \brief Return PlaneGCS point
+  const GCSPointPtr& point() const
+  { return myPoint; }
+  /// \brief Return PlaneGCS point to change
+  GCSPointPtr& changeEntity()
+  { return myPoint; }
+
+  /// \brief Return ID of current entity
+  virtual EntityID id() const
+  { return myID; }
+  /// \brief Change ID of the entity
+  void setId(EntityID theID)
+  { myID = theID; }
+
+  /// \brief Change group for the entity
+  virtual void setGroup(const GroupID& theGroup);
+  /// \brief Return identifier of the group the entity belongs to
+  virtual GroupID group() const
+  { return myGroup; }
+
+  /// \brief Return type of current entity
+  virtual SketchSolver_EntityType type() const
+  { return ENTITY_POINT; }
+
+  /// \brief Verify the feature is used in the entity
+  virtual bool isUsed(FeaturePtr theFeature) const
+  { return false; }
+  /// \brief Verify the attribute is used in the entity
+  virtual bool isUsed(AttributePtr theAttribute) const;
+
+  /// \brief Compare current entity with other
+  virtual bool isEqual(const EntityWrapperPtr& theOther);
+
+  /// \brief Update values of parameters of this entity by the parameters of given one
+  /// \return \c true if some parameters change their values
+  virtual bool update(const EntityWrapperPtr& theOther);
+
+private:
+  EntityID    myID;
+  GroupID     myGroup;
+  GCSPointPtr myPoint;
+};
+
+#endif
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.cpp
new file mode 100644 (file)
index 0000000..2811988
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_ScalarWrapper.cpp
+// Created: 14 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_ParameterWrapper.h>
+
+
+
+PlaneGCSSolver_ScalarWrapper::PlaneGCSSolver_ScalarWrapper(
+    const AttributePtr              theAttribute,
+    const ParameterWrapperPtr       theParam)
+{
+  myBaseAttribute = theAttribute;
+  myParameters.assign(1, theParam);
+}
+
+void PlaneGCSSolver_ScalarWrapper::setGroup(const GroupID& theGroup)
+{
+  myGroup = theGroup;
+  myParameters.front()->setGroup(theGroup);
+}
+
+double* PlaneGCSSolver_ScalarWrapper::scalar() const
+{
+  std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam =
+      std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(myParameters.front());
+  return aParam->parameter();
+}
+
+bool PlaneGCSSolver_ScalarWrapper::isUsed(AttributePtr theAttribute) const
+{
+  return isBase(theAttribute);
+}
+
+bool PlaneGCSSolver_ScalarWrapper::isEqual(const EntityWrapperPtr& theOther)
+{
+  if (type() != theOther->type())
+    return false;
+
+  // Verify equality of parameters
+  const std::list<ParameterWrapperPtr>& anOtherParams = theOther->parameters();
+  if (myParameters.size() != anOtherParams.size())
+    return false;
+  std::list<ParameterWrapperPtr>::const_iterator aMyIt = myParameters.begin();
+  std::list<ParameterWrapperPtr>::const_iterator anOtherIt = anOtherParams.begin();
+  for (; aMyIt != myParameters.end(); ++aMyIt, ++anOtherIt)
+    if (!(*aMyIt)->isEqual(*anOtherIt))
+      return false;
+  return true;
+}
+
+bool PlaneGCSSolver_ScalarWrapper::update(const EntityWrapperPtr& theOther)
+{
+  bool isUpdated = false;
+  std::list<ParameterWrapperPtr> aMyParams = parameters();
+  std::list<ParameterWrapperPtr> anOtherParams = theOther->parameters();
+  std::list<ParameterWrapperPtr>::const_iterator aMyParIt = aMyParams.begin();
+  std::list<ParameterWrapperPtr>::const_iterator anOtherParIt = anOtherParams.begin();
+  for (; aMyParIt != aMyParams.end() && anOtherParIt != anOtherParams.end();
+      ++aMyParIt, ++anOtherParIt)
+    isUpdated = (*aMyParIt)->update(*anOtherParIt);
+  return isUpdated;
+}
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.h
new file mode 100644 (file)
index 0000000..89e389d
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_ScalarWrapper.h
+// Created: 16 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef PlaneGCSSolver_ScalarWrapper_H_
+#define PlaneGCSSolver_ScalarWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <SketchSolver_IEntityWrapper.h>
+
+/**
+ *  Wrapper providing operations with PlaneGCS scalars.
+ */
+class PlaneGCSSolver_ScalarWrapper : public SketchSolver_IEntityWrapper
+{
+public:
+  PlaneGCSSolver_ScalarWrapper(const AttributePtr theAttribute, const ParameterWrapperPtr theParam);
+
+  /// \brief Return PlaneGCS parameter
+  double* scalar() const;
+
+  /// \brief Return ID of current entity
+  virtual EntityID id() const
+  { return myID; }
+  /// \brief Change ID of the entity
+  void setId(EntityID theID)
+  { myID = theID; }
+
+  /// \brief Change group for the entity
+  virtual void setGroup(const GroupID& theGroup);
+  /// \brief Return identifier of the group the entity belongs to
+  virtual GroupID group() const
+  { return myGroup; }
+
+  /// \brief Return type of current entity
+  virtual SketchSolver_EntityType type() const
+  { return ENTITY_SCALAR; }
+
+  /// \brief Verify the feature is used in the entity
+  virtual bool isUsed(FeaturePtr theFeature) const
+  { return false; }
+  /// \brief Verify the attribute is used in the entity
+  virtual bool isUsed(AttributePtr theAttribute) const;
+
+  /// \brief Compare current entity with other
+  virtual bool isEqual(const EntityWrapperPtr& theOther);
+
+  /// \brief Update values of parameters of this entity by the parameters of given one
+  /// \return \c true if some parameters change their values
+  virtual bool update(const EntityWrapperPtr& theOther);
+
+private:
+  EntityID                myID;
+  GroupID                 myGroup;
+};
+
+#endif
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp
new file mode 100644 (file)
index 0000000..71f6d87
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_Solver.cpp
+// Created: 14 Dec 2014
+// Author:  Artem ZHIDKOV
+
+#include "PlaneGCSSolver_Solver.h"
+#include <Events_LongOp.h>
+
+
+PlaneGCSSolver_Solver::~PlaneGCSSolver_Solver()
+{
+  clear();
+}
+
+void PlaneGCSSolver_Solver::clear()
+{
+  std::set<GCS::Constraint*>::const_iterator anIt = myConstraints.begin();
+  for (; anIt != myConstraints.end(); ++anIt)
+    myEquationSystem.removeConstraint(*anIt);
+  myConstraints.clear();
+  myParameters.clear();
+}
+
+void PlaneGCSSolver_Solver::addConstraint(GCSConstraintPtr theConstraint)
+{
+  GCS::Constraint* aConstraint = theConstraint.get();
+  if (myConstraints.find(aConstraint) != myConstraints.end())
+    return; // constraint already exists, no need to add it again
+
+  myEquationSystem.addConstraint(aConstraint);
+  myConstraints.insert(aConstraint);
+}
+
+void PlaneGCSSolver_Solver::removeConstraint(GCSConstraintPtr theConstraint)
+{
+  GCS::Constraint* aConstraint = theConstraint.get();
+  if (myConstraints.find(aConstraint) == myConstraints.end())
+    return; // no constraint, no need to remove it
+
+  myEquationSystem.removeConstraint(aConstraint);
+  myConstraints.erase(aConstraint);
+}
+
+SketchSolver_SolveStatus PlaneGCSSolver_Solver::solve()
+{
+  if (myConstraints.empty())
+    return STATUS_EMPTYSET;
+  if (myParameters.empty())
+    return STATUS_INCONSISTENT;
+
+////  myEquationSystem.calculateFaileds = myFindFaileds ? 1 : 0;
+
+  Events_LongOp::start(this);
+  GCS::SolveStatus aResult = (GCS::SolveStatus)myEquationSystem.solve(myParameters);
+  Events_LongOp::end(this);
+
+  SketchSolver_SolveStatus aStatus;
+  if (aResult == GCS::Success) {
+    myEquationSystem.applySolution();
+    aStatus = STATUS_OK;
+  } else {
+    myEquationSystem.undoSolution();
+    aStatus = STATUS_FAILED;
+  }
+  return aStatus;
+}
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h
new file mode 100644 (file)
index 0000000..605a977
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_Solver.h
+// Created: 14 Dec 2014
+// Author:  Artem ZHIDKOV
+
+#ifndef PlaneGCSSolver_Solver_H_
+#define PlaneGCSSolver_Solver_H_
+
+#include <SketchSolver_ISolver.h>
+#include <PlaneGCSSolver_Defs.h>
+
+////// Need to be defined before including SolveSpace to avoid additional dependences on Windows platform
+////#if defined(WIN32) && !defined(HAVE_C99_INTEGER_TYPES)
+////typedef unsigned int UINT32;
+////#else
+////#include <stdint.h>
+////#endif
+////#include <string.h>
+#include <GCS.h>
+
+////#include <vector>
+
+/**
+ * The main class that performs the high-level operations for connection to the PlaneGCS.
+ */
+class PlaneGCSSolver_Solver : public SketchSolver_ISolver
+{
+public:
+  PlaneGCSSolver_Solver() {}
+  ~PlaneGCSSolver_Solver();
+
+  /// \brief Clear system of equations
+  void clear();
+
+  /// \brief Add constraint to the system of equations
+  void addConstraint(GCSConstraintPtr theConstraint);
+
+  /// \brief Remove constraint from the system of equations
+  void removeConstraint(GCSConstraintPtr theConstraint);
+
+  /// \brief Initialize list of unknowns
+  void setParameters(const GCS::VEC_pD& theParams)
+  { myParameters = theParams; }
+
+  /** \brief Solve the set of equations
+   *  \return identifier whether solution succeeded
+   */
+  virtual SketchSolver_SolveStatus solve();
+
+private:
+  GCS::VEC_pD                myParameters;     ///< list of unknowns
+  std::set<GCS::Constraint*> myConstraints;    ///< list of constraints already processed by the system
+  GCS::System                myEquationSystem; ///< set of equations for solving in FreeGCS
+};
+
+#endif
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp
new file mode 100644 (file)
index 0000000..475fd7e
--- /dev/null
@@ -0,0 +1,1256 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_Storage.cpp
+// Created: 14 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#include <PlaneGCSSolver_Storage.h>
+#include <PlaneGCSSolver_Builder.h>
+#include <PlaneGCSSolver_Solver.h>
+#include <PlaneGCSSolver_ConstraintWrapper.h>
+#include <PlaneGCSSolver_EntityWrapper.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_ParameterWrapper.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+#include <GeomDataAPI_Point2D.h>
+////#include <ModelAPI_AttributeRefAttr.h>
+////#include <ModelAPI_Feature.h>
+////#include <ModelAPI_ResultConstruction.h>
+
+#include <SketchPlugin_Arc.h>
+////#include <SketchPlugin_Circle.h>
+////#include <SketchPlugin_Line.h>
+////#include <SketchPlugin_Point.h>
+////
+////#ifndef OBSOLETE
+////#include <SketchPlugin_ConstraintAngle.h>
+////#endif
+
+#include <cmath>
+
+////#ifdef OBSOLETE
+/////** \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);
+////#endif
+
+
+PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const GroupID& theGroup)
+  : SketchSolver_Storage(theGroup),
+    myEntityLastID(EID_SKETCH)
+{
+}
+
+void PlaneGCSSolver_Storage::addConstraint(
+    ConstraintPtr                   theConstraint,
+    std::list<ConstraintWrapperPtr> theSolverConstraints)
+{
+  SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraints);
+
+  // update point-point coincidence
+  if (!theSolverConstraints.empty() &&
+      theSolverConstraints.front()->type() == CONSTRAINT_PT_PT_COINCIDENT) {
+    std::list<ConstraintWrapperPtr>::iterator aCIt = theSolverConstraints.begin();
+    for (; aCIt != theSolverConstraints.end(); ++aCIt)
+      update(*aCIt);
+  }
+}
+
+
+bool PlaneGCSSolver_Storage::update(ConstraintWrapperPtr& theConstraint)
+{
+  bool isUpdated = false;
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
+      std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
+
+  // point-Line distance should be positive
+  if (aConstraint->type() == CONSTRAINT_PT_LINE_DISTANCE && aConstraint->value() < 0.0)
+    aConstraint->setValue(-aConstraint->value());
+
+  // make value of constraint unchangeable
+  ParameterWrapperPtr aValue = aConstraint->valueParameter();
+  if (aValue)
+    isUpdated = update(aValue) || isUpdated;
+
+  // update constrained entities
+  std::list<EntityWrapperPtr> anEntities = theConstraint->entities();
+  std::list<EntityWrapperPtr>::iterator anIt = anEntities.begin();
+  for (; anIt != anEntities.end(); ++anIt)
+    isUpdated = update(*anIt) || isUpdated;
+
+  return isUpdated;
+}
+
+/// \brief Update coordinates of the point or scalar using its base attribute
+static bool updateValues(EntityWrapperPtr& theEntity)
+{
+  bool isUpdated = false;
+  AttributePtr anAttr = theEntity->baseAttribute();
+  const std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
+
+  double aCoord[2];
+
+  std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
+  if (aPoint2D) {
+    aCoord[0] = aPoint2D->x();
+    aCoord[1] = aPoint2D->y();
+  } else {
+    AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttr);
+    if (aScalar)
+      aCoord[0] = aScalar->value();
+  }
+
+  std::list<ParameterWrapperPtr>::const_iterator anIt = aParams.begin();
+  for (int i = 0; anIt != aParams.end(); ++anIt, ++i)
+    if (fabs((*anIt)->value() - aCoord[i]) > tolerance) {
+      (*anIt)->setValue(aCoord[i]);
+      isUpdated = true;
+    }
+  return isUpdated;
+}
+
+bool PlaneGCSSolver_Storage::update(EntityWrapperPtr& theEntity)
+{
+  if (theEntity->type() == ENTITY_SKETCH)
+    return true; // sketch is not necessary for PlaneGCS, so it is always says true
+
+  bool isUpdated = false;
+
+  if (theEntity->baseAttribute()) {
+    isUpdated = updateValues(theEntity);
+    if (isUpdated)
+      setNeedToResolve(true);
+  }
+
+  // update parameters
+  std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
+  std::list<ParameterWrapperPtr>::iterator aPIt = aParams.begin();
+  for (; aPIt != aParams.end(); ++aPIt)
+    isUpdated = update(*aPIt) || isUpdated;
+
+  // update sub-entities
+  std::list<EntityWrapperPtr> aSubEntities = theEntity->subEntities();
+  std::list<EntityWrapperPtr>::iterator aSIt = aSubEntities.begin();
+  for (; aSIt != aSubEntities.end(); ++aSIt)
+    isUpdated = update(*aSIt) || isUpdated;
+
+  // additional constraints for the arc processing
+  if (theEntity->type() == ENTITY_ARC)
+    processArc(theEntity);
+
+  // Change entity's ID, if necessary
+  if (theEntity->id() == EID_UNKNOWN) {
+    if (theEntity->type() == ENTITY_POINT) {
+      std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
+          std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity);
+      aPoint->setId(++myEntityLastID);
+    } else if (theEntity->type() == ENTITY_SCALAR) {
+      std::shared_ptr<PlaneGCSSolver_ScalarWrapper> aScalar =
+          std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theEntity);
+      aScalar->setId(++myEntityLastID);
+    } else {
+      std::shared_ptr<PlaneGCSSolver_EntityWrapper> aGCSEnt =
+          std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theEntity);
+      aGCSEnt->setId(++myEntityLastID);
+    }
+  }
+  return isUpdated;
+}
+
+bool PlaneGCSSolver_Storage::update(ParameterWrapperPtr& theParameter)
+{
+  std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam =
+      std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(theParameter);
+  if (aParam->isProcessed())
+    return false;
+  if (theParameter->group() != myGroupID || theParameter->isParametric())
+    myConst.push_back(aParam->parameter());
+  else
+    myParameters.push_back(aParam->parameter());
+  aParam->setProcessed(true);
+  return true;
+}
+
+
+bool PlaneGCSSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
+{
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
+    std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
+
+  bool isFullyRemoved = true;
+  const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
+  std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+  for (; aSIt != aSubs.end(); ++ aSIt)
+    isFullyRemoved = remove(*aSIt) && isFullyRemoved;
+
+  if (aConstraint->valueParameter())
+    isFullyRemoved = remove(aConstraint->valueParameter()) && isFullyRemoved;
+  if (!isFullyRemoved &&
+     (!aConstraint->baseConstraint()->data() || !aConstraint->baseConstraint()->data()->isValid()))
+    isFullyRemoved = true;
+  if (isFullyRemoved) {
+    setNeedToResolve(true);
+    myRemovedConstraints.insert(myRemovedConstraints.end(),
+        aConstraint->constraints().begin(), aConstraint->constraints().end());
+  }
+  return isFullyRemoved;
+}
+
+bool PlaneGCSSolver_Storage::remove(EntityWrapperPtr theEntity)
+{
+  if ((theEntity->baseAttribute() && isUsed(theEntity->baseAttribute())) ||
+      (theEntity->baseFeature() && isUsed(theEntity->baseFeature())))
+    return false;
+
+  bool isFullyRemoved = SketchSolver_Storage::remove(theEntity);
+  if (isFullyRemoved && theEntity->id() == myEntityLastID)
+    --myEntityLastID;
+  return isFullyRemoved;
+}
+
+bool PlaneGCSSolver_Storage::remove(ParameterWrapperPtr theParameter)
+{
+  std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam =
+      std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(theParameter);
+  if (aParam->isProcessed()) {
+    double* aValPtr = aParam->parameter();
+    GCS::VEC_pD::iterator anIt =  myParameters.begin();
+    for (; anIt != myParameters.end(); ++anIt)
+      if (*anIt == aValPtr)
+        break;
+    if (anIt != myParameters.end()) {
+      myParameters.erase(anIt);
+      setNeedToResolve(true);
+    }
+    else {
+      for (anIt = myConst.begin(); anIt != myConst.end(); ++anIt)
+        if (*anIt == aValPtr)
+          break;
+      if (anIt != myConst.end()) {
+        myConst.erase(anIt);
+        setNeedToResolve(true);
+      }
+    }
+  }
+  aParam->setProcessed(false);
+  return true;
+}
+
+
+void PlaneGCSSolver_Storage::addCoincidentPoints(
+    EntityWrapperPtr theMaster, EntityWrapperPtr theSlave)
+{
+  if (theMaster->type() != ENTITY_POINT || theSlave->type() != ENTITY_POINT)
+    return;
+
+  // Search available coincidence
+  CoincidentPointsMap::iterator aMasterFound = myCoincidentPoints.find(theMaster);
+  CoincidentPointsMap::iterator aSlaveFound = myCoincidentPoints.find(theSlave);
+  if (aMasterFound == myCoincidentPoints.end() &&  aSlaveFound == myCoincidentPoints.end()) {
+    // try to find master and slave points in the lists of slaves of already existent coincidences
+    CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin();
+    for (; anIt != myCoincidentPoints.end(); ++anIt) {
+      if (anIt->second.find(theMaster) != anIt->second.end())
+        aMasterFound = anIt;
+      else if (anIt->second.find(theSlave) != anIt->second.end())
+        aSlaveFound = anIt;
+
+      if (aMasterFound != myCoincidentPoints.end() &&  aSlaveFound != myCoincidentPoints.end())
+        break;
+    }
+  }
+
+  if (aMasterFound == myCoincidentPoints.end()) {
+    // create new group
+    myCoincidentPoints[theMaster] = std::set<EntityWrapperPtr>();
+    aMasterFound = myCoincidentPoints.find(theMaster);
+  } else if (aMasterFound == aSlaveFound)
+    return; // already coincident
+
+  if (aSlaveFound != myCoincidentPoints.end()) {
+    // A slave has been found, we need to attach all points coincident with it to the new master
+    std::set<EntityWrapperPtr> aNewSlaves = aSlaveFound->second;
+    aNewSlaves.insert(aSlaveFound->first);
+    myCoincidentPoints.erase(aSlaveFound);
+
+    std::set<EntityWrapperPtr>::const_iterator aSlIt = aNewSlaves.begin();
+    for (; aSlIt != aNewSlaves.end(); ++aSlIt)
+      addCoincidentPoints(theMaster, *aSlIt);
+  } else {
+////    std::list<ParameterWrapperPtr> aSlaveParams = theSlave->parameters();
+////    theSlave->setParameters(theMaster->parameters());
+////
+////    // Remove slave's parameters
+////    std::list<ParameterWrapperPtr>::iterator aParIt = aSlaveParams.begin();
+////    for (; aParIt != aSlaveParams.end(); ++aParIt)
+////      remove(*aParIt);
+
+    aMasterFound->second.insert(theSlave);
+  }
+}
+
+
+void PlaneGCSSolver_Storage::changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup)
+{
+  theEntity->setGroup(theGroup);
+  if (theGroup == myGroupID)
+    makeVariable(theEntity);
+  else
+    makeConstant(theEntity);
+}
+
+void PlaneGCSSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup)
+{
+////  // TODO
+}
+
+void PlaneGCSSolver_Storage::verifyFixed()
+{
+////  // TODO
+}
+
+
+#ifndef OBSOLETE
+////
+////void PlaneGCSSolver_Storage::changeConstraint(
+////    const ConstraintPtr& theConstraint,
+////    const std::vector<GCSConstraintPtr>& theGCSConstraints)
+////{
+////  myConstraintsMap[theConstraint] = theGCSConstraints;
+////}
+
+////void PlaneGCSSolver_Storage::addConstraint(GCSConstraintPtr theConstraint)
+////{
+////  std::map<ConstraintPtr, std::vector<GCSConstraintPtr> >::iterator
+////      aFound = myConstraintsMap.find(ConstraintPtr());
+////  if (aFound != myConstraintsMap.end())
+////    aFound->second.push_back(theConstraint);
+////  else {
+////    std::vector<GCSConstraintPtr> aConstrVec(1, theConstraint);
+////    myConstraintsMap[ConstraintPtr()] = aConstrVec;
+////  }
+////}
+
+////EntityID PlaneGCSSolver_Storage::changeEntity(const FeaturePtr& theEntity)
+////{
+////  if (!theEntity || !theEntity->data() || !theEntity->data()->isValid())
+////    return ENTITY_UNKNOWN;
+////
+////  // Firstly, try to find entity
+////  std::map<FeaturePtr, EntityID>::const_iterator aFound = myFeatureEntityMap.find(theEntity);
+////
+////  EntityID aNewEntID;
+////  if (aFound != myFeatureEntityMap.end())
+////    aNewEntID = aFound->second;
+////
+////  const std::string& aFeatureKind = theEntity->getKind();
+////  // SketchPlugin features
+////  if (aFeatureKind == SketchPlugin_Line::ID())
+////    updateLine(theEntity, aNewEntID);
+////  // Circle
+////  else if (aFeatureKind == SketchPlugin_Circle::ID())
+////    updateCircle(theEntity, aNewEntID);
+////  // Arc
+////  else if (aFeatureKind == SketchPlugin_Arc::ID())
+////    updateArc(theEntity, aNewEntID);
+////  // 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 anAttribute = theEntity->attribute(SketchPlugin_Point::COORD_ID());
+////    if (!anAttribute->isInitialized())
+////      return ENTITY_UNKNOWN;
+////    // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
+////    aNewEntID = changeEntity(anAttribute);
+////  }
+////  else // NOTE: Other types of entities are unsupported
+////    aNewEntID = ENTITY_UNKNOWN;
+////
+////  if (aNewEntID != ENTITY_UNKNOWN)
+////    myFeatureEntityMap[theEntity] = aNewEntID;
+////  return aNewEntID;
+////}
+////
+////EntityID PlaneGCSSolver_Storage::changeEntity(const AttributePtr& theEntity)
+////{
+////  if (!theEntity)
+////    return ENTITY_UNKNOWN;
+////
+////  AttributeRefAttrPtr aRefAttr =
+////      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theEntity);
+////  if (aRefAttr) {
+////    if (aRefAttr->isObject()) {
+////      ResultConstructionPtr aRC =
+////          std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aRefAttr->object());
+////      if (!aRC)
+////        return ENTITY_UNKNOWN;
+////      return changeEntity(ModelAPI_Feature::feature(aRC));
+////    }
+////    else
+////      return changeEntity(aRefAttr->attr());
+////  }
+////
+////  EntityID aNewEntID = ENTITY_UNKNOWN;
+////
+////  // Firstly, try to find entity
+////  std::map<AttributePtr, EntityID>::const_iterator aFound = myAttributeEntityMap.find(theEntity);
+////  // Check type of attribute and create corresponding entity
+////  std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+////      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
+////  if (aPoint2D) {
+////    if (aFound != myAttributeEntityMap.end())
+////      aNewEntID = aFound->second;
+////    updatePoint(aPoint2D, aNewEntID);
+////  } else {
+////    AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
+////    if (aScalar) {
+////      // Check the scalar represents an angular value
+////      bool isAngular = false;
+////      FeaturePtr anOwner = ModelAPI_Feature::feature(aScalar->owner());
+////      if (anOwner && anOwner->getKind() == SketchPlugin_ConstraintAngle::ID())
+////        isAngular = true;
+////
+////      if (aFound != myAttributeEntityMap.end())
+////        aNewEntID = aFound->second;
+////      if (isAngular)
+////        updateAngle(aScalar, aNewEntID);
+////      else
+////        updateScalar(aScalar, aNewEntID);
+////    }
+////  }
+////  // NOTE: Other types of attributes are not supported
+////
+////  // Map attribute and new entity ID
+////  if (aFound == myAttributeEntityMap.end() && aNewEntID != ENTITY_UNKNOWN)
+////    myAttributeEntityMap[theEntity] = aNewEntID;
+////  return aNewEntID;
+////}
+
+
+////bool PlaneGCSSolver_Storage::removeConstraint(const ConstraintPtr& theConstraint)
+////{
+////  std::map<ConstraintPtr, std::vector<GCSConstraintPtr> >::iterator
+////      aFound = myConstraintsMap.find(theConstraint);
+////  if (aFound == myConstraintsMap.end())
+////    return true; // no constraint - nothing to remove
+////
+////  std::vector<GCSConstraintPtr> aConstrList = aFound->second;
+////  myConstraintsMap.erase(aFound);
+////  bool isFullyRemoved = removeEntity(theConstraint->attribute(SketchPlugin_Constraint::VALUE()));
+////  for (int ind = 0; ind < CONSTRAINT_ATTR_SIZE; ++ind)
+////    isFullyRemoved = removeEntity(theConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(ind)))
+////                   && isFullyRemoved;
+////
+////  myRemovedConstraints.insert(myRemovedConstraints.end(), aConstrList.begin(), aConstrList.end());
+////
+////  return isFullyRemoved;
+////}
+
+////bool PlaneGCSSolver_Storage::removeConstraint(GCSConstraintPtr theConstraint)
+////{
+////  std::map<ConstraintPtr, std::vector<GCSConstraintPtr> >::iterator
+////      aFound = myConstraintsMap.find(ConstraintPtr());
+////  if (aFound != myConstraintsMap.end()) {
+////    std::vector<GCSConstraintPtr>::iterator anIt = aFound->second.begin();
+////    for (; anIt != aFound->second.end(); ++anIt)
+////      if (*anIt == theConstraint) {
+////        aFound->second.erase(anIt);
+////        break;
+////      }
+////  }
+////
+////  myRemovedConstraints.push_back(theConstraint);
+////  return true;
+////}
+////
+////bool PlaneGCSSolver_Storage::removeEntity(const FeaturePtr& theFeature)
+////{
+////  if (!theFeature)
+////    return true;
+////  if (isUsed(theFeature))
+////    return false;
+////
+////  // remove feature and corresponding entity
+////  std::map<FeaturePtr, EntityID>::iterator aFound = myFeatureEntityMap.find(theFeature);
+////  if (aFound != myFeatureEntityMap.end()) {
+////    if (aFound->second.type == ARC) {
+////      // remove additional arc constraints
+////      std::map<EntityID, std::vector<GCSConstraintPtr> >::iterator aFoundArc =
+////          myArcConstraintMap.find(aFound->second);
+////      if (aFoundArc != myArcConstraintMap.end()) {
+////        myRemovedConstraints.insert(myRemovedConstraints.end(),
+////            aFoundArc->second.begin(), aFoundArc->second.end());
+////        myArcConstraintMap.erase(aFoundArc);
+////      }
+////    }
+////    myGCSEntities.erase(aFound->second);
+////    myFeatureEntityMap.erase(aFound);
+////  }
+////
+////  // remove feature's attributes
+////  bool isFullyRemoved = true;
+////  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+////  std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
+////  for (; anAttrIt != anAttributes.end(); ++anAttrIt)
+////    isFullyRemoved = removeEntity(*anAttrIt) && isFullyRemoved;
+////  return isFullyRemoved;
+////}
+////
+////bool PlaneGCSSolver_Storage::removeEntity(const AttributePtr& theAttribute)
+////{
+////  if (!theAttribute)
+////    return true;
+////  if (isUsed(theAttribute))
+////    return false;
+////
+////  AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+////  if (aRefAttr) {
+////    if (aRefAttr->isObject()) {
+////      FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+////      return removeEntity(aFeature);
+////    } else
+////      return removeEntity(aRefAttr->attr());
+////  }
+////
+////  // remove attribute and corresponding entity
+////  std::map<AttributePtr, EntityID>::iterator aFound = myAttributeEntityMap.find(theAttribute);
+////  if (aFound == myAttributeEntityMap.end())
+////    return true; // no attribute, nothing to remove
+////
+////  if (aFound->second.type == SCALAR || aFound->second.type == ANGLE) {
+////    std::map<EntityID, double*>::iterator aFoundScalar = myGCSScalars.find(aFound->second);
+////    if (aFoundScalar != myGCSScalars.end()) {
+////      removeParameters(aFoundScalar->second);
+////      myGCSScalars.erase(aFoundScalar);
+////    }
+////  }
+////  else if (aFound->second.type == POINT) {
+////    std::map<EntityID, GCSPointPtr>::iterator aFoundPoint = myGCSPoints.find(aFound->second);
+////    if (aFoundPoint != myGCSPoints.end()) {
+////      removeParameters(aFoundPoint->second->x, aFoundPoint->second->y);
+////      myGCSPoints.erase(aFoundPoint);
+////    }
+////  }
+////
+////  myAttributeEntityMap.erase(aFound);
+////  return true;
+////}
+
+////void PlaneGCSSolver_Storage::removeParameters(double* theParam1, double* theParam2)
+////{
+////  int aNbRemoved = 2;
+////  for (int ind = 0; ind < 2 && aNbRemoved > 0; ++ind) {
+////    GCS::VEC_pD& aList = ind ==0 ? myParameters : myConst;
+////
+////    GCS::VEC_pD::iterator aParIt = aList.begin();
+////    while (aNbRemoved > 0 && aParIt != aList.end()) {
+////      if (*aParIt != theParam1 && *aParIt != theParam2) {
+////        ++aParIt;
+////        continue;
+////      }
+////
+////      myRemovedParameters.push_back(*aParIt);
+////      int aShift = aParIt - aList.begin();
+////      aList.erase(aParIt);
+////      aParIt = aList.begin() + aShift;
+////      --aNbRemoved;
+////    }
+////  }
+////}
+
+
+////double* PlaneGCSSolver_Storage::createScalar(const AttributeDoublePtr& theScalar)
+////{
+////  double* aResult = new double;
+////  if (theScalar)
+////    *aResult = theScalar->value();
+////  myParameters.push_back(aResult);
+////  myNeedToResolve = true;
+////  return aResult;
+////}
+////
+////void PlaneGCSSolver_Storage::updateScalar(const AttributeDoublePtr& theScalar, EntityID& theID)
+////{
+////  std::map<EntityID, double*>::const_iterator aFound = myGCSScalars.find(theID);
+////  if (aFound == myGCSScalars.end()) {
+////    // new scalar
+////    theID = ++myEntityLastID;
+////    theID.type = SCALAR;
+////    myGCSScalars[theID] = createScalar(theScalar);
+////  }
+////  else if (fabs(*(myGCSScalars[theID]) - theScalar->value()) > tolerance) {
+////    *(myGCSScalars[theID]) = theScalar->value();
+////    myNeedToResolve = true;
+////  }
+////}
+////
+////void PlaneGCSSolver_Storage::updateAngle(const AttributeDoublePtr& theAngle, EntityID& theID)
+////{
+////  std::map<EntityID, double*>::const_iterator aFound = myGCSScalars.find(theID);
+////  if (aFound == myGCSScalars.end()) {
+////    // new scalar
+////    theID = ++myEntityLastID;
+////    theID.type = ANGLE;
+////    myGCSScalars[theID] = createScalar(theAngle);
+////  }
+////  else if (fabs(*(myGCSScalars[theID]) - theAngle->value()) > tolerance) {
+////    *(myGCSScalars[theID]) = theAngle->value();
+////    myNeedToResolve = true;
+////  }
+////  // Convert degrees to radians
+////  *(myGCSScalars[theID]) *= M_PI / 180.0;
+////}
+////
+////GCS::Point PlaneGCSSolver_Storage::createPoint(const std::shared_ptr<GeomDataAPI_Point2D>& thePoint)
+////{
+////  GCS::Point aResult;
+////  aResult.x = new double(thePoint->x());
+////  aResult.y = new double(thePoint->y());
+////
+////  myParameters.push_back(aResult.x);
+////  myParameters.push_back(aResult.y);
+////
+////  myNeedToResolve = true;
+////  return aResult;
+////}
+////
+////void PlaneGCSSolver_Storage::updatePoint(const std::shared_ptr<GeomDataAPI_Point2D>& thePoint,
+////                                             EntityID&                             theID)
+////{
+////  std::map<EntityID, GCSPointPtr>::iterator aFound = myGCSPoints.find(theID);
+////  if (aFound == myGCSPoints.end()) {
+////    // new point
+////    theID = ++myEntityLastID;
+////    theID.type = POINT;
+////    myGCSPoints[theID] = GCSPointPtr(new GCS::Point(createPoint(thePoint)));
+////  }
+////  else if (fabs(*(aFound->second->x) - thePoint->x()) > tolerance ||
+////           fabs(*(aFound->second->y) - thePoint->y()) > tolerance) {
+////    // update point
+////    *(aFound->second->x) = thePoint->x();
+////    *(aFound->second->y) = thePoint->y();
+////    myNeedToResolve = true;
+////  }
+////}
+////
+////void PlaneGCSSolver_Storage::updateLine(const FeaturePtr& theLine, EntityID& theID)
+////{
+////  std::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
+////      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+////      theLine->attribute(SketchPlugin_Line::START_ID()));
+////  std::shared_ptr<GeomDataAPI_Point2D> aEndAttr =
+////      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+////      theLine->attribute(SketchPlugin_Line::END_ID()));
+////  if (!aStartAttr->isInitialized() || !aEndAttr->isInitialized()) {
+////    theID = ENTITY_UNKNOWN;
+////    return;
+////  }
+////
+////  std::map<EntityID, GCSCurvePtr>::iterator aFound = myGCSEntities.find(theID);
+////  if (aFound == myGCSEntities.end()) {
+////////    // new line
+////////    theID = ++myEntityLastID;
+////////    theID.type = LINE;
+////////
+////////    EntityID aStartID = changeEntity(aStartAttr);
+////////    EntityID aEndID   = changeEntity(aEndAttr);
+////////    GCS::Point* aStart = getPoint(aStartID);
+////////    GCS::Point* aEnd   = getPoint(aEndID);
+////////
+////////    std::shared_ptr<GCS::Line> aLine(new GCS::Line);
+////////    aLine->p1 = *aStart;
+////////    aLine->p2 = *aEnd;
+////////    myGCSEntities[theID] = aLine;
+////  }
+////  else {
+////    // update line parameters
+////    std::map<AttributePtr, EntityID>::iterator aFoundAttr = myAttributeEntityMap.find(aStartAttr);
+////    if (aFoundAttr != myAttributeEntityMap.end())
+////      updatePoint(aStartAttr, aFoundAttr->second);
+////    aFoundAttr = myAttributeEntityMap.find(aEndAttr);
+////    if (aFoundAttr != myAttributeEntityMap.end())
+////      updatePoint(aEndAttr, aFoundAttr->second);
+////  }
+////}
+////
+////void PlaneGCSSolver_Storage::updateCircle(const FeaturePtr& theCircle, EntityID& theID)
+////{
+////  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+////      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+////      theCircle->attribute(SketchPlugin_Circle::CENTER_ID()));
+////  AttributeDoublePtr aRadiusAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+////      theCircle->attribute(SketchPlugin_Circle::RADIUS_ID()));
+////  if (!aCenterAttr->isInitialized() || !aRadiusAttr->isInitialized()) {
+////    theID = ENTITY_UNKNOWN;
+////    return;
+////  }
+////
+////  std::map<EntityID, GCSCurvePtr>::iterator aFound = myGCSEntities.find(theID);
+////  if (aFound == myGCSEntities.end()) {
+////////    // new circle
+////////    theID = ++myEntityLastID;
+////////    theID.type = CIRCLE;
+////////
+////////    EntityID aCenterID = changeEntity(aCenterAttr);
+////////    EntityID aRadiusID = changeEntity(aRadiusAttr);
+////////    GCS::Point* aCenter = getPoint(aCenterID);
+////////    double* aRadius = getScalar(aRadiusID);
+////////
+////////    std::shared_ptr<GCS::Circle> aCircle(new GCS::Circle);
+////////    aCircle->center = *aCenter;
+////////    aCircle->rad = aRadius;
+////////    myGCSEntities[theID] = aCircle;
+////  }
+////  else {
+////    // update circle parameters
+////    std::map<AttributePtr, EntityID>::iterator aFoundAttr = myAttributeEntityMap.find(aCenterAttr);
+////    if (aFoundAttr != myAttributeEntityMap.end())
+////      updatePoint(aCenterAttr, aFoundAttr->second);
+////    aFoundAttr = myAttributeEntityMap.find(aRadiusAttr);
+////    if (aFoundAttr != myAttributeEntityMap.end())
+////      updateScalar(aRadiusAttr, aFoundAttr->second);
+////  }
+////}
+////
+////void PlaneGCSSolver_Storage::updateArc(const FeaturePtr& theArc, EntityID& theID)
+////{
+////  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+////      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+////      theArc->attribute(SketchPlugin_Arc::CENTER_ID()));
+////  std::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
+////      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+////      theArc->attribute(SketchPlugin_Arc::START_ID()));
+////  std::shared_ptr<GeomDataAPI_Point2D> aEndAttr =
+////      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+////      theArc->attribute(SketchPlugin_Arc::END_ID()));
+////  if (!aCenterAttr->isInitialized() ||
+////      !aStartAttr->isInitialized()  ||
+////      !aEndAttr->isInitialized()) {
+////    theID = ENTITY_UNKNOWN;
+////    return;
+////  }
+////
+////  std::shared_ptr<GCS::Arc> anArc;
+////  std::map<EntityID, GCSCurvePtr>::iterator aFound = myGCSEntities.find(theID);
+////  if (aFound == myGCSEntities.end()) {
+////    // new arc
+////    theID = ++myEntityLastID;
+////    theID.type = ARC;
+////
+////    EntityID aCenterID = changeEntity(aCenterAttr);
+////    EntityID aStartID  = changeEntity(aStartAttr);
+////    EntityID aEndID    = changeEntity(aEndAttr);
+////    GCS::Point* aCenter = getPoint(aCenterID);
+////    GCS::Point* aStart  = getPoint(aStartID);
+////    GCS::Point* aEnd    = getPoint(aEndID);
+////
+////    anArc = std::shared_ptr<GCS::Arc>(new GCS::Arc);
+////    anArc->center = *aCenter;
+////    anArc->start  = *aStart;
+////    anArc->end    = *aEnd;
+////    anArc->startAngle = createScalar();
+////    anArc->endAngle   = createScalar();
+////    anArc->rad        = createScalar();
+////    myGCSEntities[theID] = anArc;
+////
+////    // Additional constraints for new arc
+////    processArc(theID);
+////  }
+////  else {
+////    // update arc parameters
+////    anArc = std::dynamic_pointer_cast<GCS::Arc>(aFound->second);
+////    std::map<AttributePtr, EntityID>::iterator aFoundAttr = myAttributeEntityMap.find(aCenterAttr);
+////    if (aFoundAttr != myAttributeEntityMap.end())
+////      updatePoint(aCenterAttr, aFoundAttr->second);
+////    aFoundAttr = myAttributeEntityMap.find(aStartAttr);
+////    if (aFoundAttr != myAttributeEntityMap.end())
+////      updatePoint(aStartAttr, aFoundAttr->second);
+////    aFoundAttr = myAttributeEntityMap.find(aEndAttr);
+////    if (aFoundAttr != myAttributeEntityMap.end())
+////      updatePoint(aEndAttr, aFoundAttr->second);
+////  }
+////
+////  // Calculate additional parameters necessary for FreeGCS
+////  std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = aCenterAttr->pnt();
+////  std::shared_ptr<GeomAPI_Pnt2d> aStartPnt  = aStartAttr->pnt();
+////  std::shared_ptr<GeomAPI_Pnt2d> aEndPnt    = aEndAttr->pnt();
+////
+////  *(anArc->rad) = aCenterPnt->distance(aStartPnt);
+////  std::shared_ptr<GeomAPI_Edge> anArcEdge =
+////      std::dynamic_pointer_cast<GeomAPI_Edge>(theArc->lastResult()->shape());
+////  if (!anArcEdge) {
+////    theID = ENTITY_UNKNOWN;
+////    return;
+////  }
+////  anArcEdge->getRange(*(anArc->startAngle), *(anArc->endAngle));
+////}
+
+
+////double* PlaneGCSSolver_Storage::getScalar(const EntityID& theID) const
+////{
+////  std::map<EntityID, double*>::const_iterator aFound = myGCSScalars.find(theID);
+////  if (aFound == myGCSScalars.end())
+////    return 0;
+////  return aFound->second;
+////}
+////
+////GCS::Point* PlaneGCSSolver_Storage::getPoint(const EntityID& theID) const
+////{
+////  std::map<EntityID, GCSPointPtr>::const_iterator aFound = myGCSPoints.find(theID);
+////  if (aFound == myGCSPoints.end())
+////    return 0;
+////  return aFound->second.get();
+////}
+////
+////GCS::Line* PlaneGCSSolver_Storage::getLine(const EntityID& theID) const
+////{
+////  std::map<EntityID, GCSCurvePtr>::const_iterator aFound = myGCSEntities.find(theID);
+////  if (aFound == myGCSEntities.end())
+////    return 0;
+////  std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(aFound->second);
+////  if (!aLine)
+////    return 0;
+////  return aLine.get();
+////}
+////
+////GCS::Circle* PlaneGCSSolver_Storage::getCircle(const EntityID& theID) const
+////{
+////  std::map<EntityID, GCSCurvePtr>::const_iterator aFound = myGCSEntities.find(theID);
+////  if (aFound == myGCSEntities.end())
+////    return 0;
+////  std::shared_ptr<GCS::Circle> aCircle = std::dynamic_pointer_cast<GCS::Circle>(aFound->second);
+////  if (!aCircle)
+////    return 0;
+////  return aCircle.get();
+////}
+////
+////GCS::Arc* PlaneGCSSolver_Storage::getArc(const EntityID& theID) const
+////{
+////  std::map<EntityID, GCSCurvePtr>::const_iterator aFound = myGCSEntities.find(theID);
+////  if (aFound == myGCSEntities.end())
+////    return 0;
+////  std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(aFound->second);
+////  if (!anArc)
+////    return 0;
+////  return anArc.get();
+////}
+
+void PlaneGCSSolver_Storage::processArc(const EntityWrapperPtr& theArc)
+{
+  // Calculate additional parameters necessary for PlaneGCS
+  const std::list<EntityWrapperPtr>& aSubs = theArc->subEntities();
+  std::list<EntityWrapperPtr>::const_iterator aSubIt = aSubs.begin();
+  while ((*aSubIt)->type() == ENTITY_POINT) // search scalar entities
+    ++aSubIt;
+  double* aStartAngle = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt++)->scalar();
+  double* aEndAngle   = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt++)->scalar();
+  double* aRadius     = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt)->scalar();
+
+  FeaturePtr anArcFeature = theArc->baseFeature();
+  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      anArcFeature->attribute(SketchPlugin_Arc::START_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aEndAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      anArcFeature->attribute(SketchPlugin_Arc::END_ID()));
+  std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = aCenterAttr->pnt();
+  std::shared_ptr<GeomAPI_Pnt2d> aStartPnt  = aStartAttr->pnt();
+  std::shared_ptr<GeomAPI_Pnt2d> aEndPnt    = aEndAttr->pnt();
+
+  *aRadius = aCenterPnt->distance(aStartPnt);
+  if (!anArcFeature->lastResult())
+    return;
+  std::shared_ptr<GeomAPI_Edge> anArcEdge =
+      std::dynamic_pointer_cast<GeomAPI_Edge>(anArcFeature->lastResult()->shape());
+  if (!anArcEdge)
+    return;
+  anArcEdge->getRange(*aStartAngle, *aEndAngle);
+
+  // No need to add constraints if they are already exist
+  std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >::const_iterator
+      aFound = myArcConstraintMap.find(theArc);
+  if (aFound != myArcConstraintMap.end())
+    return;
+
+  // Prepare additional constraints to produce the arc
+  std::vector<GCSConstraintPtr> anArcConstraints;
+  std::shared_ptr<PlaneGCSSolver_EntityWrapper> anArcEnt =
+      std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theArc);
+  std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anArcEnt->entity());
+  // Distances from center till start and end points are equal to radius
+  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+      anArc->center, anArc->start, anArc->rad)));
+  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+      anArc->center, anArc->end, anArc->rad)));
+  // Angles of start and end points should be equal to given angles
+  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
+      anArc->center, anArc->start, anArc->startAngle)));
+  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
+      anArc->center, anArc->end, anArc->endAngle)));
+
+  myArcConstraintMap[theArc] = anArcConstraints;
+}
+
+////const std::vector<GCSConstraintPtr>& PlaneGCSSolver_Storage::getConstraint(
+////    const ConstraintPtr& theConstraint) const
+////{
+////  static const std::vector<GCSConstraintPtr> aDummy;
+////
+////  std::map<ConstraintPtr, std::vector<GCSConstraintPtr> >::const_iterator
+////      aFound = myConstraintsMap.find(theConstraint);
+////  if (aFound == myConstraintsMap.end())
+////    return aDummy;
+////  return aFound->second;
+////}
+
+
+void PlaneGCSSolver_Storage::makeConstant(const EntityWrapperPtr& theEntity)
+{
+  toggleEntity(theEntity, myParameters, myConst);
+}
+
+void PlaneGCSSolver_Storage::makeVariable(const EntityWrapperPtr& theEntity)
+{
+  toggleEntity(theEntity, myConst, myParameters);
+}
+
+static void getParametersToMove(const EntityWrapperPtr& theEntity, std::set<double*>& theParamList)
+{
+  const std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
+  std::list<ParameterWrapperPtr>::const_iterator aPIt = aParams.begin();
+  for (; aPIt != aParams.end(); ++aPIt)
+    theParamList.insert(
+        std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(*aPIt)->parameter());
+
+  const std::list<EntityWrapperPtr> aSubs = theEntity->subEntities();
+  std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+  for (; aSIt != aSubs.end(); ++aSIt)
+    getParametersToMove(*aSIt, theParamList);
+}
+
+void PlaneGCSSolver_Storage::toggleEntity(
+    const EntityWrapperPtr& theEntity, GCS::VEC_pD& theFrom, GCS::VEC_pD& theTo)
+{
+  std::set<double*> aParamsToMove;
+  getParametersToMove(theEntity, aParamsToMove);
+
+  GCS::VEC_pD::iterator anIt = theFrom.begin();
+  while (anIt != theFrom.end()) {
+    if (aParamsToMove.find(*anIt) == aParamsToMove.end()) {
+      ++anIt;
+      continue;
+    }
+
+    theTo.push_back(*anIt);
+    int aShift = anIt - theFrom.begin();
+    theFrom.erase(anIt);
+    anIt = theFrom.begin() + aShift;
+  }
+}
+
+
+void PlaneGCSSolver_Storage::initializeSolver(SolverPtr theSolver)
+{
+  std::shared_ptr<PlaneGCSSolver_Solver> aSolver =
+      std::dynamic_pointer_cast<PlaneGCSSolver_Solver>(theSolver);
+
+  // initialize constraints
+  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+      aCIt = myConstraintMap.begin();
+  for (; aCIt != myConstraintMap.end(); ++aCIt) {
+    std::list<ConstraintWrapperPtr>::const_iterator aCWIt = aCIt->second.begin();
+    for (; aCWIt != aCIt->second.end(); ++ aCWIt) {
+      std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aGCS =
+          std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(*aCWIt);
+      std::list<GCSConstraintPtr>::const_iterator anIt = aGCS->constraints().begin();
+      for (; anIt != aGCS->constraints().end(); ++anIt)
+        aSolver->addConstraint(*anIt);
+    }
+  }
+  // additional constraints for arcs
+  std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >::const_iterator
+      anArcIt = myArcConstraintMap.begin();
+  for (; anArcIt != myArcConstraintMap.end(); ++anArcIt) {
+    std::vector<GCSConstraintPtr>::const_iterator anIt = anArcIt->second.begin();
+    for (; anIt != anArcIt->second.end(); ++anIt)
+      aSolver->addConstraint(*anIt);
+  }
+  // removed waste constraints
+  std::list<GCSConstraintPtr>::const_iterator aRemIt = myRemovedConstraints.begin();
+  for (; aRemIt != myRemovedConstraints.end(); ++aRemIt)
+    aSolver->removeConstraint(*aRemIt);
+  myRemovedConstraints.clear();
+////  // remove waste parameters
+////  std::list<double*>::const_iterator aRemParIt = myRemovedParameters.begin();
+////  for (; aRemParIt != myRemovedParameters.end(); ++aRemParIt)
+////    delete *aRemParIt;
+////  myRemovedParameters.clear();
+  // initialize unknowns
+  aSolver->setParameters(myParameters);
+}
+
+void PlaneGCSSolver_Storage::refresh(bool theFixedOnly) const
+{
+  //blockEvents(true);
+
+  std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
+  std::list<ParameterWrapperPtr> aParams;
+  std::list<ParameterWrapperPtr>::const_iterator aParIt;
+  for (; anIt != myAttributeMap.end(); ++anIt) {
+    // the external feature always should keep the up to date values, so, 
+    // refresh from the solver is never needed
+    if (anIt->first.get()) {
+      std::shared_ptr<SketchPlugin_Feature> aSketchFeature = 
+        std::dynamic_pointer_cast<SketchPlugin_Feature>(anIt->first->owner());
+      if (aSketchFeature.get() && aSketchFeature->isExternal())
+        continue;
+    }
+
+    // update parameter wrappers and obtain values of attributes
+    aParams = anIt->second->parameters();
+    double aCoords[3];
+    bool isUpd[3] = {false};
+    int i = 0;
+    for (aParIt = aParams.begin(); i < 3 && aParIt != aParams.end(); ++aParIt, ++i) {
+      if (!theFixedOnly || (*aParIt)->group() == GID_OUTOFGROUP || (*aParIt)->isParametric()) {
+        aCoords[i] = (*aParIt)->value();
+        isUpd[i] = true;
+      }
+    }
+    if (!isUpd[0] && !isUpd[1] && !isUpd[2])
+      continue; // nothing is updated
+
+    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
+    if (aPoint2D) {
+      if ((isUpd[0] && fabs(aPoint2D->x() - aCoords[0]) > tolerance) ||
+          (isUpd[1] && fabs(aPoint2D->y() - aCoords[1]) > tolerance)) {
+        if (!isUpd[0]) aCoords[0] = aPoint2D->x();
+        if (!isUpd[1]) aCoords[1] = aPoint2D->y();
+        aPoint2D->setValue(aCoords[0], aCoords[1]);
+        // Find points coincident with this one (probably not in GID_OUTOFGROUP)
+        std::map<AttributePtr, EntityWrapperPtr>::const_iterator aLocIt =
+            theFixedOnly ? myAttributeMap.begin() : anIt;
+        for (++aLocIt; aLocIt != myAttributeMap.end(); ++aLocIt)
+          if (anIt->second->id() == aLocIt->second->id()) {
+            aPoint2D = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aLocIt->first);
+            if (aPoint2D)
+              aPoint2D->setValue(aCoords[0], aCoords[1]);
+          }
+      }
+      continue;
+    }
+    AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
+    if (aScalar) {
+      if (isUpd[0] && fabs(aScalar->value() - aCoords[0]) > tolerance)
+        aScalar->setValue(aCoords[0]);
+      continue;
+    }
+  }
+
+  //blockEvents(false);
+}
+
+EntityWrapperPtr PlaneGCSSolver_Storage::calculateMiddlePoint(
+    EntityWrapperPtr theBase, double theCoeff)
+{
+  std::shared_ptr<PlaneGCSSolver_Builder> aBuilder =
+      std::dynamic_pointer_cast<PlaneGCSSolver_Builder>(PlaneGCSSolver_Builder::getInstance());
+
+  std::shared_ptr<GeomAPI_XY> aMidPoint;
+  if (theBase->type() == ENTITY_LINE) {
+    std::shared_ptr<GeomAPI_Pnt2d> aPoints[2];
+    const std::list<EntityWrapperPtr>& aSubs = theBase->subEntities();
+    std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
+    for (int i = 0; i < 2; ++i, ++anIt)
+      aPoints[i] = aBuilder->point(*anIt);
+    aMidPoint = aPoints[0]->xy()->multiplied(1.0 - theCoeff)->added(
+        aPoints[1]->xy()->multiplied(theCoeff));
+  }
+  else if (theBase->type() == ENTITY_ARC) {
+    double theX, theY;
+    double anArcPoint[3][2];
+    const std::list<EntityWrapperPtr>& aSubs = theBase->subEntities();
+    std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
+    for (int i = 0; i < 3; ++i, ++anIt) {
+      std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(*anIt);
+      anArcPoint[i][0] = aPoint->x();
+      anArcPoint[i][1] = aPoint->y();
+    }
+    // project last point of arc on the arc
+    double x = anArcPoint[1][0] - anArcPoint[0][0];
+    double y = anArcPoint[1][1] - anArcPoint[0][1];
+    double aRad = sqrt(x*x + y*y);
+    x = anArcPoint[2][0] - anArcPoint[0][0];
+    y = anArcPoint[2][1] - anArcPoint[0][1];
+    double aNorm = sqrt(x*x + y*y);
+    if (aNorm >= tolerance) {
+      anArcPoint[2][0] = x * aRad / aNorm;
+      anArcPoint[2][1] = y * aRad / aNorm;
+    }
+    anArcPoint[1][0] -= anArcPoint[0][0];
+    anArcPoint[1][1] -= anArcPoint[0][1];
+    if (theCoeff < tolerance) {
+      theX = anArcPoint[0][0] + anArcPoint[1][0];
+      theY = anArcPoint[0][1] + anArcPoint[1][1];
+    } else if (1 - theCoeff < tolerance) {
+      theX = anArcPoint[0][0] + anArcPoint[2][0];
+      theY = anArcPoint[0][1] + anArcPoint[2][1];
+    } else {
+      std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1]));
+      std::shared_ptr<GeomAPI_Dir2d> aEndDir(new GeomAPI_Dir2d(anArcPoint[2][0], anArcPoint[2][1]));
+      double anAngle = aStartDir->angle(aEndDir);
+      if (anAngle < 0)
+        anAngle += 2.0 * PI;
+      anAngle *= theCoeff;
+      double aCos = cos(anAngle);
+      double aSin = sin(anAngle);
+      theX = anArcPoint[0][0] + anArcPoint[1][0] * aCos - anArcPoint[1][1] * aSin;
+      theY = anArcPoint[0][1] + anArcPoint[1][0] * aSin + anArcPoint[1][1] * aCos;
+    }
+    aMidPoint = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(theX, theY));
+  }
+
+  if (!aMidPoint)
+    return EntityWrapperPtr();
+
+  std::list<ParameterWrapperPtr> aParameters;
+  aParameters.push_back(aBuilder->createParameter(myGroupID, aMidPoint->x()));
+  aParameters.push_back(aBuilder->createParameter(myGroupID, aMidPoint->y()));
+  // Create entity (parameters are not filled)
+  GCSPointPtr aPnt(new GCS::Point);
+  aPnt->x = std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(aParameters.front())->parameter();
+  aPnt->y = std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(aParameters.back())->parameter();
+
+  EntityWrapperPtr aResult(new PlaneGCSSolver_PointWrapper(AttributePtr(), aPnt));
+  aResult->setGroup(myGroupID);
+  aResult->setParameters(aParameters);
+
+  update(aResult);
+  return aResult;
+}
+
+////bool PlaneGCSSolver_Storage::isInteract(AttributePtr theAttribute) const
+////{
+////  std::map<AttributePtr, EntityID>::const_iterator aFound = myAttributeEntityMap.find(theAttribute);
+////  if (aFound != myAttributeEntityMap.end())
+////    return true;
+////
+////  AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+////  if (!aRefAttr)
+////    return false;
+////  if (aRefAttr->isObject()) {
+////    FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+////    if (!aFeature)
+////      return false;
+////    return isInteract(aFeature);
+////  }
+////
+////  return isInteract(aRefAttr->attr());
+////}
+////
+////bool PlaneGCSSolver_Storage::isInteract(FeaturePtr theFeature) const
+////{
+////  if (myFeatureEntityMap.find(theFeature) != myFeatureEntityMap.end())
+////    return true;
+////  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+////  std::list<AttributePtr>::iterator anIt = anAttributes.begin();
+////  for (; anIt != anAttributes.end(); ++anIt)
+////    if (isInteract(*anIt))
+////      return true;
+////  return false;
+////}
+
+
+////bool PlaneGCSSolver_Storage::isUsed(const FeaturePtr& theFeature) const
+////{
+////  // There is checked only the feature itself, not its attributes.
+////  // The attributes should be checked separately.
+////
+////  std::map<ConstraintPtr, std::vector<GCSConstraintPtr> >::const_iterator
+////      aCIt = myConstraintsMap.begin();
+////  for (; aCIt != myConstraintsMap.end(); ++aCIt) {
+////    if (!aCIt->first)
+////      continue;
+////    for (int ind = 0; ind < CONSTRAINT_ATTR_SIZE; ++ind) {
+////      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+////          aCIt->first->attribute(SketchPlugin_Constraint::ATTRIBUTE(ind)));
+////      if (aRefAttr && aRefAttr->isObject()) {
+////        FeaturePtr aFeat = ModelAPI_Feature::feature(aRefAttr->object());
+////        if (aFeat == theFeature)
+////          return true;
+////      }
+////    }
+////  }
+////  return false;
+////}
+////
+////bool PlaneGCSSolver_Storage::isUsed(const AttributePtr& theAttribute) const
+////{
+////  // Check whether the attribute is used by constraints
+////  std::map<ConstraintPtr, std::vector<GCSConstraintPtr> >::const_iterator
+////      aCIt = myConstraintsMap.begin();
+////  for (; aCIt != myConstraintsMap.end(); ++aCIt) {
+////    if (!aCIt->first)
+////      continue;
+////    if (aCIt->first->attribute(SketchPlugin_Constraint::VALUE()) == theAttribute)
+////      return true;
+////    for (int ind = 0; ind < CONSTRAINT_ATTR_SIZE; ++ind) {
+////      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+////          aCIt->first->attribute(SketchPlugin_Constraint::ATTRIBUTE(ind)));
+////      if (!aRefAttr)
+////        continue;
+////      if (aRefAttr == theAttribute ||
+////         (!aRefAttr->isObject() && aRefAttr->attr() == theAttribute))
+////        return true;
+////    }
+////  }
+////
+////  // Check whether the attribute is used by features
+////  std::map<FeaturePtr, EntityID>::const_iterator aFIt = myFeatureEntityMap.begin();
+////  for (; aFIt != myFeatureEntityMap.end(); ++aFIt) {
+////    std::list<AttributePtr> anAttrs =
+////        aFIt->first->data()->attributes(GeomDataAPI_Point2D::typeId());
+////    std::list<AttributePtr>::const_iterator anIt = anAttrs.begin();
+////    for (; anIt != anAttrs.end(); ++anIt)
+////      if (*anIt == theAttribute)
+////        return true;
+////  }
+////
+////  return false;
+////}
+
+
+////void PlaneGCSSolver_Storage::blockEvents(bool isBlocked)
+////{
+////  std::map<FeaturePtr, EntityID>::iterator aFIt = myFeatureEntityMap.begin();
+////  for (; aFIt != myFeatureEntityMap.end(); ++aFIt)
+////    if (aFIt->first->data() && aFIt->first->data()->isValid())
+////      aFIt->first->data()->blockSendAttributeUpdated(isBlocked);
+////
+////  std::map<AttributePtr, EntityID>::iterator anAIt = myAttributeEntityMap.begin();
+////  for (; anAIt != myAttributeEntityMap.end(); ++anAIt)
+////    if (anAIt->first->owner() && anAIt->first->owner()->data() &&
+////        anAIt->first->owner()->data()->isValid())
+////      anAIt->first->owner()->data()->blockSendAttributeUpdated(isBlocked);
+////}
+
+
+#else
+
+#endif
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h
new file mode 100644 (file)
index 0000000..1ddc401
--- /dev/null
@@ -0,0 +1,460 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    PlaneGCSSolver_Storage.h
+// Created: 14 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef PlaneGCSSolver_Storage_H_
+#define PlaneGCSSolver_Storage_H_
+
+#include <PlaneGCSSolver_Defs.h>
+
+#include <SketchSolver.h>
+#include <SketchSolver_Storage.h>
+#include <SketchSolver_ISolver.h>
+
+////#include <GeomDataAPI_Point2D.h>
+////#include <ModelAPI_Attribute.h>
+////#include <ModelAPI_AttributeDouble.h>
+////#include <ModelAPI_Feature.h>
+////#include <SketchPlugin_Constraint.h>
+////
+////#include <Geo.h>
+////#include <Util.h>
+////
+////#include <list>
+////#include <memory>
+////#include <set>
+////#include <vector>
+
+////#ifndef OBSOLETE
+////#include <Constraints.h>
+////
+////typedef std::shared_ptr<GCS::Point> GCSPointPtr;
+////typedef std::shared_ptr<GCS::Curve> GCSCurvePtr;
+////typedef GCS::Constraint*            GCSConstraintPtr;
+////#endif
+
+/** \class   PlaneGCSSolver_Storage
+ *  \ingroup Plugins
+ *  \brief   Contains all necessary data in PlaneGCS format to solve a single group of constraints
+ */
+class PlaneGCSSolver_Storage : public SketchSolver_Storage
+{
+public:
+  PlaneGCSSolver_Storage(const GroupID& theGroup);
+
+// =============   Inherited from SketchSolver_Storage   =============
+
+  /// \brief Change mapping between constraint from SketchPlugin and
+  ///        the list of constraints applicable for corresponding solver.
+  ///        Derived here to update point-point coincidence.
+  /// \param theConstraint        [in]   original SketchPlugin constraint
+  /// \param theSolverConstraints [in]   list of solver's constraints
+  virtual void addConstraint(ConstraintPtr                   theConstraint,
+                             std::list<ConstraintWrapperPtr> theSolverConstraints);
+
+  /// \brief Update constraint's data
+  /// \return \c true if any value is updated
+  virtual bool update(ConstraintWrapperPtr& theConstraint);
+  /// \brief Update entity's data
+  /// \return \c true if any value is updated
+  virtual bool update(EntityWrapperPtr& theEntity);
+  /// \brief Update parameter's data
+  /// \return \c true if the value of parameter is updated
+  virtual bool update(ParameterWrapperPtr& theParameter);
+
+  /// \brief Update SketchPlugin features after resolving constraints
+  /// \param theFixedOnly [in]  if \c true the fixed points will be updated only
+  virtual void refresh(bool theFixedOnly = false) const;
+
+  /// \brief Check if some parameters or entities are returned
+  ///        to the current group after removing temporary constraints
+  virtual void verifyFixed();
+
+  /// \brief Mark two points as coincident
+  virtual void addCoincidentPoints(EntityWrapperPtr theMaster, EntityWrapperPtr theSlave);
+
+  /// \brief Shows the storage has the same constraint twice
+  virtual bool hasDuplicatedConstraint() const
+  { return false; }
+
+  /// \brief Calculate point on theBase entity. Value theCoeff is in [0.0 .. 1.0] and
+  ///        shows the distance from the start point.
+  virtual EntityWrapperPtr calculateMiddlePoint(EntityWrapperPtr theBase, double theCoeff);
+
+  /// \brief Initialize solver by constraints, entities and parameters
+  virtual void initializeSolver(SolverPtr theSolver);
+
+protected:
+  /// \brief Remove constraint
+  /// \return \c true if the constraint and all its parameters are removed successfully
+  virtual bool remove(ConstraintWrapperPtr theConstraint);
+  /// \brief Remove entity
+  /// \return \c true if the entity and all its parameters are removed successfully
+  virtual bool remove(EntityWrapperPtr theEntity);
+  /// \brief Remove parameter
+  /// \return \c true if the parameter has been removed
+  virtual bool remove(ParameterWrapperPtr theParameter);
+
+  /// \brief Update the group for the given entity, its sub-entities and parameters
+  virtual void changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup);
+  /// \brief Update the group for the given parameter
+  virtual void changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup);
+
+
+// =============   Own methods   =============
+
+
+
+#ifndef OBSOLETE
+
+////  /** \brief Add or change constraint and corresponding GCS constraints to the storage
+////   *  \param theConstraint     [in] base SketchPlugin constraint
+////   *  \param theGCSConstraints [in] list of GCS constraints created by SketchSolver constraint
+////   */
+////  void changeConstraint(const ConstraintPtr& theConstraint,
+////                        const std::vector<GCSConstraintPtr>& theGCSConstraints);
+
+////  /** \brief Add GCS constraint not related to any SketchPlugin constraint.
+////   *         For example, it may be related to the moved feature.
+////   *  \param theConstraint [in] GCS constraint
+////   */
+////  void addConstraint(GCSConstraintPtr theConstraint);
+
+////  /** \brief Convert SketchPlugin_Feature to the corresponding entity in FreeGCS
+////   *  \param theEntity [in] feature to convert
+////   *  \return ID of created or updated entity
+////   */
+////  EntityID changeEntity(const FeaturePtr& theEntity);
+////  /** \brief Convert ModelAPI_Attribute to the corresponding entity in FreeGCS
+////   *  \param theEntity [in] attribute to convert
+////   *  \return ID of created or updated entity
+////   */
+////  EntityID changeEntity(const AttributePtr& theEntity);
+
+////  /** \brief Remove constraint and corresponding GCS constraints
+////   *  \param theConstraint [in] constraint to remove
+////   *  \return \c true, if the constraint is fully removed,
+////   *          \c false, if there are available entities used by other constraints
+////   */
+////  bool removeConstraint(const ConstraintPtr& theConstraint);
+////  /** \brief Remove GCS constraint
+////   *  \param theConstraint [in] constraint to remove
+////   *  \return \c true, if the constraint is fully removed
+////   */
+////  bool removeConstraint(GCSConstraintPtr theConstraint);
+////  /** \brief Remove feature and corresponding GCS entities
+////   *  \param theFeature [in] feature to remove
+////   *  \return \c true, if the feature is fully removed,
+////   *          \c false, if there are available entities used by other constraints or features
+////   */
+////  bool removeEntity(const FeaturePtr& theFeature);
+////  /** \brief Remove attribute and corresponding GCS entities
+////   *  \param theAttribute [in] attribute to remove
+////   *  \return \c true, if the attribute is removed,
+////   *          \c false, if it is used by existent features or constraints
+////   */
+////  bool removeEntity(const AttributePtr& theAttribute);
+
+  /// \brief Move parameters of the entity to the constants
+  void makeConstant(const EntityWrapperPtr& theEntity);
+  /// \brief Move parameters of the entity to the variables
+  void makeVariable(const EntityWrapperPtr& theEntity);
+
+////  /// \brief Return scalar by its ID or null pointer
+////  double*      getScalar(const EntityID& theID) const;
+////  /// \brief Return point by its ID or null pointer
+////  GCS::Point*  getPoint(const EntityID& theID) const;
+////  /// \brief Return line by its ID or null pointer
+////  GCS::Line*   getLine(const EntityID& theID) const;
+////  /// \brief Return circle by its ID or null pointer
+////  GCS::Circle* getCircle(const EntityID& theID) const;
+////  /// \brief Return arc by its ID or null pointer
+////  GCS::Arc*    getArc(const EntityID& theID) const;
+////
+////  /// \brief Return list of GCS constraints corresponding to the given
+////  const std::vector<GCSConstraintPtr>& getConstraint(const ConstraintPtr& theConstraint) const;
+
+////  /// \brief Verifies, the attribute is available in current storage
+////  bool isInteract(AttributePtr theAttribute) const;
+////  /// \brief Verifies, the feature is available in current storage
+////  bool isInteract(FeaturePtr theFeature) const;
+
+private:
+////  /** \brief Creates scalar parameter in the list of parameters
+////   *  \param theScalar [in] value to be converted
+////   *  \return pointer to new scalar
+////   */
+////  double* createScalar(const AttributeDoublePtr& theScalar = AttributeDoublePtr());
+////  /** \brief Creates two parameters in the list of parameters to store point coordinates
+////   *  \param thePoint [in] point to be converted
+////   *  \return FreeGCS point
+////   */
+////  GCS::Point createPoint(const std::shared_ptr<GeomDataAPI_Point2D>& thePoint);
+////  /** \brief Creates or updates a scalar value
+////   *  \param theScalar [in] attribute to update scalar value
+////   *  \param theID     [in] ID of scalar to be updated
+////   */
+////  void updateScalar(const AttributeDoublePtr& theScalar, EntityID& theID);
+////  /** \brief Creates or updates an angular value
+////   *  \param theAngle [in] attribute to update scalar value
+////   *  \param theID    [in] ID of scalar to be updated
+////   */
+////  void updateAngle(const AttributeDoublePtr& theAngle, EntityID& theID);
+////  /** \brief Creates or updates parameters of the point
+////   *  \param thePoint [in] point used to update parameters
+////   *  \param theID    [in] ID of FreeGCS entity to be updated
+////   */
+////  void updatePoint(const std::shared_ptr<GeomDataAPI_Point2D>& thePoint,
+////                         EntityID&                             theID);
+////  /** \brief Creates or updates parameters of the line
+////   *  \param theLine [in]     line used to update parameters
+////   *  \param theID   [in/out] ID of FreeGCS entity to be updated (cleared if problems)
+////   */
+////  void updateLine(const FeaturePtr& theLine, EntityID& theID);
+////  /** \brief Creates or updates parameters of the circle
+////   *  \param theLine [in]     circle used to update parameters
+////   *  \param theID   [in/out] ID of FreeGCS entity to be updated (cleared if problems)
+////   */
+////  void updateCircle(const FeaturePtr& theCircle, EntityID& theID);
+////  /** \brief Creates or updates parameters of the arc
+////   *  \param theLine [in]     arc used to update parameters
+////   *  \param theID   [in/out] ID of FreeGCS entity to be updated (cleared if problems)
+////   */
+////  void updateArc(const FeaturePtr& theArc, EntityID& theID);
+
+////  /// \brief Check the feature is used by constraints
+////  bool isUsed(const FeaturePtr& theFeature) const;
+////  /// \brief Check the attribute is used by constraints or features
+////  bool isUsed(const AttributePtr& theAttribute) const;
+
+////  /// \brief Remove given parameter from the lists of parameters and constants
+////  void removeParameters(double* theParam1, double* theParam2 = 0);
+
+  /// \brief Move parameters of the entity from the list of variables to the list of constants
+  ///        and vice versa
+  /// \param theEntity [in]  entity to be changed
+  /// \param theFrom   [out] source list
+  /// \param theTo     [out] destination list
+  void toggleEntity(const EntityWrapperPtr& theEntity, GCS::VEC_pD& theFrom, GCS::VEC_pD& theTo);
+
+  /// \brief Create additional constraints for correct processing of arcs
+  /// \param theArc [in]  updated arc
+  void processArc(const EntityWrapperPtr& theArc);
+
+private:
+  GCS::VEC_pD                      myParameters;         ///< list of parameters
+  GCS::VEC_pD                      myConst;              ///< list of constants
+  EntityID                         myEntityLastID;       ///< identifier of last added entity
+
+////  std::map<ConstraintPtr, std::vector<GCSConstraintPtr> >
+////                                   myConstraintsMap;     ///< map SketchPlugin constraints to corresponding GCS constraints
+////
+////  std::map<AttributePtr, EntityID> myAttributeEntityMap; ///< map attributes to corresponding entities
+////  std::map<FeaturePtr, EntityID>   myFeatureEntityMap;   ///< map features to corresponding entities
+////
+////  std::map<EntityID, double*>      myGCSScalars;         ///< list of scalar values and their IDs
+////  std::map<EntityID, GCSPointPtr>  myGCSPoints;          ///< list of points and their IDs
+////  std::map<EntityID, GCSCurvePtr>  myGCSEntities;        ///< list of lines, circles and arcs and their IDs
+
+  std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >
+                                  myArcConstraintMap;    ///< additional constraints for correct processing of the arcs
+
+////  std::list<double*>               myRemovedParameters;  ///< list of removed parameters
+  std::list<GCSConstraintPtr>      myRemovedConstraints; ///< list of removed constraints to notify solver
+
+#else
+
+// ================================================================================================
+// ===================     OBSOLETE     ===========================================================
+public:
+  PlaneGCSSolver_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 Remove all entities, which are not used in constraints
+   */
+  void removeUnusedEntities();
+  /// \brief Returns the entity by its ID
+  const Slvs_Entity& getEntity(const Slvs_hEntity& theEntityID) const;
+  /// \brief Makes a full copy of the given entity
+  Slvs_hEntity copyEntity(const Slvs_hEntity& theCopied);
+  /// \brief Copy one entity to another
+  void copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo);
+  /// \brief Check the entity is used in constraints
+  bool isUsedByConstraints(const Slvs_hEntity& theEntityID) const;
+
+  /// \brief Verifies the current point or another coincident one is fixed
+  /// \param[in]  thePointID  entity to be checked fixed
+  /// \param[out] theFixed    ID of constraint
+  /// \param[in]  theAccurate if \c true, the calculation will be made for all type of constraints,
+  ///                         if \c false, only the point is verified
+  /// \return \c true if the point is fixed
+  bool isPointFixed(const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate = false) const;
+  /// \brief Verifies the current entity is fully fixed (may not be changed by constraints)
+  /// \param[in] theEntityID entity to be checked fixed
+  /// \param[in] theAccurate if \c true, the calculation will be made for all type of constraints,
+  ///                        if \c false, only points are verified
+  /// \return \c true if the entity is fixed
+  bool isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate = false) const;
+
+  /** \brief Add new constraint to the current group
+   *  \param[in] theConstraint   SolveSpace's 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 Returns list of constraints of specified type
+  std::list<Slvs_Constraint> getConstraintsByType(int theConstraintType) const;
+
+  /// \brief Attach constraint SLVS_C_WHERE_DRAGGED to this storage. It need to make precise calculations
+  void addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID);
+
+  /// \brief Add transient constraint
+  void addTemporaryConstraint(const Slvs_hConstraint& theConstraintID);
+  /// \brief Remove all transient constraints
+  void removeTemporaryConstraints();
+  /// \brief Remove one temporary constraint. Preferable to remove the points under Point-on-Line constraint
+  /// \return Number of remaining temporary constraints
+  int deleteTemporaryConstraint();
+  /// \brief Checks the constraint is temporary
+  bool isTemporary(const Slvs_hConstraint& theConstraintID) const;
+  /// \brief Number of temporary constraints
+  int numberTemporary() const
+  { return (int)myTemporaryConstraints.size(); }
+
+  /// \brief Shows the sketch should be resolved
+  bool isNeedToResolve();
+
+  /// \brief Shows the storage has the same constraint twice
+  bool hasDuplicatedConstraint() const
+  { return myDuplicatedConstraint; }
+
+  /// \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:
+  /// \brief Store coincident points
+  void addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2);
+  /// \brief Remove point from lists of coincidence
+  void removeCoincidentPoint(const Slvs_hEntity& thePoint);
+  /// \brief Remove point-point coincidence
+  void removeCoincidence(const Slvs_Constraint& theCoincidence);
+
+public:
+  /// \brief Check two points are coincident
+  bool isCoincident(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const;
+
+  /// \brief Check two points are coincident or have same coordinates
+  bool isEqual(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const;
+
+  /// \brief Check the entity is horizontal of vertical
+  bool isAxisParallel(const Slvs_hEntity& theEntity) const;
+
+  /// \brief Verifies the entity is used in any equal constraint
+  /// \param[in]  theEntity entity to be found
+  /// \param[out] theEqual  constraint, which uses the entity
+  /// \return \c true, if the Equal constrait is found
+  bool isUsedInEqual(const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const;
+
+  /// \brief Fixes specified entity
+  /// \param theEntity  ID of the entity to be fixed
+  /// \return List of created constraints
+  std::vector<Slvs_hConstraint> fixEntity(const Slvs_hEntity& theEntity);
+
+private:
+  /// \brief Fixes specified point
+  /// \param [in]  thePoint    point to be fixed
+  /// \param [out] theCreated  list of the Fixed constraints created
+  void fixPoint(const Slvs_Entity& thePoint, std::vector<Slvs_hConstraint>& theCreated);
+  /// \brief Fixes specified line
+  /// \param [in]  theLine     line to be fixed
+  /// \param [out] theCreated  list of the Fixed constraints created
+  void fixLine(const Slvs_Entity& theLine, std::vector<Slvs_hConstraint>& theCreated);
+  /// \brief Fixes specified circle
+  /// \param [in]  theCircle   circle to be fixed
+  /// \param [out] theCreated  list of the Fixed constraints created
+  void fixCircle(const Slvs_Entity& theCircle, std::vector<Slvs_hConstraint>& theCreated);
+  /// \brief Fixes specified arc
+  /// \param [in]  theArc      arc to be fixed
+  /// \param [out] theCreated  list of the Fixed constraints created
+  void fixArc(const Slvs_Entity& theArc, std::vector<Slvs_hConstraint>& theCreated);
+
+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 (sorted by the identifier)
+  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 (sorted by the identifier)
+  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 (sorted by the identifier)
+
+  std::vector< std::set<Slvs_hEntity> > myCoincidentPoints; ///< lists of coincident points
+  Slvs_hConstraint myFixed; ///< identifier of one of temporary constraints to fix separate point
+
+  bool myNeedToResolve; ///< parameters are changed and group needs to be resolved
+  bool myDuplicatedConstraint; ///< shows the storage has same constraint twice
+
+  std::set<Slvs_hConstraint> myTemporaryConstraints; ///< list of transient constraints
+  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)
+  std::set<Slvs_hParam> myUpdatedParameters; ///< list of just updated parameters (cleared when isNeedToResolve() called)
+#endif
+};
+
+#endif
index 56fa1dba25eba093e0041f1de7595e83b29080ee..8beb83a984e5e8d150ab38abe46a4b2a70c852aa 100644 (file)
@@ -36,6 +36,7 @@ const GroupID       GID_OUTOFGROUP = 1;
 
 const ParameterID   PID_UNKNOWN    = 0;
 const EntityID      EID_UNKNOWN    = 0;
+const EntityID      EID_SKETCH     = 1;
 const ConstraintID  CID_UNKNOWN    = 0;
 
 #endif
index 49f4d796e18432c48fc239d899c47836326a17c5..15735e73358a4ea15a7d4ae2da0a4a4950349c52 100644 (file)
@@ -20,6 +20,7 @@
 enum SketchSolver_EntityType {
   ENTITY_UNKNOWN = 0,
   ENTITY_SCALAR,
+  ENTITY_ANGLE,
   ENTITY_POINT,
   ENTITY_NORMAL,
   ENTITY_LINE,
index 772846c827912327b36de799fce97f77296a0c13..c5346906ea30792d865a52d49e854a1b10fd2bfd 100644 (file)
@@ -50,7 +50,7 @@ public:
   ///        the list of constraints applicable for corresponding solver.
   /// \param theConstraint        [in]   original SketchPlugin constraint
   /// \param theSolverConstraints [in]   list of solver's constraints
-  SKETCHSOLVER_EXPORT
+  SKETCHSOLVER_EXPORT virtual
     void addConstraint(ConstraintPtr                   theConstraint,
                        std::list<ConstraintWrapperPtr> theSolverConstraints);
 
@@ -192,15 +192,15 @@ protected:
   /// \brief Update the group for the given parameter
   virtual void changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup) = 0;
 
+  /// \brief Verify the feature or any its attribute is used by constraint
+  SKETCHSOLVER_EXPORT bool isUsed(FeaturePtr theFeature) const;
+  /// \brief Verify the attribute is used by constraint
+  SKETCHSOLVER_EXPORT bool isUsed(AttributePtr theAttirubute) const;
+
 private:
   /// \brief Find the normal of the sketch
   EntityWrapperPtr getNormal() const;
 
-  /// \brief Verify the feature or any its attribute is used by constraint
-  bool isUsed(FeaturePtr theFeature) const;
-  /// \brief Verify the attribute is used by constraint
-  bool isUsed(AttributePtr theAttirubute) const;
-
 protected:
   GroupID myGroupID;       ///< identifier of the group, this storage belongs to
   bool    myNeedToResolve; ///< parameters are changed and group needs to be resolved