]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
First phase of SketchSolver refactoring
authorazv <azv@opencascade.com>
Tue, 15 Dec 2015 08:55:25 +0000 (11:55 +0300)
committerazv <azv@opencascade.com>
Tue, 15 Dec 2015 13:04:04 +0000 (16:04 +0300)
1. SketchSolver now is a base library for all other solvers
2. Created SolveSpaceSolver library to use SolveSpace.
3. Implemented minimal set of constraints: Coincidence, Fixed
4. Constraints: Horizontal, Vertical, Parallel, Perpendicular
5. Constraints: Distance, Length
6. Correct multi-coincidence of points
7. Constraints: Angle, Equal, Tangent
8. Replace list of base constraints in SketchSolver_Constraint by a single constraint
9. Constraint Mirror
10. Fix problem in arc movement
11. Multi-Rotation and Multi-Translation constraints
12. Process parametric values
13. Problem with mirror of an arc
14. Update multi-coincidence processing (several coincident points placed on single feature)

68 files changed:
src/Config/plugins.xml
src/SketchPlugin/Test/TestConstraintRigid.py
src/SketchSolver/CMakeLists.txt
src/SketchSolver/SketchSolver.h
src/SketchSolver/SketchSolver_Builder.cpp
src/SketchSolver/SketchSolver_Builder.h
src/SketchSolver/SketchSolver_Constraint.cpp
src/SketchSolver/SketchSolver_Constraint.h
src/SketchSolver/SketchSolver_ConstraintAngle.cpp
src/SketchSolver/SketchSolver_ConstraintAngle.h
src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp
src/SketchSolver/SketchSolver_ConstraintCoincidence.h
src/SketchSolver/SketchSolver_ConstraintDistance.cpp
src/SketchSolver/SketchSolver_ConstraintDistance.h
src/SketchSolver/SketchSolver_ConstraintEqual.cpp
src/SketchSolver/SketchSolver_ConstraintEqual.h
src/SketchSolver/SketchSolver_ConstraintFillet.cpp [deleted file]
src/SketchSolver/SketchSolver_ConstraintFillet.h [deleted file]
src/SketchSolver/SketchSolver_ConstraintFixed.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintFixed.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintLength.cpp
src/SketchSolver/SketchSolver_ConstraintLength.h
src/SketchSolver/SketchSolver_ConstraintManager.cpp [deleted file]
src/SketchSolver/SketchSolver_ConstraintManager.h [deleted file]
src/SketchSolver/SketchSolver_ConstraintMirror.cpp
src/SketchSolver/SketchSolver_ConstraintMirror.h
src/SketchSolver/SketchSolver_ConstraintMovement.cpp
src/SketchSolver/SketchSolver_ConstraintMovement.h
src/SketchSolver/SketchSolver_ConstraintMulti.cpp
src/SketchSolver/SketchSolver_ConstraintMulti.h
src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp
src/SketchSolver/SketchSolver_ConstraintMultiRotation.h
src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp
src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h
src/SketchSolver/SketchSolver_ConstraintParametric.cpp [deleted file]
src/SketchSolver/SketchSolver_ConstraintParametric.h [deleted file]
src/SketchSolver/SketchSolver_ConstraintRigid.cpp [deleted file]
src/SketchSolver/SketchSolver_ConstraintRigid.h [deleted file]
src/SketchSolver/SketchSolver_ConstraintTangent.cpp
src/SketchSolver/SketchSolver_ConstraintTangent.h
src/SketchSolver/SketchSolver_FeatureStorage.cpp [deleted file]
src/SketchSolver/SketchSolver_FeatureStorage.h [deleted file]
src/SketchSolver/SketchSolver_Group.cpp
src/SketchSolver/SketchSolver_Group.h
src/SketchSolver/SketchSolver_IConstraintWrapper.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_IEntityWrapper.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_IParameterWrapper.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_ISolver.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_Manager.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_Manager.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_Solver.cpp [deleted file]
src/SketchSolver/SketchSolver_Solver.h [deleted file]
src/SketchSolver/SketchSolver_Storage.cpp
src/SketchSolver/SketchSolver_Storage.h
src/SketchSolver/SolveSpaceSolver/CMakeLists.txt [new file with mode: 0644]
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.cpp [new file with mode: 0644]
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.h [new file with mode: 0644]
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintType.h [new file with mode: 0644]
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.cpp [new file with mode: 0644]
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.h [new file with mode: 0644]
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.cpp [new file with mode: 0644]
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.h [new file with mode: 0644]
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.cpp [new file with mode: 0644]
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.h [new file with mode: 0644]
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.cpp [new file with mode: 0644]
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.h [new file with mode: 0644]
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.cpp [new file with mode: 0644]
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.h [new file with mode: 0644]

index a8b4b231557d5d2eb66c78a90d58e77ba0de63c9..45903311b7f071242080f25252c200b1d57d4171 100644 (file)
@@ -12,7 +12,7 @@
   <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="SketchSolver"/>
+  <plugin library="SolveSpaceSolver"/>
   <plugin library="GeomValidators"/>
   <plugin library="DFBrowser" internal="true"/>
 </plugins>
index 6a3a352c985c77bd3f9d2f69d733d7f5ef5cd521..b40ffcd420b48f806b20694300e10dc2d3a7e33a 100644 (file)
@@ -112,7 +112,20 @@ assert (kLineBEnd == (aLineBEndPoint.x(),   aLineBEndPoint.y()))
 assert (kLineCStart == (aLineCStartPoint.x(), aLineCStartPoint.y()))
 assert (kLineCEnd == (aLineCEndPoint.x(),   aLineCEndPoint.y()))
 #=========================================================================
-# Check that
+# Check that moving line A does not affect lines
+#=========================================================================
+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()))
+#=========================================================================
+# Check that moving line B does not affect lines
 #=========================================================================
 aSession.startOperation()
 aLineBEndPoint.setValue(90., 150.)
index 126fb212e7c6cddf5886afbd8a885f0bf7fe2b93..89ddc57102b2e5fa488f4fcdc839f9dfdbe6b6a2 100644 (file)
@@ -1,60 +1,54 @@
 ## Copyright (C) 2014-20xx CEA/DEN, EDF R&D
 
 INCLUDE(Common)
-FIND_PACKAGE(SolveSpace REQUIRED)
 
 SET(PROJECT_HEADERS
     SketchSolver.h
     SketchSolver_Error.h
-    SketchSolver_Solver.h
     SketchSolver_Constraint.h
     SketchSolver_ConstraintAngle.h
     SketchSolver_ConstraintCoincidence.h
     SketchSolver_ConstraintDistance.h
     SketchSolver_ConstraintEqual.h
-    SketchSolver_ConstraintFillet.h
     SketchSolver_ConstraintLength.h
     SketchSolver_ConstraintMirror.h
-    SketchSolver_ConstraintRigid.h
+    SketchSolver_ConstraintFixed.h
     SketchSolver_ConstraintTangent.h
     SketchSolver_ConstraintMulti.h
     SketchSolver_ConstraintMultiRotation.h
     SketchSolver_ConstraintMultiTranslation.h
     SketchSolver_ConstraintMovement.h
-    SketchSolver_ConstraintParametric.h
-    SketchSolver_Builder.h
     SketchSolver_Group.h
-    SketchSolver_ConstraintManager.h
+    SketchSolver_Builder.h
+    SketchSolver_IConstraintWrapper.h
+    SketchSolver_IEntityWrapper.h
+    SketchSolver_IParameterWrapper.h
+    SketchSolver_ISolver.h
+    SketchSolver_Manager.h
     SketchSolver_Storage.h
-    SketchSolver_FeatureStorage.h
 )
 
 SET(PROJECT_SOURCES
-    SketchSolver_Solver.cpp
     SketchSolver_Constraint.cpp
     SketchSolver_ConstraintAngle.cpp
     SketchSolver_ConstraintCoincidence.cpp
     SketchSolver_ConstraintDistance.cpp
     SketchSolver_ConstraintEqual.cpp
-    SketchSolver_ConstraintFillet.cpp
     SketchSolver_ConstraintLength.cpp
     SketchSolver_ConstraintMirror.cpp
-    SketchSolver_ConstraintRigid.cpp
+    SketchSolver_ConstraintFixed.cpp
     SketchSolver_ConstraintTangent.cpp
     SketchSolver_ConstraintMulti.cpp
     SketchSolver_ConstraintMultiRotation.cpp
     SketchSolver_ConstraintMultiTranslation.cpp
-    SketchSolver_ConstraintParametric.cpp
     SketchSolver_ConstraintMovement.cpp
-    SketchSolver_Builder.cpp
     SketchSolver_Group.cpp
-    SketchSolver_ConstraintManager.cpp
+    SketchSolver_Builder.cpp
+    SketchSolver_Manager.cpp
     SketchSolver_Storage.cpp
-    SketchSolver_FeatureStorage.cpp
 )
 
 SET(PROJECT_LIBRARIES
-    ${SOLVESPACE_LIBRARIES}
     Config
     Events
     ModelAPI
@@ -62,7 +56,6 @@ SET(PROJECT_LIBRARIES
 )
 
 INCLUDE_DIRECTORIES(
-    ${SOLVESPACE_INCLUDE_DIRS}
     ${PROJECT_SOURCE_DIR}/src/Config
     ${PROJECT_SOURCE_DIR}/src/SketchPlugin
     ${PROJECT_SOURCE_DIR}/src/ModelAPI
@@ -73,10 +66,30 @@ INCLUDE_DIRECTORIES(
 
 ADD_DEFINITIONS(-DSKETCHSOLVER_EXPORTS)
 
-ADD_LIBRARY(SketchSolver MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS}
+ADD_LIBRARY(SketchSolver SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS}
 )
 
 TARGET_LINK_LIBRARIES(SketchSolver ${PROJECT_LIBRARIES}
 )
 
 INSTALL(TARGETS SketchSolver DESTINATION plugins)
+
+
+# Include specific solvers
+FIND_FILE(SSPath "SolveSpaceSolver/CMakeLists.txt" PATHS "${CMAKE_CURRENT_SOURCE_DIR}")
+STRING(COMPARE NOTEQUAL ${SSPath} "SSPath-NOTFOUND" SSPath_FOUND)
+FIND_FILE(GCSPath "PlainGCSSolver/CMakeLists.txt" PATHS "${CMAKE_CURRENT_SOURCE_DIR}")
+STRING(COMPARE NOTEQUAL ${GCSPath} "GCSPath-NOTFOUND" GCSPath_FOUND)
+
+IF(${SSPath_FOUND} OR ${GCSPath_FOUND})
+  IF(${SSPath_FOUND})
+    MESSAGE(STATUS "SolveSpaceSolver plugin found in ${SSPath}")
+    ADD_SUBDIRECTORY(SolveSpaceSolver)
+  ENDIF()
+  IF(${GCSPath_FOUND})
+    MESSAGE(STATUS "PlainGCSSolver plugin found in ${GCSPath}")
+    ADD_SUBDIRECTORY(PlainGCSSolver)
+  ENDIF()
+ELSE()
+  MESSAGE(WARNING "No sketch solver plugin is found")
+ENDIF()
index cc5013f6ed163cf32b89d7b19ac2f346652ab826..56fa1dba25eba093e0041f1de7595e83b29080ee 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef SKETCHSOLVER_H
 #define SKETCHSOLVER_H
 
+#include <stdlib.h>
+
 #if defined SKETCHSOLVER_EXPORTS
 #if defined WIN32
 #define SKETCHSOLVER_EXPORT              __declspec( dllexport )
@@ -22,4 +24,18 @@ const double tolerance = 1.e-10;
 
 #define PI 3.1415926535897932
 
+// Types for data entities enumeration
+typedef size_t GroupID;
+typedef size_t ParameterID;
+typedef size_t EntityID;
+typedef size_t ConstraintID;
+
+// Predefined values for identifiers
+const GroupID       GID_UNKNOWN    = 0;
+const GroupID       GID_OUTOFGROUP = 1;
+
+const ParameterID   PID_UNKNOWN    = 0;
+const EntityID      EID_UNKNOWN    = 0;
+const ConstraintID  CID_UNKNOWN    = 0;
+
 #endif
index 78bfc59bb19eff477c4c13b367ec68f81425fe58..c01e8817a418d2951a545b288dc6c7a3e3d5881d 100644 (file)
@@ -5,66 +5,40 @@
 // Author:  Artem ZHIDKOV
 
 #include "SketchSolver_Builder.h"
-#include <SketchPlugin_ConstraintAngle.h>
+#include <SketchSolver_Constraint.h>
 #include <SketchSolver_ConstraintAngle.h>
 #include <SketchSolver_ConstraintCoincidence.h>
 #include <SketchSolver_ConstraintDistance.h>
 #include <SketchSolver_ConstraintEqual.h>
-#include <SketchSolver_ConstraintFillet.h>
+#include <SketchSolver_ConstraintFixed.h>
 #include <SketchSolver_ConstraintLength.h>
 #include <SketchSolver_ConstraintMirror.h>
-#include <SketchSolver_ConstraintRigid.h>
 #include <SketchSolver_ConstraintTangent.h>
 #include <SketchSolver_ConstraintMultiRotation.h>
 #include <SketchSolver_ConstraintMultiTranslation.h>
 #include <SketchSolver_ConstraintMovement.h>
-#include <SketchSolver_ConstraintParametric.h>
-#include <SketchSolver_Error.h>
 
-#include <GeomAPI_Edge.h>
-#include <GeomDataAPI_Dir.h>
-#include <GeomDataAPI_Point.h>
-#include <GeomDataAPI_Point2D.h>
+#ifdef _DEBUG
 #include <Events_Error.h>
-#include <ModelAPI_Attribute.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefAttr.h>
 #include <ModelAPI_AttributeRefList.h>
 #include <ModelAPI_ResultConstruction.h>
+#include <SketchSolver_Error.h>
+#endif
 
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
+#include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
 #include <SketchPlugin_ConstraintDistance.h>
 #include <SketchPlugin_ConstraintEqual.h>
-#include <SketchPlugin_ConstraintFillet.h>
-#include <SketchPlugin_ConstraintHorizontal.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintMirror.h>
-#include <SketchPlugin_ConstraintParallel.h>
-#include <SketchPlugin_ConstraintPerpendicular.h>
-#include <SketchPlugin_ConstraintRadius.h>
 #include <SketchPlugin_ConstraintRigid.h>
 #include <SketchPlugin_ConstraintTangent.h>
-#include <SketchPlugin_ConstraintVertical.h>
 #include <SketchPlugin_MultiRotation.h>
 #include <SketchPlugin_MultiTranslation.h>
 
 #include <math.h>
 
-// Initialization of constraint builder self pointer
-SketchSolver_Builder* SketchSolver_Builder::mySelf = 0;
-
-SketchSolver_Builder* SketchSolver_Builder::getInstance()
-{
-  if (!mySelf)
-    mySelf = new SketchSolver_Builder();
-  return mySelf;
-}
-
-SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theConstraint)
+SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theConstraint) const
 {
   SolverConstraintPtr aResult;
   DataPtr aData = theConstraint->data();
@@ -106,26 +80,14 @@ SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theCons
     return SolverConstraintPtr(new SketchSolver_ConstraintDistance(theConstraint));
   } else if (theConstraint->getKind() == SketchPlugin_ConstraintEqual::ID()) {
     return SolverConstraintPtr(new SketchSolver_ConstraintEqual(theConstraint));
-  } else if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
-    return SolverConstraintPtr(new SketchSolver_ConstraintFillet(theConstraint));
-  } else if (theConstraint->getKind() == SketchPlugin_ConstraintHorizontal::ID()) {
-    return SolverConstraintPtr(new SketchSolver_ConstraintHorizontal(theConstraint));
   } else if (theConstraint->getKind() == SketchPlugin_ConstraintLength::ID()) {
     return SolverConstraintPtr(new SketchSolver_ConstraintLength(theConstraint));
   } else if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
     return SolverConstraintPtr(new SketchSolver_ConstraintMirror(theConstraint));
-  } else if (theConstraint->getKind() == SketchPlugin_ConstraintParallel::ID()) {
-    return SolverConstraintPtr(new SketchSolver_ConstraintParallel(theConstraint));
-  } else if (theConstraint->getKind() == SketchPlugin_ConstraintPerpendicular::ID()) {
-    return SolverConstraintPtr(new SketchSolver_ConstraintPerpendicular(theConstraint));
-  } else if (theConstraint->getKind() == SketchPlugin_ConstraintRadius::ID()) {
-    return SolverConstraintPtr(new SketchSolver_ConstraintRadius(theConstraint));
   } else if (theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID()) {
     return SolverConstraintPtr(new SketchSolver_ConstraintTangent(theConstraint));
-  } else if (theConstraint->getKind() == SketchPlugin_ConstraintVertical::ID()) {
-    return SolverConstraintPtr(new SketchSolver_ConstraintVertical(theConstraint));
   } else if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) {
-    return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theConstraint));
+    return SolverConstraintPtr(new SketchSolver_ConstraintFixed(theConstraint));
   } else if (theConstraint->getKind() == SketchPlugin_MultiTranslation::ID()) {
     return SolverConstraintPtr(new SketchSolver_ConstraintMultiTranslation(theConstraint));
   } else if (theConstraint->getKind() == SketchPlugin_MultiRotation::ID()) {
@@ -133,18 +95,19 @@ SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theCons
   } else if (theConstraint->getKind() == SketchPlugin_ConstraintAngle::ID()) {
     return SolverConstraintPtr(new SketchSolver_ConstraintAngle(theConstraint));
   }
-  return aResult;
+  // All other types of constraints
+  return SolverConstraintPtr(new SketchSolver_Constraint(theConstraint));
 }
 
-SolverConstraintPtr SketchSolver_Builder::createRigidConstraint(FeaturePtr theFixedFeature)
+SolverConstraintPtr SketchSolver_Builder::createFixedConstraint(FeaturePtr theFixedFeature) const
 {
   DataPtr aData = theFixedFeature->data();
   if (!aData || !aData->isValid())
     return SolverConstraintPtr();
-  return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theFixedFeature));
+  return SolverConstraintPtr(new SketchSolver_ConstraintFixed(theFixedFeature));
 }
 
-SolverConstraintPtr SketchSolver_Builder::createMovementConstraint(FeaturePtr theFixedFeature)
+SolverConstraintPtr SketchSolver_Builder::createMovementConstraint(FeaturePtr theFixedFeature) const
 {
   DataPtr aData = theFixedFeature->data();
   if (!aData || !aData->isValid())
@@ -152,185 +115,35 @@ SolverConstraintPtr SketchSolver_Builder::createMovementConstraint(FeaturePtr th
   return SolverConstraintPtr(new SketchSolver_ConstraintMovement(theFixedFeature));
 }
 
-SolverConstraintPtr SketchSolver_Builder::createParametricConstraint(AttributePtr theAttribute)
+std::shared_ptr<GeomAPI_Pnt2d> SketchSolver_Builder::point(EntityWrapperPtr theEntity) const
 {
-  return SolverConstraintPtr(new SketchSolver_ConstraintParametric(theAttribute));
+  if (theEntity->type() != ENTITY_POINT)
+    return std::shared_ptr<GeomAPI_Pnt2d>();
+
+  double aXY[2];
+  std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
+  std::list<ParameterWrapperPtr>::const_iterator anIt = aParams.begin();
+  for (int i = 0; i < 2 && anIt != aParams.end(); ++i, ++anIt)
+    aXY[i] = (*anIt)->value();
+  if (anIt != aParams.end())
+    return std::shared_ptr<GeomAPI_Pnt2d>();
+
+  return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aXY[0], aXY[1]));
 }
 
-
-
-bool SketchSolver_Builder::createWorkplane(
-    CompositeFeaturePtr theSketch,
-    std::vector<Slvs_Entity>& theEntities,
-    std::vector<Slvs_Param>& theParameters)
+std::shared_ptr<GeomAPI_Lin2d> SketchSolver_Builder::line(EntityWrapperPtr theEntity) const
 {
-  DataPtr aSketchData = theSketch->data();
-  if (!aSketchData || !aSketchData->isValid())
-    return false; // the sketch is incorrect
-
-  // Get parameters of workplane
-  std::shared_ptr<ModelAPI_Attribute> aDirX = aSketchData->attribute(
-      SketchPlugin_Sketch::DIRX_ID());
-  std::shared_ptr<ModelAPI_Attribute> aNorm = aSketchData->attribute(
-      SketchPlugin_Sketch::NORM_ID());
-  std::shared_ptr<ModelAPI_Attribute> anOrigin = aSketchData->attribute(
-      SketchPlugin_Sketch::ORIGIN_ID());
-  // Create SolveSpace entity corresponding to the sketch origin
-  if (!createEntity(anOrigin, theEntities, theParameters))
-    return false;
-  Slvs_hEntity anOriginID = theEntities.back().h;
-  // Create SolveSpace entity corresponding the the sketch normal
-  if (!createNormal(aNorm, aDirX, theEntities, theParameters))
-    return false;
-  Slvs_hEntity aNormalID = theEntities.back().h;
-
-  // Create workplane
-  Slvs_hEntity aWorkplaneID = theEntities.back().h + 1;
-  Slvs_Entity aWorkplane = Slvs_MakeWorkplane(aWorkplaneID, SLVS_G_UNKNOWN, anOriginID, aNormalID);
-  theEntities.push_back(aWorkplane);
-  return true;
+  if (theEntity->type() != ENTITY_LINE)
+    return std::shared_ptr<GeomAPI_Lin2d>();
+
+  std::shared_ptr<GeomAPI_Pnt2d> aPoints[2];
+  std::list<EntityWrapperPtr> aSubs = theEntity->subEntities();
+  std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
+  for (int i = 0; i < 2 && anIt != aSubs.end(); ++i, ++anIt)
+    aPoints[i] = point(*anIt);
+  if (anIt != aSubs.end())
+    return std::shared_ptr<GeomAPI_Lin2d>();
+
+  return std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0], aPoints[1]));
 }
 
-bool SketchSolver_Builder::createEntity(
-    AttributePtr theAttribute,
-    std::vector<Slvs_Entity>& theEntities,
-    std::vector<Slvs_Param>& theParameters)
-{
-  Slvs_hEntity anEntID = theEntities.empty() ? 0 : theEntities.back().h;
-  Slvs_hParam aParamID = theParameters.empty() ? 0 : theParameters.back().h;
-
-  // Point in 3D
-  std::shared_ptr<GeomDataAPI_Point> aPoint =
-      std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
-  if (aPoint) {
-    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->x()));
-    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->y()));
-    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->z()));
-    theEntities.push_back(Slvs_MakePoint3d(++anEntID, SLVS_G_UNKNOWN,
-        aParamID-2, aParamID-1, aParamID));
-    return true;
-  }
-  // Point in 2D
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
-  if (aPoint2D) {
-    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->x()));
-    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->y()));
-    theEntities.push_back(Slvs_MakePoint2d(++anEntID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
-      aParamID-1, aParamID));
-    return true;
-  }
-  // Scalar value (used for the distance entities)
-  AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
-  if (aScalar) {
-    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aScalar->value()));
-    theEntities.push_back(Slvs_MakeDistance(++anEntID, SLVS_G_UNKNOWN,
-      SLVS_E_UNKNOWN, aParamID));
-    return true;
-  }
-  // unknown attribute type
-  return false;
-}
-
-bool SketchSolver_Builder::createEntity(
-    FeaturePtr theFeature,
-    std::vector<Slvs_Entity>& theEntities,
-    std::vector<Slvs_Param>& theParameters)
-{
-  if (!theFeature->data()->isValid())
-    return false;
-
-  // SketchPlugin features
-  std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
-      SketchPlugin_Feature>(theFeature);
-  if (!aFeature)
-    return false;
-
-  // Verify the feature by its kind
-  const std::string& aFeatureKind = aFeature->getKind();
-  DataPtr aData = aFeature->data();
-  // Line
-  if (aFeatureKind == SketchPlugin_Line::ID()) {
-    AttributePtr aStart = aData->attribute(SketchPlugin_Line::START_ID());
-    AttributePtr aEnd = aData->attribute(SketchPlugin_Line::END_ID());
-    if (!aStart->isInitialized() || !aEnd->isInitialized())
-      return false;
-    if (!createEntity(aStart, theEntities, theParameters) ||
-        !createEntity(aEnd, theEntities, theParameters))
-      return false;
-    Slvs_hEntity aLineID = theEntities.back().h + 1;
-    theEntities.push_back(Slvs_MakeLineSegment(aLineID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
-        aLineID-2, aLineID-1));
-  }
-  // Circle
-  else if (aFeatureKind == SketchPlugin_Circle::ID()) {
-    AttributePtr aCenter = aData->attribute(SketchPlugin_Circle::CENTER_ID());
-    AttributePtr aRadius = aData->attribute(SketchPlugin_Circle::RADIUS_ID());
-    if (!aCenter->isInitialized() || !aRadius->isInitialized())
-      return false;
-    if (!createEntity(aCenter, theEntities, theParameters) ||
-        !createEntity(aRadius, theEntities, theParameters))
-      return false;
-    Slvs_hEntity aCircID = theEntities.back().h;
-    theEntities.push_back(Slvs_MakeCircle(aCircID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, aCircID-2,
-      SLVS_E_UNKNOWN, aCircID-1));
-  }
-  // Arc
-  else if (aFeatureKind == SketchPlugin_Arc::ID()) {
-    AttributePtr aCenter = aData->attribute(SketchPlugin_Arc::CENTER_ID());
-    AttributePtr aStart = aData->attribute(SketchPlugin_Arc::START_ID());
-    AttributePtr aEnd = aData->attribute(SketchPlugin_Arc::END_ID());
-    if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
-      return false;
-    if (!createEntity(aCenter, theEntities, theParameters) ||
-        !createEntity(aStart, theEntities, theParameters) ||
-        !createEntity(aEnd, theEntities, theParameters))
-      return false;
-    Slvs_hEntity anArcID = theEntities.back().h;
-    theEntities.push_back(Slvs_MakeArcOfCircle(anArcID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
-        SLVS_E_UNKNOWN, anArcID-3, anArcID-2, anArcID-1));
-  }
-  // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
-  else if (aFeatureKind == SketchPlugin_Point::ID()) {
-    AttributePtr aPoint = aData->attribute(SketchPlugin_Point::COORD_ID());
-    if (!aPoint->isInitialized() ||
-        !createEntity(aPoint, theEntities, theParameters))
-      return false;
-    // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier.
-    // No need to add another entity.
-  }
-  return true;
-}
-
-bool SketchSolver_Builder::createNormal(
-    AttributePtr theNormal,
-    AttributePtr theDirX,
-    std::vector<Slvs_Entity>& theEntities,
-    std::vector<Slvs_Param>& theParameters)
-{
-  std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
-  std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
-  if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) || 
-      !aNorm->isInitialized())
-    return false;
-  // calculate Y direction
-  std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
-
-  // quaternion parameters of normal vector
-  double qw, qx, qy, qz;
-  Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
-                      &qx, &qy, &qz);
-  double aNormCoord[4] = { qw, qx, qy, qz };
-
-  // Create parameters of the normal
-  Slvs_hParam aCurParam = theParameters.back().h;
-  for (int i = 0; i < 4; i++)
-    theParameters.push_back(Slvs_MakeParam(++aCurParam, SLVS_G_UNKNOWN, aNormCoord[i]));
-
-  // Create a normal
-  Slvs_hEntity aCurEntity = theEntities.back().h + 1;
-  Slvs_Entity aNormal = Slvs_MakeNormal3d(aCurEntity, SLVS_G_UNKNOWN,
-      aCurParam-3, aCurParam-2, aCurParam-1, aCurParam);
-  theEntities.push_back(aNormal);
-  return true;
-}
index 21beac3191fe136cf2f47f8a38d055f213b29ea3..3da7e2fd7e958fe7b64c3c4cd91151d02ad0814b 100644 (file)
 #ifndef SketchSolver_Builder_H_
 #define SketchSolver_Builder_H_
 
-#include "SketchSolver.h"
 #include <SketchSolver_Constraint.h>
-
 #include <SketchPlugin_Constraint.h>
 
-#include <ModelAPI_CompositeFeature.h>
+#include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Pnt2d.h>
 
 /** \class   SketchSolver_Builder
  *  \ingroup Plugins
- *  \brief   Create bridges between SketchPlugin constraints and SolveSpace constraints
+ *  \brief   Abstract class for builders of solver's entities
  */
 class SketchSolver_Builder
 {
-private:
-  /// Default constructor
-  SketchSolver_Builder() {}
-
 public:
-  /// \brief Returns single instance of builder
-  static SketchSolver_Builder* getInstance();
+  /// \brief Creates a storage specific for used solver
+  virtual StoragePtr createStorage(const GroupID& theGroup) const = 0;
+  /// \brief Creates specific solver
+  virtual SolverPtr createSolver() const = 0;
 
   /// \brief Creates a solver's constraint using given SketchPlugin constraint
   ///        or returns empty pointer if not all attributes are correct
-  SolverConstraintPtr createConstraint(ConstraintPtr theConstraint);
+  SolverConstraintPtr createConstraint(ConstraintPtr theConstraint) const;
 
   /// \brief Creates temporary constraint to fix the placement of the feature
-  SolverConstraintPtr createRigidConstraint(FeaturePtr theFixedFeature);
+  SolverConstraintPtr createFixedConstraint(FeaturePtr theFixedFeature) const;
 
   /// \brief Creates temporary constraint to fix the feature after movement
-  SolverConstraintPtr createMovementConstraint(FeaturePtr theFixedFeature);
-
-  /// \brief Creates constraint for parametrically given attribute
-  SolverConstraintPtr createParametricConstraint(AttributePtr theAttribute);
-
-  /// \brief Converts sketch parameters to the list of SolveSpace entities.
-  ///        Identifiers of entities and parameters are local. They should be changed while adding into storage.
-  ///        The sketch entity goes last.
-  /// \param[in]  theSketch     the element to be converted
-  /// \param[out] theEntities   created list of entities
-  /// \param[out] theParameters created list of parameters of the entities
-  /// \return \c true if workplane created
-  bool createWorkplane(CompositeFeaturePtr theSketch,
-                       std::vector<Slvs_Entity>& theEntities,
-                       std::vector<Slvs_Param>& theParameters);
-
-  /// \brief Converts attribute to the list of entities.
-  ///        Identifiers are local (see createWorkplane).
-  ///        The main entity goes last.
-  bool createEntity(AttributePtr theAttribute,
-                    std::vector<Slvs_Entity>& theEntities,
-                    std::vector<Slvs_Param>& theParameters);
-  /// \brief Converts feature to the list of entities.
-  ///        Identifiers are local (see createWorkplane).
-  ///        The main entity goes last.
-  bool createEntity(FeaturePtr theFeature,
-                    std::vector<Slvs_Entity>& theEntities,
-                    std::vector<Slvs_Param>& theParameters);
-
-  /// \brief Converts normal and OX direction to the list of entities representing a normal in SolveSpace.
-  ///        Identifiers are local (see createWorkplane).
-  ///        The main entity goes last.
-  bool createNormal(AttributePtr theNormal,
-                    AttributePtr theDirX,
-                    std::vector<Slvs_Entity>& theEntities,
-                    std::vector<Slvs_Param>& theParameters);
-
-private:
-  static SketchSolver_Builder* mySelf;
+  SolverConstraintPtr createMovementConstraint(FeaturePtr theFixedFeature) 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& theGroup,
+                     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 = 0;
+
+  /// \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& theGroup,
+                     const EntityID& theSketchID,
+                     const SketchSolver_ConstraintType& theType,
+                     const double& theValue,
+                     const EntityWrapperPtr& thePoint1,
+                     const EntityWrapperPtr& thePoint2,
+                     const std::list<EntityWrapperPtr>& theTrsfEnt) const = 0;
+
+  /// \brief Update flags for several kinds of constraints
+  virtual void adjustConstraint(ConstraintWrapperPtr theConstraint) const = 0;
+
+  /// \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 = 0;
+
+  /// \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 = 0;
+
+
+  /// \brief Convert entity to point
+  /// \return empty pointer if the entity is not a point
+  SKETCHSOLVER_EXPORT std::shared_ptr<GeomAPI_Pnt2d> point(EntityWrapperPtr theEntity) const;
+  /// \brief Convert entity to line
+  /// \return empty pointer if the entity is not a line
+  SKETCHSOLVER_EXPORT std::shared_ptr<GeomAPI_Lin2d> line(EntityWrapperPtr theEntity) const;
 };
 
+typedef std::shared_ptr<SketchSolver_Builder> BuilderPtr;
+
 #endif
index b4b888fa3b75607f333ce26e27e8779247068f31..e5a2b695ba505acfce62299472941f126194bce4 100644 (file)
@@ -1,12 +1,27 @@
 #include <SketchSolver_Constraint.h>
 #include <SketchSolver_Group.h>
 #include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
 
+#include <SketchPlugin_ConstraintAngle.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintEqual.h>
+#include <SketchPlugin_ConstraintHorizontal.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintParallel.h>
+#include <SketchPlugin_ConstraintPerpendicular.h>
+#include <SketchPlugin_ConstraintRadius.h>
+#include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_ConstraintVertical.h>
+
 #include <GeomAPI_Dir2d.h>
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
 SketchSolver_Constraint::SketchSolver_Constraint(
     ConstraintPtr  theConstraint)
   : myBaseConstraint(theConstraint),
-    myGroup(0)
-{
-}
-
-SketchSolver_Constraint::~SketchSolver_Constraint()
+    myGroupID(GID_UNKNOWN),
+    myType(CONSTRAINT_UNKNOWN)
 {
-  std::map<AttributePtr, Slvs_hParam>::const_iterator anIt1 = myValueMap.begin();
-  for (; anIt1 != myValueMap.end(); anIt1++)
-    myStorage->removeParameter(anIt1->second);
-  myValueMap.clear();
-
-  std::map<AttributePtr, Slvs_hEntity>::const_iterator anIt2 = myAttributeMap.begin();
-  for (; anIt2 != myAttributeMap.end(); anIt2++)
-    myStorage->removeEntity(anIt2->second);
-  myAttributeMap.clear();
-
-  std::map<FeaturePtr, Slvs_hEntity>::iterator anIt3 =  myFeatureMap.begin();
-  while (!myFeatureMap.empty()) {
-    std::shared_ptr<SketchPlugin_Feature> aFeature =
-        std::dynamic_pointer_cast<SketchPlugin_Feature>(anIt3->first);
-    Slvs_hEntity anEnt = anIt3->second;
-    std::map<FeaturePtr, Slvs_hEntity>::iterator aRemIt = anIt3++;
-    myFeatureMap.erase(aRemIt);
-    if (!myGroup->isInteract(aFeature))
-      myStorage->removeEntity(anEnt);
-  }
-
-  std::vector<Slvs_hConstraint>::const_iterator anIt4 = mySlvsConstraints.begin();
-  for (; anIt4 != mySlvsConstraints.end(); anIt4++)
-    myStorage->removeConstraint(*anIt4);
-  mySlvsConstraints.clear();
 }
 
-void SketchSolver_Constraint::setStorage(StoragePtr theStorage)
+void SketchSolver_Constraint::process(StoragePtr theStorage,
+                                      const GroupID& theGroupID,
+                                      const EntityID& theSketchID)
 {
   myStorage = theStorage;
+  myGroupID = theGroupID;
+  mySketchID = theSketchID;
+  // Process constraint according to its type
   process();
 }
 
-void SketchSolver_Constraint::setGroup(SketchSolver_Group* theGroup)
-{
-  myGroup = theGroup;
-  process();
-}
 
-void SketchSolver_Constraint::addFeature(FeaturePtr theFeature)
-{
-  int aType;
-  changeEntity(theFeature, aType);
+SketchSolver_ConstraintType SketchSolver_Constraint::TYPE(ConstraintPtr theConstraint)
+{
+  const std::string& aType = theConstraint->getKind();
+  if (aType == SketchPlugin_ConstraintCoincidence::ID())
+    return CONSTRAINT_COINCIDENCE;
+  else if (aType == SketchPlugin_ConstraintRigid::ID())
+    return CONSTRAINT_FIXED;
+  else if (aType == SketchPlugin_ConstraintHorizontal::ID())
+    return CONSTRAINT_HORIZONTAL;
+  else if (aType == SketchPlugin_ConstraintVertical::ID())
+    return CONSTRAINT_VERTICAL;
+  else if (aType == SketchPlugin_ConstraintAngle::ID())
+    return CONSTRAINT_ANGLE;
+  else if (aType == SketchPlugin_ConstraintDistance::ID())
+    return CONSTRAINT_DISTANCE;
+  else if (aType == SketchPlugin_ConstraintEqual::ID())
+    return CONSTRAINT_EQUAL;
+  else if (aType == SketchPlugin_ConstraintLength::ID())
+    return CONSTRAINT_PT_PT_DISTANCE;
+  else if (aType == SketchPlugin_ConstraintMirror::ID())
+    return CONSTRAINT_SYMMETRIC;
+  else if (aType == SketchPlugin_ConstraintParallel::ID())
+    return CONSTRAINT_PARALLEL;
+  else if (aType == SketchPlugin_ConstraintPerpendicular::ID())
+    return CONSTRAINT_PERPENDICULAR;
+  else if (aType == SketchPlugin_ConstraintRadius::ID())
+    return CONSTRAINT_RADIUS;
+  else if (aType == SketchPlugin_ConstraintTangent::ID())
+    return CONSTRAINT_TANGENT;
+  return CONSTRAINT_UNKNOWN;
 }
 
-
 void SketchSolver_Constraint::process()
 {
   cleanErrorMsg();
-  if (!myBaseConstraint || !myStorage || myGroup == 0) {
-    /// TODO: Put error message here
+  if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) {
+    // Not enough parameters are assigned
     return;
   }
-  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-    update(myBaseConstraint);
 
-  int aConstrType = getType();
-  double aValue = 0.0;
-  std::vector<Slvs_hEntity> anAttributes;
+  SketchSolver_ConstraintType aConstrType = getType();
+  double aValue;
+  std::vector<EntityWrapperPtr> anAttributes;
   getAttributes(aValue, anAttributes);
   if (!myErrorMsg.empty())
     return;
-  if (aConstrType == SLVS_C_UNKNOWN)
+  if (anAttributes.empty()) {
+    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+    return;
+  }
+  if (aConstrType == CONSTRAINT_UNKNOWN)
     aConstrType = getType();
 
-  Slvs_hGroup aGroupID = myGroup->getId();
-  Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
-  Slvs_Constraint aConstraint;
-  if (mySlvsConstraints.empty())
-    aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, aGroupID, aConstrType, aWorkplaneID,
-        aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
-  else {
-    aConstraint = myStorage->getConstraint(mySlvsConstraints[0]);
-    aConstraint.valA = aValue;
-    static const int aNbAttrs = 6;
-    Slvs_hEntity* aConstrAttrs[aNbAttrs] = {
-        &aConstraint.ptA, &aConstraint.ptB,
-        &aConstraint.entityA, &aConstraint.entityB,
-        &aConstraint.entityC, &aConstraint.entityD};
-    std::vector<Slvs_hEntity>::const_iterator anIter = anAttributes.begin();
-    for (int i = 0; i < aNbAttrs && anIter != anAttributes.end(); i++, anIter++)
-      *(aConstrAttrs[i]) = *anIter;
-  }
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+  std::list<ConstraintWrapperPtr> aNewConstraints = aBuilder->createConstraint(
+      myBaseConstraint, myGroupID, mySketchID, aConstrType,
+      aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
+  myStorage->addConstraint(myBaseConstraint, aNewConstraints);
 
-  Slvs_hConstraint anID = myStorage->addConstraint(aConstraint);
-  if (mySlvsConstraints.empty())
-    mySlvsConstraints.push_back(anID);
-  else
-    mySlvsConstraints[0] = anID;
   adjustConstraint();
 }
 
-bool SketchSolver_Constraint::checkAttributesChanged(ConstraintPtr theConstraint)
-{
-  std::set<Slvs_hEntity> aCurAttrs; // list of currently used attributes
-  std::vector<Slvs_hConstraint>::const_iterator aConstrIter = mySlvsConstraints.begin();
-  for (; aConstrIter != mySlvsConstraints.end(); aConstrIter++) {
-    Slvs_Constraint aConstr = myStorage->getConstraint(*aConstrIter);
-    if (aConstr.ptA != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.ptA);
-    if (aConstr.ptB != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.ptB);
-    if (aConstr.entityA != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityA);
-    if (aConstr.entityB != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityB);
-    if (aConstr.entityC != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityC);
-    if (aConstr.entityD != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityD);
-  }
-  // Check the attrbutes of constraint are changed
-  ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
-  std::list<AttributePtr> anAttrList = aConstraint->data()->attributes(std::string());
-  std::list<AttributePtr>::iterator anAttrIter = anAttrList.begin();
-  for (; anAttrIter != anAttrList.end(); anAttrIter++) {
-    AttributeRefAttrPtr aRefAttr =
-        std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
-    if (aRefAttr) {
-      if (aRefAttr->isObject()) {
-        FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
-        std::map<FeaturePtr, Slvs_hEntity>::iterator aFIt = myFeatureMap.find(aFeature);
-        if (aFeature) {
-          if (aFIt == myFeatureMap.end())
-            return true;
-          // Additional check the points of entity
-          if (aCurAttrs.find(aFIt->second) == aCurAttrs.end()) {
-            Slvs_Entity anEntity = myStorage->getEntity(aFIt->second);
-            bool isFound = false;
-            for (int i = 0; i < 4 && !isFound; i++)
-              if (anEntity.point[i] != SLVS_E_UNKNOWN && 
-                  aCurAttrs.find(anEntity.point[i]) != aCurAttrs.end())
-                isFound = true;
-            if (!isFound)
-              return true;
-          }
-        }
-      } else if (aRefAttr->attr()) {
-        std::map<AttributePtr, Slvs_hEntity>::iterator anAIt = myAttributeMap.find(aRefAttr->attr());
-        if (anAIt == myAttributeMap.end() || aCurAttrs.find(anAIt->second) == aCurAttrs.end())
-          return true;
-      }
-    }
-    AttributeRefListPtr aRefList =
-        std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrIter);
-    if (aRefList) {
-      std::list<ObjectPtr> anItems = aRefList->list();
-      std::list<ObjectPtr>::iterator anIt = anItems.begin();
-      for (; anIt != anItems.end(); anIt++) {
-        FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
-        if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
-          return true;
-      }
-    }
-  }
-  return false;
-}
-
-void SketchSolver_Constraint::update(ConstraintPtr theConstraint)
+void SketchSolver_Constraint::update()
 {
   cleanErrorMsg();
-  bool needToRebuild = (theConstraint && theConstraint != myBaseConstraint);
-  if (!needToRebuild)
-    needToRebuild = checkAttributesChanged(theConstraint);
-  if (needToRebuild) {
-    if (theConstraint && theConstraint->getKind() != myBaseConstraint->getKind())
-      return;
-    remove(myBaseConstraint);
-    if (theConstraint)
-      myBaseConstraint = theConstraint;
-    process();
-    return;
-  }
 
-  // Update all attributes
-  int aType;
-  std::map<Slvs_hEntity, Slvs_hEntity> aRelocationMap;
-  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myFeatureMap.begin();
-  for (; aFeatIter != myFeatureMap.end(); aFeatIter++) {
-    Slvs_hEntity aPrevID = aFeatIter->second;
-    aFeatIter->second = changeEntity(aFeatIter->first, aType);
-    if (aFeatIter->second != aPrevID)
-      aRelocationMap[aPrevID] = aFeatIter->second;
-  }
-  std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
-  for (; anAttrIter != myAttributeMap.end(); anAttrIter++) {
-    Slvs_hEntity aPrevID = anAttrIter->second;
-    anAttrIter->second = changeEntity(anAttrIter->first, aType);
-    if (anAttrIter->second != aPrevID)
-      aRelocationMap[aPrevID] = anAttrIter->second;
-  }
-
-  // Value if exists
-  DataPtr aData = myBaseConstraint->data();
-  if (!aData) return;
+  std::list<ConstraintWrapperPtr> aWrapper = myStorage->constraint(myBaseConstraint);
   AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-    myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE()));
-  double aValue = aValueAttr ? aValueAttr->value() : 0.0;
-
-  // Update constraint
-  std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
-  for (; aCIter != mySlvsConstraints.end(); aCIter++) {
-    Slvs_Constraint aConstraint = myStorage->getConstraint(*aCIter);
-    if (aValueAttr) {
-      aConstraint.valA = aValue;
-      if (aConstraint.type == SLVS_C_DIAMETER)
-        aConstraint.valA *= 2.0;
-    }
-    Slvs_hEntity* aCoeffs[6] = {
-        &aConstraint.ptA, &aConstraint.ptB,
-        &aConstraint.entityA, &aConstraint.entityB,
-        &aConstraint.entityC, &aConstraint.entityD};
-    for (int i = 0; i < 6; i++) {
-      if (*(aCoeffs[i]) == SLVS_E_UNKNOWN)
-        continue;
-      std::map<Slvs_hEntity, Slvs_hEntity>::iterator aFound = aRelocationMap.find(*(aCoeffs[i]));
-      if (aFound != aRelocationMap.end())
-        *(aCoeffs[i]) = aFound->second;
-    }
-    *aCIter = myStorage->addConstraint(aConstraint);
+      myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE()));
+  if (aValueAttr) {
+    std::list<ConstraintWrapperPtr>::iterator aWIt = aWrapper.begin();
+    for (; aWIt != aWrapper.end(); ++aWIt)
+      (*aWIt)->setValue(aValueAttr->value());
   }
+  myStorage->addConstraint(myBaseConstraint, aWrapper);
+
   adjustConstraint();
 }
 
-bool SketchSolver_Constraint::remove(ConstraintPtr theConstraint)
+bool SketchSolver_Constraint::remove()
 {
   cleanErrorMsg();
-  if (theConstraint && theConstraint != myBaseConstraint)
-    return false;
-  if (mySlvsConstraints.empty())
-    return true;
-  bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints.front());
-  if (isFullyRemoved) {
-    myFeatureMap.clear();
-    myAttributeMap.clear();
-    myValueMap.clear();
-  } else
-    cleanRemovedEntities();
-  mySlvsConstraints.clear();
-  return true;
-}
-
-void SketchSolver_Constraint::cleanRemovedEntities()
-{
-  std::set<Slvs_hParam> aRemovedParams;
-  std::set<Slvs_hEntity> aRemovedEntities;
-  std::set<Slvs_hConstraint> aRemovedConstraints;
-  myStorage->getRemoved(aRemovedParams, aRemovedEntities, aRemovedConstraints);
-  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
-  while (aFeatIt != myFeatureMap.end()) {
-    if (aRemovedEntities.find(aFeatIt->second) == aRemovedEntities.end()) {
-      aFeatIt++;
-      continue;
-    }
-    std::map<FeaturePtr, Slvs_hEntity>::iterator aTmpIter = aFeatIt++;
-    myFeatureMap.erase(aTmpIter);
-  }
-  std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIt = myAttributeMap.begin();
-  while (anAttrIt != myAttributeMap.end()) {
-    if (aRemovedEntities.find(anAttrIt->second) == aRemovedEntities.end()) {
-      anAttrIt++;
-      continue;
-    }
-    std::map<AttributePtr, Slvs_hEntity>::iterator aTmpIter = anAttrIt++;
-    myAttributeMap.erase(aTmpIter);
-  }
-  std::map<AttributePtr, Slvs_hParam>::iterator aValIt = myValueMap.begin();
-  while (aValIt != myValueMap.end()) {
-    if (aRemovedParams.find(aValIt->second) == aRemovedParams.end()) {
-      aValIt++;
-      continue;
-    }
-    std::map<AttributePtr, Slvs_hParam>::iterator aTmpIter = aValIt++;
-    myValueMap.erase(aTmpIter);
-  }
-  for (size_t i = 0; i < mySlvsConstraints.size(); i++)
-    if (aRemovedConstraints.find(mySlvsConstraints[i]) != aRemovedConstraints.end()) {
-      mySlvsConstraints.erase(mySlvsConstraints.begin() + i);
-      i--;
-    }
+  return myStorage->removeConstraint(myBaseConstraint);
 }
 
 void SketchSolver_Constraint::getAttributes(
     double& theValue,
-    std::vector<Slvs_hEntity>& theAttributes)
+    std::vector<EntityWrapperPtr>& theAttributes)
 {
   static const int anInitNbOfAttr = 4;
-  theAttributes.assign(anInitNbOfAttr, SLVS_E_UNKNOWN);
+  theAttributes.assign(anInitNbOfAttr, EntityWrapperPtr());
 
   DataPtr aData = myBaseConstraint->data();
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+
+  myType = TYPE(myBaseConstraint);
 
   AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-    aData->attribute(SketchPlugin_Constraint::VALUE()));
+      aData->attribute(SketchPlugin_Constraint::VALUE()));
   theValue = aValueAttr ? aValueAttr->value() : 0.0;
 
   int aPtInd = 0; // index of first point in the list of attributes
-  int aEntInd = 2; // index of first antity in the list of attributes
+  int aEntInd = 2; // index of first entity in the list of attributes
   std::list<AttributePtr> aConstrAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId());
   std::list<AttributePtr>::iterator anIter = aConstrAttrs.begin();
   for (; anIter != aConstrAttrs.end(); anIter++) {
@@ -325,18 +163,13 @@ void SketchSolver_Constraint::getAttributes(
       return;
     }
 
-    int aType = SLVS_E_UNKNOWN; // type of created entity
-    Slvs_hEntity anEntity = myGroup->getAttributeId(aRefAttr);
-    if (anEntity == SLVS_E_UNKNOWN)
-      anEntity = changeEntity(aRefAttr, aType);
-    else {
-      Slvs_Entity anEnt = myStorage->getEntity(anEntity);
-      aType = anEnt.type;
-    }
+    myStorage->update(*anIter, myGroupID);
+    EntityWrapperPtr anEntity = myStorage->entity(*anIter);
 
-    if (aType == SLVS_E_UNKNOWN)
+    SketchSolver_EntityType aType = anEntity->type();
+    if (aType == ENTITY_UNKNOWN)
       continue;
-    else if (aType == SLVS_E_POINT_IN_2D || aType == SLVS_E_POINT_IN_3D)
+    else if (aType == ENTITY_POINT)
       theAttributes[aPtInd++] = anEntity; // the point is created
     else { // another entity (not a point) is created
       if (aEntInd < anInitNbOfAttr)
@@ -348,403 +181,45 @@ void SketchSolver_Constraint::getAttributes(
   }
 }
 
-Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributeRefAttrPtr theAttribute, int& theType)
-{
-  // Convert the object of the attribute to the feature
-  FeaturePtr aFeature;
-  if (theAttribute->isObject() && theAttribute->object()) {
-    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-        theAttribute->object());
-    if (!aRC) {
-      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
-      return SLVS_E_UNKNOWN;
-    }
-    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-    aFeature = aDoc->feature(aRC);
-
-    return changeEntity(aFeature, theType);
-  }
-
-  return changeEntity(theAttribute->attr(), theType);
-}
-
-Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& theType)
+bool SketchSolver_Constraint::isUsed(FeaturePtr theFeature) const
 {
-  Slvs_hEntity aResult = SLVS_E_UNKNOWN;
-  if (!theEntity || !isInitialized(theEntity)) {
-    myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
-    return SLVS_E_UNKNOWN;
-  }
+  const std::list<ConstraintWrapperPtr>& aCList = myStorage->constraint(myBaseConstraint);
+  std::list<ConstraintWrapperPtr>::const_iterator aCIt = aCList.begin();
+  for (; aCIt != aCList.end(); ++aCIt)
+    if ((*aCIt)->isUsed(theFeature))
+      return true;
 
-  // If the entity is already in the group, try to find it
-  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
-      myAttributeMap.find(theEntity);
-  Slvs_Entity aCurrentEntity;
-  aCurrentEntity.h = SLVS_E_UNKNOWN;
-  if (anEntIter != myAttributeMap.end())
-    aCurrentEntity = myStorage->getEntity(anEntIter->second);
-  else {
-    aResult = myGroup->getAttributeId(theEntity);
-    if (aResult != SLVS_E_UNKNOWN) {
-      Slvs_Entity anEnt = myStorage->getEntity(aResult);
-      theType = anEnt.type;
-      myAttributeMap[theEntity] = aResult;
-      return aResult;
-    }
-  }
+  std::list<AttributePtr> anAttrList = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
+  std::list<AttributePtr>::const_iterator anAttrIt = anAttrList.begin();
+  for (; anAttrIt != anAttrList.end(); ++ anAttrIt)
+    if (isUsed(*anAttrIt))
+      return true;
 
-  Slvs_hGroup aGroupID = myGroup->getId();
-  // do not update entity from another group
-  if (aCurrentEntity.h != SLVS_E_UNKNOWN && aGroupID != aCurrentEntity.group)
-    return aCurrentEntity.h;
-
-  // Point in 3D
-  std::shared_ptr<GeomDataAPI_Point> aPoint =
-      std::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
-  if (aPoint) {
-    double aXYZ[3] = {aPoint->x(), aPoint->y(), aPoint->z()};
-    Slvs_hParam aParams[3];
-    for (int i = 0; i < 3; i++) {
-      Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
-          myStorage->getParameter(aCurrentEntity.param[i]) :
-          Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
-      aPar.val = aXYZ[i];
-      aParams[i] = myStorage->addParameter(aPar);
-    }
-
-    if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
-      aCurrentEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, aGroupID, aParams[0], aParams[1], aParams[2]);
-    else { // update entity data
-      for (int i = 0; i < 3; i++)
-        aCurrentEntity.param[i] = aParams[i];
-    }
-    aResult = myStorage->addEntity(aCurrentEntity);
-  } else {
-    // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
-    Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
-    if (aWorkplaneID == SLVS_E_UNKNOWN)
-      return SLVS_E_UNKNOWN;
-
-    // Point in 2D
-    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
-    if (aPoint2D) {
-      double aXY[2] = {aPoint2D->x(), aPoint2D->y()};
-      Slvs_hParam aParams[2];
-      for (int i = 0; i < 2; i++) {
-        Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
-            myStorage->getParameter(aCurrentEntity.param[i]) :
-            Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
-        aPar.val = aXY[i];
-        aParams[i] = myStorage->addParameter(aPar);
-      }
-
-      if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
-        aCurrentEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aParams[0], aParams[1]);
-      else { // update entity data
-        for (int i = 0; i < 2; i++)
-          aCurrentEntity.param[i] = aParams[i];
-      }
-      aResult = myStorage->addEntity(aCurrentEntity);
-    } else {
-      // Scalar value (used for the distance entities)
-      AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
-      if (aScalar) {
-        Slvs_Param aParam = aCurrentEntity.h != SLVS_E_UNKNOWN ?
-            myStorage->getParameter(aCurrentEntity.param[0]) :
-            Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
-        aParam.val = aScalar->value();
-        Slvs_hParam aValue = myStorage->addParameter(aParam);
-
-        if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
-          aCurrentEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aValue);
-        else
-          aCurrentEntity.param[0] = aValue;
-        aResult = myStorage->addEntity(aCurrentEntity);
-      }
-    }
-  }
-
-  myAttributeMap[theEntity] = aResult;
-  theType = aCurrentEntity.type;
-  return aResult;
-}
-
-Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& theType)
-{
-  Slvs_hEntity aResult = SLVS_E_UNKNOWN;
-  if (!theEntity || !theEntity->data() || !theEntity->data()->isValid())
-    return SLVS_E_UNKNOWN;
-  // If the entity is already in the group, try to find it
-  std::map<FeaturePtr, Slvs_hEntity>::const_iterator anEntIter = myFeatureMap.find(theEntity);
-  Slvs_Entity aCurrentEntity;
-  aCurrentEntity.h = SLVS_E_UNKNOWN;
-  if (anEntIter != myFeatureMap.end())
-    aCurrentEntity = myStorage->getEntity(anEntIter->second);
-  else {
-    aResult = myGroup->getFeatureId(theEntity);
-    if (aResult != SLVS_E_UNKNOWN) {
-      Slvs_Entity anEnt = myStorage->getEntity(aResult);
-      theType = anEnt.type;
-      myFeatureMap[theEntity] = aResult;
-      return aResult;
-    }
-  }
-
-  Slvs_hGroup aGroupID = myGroup->getId();
-  // do not update entity from another group
-  if (aCurrentEntity.h != SLVS_E_UNKNOWN && aGroupID != aCurrentEntity.group)
-    return aCurrentEntity.h;
-
-  Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
-  DataPtr aData = theEntity->data();
-
-  // SketchPlugin features
-  const std::string& aFeatureKind = theEntity->getKind();
-  AttributePtr anAttribute;
-  int anAttrType;
-  // Line
-  if (aFeatureKind == SketchPlugin_Line::ID()) {
-    anAttribute = aData->attribute(SketchPlugin_Line::START_ID());
-    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
-    Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
-
-    anAttribute = aData->attribute(SketchPlugin_Line::END_ID());
-    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
-    Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
-
-    if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
-      aCurrentEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aStart, aEnd);
-    else {
-      aCurrentEntity.point[0] = aStart;
-      aCurrentEntity.point[1] = aEnd;
-    }
-    aResult = myStorage->addEntity(aCurrentEntity);
-  }
-  // Circle
-  else if (aFeatureKind == SketchPlugin_Circle::ID()) {
-    anAttribute = aData->attribute(SketchPlugin_Circle::CENTER_ID());
-    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
-    Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
-
-    anAttribute = aData->attribute(SketchPlugin_Circle::RADIUS_ID());
-    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
-    Slvs_hEntity aRadius = changeEntity(anAttribute, anAttrType);
-
-    if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
-      Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
-      aCurrentEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
-                                        aCenter, aWorkplane.normal, aRadius);
-    } else {
-      aCurrentEntity.point[0] = aCenter;
-      aCurrentEntity.distance = aRadius;
-    }
-    aResult = myStorage->addEntity(aCurrentEntity);
-  }
-  // Arc
-  else if (aFeatureKind == SketchPlugin_Arc::ID()) {
-    anAttribute = aData->attribute(SketchPlugin_Arc::CENTER_ID());
-    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
-    Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
-
-    anAttribute = aData->attribute(SketchPlugin_Arc::START_ID());
-    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
-    Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
-
-    anAttribute = aData->attribute(SketchPlugin_Arc::END_ID());
-    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
-    Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
-
-    if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
-      Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
-      aCurrentEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
-                                            aWorkplane.normal, aCenter, aStart, aEnd);
-    } else {
-      aCurrentEntity.point[0] = aCenter;
-      aCurrentEntity.point[1] = aStart;
-      aCurrentEntity.point[2] = aEnd;
-    }
-    aResult = myStorage->addEntity(aCurrentEntity);
-  }
-  // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
-  else if (aFeatureKind == SketchPlugin_Point::ID()) {
-    anAttribute = aData->attribute(SketchPlugin_Point::COORD_ID());
-    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
-    // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
-    aResult = changeEntity(anAttribute, anAttrType);
-    aCurrentEntity.type = SLVS_E_POINT_IN_3D;
-  }
-
-  if (aResult != SLVS_E_UNKNOWN) {
-    myFeatureMap[theEntity] = aResult;
-    theType = aCurrentEntity.type;
-  }
-  return aResult;
-}
-
-std::list<ConstraintPtr> SketchSolver_Constraint::constraints() const
-{
-  std::list<ConstraintPtr> aConstraints;
-  aConstraints.push_back(myBaseConstraint);
-  return aConstraints;
+  return false;
 }
 
-void SketchSolver_Constraint::refresh()
+bool SketchSolver_Constraint::isUsed(AttributePtr theAttribute) const
 {
-  cleanErrorMsg();
-  std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
-  while (anAttrIter != myAttributeMap.end()) {
-    std::shared_ptr<GeomDataAPI_Point> aPoint =
-        std::dynamic_pointer_cast<GeomDataAPI_Point>(anAttrIter->first);
-    Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
-    if (anEntity.h == SLVS_E_UNKNOWN) {
-      std::map<AttributePtr, Slvs_hEntity>::iterator aTmpIter = anAttrIter++;
-      myAttributeMap.erase(aTmpIter);
-      continue;
-    }
-    if (aPoint) {
-      double aXYZ[3];
-      for (int i = 0; i < 3; i++) {
-        Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
-        aXYZ[i] = aPar.val;
-      }
-      if (fabs(aPoint->x() - aXYZ[0]) > tolerance ||
-          fabs(aPoint->y() - aXYZ[1]) > tolerance ||
-          fabs(aPoint->z() - aXYZ[2]) > tolerance)
-        aPoint->setValue(aXYZ[0], aXYZ[1], aXYZ[2]);
-    } else {
-      // Point in 2D
-      std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrIter->first);
-      if (aPoint2D) {
-        double aXY[2];
-        for (int i = 0; i < 2; i++) {
-          Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
-          aXY[i] = aPar.val;
-        }
-        if (fabs(aPoint2D->x() - aXY[0]) > tolerance ||
-            fabs(aPoint2D->y() - aXY[1]) > tolerance)
-          aPoint2D->setValue(aXY[0], aXY[1]);
-      } else {
-        // Scalar value (used for the distance entities)
-        AttributeDoublePtr aScalar =
-            std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
-        if (aScalar) {
-          Slvs_Param aPar = myStorage->getParameter(anEntity.param[0]);
-          if (fabs(aScalar->value() - aPar.val) > tolerance)
-            aScalar->setValue(aPar.val);
-        }
-      }
-    }
-    anAttrIter++;
+  AttributePtr anAttribute = theAttribute;
+  AttributeRefAttrPtr aRefAttr =
+      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
+  if (aRefAttr) {
+    if (aRefAttr->isObject())
+      return isUsed(ModelAPI_Feature::feature(aRefAttr->object()));
+    else
+      anAttribute = aRefAttr->attr();
   }
 
-  std::map<AttributePtr, Slvs_hParam>::iterator aValIter = myValueMap.begin();
-  for (; aValIter != myValueMap.end(); aValIter++) {
-    AttributeDoublePtr aScalar =
-        std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
-    if (aScalar) {
-      Slvs_Param aPar = myStorage->getParameter(anAttrIter->second);
-      aScalar->setValue(aPar.val);
-    }
-  }
-}
-
-Slvs_hEntity SketchSolver_Constraint::getId(FeaturePtr theFeature) const
-{
-  std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFIter = myFeatureMap.find(theFeature);
-  if (aFIter == myFeatureMap.end())
-    return SLVS_E_UNKNOWN;
-  //// check the Feature is really in the storage
-  //Slvs_Entity anEntity = myStorage->getEntity(aFIter->second);
-  //if (anEntity.h == SLVS_E_UNKNOWN) {
-  //  // rebuild feature
-  //  int aType;
-  //  anEntity.h = const_cast<SketchSolver_Constraint*>(this)->changeEntity(aFIter->first, aType);
-  //  const_cast<SketchSolver_Constraint*>(this)->myFeatureMap[theFeature] = anEntity.h;
-  //}
-  //return anEntity.h;
-  return aFIter->second;
-}
-
-Slvs_hEntity SketchSolver_Constraint::getId(AttributePtr theAttribute) const
-{
-  std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrIter = myAttributeMap.find(theAttribute);
-  if (anAttrIter == myAttributeMap.end())
-    return SLVS_E_UNKNOWN;
-  return anAttrIter->second;
-}
-
-bool SketchSolver_Constraint::isInitialized(AttributePtr theAttribute)
-{
-  if (theAttribute->isInitialized())
-    return true;
-  myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+  const std::list<ConstraintWrapperPtr>& aCList = myStorage->constraint(myBaseConstraint);
+  std::list<ConstraintWrapperPtr>::const_iterator aCIt = aCList.begin();
+  for (; aCIt != aCList.end(); ++aCIt)
+    if ((*aCIt)->isUsed(theAttribute))
+      return true;
   return false;
 }
 
-
-void SketchSolver_Constraint::calculateMiddlePoint(
-    const Slvs_Entity& theEntity, double theCoeff, double& theX, double& theY) const
-{
-  if (theEntity.type == SLVS_E_LINE_SEGMENT) {
-    double aStartEndXY[2][2];
-    Slvs_Entity aPoint;
-    for (int i = 0; i < 2; i++) {
-      aPoint = myStorage->getEntity(theEntity.point[i]);
-      for (int j = 0; j < 2; j++)
-        aStartEndXY[i][j] = myStorage->getParameter(aPoint.param[j]).val;
-    }
-    theX = (1.0 - theCoeff) * aStartEndXY[0][0] + theCoeff * aStartEndXY[1][0];
-    theY = (1.0 - theCoeff) * aStartEndXY[0][1] + theCoeff * aStartEndXY[1][1];
-  } else if (theEntity.type == SLVS_E_ARC_OF_CIRCLE) {
-    double anArcPoint[3][2];
-    Slvs_Entity aPoint;
-    for (int i = 0; i < 3; i++) {
-      aPoint = myStorage->getEntity(theEntity.point[i]);
-      for (int j = 0; j < 2; j++)
-        anArcPoint[i][j] = myStorage->getParameter(aPoint.param[j]).val;
-    }
-    // project last point of arc on the arc
-    double x = anArcPoint[1][0] - anArcPoint[0][0];
-    double y = anArcPoint[1][1] - anArcPoint[0][1];
-    double aRad = sqrt(x*x + y*y);
-    x = anArcPoint[2][0] - anArcPoint[0][0];
-    y = anArcPoint[2][1] - anArcPoint[0][1];
-    double aNorm = sqrt(x*x + y*y);
-    if (aNorm >= tolerance) {
-      anArcPoint[2][0] = 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];
-      return;
-    } else if (1 - theCoeff < tolerance) {
-      theX = anArcPoint[0][0] + anArcPoint[2][0];
-      theY = anArcPoint[0][1] + anArcPoint[2][1];
-      return;
-    }
-
-    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;
-  }
-}
-
 void SketchSolver_Constraint::makeTemporary() const
 {
-  std::vector<Slvs_hConstraint>::const_iterator anIt = mySlvsConstraints.begin();
-  for (; anIt != mySlvsConstraints.end(); anIt++)
-    myStorage->addTemporaryConstraint(*anIt);
+  myStorage->setTemporary(myBaseConstraint);
 }
 
index 974143246cff2f493fdf6547bc8941660265fd9f..6f8a6fd7942f1f6a34753f1f0bbf05ac6c650dae 100644 (file)
 #include <string>
 #include <vector>
 
-class SketchSolver_Group;
-
 /** \class   SketchSolver_Constraint
  *  \ingroup Plugins
- *  \brief   Stores mapping between SketchPlugin and SolveSpace constraints data
+ *  \brief   Converts SketchPlugin constraint to the constraint applicable for solver
  */
 class SketchSolver_Constraint
 {
 protected:
   /// Default constructor
-  SketchSolver_Constraint() {}
-  /// Constructor based on SketchPlugin constraint
-  SketchSolver_Constraint(ConstraintPtr theConstraint);
+  SketchSolver_Constraint()
+    : myGroupID(GID_UNKNOWN),
+      myType(CONSTRAINT_UNKNOWN)
+  {}
 
 public:
-  virtual ~SketchSolver_Constraint();
+  /// Constructor based on SketchPlugin constraint
+  SKETCHSOLVER_EXPORT SketchSolver_Constraint(ConstraintPtr theConstraint);
+
+  virtual ~SketchSolver_Constraint() {}
 
-  /// \brief Initializes the storage of SolveSpace constraints
-  void setStorage(StoragePtr theStorage);
-  /// \brief Initializes group ID for this constraint
-  void setGroup(SketchSolver_Group* theGroup);
+  /// \brief Initializes parameters and start constraint creation
+  /// \param theStorage  [in]  storage where to place new constraint
+  /// \param theGroupID  [in]  group for constraint
+  /// \param theSketchID [in] sketch for constraint
+  void process(StoragePtr theStorage, const GroupID& theGroupID, const EntityID& theSketchID);
 
   /// \brief Update constraint
-  virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
+  SKETCHSOLVER_EXPORT virtual void update();
 
   /// \brief Tries to remove constraint
   /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
-  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+  SKETCHSOLVER_EXPORT virtual bool remove();
 
-  /// \brief Update SketchPlugin attributes using the data obtained from SolveSpace entities
-  virtual void refresh();
+  /// \brief Obtain a type of SketchPlugin constraint
+  SKETCHSOLVER_EXPORT static SketchSolver_ConstraintType TYPE(ConstraintPtr theConstraint);
 
   /// \brief Returns the type of constraint
-  virtual int getType() const = 0;
+  virtual SketchSolver_ConstraintType getType() const
+  { return myType; }
 
   /// \brief The constraint is made temporary
   void makeTemporary() const;
 
-  /// \brief Checks the constraint is used by current object
-  virtual bool hasConstraint(ConstraintPtr theConstraint) const
-  { return theConstraint == myBaseConstraint; }
-
-  /// \brief Return list of SketchPlugin constraints attached to this object
-  virtual std::list<ConstraintPtr> constraints() const;
-
-  /// \brief Return identifier of SolveSpace entity relating to the feature
-  Slvs_hEntity getId(FeaturePtr theFeature) const;
-  /// \brief Return identifier of SolveSpace entity relating to the attribute
-  Slvs_hEntity getId(AttributePtr theAttribute) const;
-
-  /// \brief Adds a feature to constraint and create its analogue in SolveSpace
-  virtual void addFeature(FeaturePtr theFeature);
+  /// \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 theAttribute) const;
 
   /// \brief Shows error message
   const std::string& error() const
   { return myErrorMsg; }
 
 protected:
-  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  /// \brief Converts SketchPlugin constraint to a list of solver's constraints
   virtual void process();
 
-  /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+  /// \brief Generate list of attributes of constraint in order useful for constraints
   /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
   /// \param[out] theAttributes list of attributes to be filled
-  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
-
-  /// \brief Verify the attributes of constraint are changed (and constraint need to rebuild)
-  /// \param[in] theConstraint constraint, which attributes should be checked (if NULL, the myBaseConstraint is used)
-  /// \return \c true if some attributes are changed
-  virtual bool checkAttributesChanged(ConstraintPtr theConstraint);
+  virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
 
   /// \brief This method is used in derived objects to check consistency of constraint.
   ///        E.g. the distance between line and point may be signed.
   virtual void adjustConstraint()
   {}
 
-  /// \brief Create or change SlveSpace entity according to the given attribute
-  /// \param[in]  theAttribute  reference to the entity to be changed
-  /// \param[out] theType       type of created entity
-  /// \return identifier of created/updated entity
-  Slvs_hEntity changeEntity(AttributeRefAttrPtr theAttribute, int& theType);
-  /// \brief Create or change SlveSpace entity according to the given attribute
-  Slvs_hEntity changeEntity(AttributePtr theAttribute, int& theType);
-  /// \brief Create or change SlveSpace entity according to the given feature
-  Slvs_hEntity changeEntity(FeaturePtr theFeature, int& theType);
-
-  /// \brief Calculate middle point on the specified entity
-  /// \param[in]  theEntity  arc or line
-  /// \param[in]  theCoeff   is a value in [0.0, 1.0] which shows the position of the point on the entity (0.0 - start point, 1.0 - end point)
-  /// \param[out] theX       X coordinate of middle point
-  /// \param[out] theY       Y coordinate of middle point
-  void calculateMiddlePoint(const Slvs_Entity& theEntity, double theCoeff,
-                            double& theX, double& theY) const;
-
-  /// \brief Removes the links to unused entities
-  void cleanRemovedEntities();
-
   /// \brief Removes last error
   void cleanErrorMsg()
   { myErrorMsg.clear(); }
 
-private:
-  /// \brief Sets error, if the attribute is not initialized
-  bool isInitialized(AttributePtr theAttribute);
-
 protected:
-  SketchSolver_Group* myGroup; ///< the group which contains current constraint
-  ConstraintPtr myBaseConstraint; ///< SketchPlugin constraint
-  std::vector<Slvs_hConstraint> mySlvsConstraints; ///< list of indices of SolveSpace constraints, together which equivalent to SketchPlugin constraint
-  std::map<FeaturePtr, Slvs_hEntity> myFeatureMap; ///< map feature to the entity it represents
-  std::map<AttributePtr, Slvs_hEntity> myAttributeMap; ///< map attribute to the corresponding entity
-  std::map<AttributePtr, Slvs_hParam> myValueMap; ///< list of attributes, which represents single value (e.g. distance) used in constraint
-  StoragePtr myStorage; ///< storage, which contains all information about entities and constraints in current group
-
-  std::string myErrorMsg; ///< error message
-};
-
-typedef std::shared_ptr<SketchSolver_Constraint> SolverConstraintPtr;
-
-
-
-/** \class   SketchSolver_ConstraintParallel
- *  \ingroup Plugins
- *  \brief   Convert Parallel constraint to SolveSpace structure
- */
-class SketchSolver_ConstraintParallel : public SketchSolver_Constraint
-{
-public:
-  /// Constructor based on SketchPlugin constraint
-  SketchSolver_ConstraintParallel(ConstraintPtr theConstraint) :
-      SketchSolver_Constraint(theConstraint)
-  {}
-
-  virtual int getType() const
-  { return SLVS_C_PARALLEL; }
-};
-
-
-/** \class   SketchSolver_ConstraintPerpendicular
- *  \ingroup Plugins
- *  \brief   Convert Perpendicular constraint to SolveSpace structure
- */
-class SketchSolver_ConstraintPerpendicular : public SketchSolver_Constraint
-{
-public:
-  /// Constructor based on SketchPlugin constraint
-  SketchSolver_ConstraintPerpendicular(ConstraintPtr theConstraint) :
-      SketchSolver_Constraint(theConstraint)
-  {}
+  GroupID       myGroupID;  ///< identifier of the group, the constraint belongs to
+  EntityID      mySketchID; ///< identifier of the sketch, the constraint belongs to
+  ConstraintPtr myBaseConstraint; ///< base SketchPlugin constraint
+  StoragePtr    myStorage; ///< storage, which contains all information about entities and constraints
+  SketchSolver_ConstraintType myType; ///< type of constraint
 
-  virtual int getType() const
-  { return SLVS_C_PERPENDICULAR; }
+  std::string   myErrorMsg; ///< error message
 };
 
-
-/** \class   SketchSolver_ConstraintHorizontal
- *  \ingroup Plugins
- *  \brief   Convert Horizontal constraint to SolveSpace structure
- */
-class SketchSolver_ConstraintHorizontal : public SketchSolver_Constraint
-{
-public:
-  /// Constructor based on SketchPlugin constraint
-  SketchSolver_ConstraintHorizontal(ConstraintPtr theConstraint) :
-      SketchSolver_Constraint(theConstraint)
-  {}
-
-  virtual int getType() const
-  { return SLVS_C_HORIZONTAL; }
-};
-
-
-/** \class   SketchSolver_ConstraintVertical
- *  \ingroup Plugins
- *  \brief   Convert Vertical constraint to SolveSpace structure
- */
-class SketchSolver_ConstraintVertical : public SketchSolver_Constraint
-{
-public:
-  /// Constructor based on SketchPlugin constraint
-  SketchSolver_ConstraintVertical(ConstraintPtr theConstraint) :
-      SketchSolver_Constraint(theConstraint)
-  {}
-
-  virtual int getType() const
-  { return SLVS_C_VERTICAL; }
-};
-
-
-/** \class   SketchSolver_ConstraintRadius
- *  \ingroup Plugins
- *  \brief   Convert Radius constraint to SolveSpace structure
- */
-class SketchSolver_ConstraintRadius : public SketchSolver_Constraint
-{
-public:
-  /// Constructor based on SketchPlugin constraint
-  SketchSolver_ConstraintRadius(ConstraintPtr theConstraint) :
-      SketchSolver_Constraint(theConstraint)
-  {}
-
-  virtual int getType() const
-  { return SLVS_C_DIAMETER; }
-
-  virtual void adjustConstraint()
-  {
-    AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-        myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE()));
-    Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front());
-    aConstraint.valA = 2.0 * aValueAttr->value();
-    myStorage->updateConstraint(aConstraint);
-  }
-};
+typedef std::shared_ptr<SketchSolver_Constraint> SolverConstraintPtr;
 
 #endif
index 10dbae16549bc0ab16c9024acee89c9c0b085199..553d5a8031803b12f97df3f28168492ebe320538 100644 (file)
@@ -1,4 +1,5 @@
 #include <SketchSolver_ConstraintAngle.h>
+#include <SketchSolver_Manager.h>
 
 #include <GeomAPI_Dir2d.h>
 #include <GeomAPI_Lin2d.h>
@@ -8,7 +9,7 @@
 #include <cmath>
 
 void SketchSolver_ConstraintAngle::getAttributes(
-    double& theValue, std::vector<Slvs_hEntity>& theAttributes)
+    double& theValue, std::vector<EntityWrapperPtr>& theAttributes)
 {
   SketchSolver_Constraint::getAttributes(theValue, theAttributes);
 
@@ -19,25 +20,29 @@ void SketchSolver_ConstraintAngle::getAttributes(
 void SketchSolver_ConstraintAngle::adjustConstraint()
 {
   static const double aTol = 1000. * tolerance;
-  Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front());
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+
+  ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
+  if (fabs(myAngle - aConstraint->value()) < aTol)
+    return;
+  myAngle = aConstraint->value();
 
   bool isFixed[2][2];
   std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
-  Slvs_hConstraint aFixedConstraint;
-  Slvs_hEntity anEnt[2] = {aConstraint.entityA, aConstraint.entityB};
-  for (int i = 0; i < 2; i++) {
-    const Slvs_Entity& aLine = myStorage->getEntity(anEnt[i]);
-    double aCoef = -1.0;
-    for (int j = 0; j < 2; j++, aCoef += 2.0) {
-      const Slvs_Entity& aPoint = myStorage->getEntity(aLine.point[j]);
-      double aCoords[2];
-      for (int k = 0; k < 2; k++)
-        aCoords[k] = myStorage->getParameter(aPoint.param[k]).val;
-      isFixed[i][j] = myStorage->isPointFixed(aPoint.h, aFixedConstraint, true);
-      aPoints[i][j] = std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aCoords[0], aCoords[1]));
+  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) {
+      isFixed[i][j] = ((*aLPIt)->group() != myGroupID);
+      aPoints[i][j] = aBuilder->point(*aLPIt);
     }
   }
 
+  if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1])
+    return; // both lines are fixed => no need to update them
+
   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]))
@@ -75,21 +80,6 @@ void SketchSolver_ConstraintAngle::adjustConstraint()
       }
     }
 
-  aConstraint.other = false;
-  for (int i = 0; i < 2; i++)
-    if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
-      aConstraint.other = !aConstraint.other;
-  myStorage->updateConstraint(aConstraint);
-
-  bool isChanged = fabs(myAngle - aConstraint.valA) > aTol;
-  // myAngle should be updated even if the angle of constraint is changed too little
-  myAngle = aConstraint.valA;
-  if (!isChanged)
-    return; // the angle was not changed, no need to recalculate positions of lines
-
-  if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1])
-    return; // both lines are fixed => no need to update them
-
   // Recalculate positions of lines to avoid conflicting constraints
   // while changing angle value several times
   double cosA = cos(myAngle * PI / 180.0);
@@ -124,15 +114,18 @@ void SketchSolver_ConstraintAngle::adjustConstraint()
   }
 
   // Update positions of points
-  const Slvs_Entity& anUpdLine = myStorage->getEntity(anEnt[aLineToUpd]);
-  Slvs_Param aParam;
-  for (int i = 0; i < 2; i++) {
-    const Slvs_Entity& aPoint = myStorage->getEntity(anUpdLine.point[i]);
-    aParam = myStorage->getParameter(aPoint.param[0]);
-    aParam.val = aNewPoints[i]->x();
-    myStorage->updateParameter(aParam);
-    aParam = myStorage->getParameter(aPoint.param[1]);
-    aParam.val = aNewPoints[i]->y();
-    myStorage->updateParameter(aParam);
+  std::list<EntityWrapperPtr>::const_iterator anUpdLine = aConstrLines.begin();
+  if (aLineToUpd > 0) ++anUpdLine;
+  const std::list<EntityWrapperPtr>& anUpdPoints = (*anUpdLine)->subEntities();
+  std::list<EntityWrapperPtr>::const_iterator aPIt = anUpdPoints.begin();
+  for (int i = 0; aPIt != anUpdPoints.end(); ++aPIt, ++i) {
+    double aCoord[2] = {aNewPoints[i]->x(), aNewPoints[i]->y()};
+    const std::list<ParameterWrapperPtr>& aParams = (*aPIt)->parameters();
+    std::list<ParameterWrapperPtr>::const_iterator aParIt = aParams.begin();
+    for (int j = 0; aParIt != aParams.end(); ++j, ++aParIt)
+      (*aParIt)->setValue(aCoord[j]);
   }
+
+  aBuilder->adjustConstraint(aConstraint);
+  myStorage->addConstraint(myBaseConstraint, aConstraint);
 }
index 4d91aced435e949b13f2f0a1c76ccd82c70e6eeb..3e979aa6d0b05d2f2b60e700709e7660f9f66b62 100644 (file)
@@ -22,17 +22,14 @@ public:
       myAngle(0.0)
   {}
 
-  virtual int getType() const
-  { return SLVS_C_ANGLE; }
-
   /// \brief This method is used in derived objects to check consistence of constraint.
   virtual void adjustConstraint();
 
 protected:
-  /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+  /// \brief Generate list of attributes of constraint in order useful for constraints
   /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
   /// \param[out] theAttributes list of attributes to be filled
-  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
+  virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
 
 private:
   double myAngle;
index e1242606ea82f1f6c216f3f46da63f628175c105..b10d7e95d44f25e14850f441cd45410275752e05 100644 (file)
@@ -1,41 +1,31 @@
 #include <SketchSolver_ConstraintCoincidence.h>
 #include <SketchSolver_Error.h>
-#include <SketchSolver_Group.h>
-
-#include <SketchPlugin_Point.h>
-#include <GeomDataAPI_Point2D.h>
-
-#include <map>
+#include <SketchSolver_Manager.h>
 
 void SketchSolver_ConstraintCoincidence::getAttributes(
     double& theValue,
-    std::vector<Slvs_hEntity>& theAttributes)
+    std::vector<EntityWrapperPtr>& theAttributes)
 {
   SketchSolver_Constraint::getAttributes(theValue, theAttributes);
-  if (!myErrorMsg.empty() || theAttributes[0] == SLVS_E_UNKNOWN)
+  if (!myErrorMsg.empty() || !theAttributes[0]) {
+    theAttributes.clear();
     return;
+  }
 
-  if (theAttributes[1] != SLVS_E_UNKNOWN) {
-    myType = SLVS_C_POINTS_COINCIDENT;
-
-    // set coordinates of slave (second) point equal to the master (first) point
-    Slvs_Entity aFirst  = myStorage->getEntity(theAttributes[0]);
-    Slvs_Entity aSecond = myStorage->getEntity(theAttributes[1]);
-    for (int i = 0; i < 4; i++)
-      if (aFirst.param[i] != SLVS_E_UNKNOWN && aSecond.param[i] != SLVS_E_UNKNOWN) {
-        Slvs_Param aPar1 = myStorage->getParameter(aFirst.param[i]);
-        Slvs_Param aPar2 = myStorage->getParameter(aSecond.param[i]);
-        aPar2.val = aPar1.val;
-        myStorage->updateParameter(aPar2);
-      }
+  if (theAttributes[1]) {
+    myType = CONSTRAINT_PT_PT_COINCIDENT;
+    // Set the slave (second) point the same as master (first) point.
+    // This will allow to skip adding point-point coincidence to the set of constraints
+    // and give us speed-up in solving the set of equations
+    myStorage->addCoincidentPoints(theAttributes[0], theAttributes[1]);
   }
-  else if (theAttributes[2] != SLVS_E_UNKNOWN) {
+  else if (theAttributes[2]) {
     // check the type of entity (line or circle)
-    Slvs_Entity anEnt = myStorage->getEntity(theAttributes[2]);
-    if (anEnt.type == SLVS_E_LINE_SEGMENT)
-      myType = SLVS_C_PT_ON_LINE;
-    else if (anEnt.type == SLVS_E_CIRCLE || anEnt.type == SLVS_E_ARC_OF_CIRCLE)
-      myType = SLVS_C_PT_ON_CIRCLE;
+    SketchSolver_EntityType anEntType = theAttributes[2]->type();
+    if (anEntType == ENTITY_LINE)
+      myType = CONSTRAINT_PT_ON_LINE;
+    else if (anEntType == ENTITY_CIRCLE || anEntType == ENTITY_ARC)
+      myType = CONSTRAINT_PT_ON_CIRCLE;
     else
       myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
   } else
@@ -43,339 +33,26 @@ void SketchSolver_ConstraintCoincidence::getAttributes(
 }
 
 
-bool SketchSolver_ConstraintCoincidence::hasConstraint(ConstraintPtr theConstraint) const
-{
-  if (myBaseConstraint == theConstraint)
-    return true;
-  return myExtraCoincidence.find(theConstraint) != myExtraCoincidence.end();
-}
-
-std::list<ConstraintPtr> SketchSolver_ConstraintCoincidence::constraints() const
-{
-  std::list<ConstraintPtr> aConstraints;
-  aConstraints.push_back(myBaseConstraint);
-  std::map<ConstraintPtr, Slvs_hConstraint>::const_iterator anIt = myExtraCoincidence.begin();
-  for (; anIt != myExtraCoincidence.end(); anIt++)
-    aConstraints.push_back(anIt->first);
-  return aConstraints;
-}
-
-bool SketchSolver_ConstraintCoincidence::isCoincide(
-    std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const
-{
-  std::set<AttributePtr>::const_iterator anAttrIter = theConstraint->myCoincidentPoints.begin();
-  for (; anAttrIter != theConstraint->myCoincidentPoints.end(); anAttrIter++)
-    if (myCoincidentPoints.find(*anAttrIter) != myCoincidentPoints.end())
-      return true;
-  return false;
-}
-
-void SketchSolver_ConstraintCoincidence::attach(
-    std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint)
+static bool isBase(const std::list<ConstraintWrapperPtr>& theConstraints, AttributePtr theAttribute)
 {
-  cleanErrorMsg();
-  // Remove constraints from theConstraint
-  std::vector<Slvs_hConstraint>::iterator aCIter = theConstraint->mySlvsConstraints.begin();
-  for (; aCIter != theConstraint->mySlvsConstraints.end(); aCIter++)
-    theConstraint->myStorage->removeConstraint(*aCIter);
-
-  if (myStorage == theConstraint->myStorage) {
-    // Clean removed items
-    std::set<Slvs_hParam> aRemParams;
-    std::set<Slvs_hEntity> aRemEnts;
-    std::set<Slvs_hConstraint> aRemConstr;
-    theConstraint->myStorage->getRemoved(aRemParams, aRemEnts, aRemConstr);
-
-    if (!aRemEnts.empty()) {
-      std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = theConstraint->myFeatureMap.begin();
-      while (aFeatIt != theConstraint->myFeatureMap.end()) {
-        if (aRemEnts.find(aFeatIt->second) != aRemEnts.end()) {
-          // remove feature
-          std::map<FeaturePtr, Slvs_hEntity>::iterator aRemoveIt = aFeatIt++;
-          theConstraint->myFeatureMap.erase(aRemoveIt);
-        } else
-          ++aFeatIt;
-      }
-      std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIt = theConstraint->myAttributeMap.begin();
-      while (anAttrIt != theConstraint->myAttributeMap.end()) {
-        if (aRemEnts.find(anAttrIt->second) != aRemEnts.end()) {
-          // remove attribute
-          std::map<AttributePtr, Slvs_hEntity>::iterator aRemoveIt = anAttrIt++;
-          theConstraint->myAttributeMap.erase(aRemoveIt);
-        } else
-          ++anAttrIt;
-      }
-    }
-  }
-
-  // Copy data.
-  addConstraint(theConstraint->myBaseConstraint);
-  std::map<ConstraintPtr, Slvs_hConstraint>::iterator aConstrIter =
-      theConstraint->myExtraCoincidence.begin();
-  for (; aConstrIter != theConstraint->myExtraCoincidence.end(); aConstrIter++)
-    addConstraint(aConstrIter->first);
-  // Clear the lists to not remove the entities on destruction
-  theConstraint->mySlvsConstraints.clear();
-  theConstraint->myFeatureMap.clear();
-  theConstraint->myAttributeMap.clear();
-}
-
-Slvs_hConstraint SketchSolver_ConstraintCoincidence::addConstraint(
-    Slvs_hEntity thePoint1, Slvs_hEntity thePoint2)
-{
-  if (thePoint1 == thePoint2)
-    return SLVS_E_UNKNOWN;
-
-  bool hasDuplicated = myStorage->hasDuplicatedConstraint();
-  Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
-      SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(), 0.0, thePoint1, thePoint2, 
-      SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-  Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
-  if (!hasDuplicated && myStorage->hasDuplicatedConstraint()) {
-    // the duplicated constraint appears
-    myStorage->removeConstraint(aNewID);
-    return SLVS_E_UNKNOWN;
-  }
-  mySlvsConstraints.push_back(aNewID);
-  return aNewID;
-}
-
-Slvs_hConstraint SketchSolver_ConstraintCoincidence::addPointOnEntity(
-    Slvs_hEntity thePoint, Slvs_hEntity theEntity)
-{
-  // Check the point is not coincident with boundaries of the entity
-  Slvs_Entity anEnt = myStorage->getEntity(theEntity);
-  int aPos = anEnt.type == SLVS_E_LINE_SEGMENT ? 0 : 1;
-  for (; anEnt.point[aPos] != SLVS_E_UNKNOWN; aPos++)
-    if (anEnt.point[aPos] == thePoint ||
-        myStorage->isCoincident(anEnt.point[aPos], thePoint))
-      return SLVS_E_UNKNOWN;
-
-  bool hasDuplicated = myStorage->hasDuplicatedConstraint();
-  Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
-  Slvs_hConstraint aType = anEnt.type == SLVS_E_LINE_SEGMENT ?
-      SLVS_C_PT_ON_LINE : SLVS_C_PT_ON_CIRCLE;
-  Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
-      aType, myGroup->getWorkplaneId(), 0.0, aBaseCoincidence.ptA, SLVS_E_UNKNOWN,
-      theEntity, SLVS_E_UNKNOWN);
-  Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
-  if (!hasDuplicated && myStorage->hasDuplicatedConstraint()) {
-    // the duplicated constraint appears
-    myStorage->removeConstraint(aNewID);
-    return SLVS_E_UNKNOWN;
-  }
-  mySlvsConstraints.push_back(aNewID);
-  return aNewID;
-}
-
-void SketchSolver_ConstraintCoincidence::addConstraint(ConstraintPtr theConstraint)
-{
-  if (mySlvsConstraints.empty()) {
-    // This constraint is empty, rebuild it from scratch
-    myBaseConstraint = theConstraint;
-    process();
-    return;
-  }
-
-  std::list<AttributePtr> anAttrList =
-      theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
-  std::list<AttributePtr>::iterator anIter = anAttrList.begin();
-  std::vector<Slvs_hEntity> aPoints;
-  Slvs_hEntity anEntity = SLVS_E_UNKNOWN;
-  int anEntType;
-  for (; anIter != anAttrList.end(); anIter++) {
-    Slvs_hEntity aPointID = SLVS_E_UNKNOWN;
-    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
-    if (!aRefAttr)
-      continue;
-
-    AttributePtr aPointAttr;
-    if (aRefAttr->isObject()) {
-      FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
-      std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFeatFound = 
-          myFeatureMap.find(aFeature);
-      if (aFeatFound != myFeatureMap.end())
-        anEntity = aFeatFound->second;
-      else {
-        anEntity = myGroup->getFeatureId(aFeature);
-        if (anEntity == SLVS_E_UNKNOWN)
-          anEntity = changeEntity(aFeature, anEntType);
-        else {
-          myFeatureMap[aFeature] = anEntity;
-          // Obtain relations between attributes of the feature and SolveSpace entities
-          std::list<AttributePtr> anAttrList =
-              aFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
-          std::list<AttributePtr>::iterator anIt = anAttrList.begin();
-          for (; anIt != anAttrList.end(); ++anIt) {
-            Slvs_hEntity anAttrID = myGroup->getAttributeId(*anIt);
-            if (anAttrID != SLVS_E_UNKNOWN)
-              myAttributeMap[*anIt] = anAttrID;
-          }
-        }
-      }
-      // If the feature is a point, add it to the list of coincident points
-      if (aFeature->getKind() == SketchPlugin_Point::ID()) {
-        aPointID = anEntity;
-        anEntity = SLVS_E_UNKNOWN;
-        aPointAttr = aFeature->attribute(SketchPlugin_Point::COORD_ID());
-      }
-    } else {
-      aPointAttr = aRefAttr->attr();
-      std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrFound =
-          myAttributeMap.find(aPointAttr);
-      if (anAttrFound != myAttributeMap.end())
-        aPointID = anAttrFound->second;
-      else {
-        aPointID = myGroup->getAttributeId(aPointAttr);
-        if (aPointID == SLVS_E_UNKNOWN)
-          aPointID = changeEntity(aPointAttr, anEntType);
-      }
-    }
-
-    if (aPointAttr) { // the point is found
-      aPoints.push_back(aPointID);
-      myCoincidentPoints.insert(aPointAttr);
-      myAttributeMap[aPointAttr] = aPointID;
-    }
-  }
-
-  Slvs_hConstraint aNewConstr = SLVS_E_UNKNOWN;
-  if (anEntity != SLVS_E_UNKNOWN)
-    aNewConstr = addPointOnEntity(aPoints.front(), anEntity);
-  else { // coincidence between two points
-    Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
-    std::vector<Slvs_hEntity>::const_iterator aPtIter = aPoints.begin();
-    for (; aPtIter != aPoints.end(); aPtIter++) {
-      Slvs_hConstraint aC = addConstraint(aBaseCoincidence.ptA, *aPtIter);
-      if (aC != SLVS_E_UNKNOWN)
-        aNewConstr = aC;
-    }
-  }
-  myExtraCoincidence[theConstraint] = aNewConstr;
-}
-
-void SketchSolver_ConstraintCoincidence::process()
-{
-  SketchSolver_Constraint::process();
-
-  // Fill the list of coincident points
-  std::list<AttributePtr> anAttrList =
-      myBaseConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
-  std::list<AttributePtr>::iterator anIt = anAttrList.begin();
-  for (; anIt != anAttrList.end(); anIt++) {
-    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
-    if (!aRefAttr || aRefAttr->isObject())
-      continue;
-    myCoincidentPoints.insert(aRefAttr->attr());
-  }
-}
-
-bool SketchSolver_ConstraintCoincidence::remove(ConstraintPtr theConstraint)
-{
-  cleanErrorMsg();
-  if (mySlvsConstraints.empty())
-    return true;
-  ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
-  int aPos = -1; // position of constraint in the list (-1 for base constraint)
-  std::map<ConstraintPtr, Slvs_hConstraint>::iterator anExtraIt;
-  if (aConstraint != myBaseConstraint) {
-    anExtraIt = myExtraCoincidence.find(aConstraint);
-    if (anExtraIt == myExtraCoincidence.end())
-      return false; // there is no constraint, which is specified to remove
-    else {
-      bool isEmpty = anExtraIt->second == SLVS_E_UNKNOWN;
-      if (!isEmpty) {
-        isEmpty = true;
-        for (aPos = 0; aPos < (int)mySlvsConstraints.size(); aPos++)
-          if (mySlvsConstraints[aPos] == anExtraIt->second) {
-            isEmpty = false;
-            break;
-          }
-        aPos -= 1;
-      }
-      myExtraCoincidence.erase(anExtraIt);
-      if (isEmpty)
-        return false;
-    }
-  }
-
-  bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints[aPos+1]);
-  mySlvsConstraints.erase(mySlvsConstraints.begin() + (1+aPos));
-  if (aPos < 0 && !myExtraCoincidence.empty()) {
-    anExtraIt = myExtraCoincidence.begin();
-    // Remove invalid constraints
-    while (anExtraIt != myExtraCoincidence.end()) {
-      if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) {
-        std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
-        if (aTempIt->first != SLVS_E_UNKNOWN) {
-          myStorage->removeConstraint(aTempIt->second);
-          std::vector<Slvs_hConstraint>::iterator anIt = mySlvsConstraints.begin();
-          for (; anIt != mySlvsConstraints.end(); anIt++)
-            if (*anIt == aTempIt->second) {
-              mySlvsConstraints.erase(anIt);
-              break;
-            }
-        }
-        myExtraCoincidence.erase(aTempIt);
-        continue;
-      }
-      anExtraIt++;
-    }
-    // Find first non-extra conststraint
-    anExtraIt = myExtraCoincidence.begin();
-    while (anExtraIt != myExtraCoincidence.end() && anExtraIt->second == SLVS_E_UNKNOWN)
-      anExtraIt++;
-    if (anExtraIt != myExtraCoincidence.end()) {
-      // Need to specify another base coincidence constraint
-      myBaseConstraint = anExtraIt->first;
-      myExtraCoincidence.erase(anExtraIt);
-      if (mySlvsConstraints.empty()) {
-        std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
-        Slvs_Constraint aBase = myStorage->getConstraint(*aCIter);
-        for (++aCIter; aCIter != mySlvsConstraints.end(); aCIter++) {
-          Slvs_Constraint aConstr = myStorage->getConstraint(*aCIter);
-          aConstr.ptA = aBase.ptA;
-          myStorage->updateConstraint(aConstr);
-        }
-      }
-    }
-  }
-  // Clear removed attributes
-  std::set<Slvs_hParam> aParamRemoved;
-  std::set<Slvs_hEntity> anEntRemoved;
-  std::set<Slvs_hConstraint> aConstrRemoved;
-  myStorage->getRemoved(aParamRemoved, anEntRemoved, aConstrRemoved);
-  std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
-  while (anAttrIter != myAttributeMap.end()) {
-    if (anEntRemoved.find(anAttrIter->second) != anEntRemoved.end()) {
-      std::map<AttributePtr, Slvs_hEntity>::iterator aTempIt = anAttrIter++;
-      myCoincidentPoints.erase(aTempIt->first);
-      myAttributeMap.erase(aTempIt);
-      continue;
-    }
-    anAttrIter++;
+  AttributePtr anAttribute = theAttribute;
+  FeaturePtr aFeature;
+  AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+  if (aRefAttr) {
+    if (aRefAttr->isObject())
+      aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+    else
+      anAttribute = aRefAttr->attr();
   }
 
-  // Go through remaining extra coincidence and try to add or remove them
-  anExtraIt = myExtraCoincidence.begin();
-  while (anExtraIt != myExtraCoincidence.end()) {
-    if (anExtraIt->first == SLVS_E_UNKNOWN) {
-      if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) {
-        std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
-        myExtraCoincidence.erase(aTempIt);
-        continue;
-      }
-      if (mySlvsConstraints.empty()) {
-        myBaseConstraint = anExtraIt->first;
-        std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
-        myExtraCoincidence.erase(aTempIt);
-        process();
-        continue;
-      } else
-        addConstraint(anExtraIt->first);
-    }
-    anExtraIt++;
+  std::list<ConstraintWrapperPtr>::const_iterator aCIt = theConstraints.begin();
+  for (; aCIt != theConstraints.end(); ++aCIt) {
+    std::list<EntityWrapperPtr> aSubs = (*aCIt)->entities();
+    std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+    for (; aSIt != aSubs.end(); ++aSIt)
+      if ((aFeature && (*aSIt)->isBase(aFeature)) ||
+         (!aFeature && (*aSIt)->isBase(anAttribute)))
+        return true;
   }
-  return mySlvsConstraints.empty();
+  return false;
 }
-
index efb01572d063fa923a1fff61237a4728eb014a65..58b0d98dfdad486a6c53818215d2bf95fdce21c0 100644 (file)
@@ -9,7 +9,6 @@
 
 #include "SketchSolver.h"
 #include <SketchSolver_Constraint.h>
-#include <SketchSolver_Storage.h>
 
 /** \class   SketchSolver_ConstraintCoincidence
  *  \ingroup Plugins
@@ -19,53 +18,15 @@ class SketchSolver_ConstraintCoincidence : public SketchSolver_Constraint
 {
 public:
   /// Constructor based on SketchPlugin constraint
-  SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) :
-      SketchSolver_Constraint(theConstraint),
-      myType(SLVS_C_UNKNOWN)
+  SKETCHSOLVER_EXPORT SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
   {}
 
-  virtual int getType() const
-  { return myType; }
-
-  /// \brief Tries to remove constraint
-  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
-  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
-
-  /// \brief Checks the constraint is used by current object
-  virtual bool hasConstraint(ConstraintPtr theConstraint) const;
-
-  /// \brief Return list of SketchPlugin constraints attached to this object
-  virtual std::list<ConstraintPtr> constraints() const;
-
-  /// \brief Verifies the two Coincidence constraints are intersects (have shared point)
-  bool isCoincide(std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const;
-
-  /// \brief Append all data of coincidence constaint to the current
-  void attach(std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint);
-
 protected:
-  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
-  virtual void process();
-
-  /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+  /// \brief Generate list of attributes of constraint in order useful for constraints
   /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
   /// \param[out] theAttributes list of attributes to be filled
-  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
-
-private:
-  /// \brief Creates new coincidence constraint
-  Slvs_hConstraint addConstraint(Slvs_hEntity thePoint1, Slvs_hEntity thePoint2);
-
-  /// \brief Create full SolveSpace structure according to given constraint
-  void addConstraint(ConstraintPtr theConstraint);
-
-  /// \brief Create constraint of point concident to the line or circle
-  Slvs_hConstraint addPointOnEntity(Slvs_hEntity thePoint, Slvs_hEntity theEntity);
-
-private:
-  int myType; ///< type of constraint (applicable SLVS_C_POINTS_COINCIDENT or SLVS_C_PT_ON_LINE or SLVS_C_PT_ON_CIRCLE)
-  std::map<ConstraintPtr, Slvs_hConstraint> myExtraCoincidence; ///< multiple coincidence of points
-  std::set<AttributePtr> myCoincidentPoints; ///< list of points under the Coincidence constraint
+  virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
 };
 
 #endif
index 63bd0ae7ddbd2c3d2f8bffb7a278a8d245cda1bd..e82568d3ef089f60cd569a3c5895a3bc565dab25 100644 (file)
 #include <SketchSolver_ConstraintDistance.h>
-#include <SketchSolver_Group.h>
 #include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
 
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_XY.h>
 
 #include <math.h>
 
 
-void SketchSolver_ConstraintDistance::process()
+void SketchSolver_ConstraintDistance::getAttributes(
+    double& theValue,
+    std::vector<EntityWrapperPtr>& theAttributes)
 {
-  cleanErrorMsg();
-  if (!myBaseConstraint || !myStorage || myGroup == 0) {
-    /// TODO: Put error message here
+  SketchSolver_Constraint::getAttributes(theValue, theAttributes);
+  if (!myErrorMsg.empty() || !theAttributes[0]) {
+    theAttributes.clear();
     return;
   }
-  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-    update(myBaseConstraint);
 
-  double aValue;
-  std::vector<Slvs_hEntity> anEntities;
-  getAttributes(aValue, anEntities);
-  if (!myErrorMsg.empty())
-    return;
-
-  // Obtain entities to identify the type of distance
-  static const int aNbPoints = 2;
-  Slvs_hEntity aPoint[aNbPoints] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
-  Slvs_hEntity aLine = SLVS_E_UNKNOWN;
-  myType = SLVS_C_PT_PT_DISTANCE;
-  int aPtPos = 0;
-  std::vector<Slvs_hEntity>::iterator anEntIter = anEntities.begin();
-  for (; anEntIter != anEntities.end(); anEntIter++) {
-    if (*anEntIter == SLVS_E_UNKNOWN)
-      continue;
-    Slvs_Entity anEnt = myStorage->getEntity(*anEntIter);
-    if (anEnt.type == SLVS_E_POINT_IN_2D || anEnt.type == SLVS_E_POINT_IN_3D) {
-      if (aPtPos >= aNbPoints) {
-        myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
-        return;
-      }
-      aPoint[aPtPos++] = *anEntIter;
-    }
-    else if (anEnt.type == SLVS_E_LINE_SEGMENT) {
-      if (myType == SLVS_C_PT_LINE_DISTANCE) {
-        myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
-        return;
-      }
-      aLine = *anEntIter;
-      myType = SLVS_C_PT_LINE_DISTANCE;
-    }
-  }
-
-  Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
-      getType(), myGroup->getWorkplaneId(), aValue, aPoint[0], aPoint[1], aLine, SLVS_E_UNKNOWN);
-  aConstraint.h = myStorage->addConstraint(aConstraint);
-  mySlvsConstraints.push_back(aConstraint.h);
+  if (theAttributes[1])
+    myType = CONSTRAINT_PT_PT_DISTANCE;
+  else if (theAttributes[2] && theAttributes[2]->type() == ENTITY_LINE)
+    myType = CONSTRAINT_PT_LINE_DISTANCE;
+  else
+    theAttributes.clear();
 
   myPrevValue = 0.0;
-  adjustConstraint();
 }
 
 void SketchSolver_ConstraintDistance::adjustConstraint()
 {
   // Adjust point-line distance
-  if (getType() != SLVS_C_PT_LINE_DISTANCE)
+  if (getType() != CONSTRAINT_PT_LINE_DISTANCE)
     return;
 
   // Check the sign of distance is changed
-  Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front());
-  if (fabs(myPrevValue) == fabs(aConstraint.valA)) {
-    aConstraint.valA = myPrevValue;
-    myStorage->updateConstraint(aConstraint);
+  ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
+  if (fabs(myPrevValue) == fabs(aConstraint->value())) {
+    aConstraint->setValue(myPrevValue);
+    myStorage->addConstraint(myBaseConstraint, aConstraint);
     return;
   }
 
   // Get constraint parameters and check the sign of constraint value
-  std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
-  for (; aCIter != mySlvsConstraints.end(); aCIter++) {
-    aConstraint = myStorage->getConstraint(*aCIter);
-    Slvs_Entity aLine = myStorage->getEntity(aConstraint.entityA);
-    // Obtain point and line coordinates
-    Slvs_hEntity aPointID[3] = {aConstraint.ptA, aLine.point[0], aLine.point[1]};
-    std::shared_ptr<GeomAPI_XY> aPoints[3];
-    for (int i = 0; i < 3; i++) {
-      Slvs_Entity aPoint = myStorage->getEntity(aPointID[i]);
-      Slvs_Param aParams[2] = {
-          myStorage->getParameter(aPoint.param[0]),
-          myStorage->getParameter(aPoint.param[1])};
-      aPoints[i] = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(aParams[0].val, aParams[1].val));
-    }
-    std::shared_ptr<GeomAPI_XY> aLineVec = aPoints[2]->decreased(aPoints[1]);
-    std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoints[0]->decreased(aPoints[1]);
-    if (aPtLineVec->cross(aLineVec) * aConstraint.valA < 0.0 || myIsNegative) {
-      aConstraint.valA *= -1.0;
-      myStorage->updateConstraint(aConstraint);
-      myIsNegative = true;
-    }
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+  std::shared_ptr<GeomAPI_Pnt2d> aPoint;
+  std::shared_ptr<GeomAPI_Lin2d> aLine;
+  std::list<EntityWrapperPtr> aSubs = aConstraint->entities();
+  std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+  for (; aSIt != aSubs.end(); ++aSIt) {
+    if ((*aSIt)->type() == ENTITY_POINT)
+      aPoint = aBuilder->point(*aSIt);
+    else if ((*aSIt)->type() == ENTITY_LINE)
+      aLine = aBuilder->line(*aSIt);
+  }
+
+  std::shared_ptr<GeomAPI_XY> aLineVec = aLine->direction()->xy();
+  std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy());
+  if (aPtLineVec->cross(aLineVec) * aConstraint->value() < 0.0 || myIsNegative) {
+    aConstraint->setValue(aConstraint->value() * (-1.0));
+    myStorage->addConstraint(myBaseConstraint, aConstraint);
+    myIsNegative = true;
   }
 }
 
-void SketchSolver_ConstraintDistance::update(ConstraintPtr theConstraint)
+void SketchSolver_ConstraintDistance::update()
 {
-  Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front());
-  myPrevValue = aConstraint.valA;
-  SketchSolver_Constraint::update(theConstraint);
+  ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
+  myPrevValue = aConstraint->value();
+
+  SketchSolver_Constraint::update();
 }
index 5c1569f9a4f160f78b06f7ec81571f359dd36d47..b11e0a8a55d730345d30c641502df30ecb52f0f7 100644 (file)
@@ -20,26 +20,23 @@ public:
   /// Constructor based on SketchPlugin constraint
   SketchSolver_ConstraintDistance(ConstraintPtr theConstraint) :
       SketchSolver_Constraint(theConstraint),
-      myType(SLVS_C_UNKNOWN),
       myIsNegative(false)
   {}
 
   /// \brief Update constraint
-  virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
-
-  virtual int getType() const
-  {return myType; }
+  virtual void update();
 
 protected:
-  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
-  virtual void process();
+  /// \brief Generate list of attributes of constraint in order useful for constraints
+  /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
+  /// \param[out] theAttributes list of attributes to be filled
+  virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
 
   /// \brief This method is used in derived objects to check consistence of constraint.
   ///        E.g. the distance between line and point may be signed.
   virtual void adjustConstraint();
 
 private:
-  int myType; ///< type of constraint (applicable: SLVS_C_PT_PT_DISTANCE, SLVS_C_PT_LINE_DISTANCE)
   double myPrevValue; ///< previous value of distance (for correct calculation of a distance sign)
   bool myIsNegative;  ///< \c true, if the point if placed rightside of line direction (SLVS_C_PT_LINE_DISTANCE only)
 };
index e91ca2cf0f2a8d0f25db12649303f8e081ac013e..a6120533ecb1a46f21b0a1673071e8aa8b3a4410 100644 (file)
@@ -1,70 +1,54 @@
 #include <SketchSolver_ConstraintEqual.h>
-#include <SketchSolver_Group.h>
 #include <SketchSolver_Error.h>
 
-
-void SketchSolver_ConstraintEqual::process()
+void SketchSolver_ConstraintEqual::getAttributes(
+    double& theValue,
+    std::vector<EntityWrapperPtr>& theAttributes)
 {
-  cleanErrorMsg();
-  if (!myBaseConstraint || !myStorage || myGroup == 0) {
-    /// TODO: Put error message here
+  SketchSolver_Constraint::getAttributes(theValue, theAttributes);
+  if (!myErrorMsg.empty() || !theAttributes[2] || !theAttributes[3]) {
+    theAttributes.clear();
     return;
   }
-  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-    update(myBaseConstraint);
-
-  double aValue;
-  std::vector<Slvs_hEntity> anEntities;
-  getAttributes(aValue, anEntities);
-  if (!myErrorMsg.empty())
-    return;
 
   // Check the quantity of entities of each type
   int aNbLines = 0;
   int aNbArcs = 0;
   int aNbCircs = 0;
   bool isArcFirst = false; // in line-arc equivalence, the line should be first
-  std::vector<Slvs_hEntity>::iterator anEntIter = anEntities.begin();
-  for (; anEntIter != anEntities.end(); anEntIter++) {
-    Slvs_Entity anEnt = myStorage->getEntity(*anEntIter);
-    if (anEnt.type == SLVS_E_LINE_SEGMENT)
-      aNbLines++;
-    else if (anEnt.type == SLVS_E_CIRCLE)
-      aNbCircs++;
-    else if (anEnt.type == SLVS_E_ARC_OF_CIRCLE) {
-      aNbArcs++;
+  std::vector<EntityWrapperPtr>::iterator anAttrIt = theAttributes.begin() + 2;
+  for (; anAttrIt != theAttributes.end(); ++anAttrIt) {
+    SketchSolver_EntityType aType = (*anAttrIt)->type();
+    if (aType == ENTITY_LINE)
+      ++aNbLines;
+    else if (aType == ENTITY_CIRCLE)
+      ++aNbCircs;
+    else if (aType == ENTITY_ARC) {
+      ++aNbArcs;
       isArcFirst = (aNbLines == 0);
     }
   }
 
   if (aNbLines + aNbArcs + aNbCircs != 2 ||
-      (aNbLines == aNbCircs && aNbArcs == 0)) {
+     (aNbLines == aNbCircs && aNbArcs == 0)) {
     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
     return;
   }
 
   switch (aNbLines) {
   case 0:
-    myType = SLVS_C_EQUAL_RADIUS;
+    myType = CONSTRAINT_EQUAL_RADIUS;
     break;
   case 1:
-    myType = SLVS_C_EQUAL_LINE_ARC_LEN;
+    myType = CONSTRAINT_EQUAL_LINE_ARC;
     if (isArcFirst) { // change the order of arc and line
-      Slvs_hEntity aTmp = anEntities[2];
-      anEntities[2] = anEntities[3];
-      anEntities[3] = aTmp;
+      EntityWrapperPtr aTmp = theAttributes[2];
+      theAttributes[2] = theAttributes[3];
+      theAttributes[3] = aTmp;
     }
     break;
   default:
-    myType = SLVS_C_EQUAL_LENGTH_LINES;
+    myType = CONSTRAINT_EQUAL_LINES;
     break;
   }
-
-  Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
-      getType(), myGroup->getWorkplaneId(), aValue,
-      anEntities[0], anEntities[1], anEntities[2], anEntities[3]);
-  aConstraint.h = myStorage->addConstraint(aConstraint);
-  mySlvsConstraints.push_back(aConstraint.h);
-  adjustConstraint();
 }
-
index 2aca9c850a265fca96d897296e4fcbdce4a86162..12e6a334e973650cc65b7c8c01699c1690d36df3 100644 (file)
@@ -22,15 +22,11 @@ public:
       SketchSolver_Constraint(theConstraint)
   {}
 
-  virtual int getType() const
-  { return myType; }
-
 protected:
-  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
-  virtual void process();
-
-private:
-  int myType; ///< type of constraint (applicable: SLVS_C_EQUAL_LENGTH_LINES, SLVS_C_EQUAL_RADIUS, SLVS_C_EQUAL_LINE_ARC_LEN)
+  /// \brief Generate list of attributes of constraint in order useful for constraints
+  /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
+  /// \param[out] theAttributes list of attributes to be filled
+  virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
 };
 
 #endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintFillet.cpp b/src/SketchSolver/SketchSolver_ConstraintFillet.cpp
deleted file mode 100644 (file)
index 3d53b90..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-#include <SketchSolver_ConstraintFillet.h>
-#include <SketchSolver_Group.h>
-#include <SketchSolver_Error.h>
-
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefAttr.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_ResultConstruction.h>
-
-
-void SketchSolver_ConstraintFillet::getAttributes(
-    double& theValue, std::vector<Slvs_hEntity>& theAttributes)
-{
-  theAttributes.clear();
-
-  DataPtr aData = myBaseConstraint->data();
-  AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-    aData->attribute(SketchPlugin_Constraint::VALUE()));
-  theValue = aValueAttr ? aValueAttr->value() : 0.0;
-
-  std::list<AttributePtr> aBaseAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId());
-  std::list<AttributePtr>::iterator anIter = aBaseAttrs.begin();
-  for (; anIter != aBaseAttrs.end(); anIter++) {
-    AttributeRefAttrPtr aRefAttr =
-        std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
-    if (!aRefAttr || !aRefAttr->isInitialized()) {
-      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
-      return;
-    }
-
-    int aType = SLVS_E_UNKNOWN; // type of created entity
-    Slvs_hEntity anEntity = myGroup->getAttributeId(aRefAttr);
-    if (anEntity == SLVS_E_UNKNOWN)
-      anEntity = changeEntity(aRefAttr, aType);
-
-    if (aType == SLVS_E_UNKNOWN)
-      continue;
-    theAttributes.push_back(anEntity);
-  }
-
-  // Fillet objects
-  AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-    aData->attribute(SketchPlugin_Constraint::ENTITY_C()));
-  if (!aFilletRefList || !aFilletRefList->isInitialized()) {
-    myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
-    return;
-  }
-  std::list<ObjectPtr> aFilletList = aFilletRefList->list();
-  if (aFilletList.size() < theAttributes.size() + 1) {
-    myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
-    return;
-  }
-  FeaturePtr aFilletFeature;
-  ResultConstructionPtr aRC;
-  int aType;
-  std::list<ObjectPtr>::iterator aFilIter = aFilletList.begin();
-  for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) {
-    aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aFilIter);
-    aFilletFeature = aRC ? aRC->document()->feature(aRC) :
-        std::dynamic_pointer_cast<ModelAPI_Feature>(*aFilIter);
-    if (!aFilletFeature) {
-      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
-      return;
-    }
-    Slvs_hEntity anEntity = changeEntity(aFilletFeature, aType);
-    theAttributes.push_back(anEntity);
-  }
-}
-
-void SketchSolver_ConstraintFillet::process()
-{
-  cleanErrorMsg();
-  if (!myBaseConstraint || !myStorage || myGroup == 0) {
-    /// TODO: Put error message here
-    return;
-  }
-  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-    update(myBaseConstraint);
-
-  double aValue;
-  std::vector<Slvs_hEntity> anEntID;
-  getAttributes(aValue, anEntID);
-  if (!myErrorMsg.empty())
-    return;
-
-  // Obtain the entities itself:
-  // First two are base entities
-  // Second two are trimmed them
-  // Last one is a fillet arc
-  std::vector<Slvs_Entity> anEntities;
-  std::vector<Slvs_hEntity>::iterator anIt = anEntID.begin();
-  for (; anIt != anEntID.end(); anIt++)
-    anEntities.push_back(myStorage->getEntity(*anIt));
-
-  // Check the base entities have a coincident point
-  Slvs_hEntity aPointsToFind[4];
-  for (int i = 0; i < 2; i++) {
-    int aShift = anEntities[i].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
-    aPointsToFind[2*i]  = anEntities[i].point[aShift];
-    aPointsToFind[2*i+1]= anEntities[i].point[aShift+1];
-  }
-  // Search coincident points
-  int aCoincInd[2]; // indices of coincident points on each entity (0 - first, 1 - last)
-  bool isPointFound = false;
-  for (int i = 0; i < 2 && !isPointFound; i++)
-    for (int j = 2; j < 4 && !isPointFound; j++)
-      if (myStorage->isEqual(aPointsToFind[i], aPointsToFind[j])) {
-        aCoincInd[0] = i;
-        aCoincInd[1] = j - 2;
-        isPointFound = true;
-      }
-  if (!isPointFound) {
-    // There is no coincident points between tangential objects. Generate error message
-    myErrorMsg = SketchSolver_Error::NO_COINCIDENT_POINTS();
-    return;
-  }
-
-  // For correct result, move floating points of fillet on the middle points of base objects
-  Slvs_Entity aPoint;
-  Slvs_Param aParam;
-  double anArcPoints[3][2];
-  for (int i = 0; i < 2; i++) {
-    calculateMiddlePoint(anEntities[i], 0.1 + 0.8 * aCoincInd[i], anArcPoints[i+1][0], anArcPoints[i+1][1]);
-    aPoint = myStorage->getEntity(anEntities[i+2].point[aCoincInd[i]]);
-    for (int j = 0; j < 2; j++) {
-      aParam = myStorage->getParameter(aPoint.param[j]);
-      aParam.val = anArcPoints[i+1][j];
-      aPoint.param[j] = myStorage->updateParameter(aParam);
-    }
-  }
-  anArcPoints[0][0] = 0.5 * (anArcPoints[1][0] + anArcPoints[2][0]);
-  anArcPoints[0][1] = 0.5 * (anArcPoints[1][1] + anArcPoints[2][1]);
-  // Check the arc is need to be reversed
-  double aSharedPoint[2];
-  aPoint = myStorage->getEntity(aPointsToFind[aCoincInd[0]]);
-  for (int j = 0; j < 2; j++)
-    aSharedPoint[j] = myStorage->getParameter(aPoint.param[j]).val;
-  double aCross = (anArcPoints[1][0] - anArcPoints[0][0]) * (aSharedPoint[1] - anArcPoints[0][1]) -
-                  (anArcPoints[1][1] - anArcPoints[0][1]) * (aSharedPoint[0] - anArcPoints[0][0]);
-  if (aCross < 0.0) { // reverse fillet arc
-    double aTmp;
-    for (int j = 0; j < 2; j++) {
-      aTmp = anArcPoints[1][j];
-      anArcPoints[1][j] = anArcPoints[2][j];
-      anArcPoints[2][j] = aTmp;
-    }
-  }
-  // update fillet arc coordinates
-  for (int indArcPt = 0; indArcPt < 3; indArcPt++) {
-    aPoint = myStorage->getEntity(anEntities.back().point[indArcPt]);
-    for (int j = 0; j < 2; j++) {
-      aParam = myStorage->getParameter(aPoint.param[j]);
-      aParam.val = anArcPoints[indArcPt][j];
-      aPoint.param[j] = myStorage->updateParameter(aParam);
-    }
-  }
-
-  for (int indEnt = 0; indEnt < 2; indEnt++) {
-    int aShift = anEntities[indEnt].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
-    // one point of fillet object should be coincident with the point on base, non-coincident with another base object
-    Slvs_hEntity aBaseID = anEntities[indEnt].point[1 - aCoincInd[indEnt] + aShift];
-    Slvs_hEntity aFilletID = anEntities[2 + indEnt].point[1 - aCoincInd[indEnt] + aShift];
-    Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
-        SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(),
-        0.0, aBaseID, aFilletID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-    aCoincConstr.h = myStorage->addConstraint(aCoincConstr);
-    mySlvsConstraints.push_back(aCoincConstr.h);
-
-    // another point of fillet object should be placed on the base object
-    Slvs_Constraint aPonCurveConstr;
-    if (anEntities[indEnt].type == SLVS_E_ARC_OF_CIRCLE) {
-      // centers of arcs should be coincident
-      aBaseID = anEntities[indEnt].point[0];
-      aFilletID = anEntities[2 + indEnt].point[0];
-      aPonCurveConstr = Slvs_MakeConstraint(
-          SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(),
-          0.0, aBaseID, aFilletID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-    } else {
-      aFilletID = anEntities[2 + indEnt].point[aCoincInd[indEnt]];
-      aPonCurveConstr = Slvs_MakeConstraint(
-          SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_LINE, myGroup->getWorkplaneId(),
-          0.0, aFilletID, SLVS_E_UNKNOWN, anEntities[indEnt].h, SLVS_E_UNKNOWN);
-    }
-    aPonCurveConstr.h = myStorage->addConstraint(aPonCurveConstr);
-    mySlvsConstraints.push_back(aPonCurveConstr.h);
-  }
-}
-
-bool SketchSolver_ConstraintFillet::remove(ConstraintPtr theConstraint)
-{
-  cleanErrorMsg();
-  if (theConstraint && theConstraint != myBaseConstraint)
-    return false;
-  bool isFullyRemoved = true;
-  std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
-  for (; aCIter != mySlvsConstraints.end(); aCIter++)
-   isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
-  mySlvsConstraints.clear();
-
-  if (isFullyRemoved) {
-    myFeatureMap.clear();
-    myAttributeMap.clear();
-    myValueMap.clear();
-  } else
-    cleanRemovedEntities();
-  return true;
-}
-
diff --git a/src/SketchSolver/SketchSolver_ConstraintFillet.h b/src/SketchSolver/SketchSolver_ConstraintFillet.h
deleted file mode 100644 (file)
index 44caaf0..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_ConstraintFillet.h
-// Created: 1 Apr 2015
-// Author:  Artem ZHIDKOV
-
-#ifndef SketchSolver_ConstraintFillet_H_
-#define SketchSolver_ConstraintFillet_H_
-
-#include "SketchSolver.h"
-#include <SketchSolver_Constraint.h>
-
-/** \class   SketchSolver_ConstraintFillet
- *  \ingroup Plugins
- *  \brief   Convert fillet constraint to SolveSpace structure
- */
-class SketchSolver_ConstraintFillet : public SketchSolver_Constraint
-{
-public:
-  /// Constructor based on SketchPlugin constraint
-  SketchSolver_ConstraintFillet(ConstraintPtr theConstraint) :
-      SketchSolver_Constraint(theConstraint)
-  {}
-
-  virtual int getType() const
-  { return SLVS_C_FILLET; }
-
-  /// \brief Tries to remove constraint
-  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
-  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
-
-protected:
-  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
-  virtual void process();
-
-  /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
-  /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
-  /// \param[out] theAttributes list of attributes to be filled
-  ///
-  /// Parameter theAttributes contains 5 elements:
-  /// Two first entities in theAttributes list correspond to base features of fillet,
-  /// the next two entities represent trimmed base features and the last one is a fillet arc.
-  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
-};
-
-#endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintFixed.cpp b/src/SketchSolver/SketchSolver_ConstraintFixed.cpp
new file mode 100644 (file)
index 0000000..1417bde
--- /dev/null
@@ -0,0 +1,111 @@
+#include <SketchSolver_ConstraintFixed.h>
+#include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeDouble.h>
+
+#include <math.h>
+
+SketchSolver_ConstraintFixed::SketchSolver_ConstraintFixed(ConstraintPtr theConstraint)
+  : SketchSolver_Constraint()
+{
+  myBaseConstraint = theConstraint;
+  myType = CONSTRAINT_FIXED;
+  myFixedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+      theConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
+}
+
+SketchSolver_ConstraintFixed::SketchSolver_ConstraintFixed(FeaturePtr theFeature)
+  : SketchSolver_Constraint(),
+    myBaseFeature(theFeature)
+{
+  myType = CONSTRAINT_FIXED;
+  process();
+}
+
+void SketchSolver_ConstraintFixed::process()
+{
+  cleanErrorMsg();
+  if ((!myBaseConstraint && !myBaseFeature) || !myStorage || myGroupID == GID_UNKNOWN) {
+    // Not enough parameters are assigned
+    return;
+  }
+
+  ParameterWrapperPtr aValue;
+  std::vector<EntityWrapperPtr> anEntities;
+  getAttributes(aValue, anEntities);
+  if (!myErrorMsg.empty() || anEntities.empty())
+    return;
+  fixFeature(anEntities.front());
+}
+
+void SketchSolver_ConstraintFixed::fixFeature(EntityWrapperPtr theFeature)
+{
+  // extract feature from the group
+  if (theFeature->baseAttribute())
+    myStorage->update(theFeature->baseAttribute(), GID_OUTOFGROUP);
+  else
+    myStorage->update(theFeature->baseFeature(), GID_OUTOFGROUP);
+}
+
+void SketchSolver_ConstraintFixed::getAttributes(
+    ParameterWrapperPtr& theValue,
+    std::vector<EntityWrapperPtr>& theAttributes)
+{
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+
+  EntityWrapperPtr aSolverEntity;
+  if (myBaseFeature) {
+    // The feature is fixed.
+    myStorage->update(myBaseFeature, myGroupID);
+    aSolverEntity = myStorage->entity(myBaseFeature);
+  } else if (myBaseConstraint) {
+    // Constraint Fixed is added by user.
+    // Get the attribute of constraint (it should be alone in the list of constraints).
+    AttributePtr anAttr = myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A());
+    AttributeRefAttrPtr aRefAttr =
+        std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
+    if (!aRefAttr || !aRefAttr->isInitialized()) {
+      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+      return;
+    }
+
+    myStorage->update(anAttr, myGroupID);
+    aSolverEntity = myStorage->entity(anAttr);
+  } else
+    myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+
+  if (aSolverEntity)
+    theAttributes.push_back(aSolverEntity);
+}
+
+
+bool SketchSolver_ConstraintFixed::remove()
+{
+  cleanErrorMsg();
+  // Move fixed entities back to the current group
+  FeaturePtr aFeature = myBaseFeature;
+  if (myBaseConstraint && myFixedAttribute && myFixedAttribute->isObject())
+    aFeature = ModelAPI_Feature::feature(myFixedAttribute->object());
+  if (aFeature)
+    myStorage->update(aFeature, myGroupID);
+
+  // Remove constraint or base feature
+  if (myBaseConstraint) {
+    bool isRemoved = false;
+    if (aFeature)
+      isRemoved = myStorage->removeEntity(aFeature);
+    return SketchSolver_Constraint::remove() || isRemoved;
+  } else if (myBaseFeature)
+    myStorage->removeEntity(myBaseFeature);
+  return true;
+}
diff --git a/src/SketchSolver/SketchSolver_ConstraintFixed.h b/src/SketchSolver/SketchSolver_ConstraintFixed.h
new file mode 100644 (file)
index 0000000..5186837
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_ConstraintFixed.h
+// Created: 30 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintFixed_H_
+#define SketchSolver_ConstraintFixed_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class   SketchSolver_ConstraintFixed
+ *  \ingroup Plugins
+ *  \brief   Stores data of the Fixed constraint
+ *
+ *  Fixed constraint may have NULL basic SketchPlugin constraint,
+ *  because the Fixed constraint may be temporary for correct moving of objects.
+ *
+ *  Fixed constraint does not create a constraint, but builds the entities in separate group,
+ *  so they will not be moved while resolving the set of constraints.
+ */
+class SketchSolver_ConstraintFixed : public SketchSolver_Constraint
+{
+public:
+  /// Creates constraint to manage the given constraint from plugin
+  SketchSolver_ConstraintFixed(ConstraintPtr theConstraint);
+  /// Creates temporary constraint based on feature
+  SketchSolver_ConstraintFixed(FeaturePtr theFeature);
+
+  /// \brief Tries to remove constraint
+  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+  virtual bool remove();
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process();
+
+  /// \brief Generate list of attributes of constraint in order useful for constraints
+  /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
+  /// \param[out] theAttributes list of attributes to be filled
+  virtual void getAttributes(ParameterWrapperPtr& theValue, std::vector<EntityWrapperPtr>& theAttributes);
+
+  /// \brief Fixed feature basing on its type
+  /// \param theFeature [in]  feature, converted to solver specific format
+  virtual void fixFeature(EntityWrapperPtr theFeature);
+
+protected:
+  FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL)
+
+private:
+  AttributeRefAttrPtr myFixedAttribute; ///< attribute of a fixed constraint (for correct remove)
+};
+
+#endif
index 06d854d175ba7a4724bf8ef920249746be45ceea..5c3bbc088637187d5ee63c0cd3d746e27c89196f 100644 (file)
@@ -1,44 +1,26 @@
 #include <SketchSolver_ConstraintLength.h>
-#include <SketchSolver_Group.h>
 #include <SketchSolver_Error.h>
 
 
-void SketchSolver_ConstraintLength::process()
+void SketchSolver_ConstraintLength::getAttributes(
+    double& theValue,
+    std::vector<EntityWrapperPtr>& theAttributes)
 {
-  cleanErrorMsg();
-  if (!myBaseConstraint || !myStorage || myGroup == 0) {
-    /// TODO: Put error message here
+  SketchSolver_Constraint::getAttributes(theValue, theAttributes);
+  if (!myErrorMsg.empty() || !theAttributes[2] || 
+      theAttributes[2]->type() != ENTITY_LINE) {
+    theAttributes.clear();
     return;
   }
-  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-    update(myBaseConstraint);
 
-  double aValue;
-  std::vector<Slvs_hEntity> anEntities;
-  getAttributes(aValue, anEntities);
-  if (!myErrorMsg.empty())
-    return;
-
-  // Check the entity is a line
-  Slvs_Entity aLine = myStorage->getEntity(anEntities[2]);
-  if (aLine.type != SLVS_E_LINE_SEGMENT){
-    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
-    return;
-  }
+  // Get boundary points of line segment and create point-point distance constraint
+  std::list<EntityWrapperPtr> aSubs = theAttributes[2]->subEntities();
+  theAttributes.assign(theAttributes.size(), EntityWrapperPtr());
+  std::vector<EntityWrapperPtr>::iterator anAttrIt = theAttributes.begin();
+  std::list<EntityWrapperPtr>::const_iterator aSubIt = aSubs.begin();
+  for (; aSubIt != aSubs.end(); ++aSubIt, ++anAttrIt)
+    *anAttrIt = *aSubIt;
 
-  Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
-      getType(), myGroup->getWorkplaneId(), aValue,
-      aLine.point[0], aLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-  aConstraint.h = myStorage->addConstraint(aConstraint);
-  mySlvsConstraints.push_back(aConstraint.h);
-  adjustConstraint();
-}
-
-void SketchSolver_ConstraintLength::adjustConstraint()
-{
-  // No need to store the line, which length is constrained
-  // Upd: The line need to be stored to check that constraint
-  //      is changed/unchanged during modifications in GUI
-  //myFeatureMap.clear();
+  myType = CONSTRAINT_PT_PT_DISTANCE;
 }
 
index f9c0da65ce54dd706629d07028d7447e50cf4c88..0899d8b732419e138208af79263d0f7c56abc20c 100644 (file)
@@ -22,16 +22,11 @@ public:
       SketchSolver_Constraint(theConstraint)
   {}
 
-  virtual int getType() const
-  { return SLVS_C_PT_PT_DISTANCE; }
-
 protected:
-  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
-  virtual void process();
-
-  /// \brief This method is used in derived objects to check consistence of constraint.
-  ///        E.g. the distance between line and point may be signed.
-  virtual void adjustConstraint();
+  /// \brief Generate list of attributes of constraint in order useful for constraints
+  /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
+  /// \param[out] theAttributes list of attributes to be filled
+  virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
 };
 
 #endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintManager.cpp b/src/SketchSolver/SketchSolver_ConstraintManager.cpp
deleted file mode 100644 (file)
index 682bbf2..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_ConstraintManager.cpp
-// Created: 08 May 2014
-// Author:  Artem ZHIDKOV
-
-#include "SketchSolver_ConstraintManager.h"
-
-#include <Events_Loop.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_Data.h>
-#include <ModelAPI_Events.h>
-#include <ModelAPI_Object.h>
-#include <ModelAPI_ResultConstruction.h>
-#include <ModelAPI_Attribute.h>
-
-#include <SketchPlugin_Constraint.h>
-
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Sketch.h>
-#include <SketchPlugin_Feature.h>
-
-#include <list>
-#include <set>
-#include <memory>
-
-// Initialization of constraint manager self pointer
-SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
-
-/// Global constraint manager object
-SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance();
-
-
-// ========================================================
-// ========= SketchSolver_ConstraintManager ===============
-// ========================================================
-SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance()
-{
-  if (!_self)
-    _self = new SketchSolver_ConstraintManager();
-  return _self;
-}
-
-SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
-{
-  myGroups.clear();
-  myIsComputed = false;
-
-  // Register in event loop
-  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
-  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
-  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
-  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
-}
-
-SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
-{
-  myGroups.clear();
-}
-
-// ============================================================================
-//  Function: processEvent
-//  Class:    SketchSolver_Session
-//  Purpose:  listen the event loop and process the message
-// ============================================================================
-void SketchSolver_ConstraintManager::processEvent(
-  const std::shared_ptr<Events_Message>& theMessage)
-{
-  if (myIsComputed)
-    return;
-  if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
-      || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)
-      || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
-    std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
-        std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
-    std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
-
-    // Shows the message has at least one feature applicable for solver
-    bool hasProperFeature = false;
-
-    bool isMovedEvt = theMessage->eventID()
-          == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
-    if (isMovedEvt) {
-      std::set<ObjectPtr>::iterator aFeatIter;
-      for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
-        std::shared_ptr<SketchPlugin_Feature> aSFeature = 
-            std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
-        if (aSFeature) {
-          moveEntity(aSFeature);
-          hasProperFeature = true;
-        }
-      }
-    } else {
-      std::list<FeaturePtr> aSketchFeatures = SketchSolver_Group::selectApplicableFeatures(aFeatures);
-      std::list<FeaturePtr>::iterator aFeatIter = aSketchFeatures.begin();
-      for (; aFeatIter != aSketchFeatures.end(); ++aFeatIter) {
-        if ((*aFeatIter)->getKind() == SketchPlugin_Sketch::ID()) {
-          std::shared_ptr<ModelAPI_CompositeFeature> aSketch = 
-              std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFeatIter);
-          hasProperFeature = changeWorkplane(aSketch) || hasProperFeature;
-          continue;
-        }
-        std::shared_ptr<SketchPlugin_Feature> aFeature = 
-            std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
-        if (!aFeature)
-          continue;
-        hasProperFeature = changeConstraintOrEntity(aFeature) || hasProperFeature;
-      }
-    }
-
-    // Solve the set of constraints
-    if (hasProperFeature)
-      resolveConstraints(isMovedEvt); // send update for movement in any case
-  } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
-    std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
-      std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
-    const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
-
-    // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch
-    std::set<std::string>::const_iterator aFGrIter;
-    for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
-      if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 ||
-        aFGrIter->compare(ModelAPI_Feature::group()) == 0)
-        break;
-
-    if (aFGrIter != aFeatureGroups.end()) {
-      std::vector<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
-      std::vector<SketchSolver_Group*> aSeparatedGroups;
-      while (aGroupIter != myGroups.end()) {
-        if (!(*aGroupIter)->isWorkplaneValid()) {  // the group should be removed
-          delete *aGroupIter;
-          int aShift = aGroupIter - myGroups.begin();
-          myGroups.erase(aGroupIter);
-          aGroupIter = myGroups.begin() + aShift;
-          continue;
-        }
-        if (!(*aGroupIter)->isConsistent()) {  // some constraints were removed, try to split the group
-          (*aGroupIter)->splitGroup(aSeparatedGroups);
-        }
-        aGroupIter++;
-      }
-      if (aSeparatedGroups.size() > 0)
-        myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
-    }
-  }
-}
-
-// ============================================================================
-//  Function: changeWorkplane
-//  Class:    SketchSolver_Session
-//  Purpose:  update workplane by given parameters of the sketch
-// ============================================================================
-bool SketchSolver_ConstraintManager::changeWorkplane(CompositeFeaturePtr theSketch)
-{
-  bool aResult = true;  // changed when a workplane wrongly updated
-  bool isUpdated = false;
-  // Try to update specified workplane in all groups
-  std::vector<SketchSolver_Group*>::iterator aGroupIter;
-  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
-    if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
-      isUpdated = true;
-      if (!(*aGroupIter)->updateWorkplane())
-        aResult = false;
-    }
-  // If the workplane is not updated, so this is a new workplane
-  if (!isUpdated) {
-    SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch);
-    // Verify that the group is created successfully
-    if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) {
-      delete aNewGroup;
-      return false;
-    }
-    myGroups.push_back(aNewGroup);
-  }
-  return aResult;
-}
-
-// ============================================================================
-//  Function: changeConstraintOrEntity
-//  Class:    SketchSolver_Session
-//  Purpose:  create/update the constraint or the feature and place it into appropriate group
-// ============================================================================
-bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
-    std::shared_ptr<SketchPlugin_Feature> theFeature)
-{
-  // Search the groups which this feature touches
-  std::set<Slvs_hGroup> aGroups;
-  findGroups(theFeature, aGroups);
-
-  std::shared_ptr<SketchPlugin_Constraint> aConstraint = 
-      std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
-
-  // Process the groups list
-  if (aGroups.size() == 0) {
-    // There are no groups applicable for this constraint => create new one
-    // The group will be created only for constraints, not for features
-    if (!aConstraint) return false;
-    std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(aConstraint);
-    if (!aWP)
-      return false;
-    SketchSolver_Group* aGroup = new SketchSolver_Group(aWP);
-    if (!aGroup->changeConstraint(aConstraint)) {
-      delete aGroup;
-      return false;
-    }
-    myGroups.push_back(aGroup);
-    return true;
-  } else if (aGroups.size() == 1) {  // Only one group => add feature into it
-    Slvs_hGroup aGroupId = *(aGroups.begin());
-    std::vector<SketchSolver_Group*>::iterator aGroupIter;
-    for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
-      if ((*aGroupIter)->getId() == aGroupId) {
-        // If the group is empty, the feature is not added (the constraint only)
-        if (!aConstraint && !(*aGroupIter)->isEmpty())
-          return (*aGroupIter)->updateFeature(theFeature);
-        return (*aGroupIter)->changeConstraint(aConstraint);
-      }
-  } else if (aGroups.size() > 1) {  // Several groups applicable for this feature => need to merge them
-    std::set<Slvs_hGroup>::const_iterator aGroupsIter = aGroups.begin();
-
-    // Search first group
-    std::vector<SketchSolver_Group*>::iterator aFirstGroupIter;
-    for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
-      if ((*aFirstGroupIter)->getId() == *aGroupsIter)
-        break;
-    if (aFirstGroupIter == myGroups.end())
-      return false;
-
-    // Append other groups to the first one
-    std::vector<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
-    for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
-      for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
-        if ((*anOtherGroupIter)->getId() == *aGroupsIter)
-          break;
-      if (anOtherGroupIter == myGroups.end()) {  // Group disappears
-        anOtherGroupIter = aFirstGroupIter + 1;
-        continue;
-      }
-
-      (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
-      int aShiftFirst = aFirstGroupIter - myGroups.begin();
-      int aShiftOther = anOtherGroupIter - myGroups.begin();
-      delete *anOtherGroupIter;
-      myGroups.erase(anOtherGroupIter);
-      aFirstGroupIter = myGroups.begin() + aShiftFirst;
-      anOtherGroupIter = myGroups.begin() + aShiftOther;
-    }
-
-    if (aConstraint)
-      return (*aFirstGroupIter)->changeConstraint(aConstraint);
-    return (*aFirstGroupIter)->updateFeature(theFeature);
-  }
-
-  // Something goes wrong
-  return false;
-}
-
-// ============================================================================
-//  Function: moveEntity
-//  Class:    SketchSolver_Session
-//  Purpose:  update element moved on the sketch, which is used by constraints
-// ============================================================================
-void SketchSolver_ConstraintManager::moveEntity(
-    std::shared_ptr<SketchPlugin_Feature> theFeature)
-{
-  std::vector<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
-  for (; aGroupIt != myGroups.end(); aGroupIt++)
-    if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature))
-      (*aGroupIt)->moveFeature(theFeature);
-}
-
-// ============================================================================
-//  Function: findGroups
-//  Class:    SketchSolver_Session
-//  Purpose:  search groups of entities interacting with given feature
-// ============================================================================
-void SketchSolver_ConstraintManager::findGroups(
-    std::shared_ptr<SketchPlugin_Feature> theFeature,
-    std::set<Slvs_hGroup>& theGroupIDs) const
-{
-  std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(theFeature);
-
-  SketchSolver_Group* anEmptyGroup = 0;  // appropriate empty group for specified constraint
-  std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
-  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
-    if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) {
-      if (!(*aGroupIter)->isEmpty())
-        theGroupIDs.insert((*aGroupIter)->getId());
-      else if (!anEmptyGroup)
-        anEmptyGroup = *aGroupIter;
-    }
-
-  // When only empty group is found, use it
-  if (anEmptyGroup && theGroupIDs.empty())
-    theGroupIDs.insert(anEmptyGroup->getId());
-}
-
-// ============================================================================
-//  Function: findWorkplane
-//  Class:    SketchSolver_Session
-//  Purpose:  search workplane containing given feature
-// ============================================================================
-std::shared_ptr<ModelAPI_CompositeFeature> SketchSolver_ConstraintManager
-::findWorkplane(std::shared_ptr<SketchPlugin_Feature> theFeature) const
-{
-  // Already verified workplanes
-  std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
-
-  std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
-  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
-    std::shared_ptr<ModelAPI_CompositeFeature> aWP = (*aGroupIter)->getWorkplane();
-    if (aVerified.find(aWP) != aVerified.end())
-      continue;
-
-    DataPtr aData = aWP->data();
-    if (aData->isValid()) {
-      std::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures = std::dynamic_pointer_cast<
-          ModelAPI_AttributeRefList>(aData->attribute(SketchPlugin_Sketch::FEATURES_ID()));
-      std::list<ObjectPtr> aFeaturesList = aWPFeatures->list();
-      std::list<ObjectPtr>::const_iterator anIter;
-      for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
-        if (*anIter == theFeature)
-          return aWP;  // workplane is found
-    }
-    aVerified.insert(aWP);
-  }
-
-  return std::shared_ptr<ModelAPI_CompositeFeature>();
-}
-
-// ============================================================================
-//  Function: resolveConstraints
-//  Class:    SketchSolver_Session
-//  Purpose:  change entities according to available constraints
-// ============================================================================
-void SketchSolver_ConstraintManager::resolveConstraints(const bool theForceUpdate)
-{
-  myIsComputed = true;
-  bool needToUpdate = false;
-  static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
-  // to avoid redisplay of each segment on update by solver one by one in the viewer
-  bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
-  if (isUpdateFlushed) {
-    Events_Loop::loop()->setFlushed(anUpdateEvent, false);
-  }
-
-  std::vector<SketchSolver_Group*>::iterator aGroupIter;
-  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
-    if ((*aGroupIter)->resolveConstraints())
-      needToUpdate = true;
-
-  // Features may be updated => now send events, but for all changed at once
-  if (isUpdateFlushed) {
-    Events_Loop::loop()->setFlushed(anUpdateEvent, true);
-  }
-  // Must be before flush because on "Updated" flush the results may be produced
-  // and the creation event is appeared with many new objects. If myIsComputed these
-  // events are missed in processEvents and some elements are not added.
-  myIsComputed = false;
-  if (needToUpdate || theForceUpdate)
-    Events_Loop::loop()->flush(anUpdateEvent);
-}
-
diff --git a/src/SketchSolver/SketchSolver_ConstraintManager.h b/src/SketchSolver/SketchSolver_ConstraintManager.h
deleted file mode 100644 (file)
index a2d7ffa..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_ConstraintManager.h
-// Created: 08 May 2014
-// Author:  Artem ZHIDKOV
-
-#ifndef SketchSolver_ConstraintManager_H_
-#define SketchSolver_ConstraintManager_H_
-
-#include "SketchSolver.h"
-#include <SketchSolver_Solver.h>
-#include <SketchSolver_Group.h>
-
-#include <Events_Listener.h>
-#include <SketchPlugin_Constraint.h>
-
-#include <string.h>
-#include <slvs.h>
-
-#include <list>
-#include <map>
-#include <vector>
-#include <set>
-
-/** \class   SketchSolver_ConstraintManager
- *  \ingroup Plugins
- *  \brief   Listens the changes of SketchPlugin features and transforms the Constraint
- *           feature into the format understandable by SolveSpace library.
- *
- *  Constraints created for SolveSpace library are divided into the groups.
- *  The division order based on connectedness of the features by the constraints.
- *  The groups may be fused or separated according to the new constraints.
- *
- *  \remark This is a singleton.
- */
-class SketchSolver_ConstraintManager : public Events_Listener
-{
- public:
-  /** \brief Main method to create constraint manager
-   *  \return pointer to the singleton
-   */
-  static SketchSolver_ConstraintManager* Instance();
-
-  /** \brief Implementation of Event Listener method
-   *  \param[in] theMessage the data of the event
-   */
-  virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
-
- protected:
-  SketchSolver_ConstraintManager();
-  ~SketchSolver_ConstraintManager();
-
-  /** \brief Adds or updates a constraint or an entity in the suitable group
-   *  \param[in] theFeature sketch feature to be changed
-   *  \return \c true if the feature changed successfully
-   */
-  bool changeConstraintOrEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
-
-  /** \brief Removes a constraint from the manager
-   *  \param[in] theConstraint constraint to be removed
-   *  \return \c true if the constraint removed successfully
-   */
-  bool removeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
-  /** \brief Adds or updates a workplane in the manager
-   *  \param[in] theSketch the feature to create or update workplane
-   *  \return \c true if the workplane changed successfully
-   *  \remark Type of theSketch is not verified inside
-   */
-  bool changeWorkplane(CompositeFeaturePtr theSketch);
-
-  /** \brief Removes a workplane from the manager.
-   *         All groups based on such workplane will be removed too.
-   *  \param[in] theSketch the feature to be removed
-   *  \return \c true if the workplane removed successfully
-   */
-  bool removeWorkplane(std::shared_ptr<SketchPlugin_Sketch> theSketch);
-
-  /** \brief Updates entity which is moved in GUI
-   *  \param[in] theFeature entity to be updated
-   */
-  void moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
-
-  /** \brief Goes through the list of groups and solve the constraints
-   *  \param theForceUpdate flushes the update event in any case: something changed or not
-   */
-  void resolveConstraints(const bool theForceUpdate);
-
- private:
-  /** \brief Searches list of groups which interact with specified feature
-   *  \param[in]  theFeature  object to be found
-   *  \param[out] theGroups   list of group indexes interacted with the feature
-   */
-  void findGroups(std::shared_ptr<SketchPlugin_Feature> theFeature,
-                  std::set<Slvs_hGroup>& theGroupIDs) const;
-
-  /** \brief Searches in the list of groups the workplane which constains specified feature
-   *  \param[in] theFeature object to be found
-   *  \return workplane containing the feature
-   */
-  std::shared_ptr<ModelAPI_CompositeFeature> findWorkplane(
-      std::shared_ptr<SketchPlugin_Feature> theFeature) const;
-
- private:
-  static SketchSolver_ConstraintManager* _self;  ///< Self pointer to implement singleton functionality
-  std::vector<SketchSolver_Group*> myGroups;  ///< Groups of constraints
-  /// true if computation is performed and all "updates" are generated by this algo
-  /// and needs no recomputation
-  bool myIsComputed;
-};
-
-#endif
index 9d1477545f9d969234e7c7115d2fe04b16ab2d5f..c496b719d77b5862283b61a0838d5e8f4e13ed03 100644 (file)
@@ -1,34 +1,25 @@
 #include <SketchSolver_ConstraintMirror.h>
-#include <SketchSolver_Group.h>
 #include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
 
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefAttr.h>
 #include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_ResultConstruction.h>
-
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_XY.h>
-
-#include <cmath>
 
 void SketchSolver_ConstraintMirror::getAttributes(
-    Slvs_Entity& theMirrorLine,
-    std::vector<Slvs_Entity>& theBaseEntities,
-    std::vector<Slvs_Entity>& theMirrorEntities)
+    EntityWrapperPtr& theMirrorLine,
+    std::vector<EntityWrapperPtr>& theBaseEntities,
+    std::vector<EntityWrapperPtr>& theMirrorEntities)
 {
-  DataPtr aData = myBaseConstraint->data();
-  AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-      myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-  if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) {
+  AttributePtr aMirLineAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A());
+  AttributeRefAttrPtr aMirLineRefAttr =
+      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aMirLineAttr);
+  if (!aMirLineRefAttr || !aMirLineRefAttr->isInitialized() || !aMirLineRefAttr->isObject()) {
     myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
     return;
   }
-  int aType = SLVS_E_UNKNOWN; // type of created entity
-  Slvs_hEntity anEntity = myGroup->getAttributeId(aMirLineAttr);
-  if (anEntity == SLVS_E_UNKNOWN)
-    anEntity = changeEntity(aMirLineAttr, aType);
-  theMirrorLine = myStorage->getEntity(anEntity);
+
+  myType = TYPE(myBaseConstraint);
+  myStorage->update(aMirLineAttr, myGroupID);
+  theMirrorLine = myStorage->entity(aMirLineAttr);
 
   // Create SolveSpace entity for all features
   AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
@@ -45,26 +36,17 @@ void SketchSolver_ConstraintMirror::getAttributes(
   std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
 
   FeaturePtr aFeature;
-  ResultConstructionPtr aRC;
   for (int i = 0; i < 2; i++) {
     std::list<ObjectPtr>::iterator anIter = i == 0 ? aBaseList.begin() : aMirroredList.begin();
     std::list<ObjectPtr>::iterator aEndIter = i == 0 ? aBaseList.end() : aMirroredList.end();
-    std::vector<Slvs_Entity>* aList = i == 0 ? &theBaseEntities : & theMirrorEntities;
+    std::vector<EntityWrapperPtr>* aList = i == 0 ? &theBaseEntities : & theMirrorEntities;
     for ( ; anIter != aEndIter; anIter++) {
-      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anIter);
-      aFeature = aRC ? aRC->document()->feature(aRC) :
-        std::dynamic_pointer_cast<ModelAPI_Feature>(*anIter);
+      aFeature = ModelAPI_Feature::feature(*anIter);
       if (!aFeature)
         continue;
 
-      anEntity = changeEntity(aFeature, aType);
-      // Sort entities by their type
-      std::vector<Slvs_Entity>::iterator anIt = aList->begin();
-      for (; anIt != aList->end(); anIt++)
-        if (aType < anIt->type)
-          break;
-//      aList->push_back(myStorage->getEntity(anEntity));
-      aList->insert(anIt, myStorage->getEntity(anEntity));
+      myStorage->update(aFeature, myGroupID);
+      aList->push_back(myStorage->entity(aFeature));
     }
   }
 
@@ -75,16 +57,14 @@ void SketchSolver_ConstraintMirror::getAttributes(
 void SketchSolver_ConstraintMirror::process()
 {
   cleanErrorMsg();
-  if (!myBaseConstraint || !myStorage || myGroup == 0) {
-    /// TODO: Put error message here
+  if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) {
+    // Not enough parameters are assigned
     return;
   }
-  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-    update(myBaseConstraint);
 
-  Slvs_Entity aMirrorLine;
-  std::vector<Slvs_Entity> aBaseList;
-  std::vector<Slvs_Entity> aMirrorList;
+  EntityWrapperPtr aMirrorLine;
+  std::vector<EntityWrapperPtr> aBaseList;
+  std::vector<EntityWrapperPtr> aMirrorList;
   getAttributes(aMirrorLine, aBaseList, aMirrorList);
   if (!myErrorMsg.empty())
     return;
@@ -94,389 +74,61 @@ void SketchSolver_ConstraintMirror::process()
     return;
   }
 
-  Slvs_Constraint aConstraint;
-  // Get coordinates of mirror line points for speed up
-  double aStartEnd[4];
-  for (int i = 0; i < 2; i++) {
-    Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]);
-    for (int j = 0; j < 2; j++)
-      aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val;
-  }
-
-  std::vector<Slvs_Entity>::iterator aBaseIter = aBaseList.begin();
-  std::vector<Slvs_Entity>::iterator aMirrorIter = aMirrorList.begin();
-  for (; aBaseIter != aBaseList.end(); aBaseIter++, aMirrorIter++) {
-    // Make aMirrorEnt parameters to be symmetric with aBaseEnt
-    makeMirrorEntity(*aBaseIter, *aMirrorIter, aStartEnd);
-
-    if (aBaseIter->type == SLVS_E_POINT_IN_2D) {
-      aConstraint = Slvs_MakeConstraint(
-          SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
-          0.0, aBaseIter->h, aMirrorIter->h, aMirrorLine.h, SLVS_E_UNKNOWN);
-      aConstraint.h = myStorage->addConstraint(aConstraint);
-      mySlvsConstraints.push_back(aConstraint.h);
-    } else if (aBaseIter->type == SLVS_E_LINE_SEGMENT) {
-      for (int i = 0; i < 2; i++) {
-        aConstraint = Slvs_MakeConstraint(
-            SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
-            aBaseIter->point[i], aMirrorIter->point[i], aMirrorLine.h, SLVS_E_UNKNOWN);
-        aConstraint.h = myStorage->addConstraint(aConstraint);
-        mySlvsConstraints.push_back(aConstraint.h);
-      }
-    } else if (aBaseIter->type == SLVS_E_CIRCLE) {
-      aConstraint = Slvs_MakeConstraint(
-          SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
-          aBaseIter->point[0], aMirrorIter->point[0], aMirrorLine.h, SLVS_E_UNKNOWN);
-      aConstraint.h = myStorage->addConstraint(aConstraint);
-      mySlvsConstraints.push_back(aConstraint.h);
-      // Additional constraint for equal radii
-      Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
-          SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_EQUAL_RADIUS, myGroup->getWorkplaneId(),
-          0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseIter->h, aMirrorIter->h);
-      anEqRadConstr.h = myStorage->addConstraint(anEqRadConstr);
-      mySlvsConstraints.push_back(anEqRadConstr.h);
-    } else if (aBaseIter->type == SLVS_E_ARC_OF_CIRCLE) {
-      // Workaround to avoid problems in SolveSpace.
-      // The symmetry of two arcs will be done using symmetry of three points on these arcs:
-      // start point, end point, and any other point on the arc
-      Slvs_hEntity aBaseArcPoints[3] = {
-          aBaseIter->point[1],
-          aBaseIter->point[2],
-          SLVS_E_UNKNOWN};
-      Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
-          aMirrorIter->point[2],
-          aMirrorIter->point[1],
-          SLVS_E_UNKNOWN};
-
-      Slvs_Entity aBothArcs[2] = {*aBaseIter, *aMirrorIter};
-      Slvs_hEntity aBothMiddlePoints[2];
-      for (int i = 0; i < 2; i++) {
-        double x, y;
-        calculateMiddlePoint(aBothArcs[i], 0.5, x, y);
-        Slvs_Param aParamX = Slvs_MakeParam(SLVS_E_UNKNOWN, myGroup->getId(), x);
-        Slvs_Param aParamY = Slvs_MakeParam(SLVS_E_UNKNOWN, myGroup->getId(), y);
-        aParamX.h = myStorage->addParameter(aParamX);
-        aParamY.h = myStorage->addParameter(aParamY);
-        Slvs_Entity aPoint = Slvs_MakePoint2d(SLVS_E_UNKNOWN, myGroup->getId(),
-            myGroup->getWorkplaneId(), aParamX.h, aParamY.h);
-        aBothMiddlePoints[i] = myStorage->addEntity(aPoint);
-        // additional constraint point-on-curve
-        Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
-            SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_CIRCLE, myGroup->getWorkplaneId(),
-            0.0, aBothMiddlePoints[i], SLVS_E_UNKNOWN, aBothArcs[i].h, SLVS_E_UNKNOWN);
-        aPonCircConstr.h = myStorage->addConstraint(aPonCircConstr);
-        mySlvsConstraints.push_back(aPonCircConstr.h);
-        if (i == 0) {
-          // additional constraint for the point to be in the middle of a base arc
-          Slvs_Entity aLine1 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
-              myGroup->getWorkplaneId(), aBothArcs[i].point[1], aBothMiddlePoints[i]);
-          aLine1.h = myStorage->addEntity(aLine1);
-          Slvs_Entity aLine2 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
-              myGroup->getWorkplaneId(), aBothArcs[i].point[2], aBothMiddlePoints[i]);
-          aLine2.h = myStorage->addEntity(aLine2);
-          Slvs_Constraint aMiddleConstr = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
-              SLVS_C_EQUAL_LENGTH_LINES, myGroup->getWorkplaneId(),
-              0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aLine1.h, aLine2.h);
-          aMiddleConstr.h = myStorage->addConstraint(aMiddleConstr);
-          mySlvsConstraints.push_back(aMiddleConstr.h);
-        }
-      }
-
-      aBaseArcPoints[2] = aBothMiddlePoints[0];
-      aMirrorArcPoints[2] = aBothMiddlePoints[1];
-      for (int ind = 0; ind < 3; ind++) {
-        Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-            SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
-            aBaseArcPoints[ind], aMirrorArcPoints[ind], aMirrorLine.h, SLVS_E_UNKNOWN);
-        aConstraint.h = myStorage->addConstraint(aConstraint);
-        mySlvsConstraints.push_back(aConstraint.h);
-      }
+  std::list<ConstraintWrapperPtr> aNewConstraints;
+  SketchSolver_ConstraintType aConstrType = getType();
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+  std::list<ConstraintWrapperPtr> aMirConstrList;
+
+  std::vector<EntityWrapperPtr>::iterator aBIt = aBaseList.begin();
+  std::vector<EntityWrapperPtr>::iterator aMIt = aMirrorList.begin();
+  for (; aBIt != aBaseList.end(); ++aBIt, ++aMIt) {
+    if ((*aBIt)->type() == ENTITY_ARC) {
+      // add new points on arcs and mirror them
+      EntityWrapperPtr aBasePnt = myStorage->calculateMiddlePoint(*aBIt, 0.5);
+      EntityWrapperPtr aMirrPnt = myStorage->calculateMiddlePoint(*aMIt, 0.5);
+      // point on base arc
+      aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID,
+          CONSTRAINT_PT_ON_CIRCLE, 0.0, aBasePnt, EntityWrapperPtr(), *aBIt);
+      aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end());
+      // point on mirrored arc
+      aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID,
+          CONSTRAINT_PT_ON_CIRCLE, 0.0, aMirrPnt, EntityWrapperPtr(), *aMIt);
+      aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end());
+      // mirror these points
+      aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID,
+          aConstrType, 0.0, aBasePnt, aMirrPnt, aMirrorLine);
+      aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end());
     }
+    aNewConstraints = aBuilder->createConstraint(
+        myBaseConstraint, myGroupID, mySketchID, aConstrType,
+        0.0, *aBIt, *aMIt, aMirrorLine);
+    aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end());
   }
+
+  myStorage->addConstraint(myBaseConstraint, aMirConstrList);
 }
 
 
-void SketchSolver_ConstraintMirror::update(ConstraintPtr theConstraint)
+void SketchSolver_ConstraintMirror::update()
 {
   cleanErrorMsg();
-  if (!theConstraint || theConstraint == myBaseConstraint) {
-    AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-        myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C()));
-    if (aMirroredRefList->size() != myNumberOfObjects) {
-      remove(myBaseConstraint);
-      process();
-      return;
-    }
+  AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+    myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C()));
+  if (aMirroredRefList->size() != myNumberOfObjects) {
+    remove();
+    process();
+    return;
   }
   SketchSolver_Constraint::update();
 }
 
-bool SketchSolver_ConstraintMirror::remove(ConstraintPtr theConstraint)
-{
-  cleanErrorMsg();
-  if (theConstraint && theConstraint != myBaseConstraint)
-    return false;
-  bool isFullyRemoved = true;
-  std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
-  for (; aCIter != mySlvsConstraints.end(); aCIter++)
-   isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
-  mySlvsConstraints.clear();
-
-  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
-  for (; aFeatIt != myFeatureMap.end(); aFeatIt++)
-    myStorage->removeEntity(aFeatIt->second);
-
-  if (isFullyRemoved) {
-    myFeatureMap.clear();
-    myAttributeMap.clear();
-    myValueMap.clear();
-  } else
-    cleanRemovedEntities();
-  return true;
-}
-
-bool SketchSolver_ConstraintMirror::checkAttributesChanged(ConstraintPtr theConstraint)
-{
-  // First of all, check the mirror line is changed.
-  // It may be changed to one of mirrored lines, which is already in this constraint
-  // (this case is not marked as attribute changing)
-  ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
-  AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-      aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-  if (!aRefAttr || !aRefAttr->isObject() || !aRefAttr->object())
-    return true;
-  FeaturePtr aMirrorLine = ModelAPI_Feature::feature(aRefAttr->object());
-  if (!aMirrorLine)
-    return true;
-
-  std::map<FeaturePtr, Slvs_hEntity>::iterator aMirrorIter = myFeatureMap.find(aMirrorLine);
-  if (aMirrorIter == myFeatureMap.end())
-    return true;
-
-  // Check the entity is not used as mirror line
-  std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
-  for (; aCIter != mySlvsConstraints.end(); aCIter++) {
-    Slvs_Constraint aMirrorConstr = myStorage->getConstraint(*aCIter);
-    if (aMirrorConstr.type != SLVS_C_SYMMETRIC_LINE)
-      continue;
-    if (aMirrorConstr.entityA != aMirrorIter->second)
-      return true;
-    else break; // check just one symmetric constraint
-  }
-
-  // Base verification
-  return SketchSolver_Constraint::checkAttributesChanged(theConstraint);
-}
-
-void SketchSolver_ConstraintMirror::makeMirrorEntity(
-    const Slvs_Entity& theBase,
-    const Slvs_Entity& theMirror,
-    const double theMirrorLine[]) const
-{
-  Slvs_hEntity aBasePoint[4];
-  Slvs_hEntity aMirrorPoint[4];
-  for (int i = 0; i < 4; i++) {
-    aBasePoint[i] = theBase.point[i];
-    aMirrorPoint[i] = theMirror.point[i];
-  }
-  if (theBase.type == SLVS_E_ARC_OF_CIRCLE) {
-    Slvs_hEntity aTmp = aMirrorPoint[2];
-    aMirrorPoint[2] = aMirrorPoint[1];
-    aMirrorPoint[1] = aTmp;
-    adjustArcPoints(theBase);
-  }
-  if (theBase.type == SLVS_E_POINT_IN_2D || theBase.type == SLVS_E_POINT_IN_3D) {
-    aBasePoint[0] = theBase.h;
-    aMirrorPoint[0] = theMirror.h;
-  }
-
-  // Mirror line parameters
-  std::shared_ptr<GeomAPI_XY> aLinePoints[2];
-  for (int i = 0; i < 2; i++)
-    aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
-        new GeomAPI_XY(theMirrorLine[2*i], theMirrorLine[2*i+1]));
-  // direction of a mirror line
-  std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
-    new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
-  // orthogonal direction
-  aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
-
-  Slvs_hConstraint aFixed; // transient variable
-  for (int i = 0; i < 4; i++) {
-    if (aBasePoint[i] == SLVS_E_UNKNOWN || aMirrorPoint[i] == SLVS_E_UNKNOWN)
-      continue;
-    // check the mirror point is not fixed
-    if (myStorage->isPointFixed(aMirrorPoint[i], aFixed, true))
-      continue;
-
-    Slvs_Entity aPointEnt = myStorage->getEntity(aBasePoint[i]);
-    double aBaseX = myStorage->getParameter(aPointEnt.param[0]).val;
-    double aBaseY = myStorage->getParameter(aPointEnt.param[1]).val;
-    std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(aBaseX, aBaseY));
-
-    std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
-        new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
-    double aDist = aVec->dot(aDir->xy());
-    aPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
-
-    Slvs_Entity aMirrorEnt = myStorage->getEntity(aMirrorPoint[i]);
-    Slvs_Param aParam = Slvs_MakeParam(aMirrorEnt.param[0], myGroup->getId(), aPoint->x());
-    myStorage->updateParameter(aParam);
-    aParam = Slvs_MakeParam(aMirrorEnt.param[1], myGroup->getId(), aPoint->y());
-    myStorage->updateParameter(aParam);
-  }
-}
-
-void SketchSolver_ConstraintMirror::adjustArcPoints(const Slvs_Entity& theArc) const
-{
-  Slvs_Param aParam;
-  Slvs_Entity aPoint;
-  double anArcParams[3][2];
-  for (int i = 0; i < 3; i++) {
-    aPoint = myStorage->getEntity(theArc.point[i]);
-    for (int j = 0; j < 2; j++) {
-      aParam = myStorage->getParameter(aPoint.param[j]);
-      anArcParams[i][j] = aParam.val;
-      if (i > 0)
-        anArcParams[i][j] -= anArcParams[0][j];
-    }
-  }
-  double aRad2 = anArcParams[1][0] * anArcParams[1][0] + anArcParams[1][1] * anArcParams[1][1];
-  double aDist2 = anArcParams[2][0] * anArcParams[2][0] + anArcParams[2][1] * anArcParams[2][1];
-  if (std::fabs(aRad2 - aDist2) < tolerance)
-    return; // nothing to update (last point already on the arc)
-  if (aDist2 < tolerance)
-    return; // unable to update
-  double aCoeff = std::sqrt(aRad2 / aDist2);
-  anArcParams[2][0] *= aCoeff;
-  anArcParams[2][1] *= aCoeff;
-
-  // Update last point
-  aPoint = myStorage->getEntity(theArc.point[2]);
-  for (int i = 0; i < 2; i++) {
-    aParam = Slvs_MakeParam(aPoint.param[i], myGroup->getId(),
-        anArcParams[0][i] + anArcParams[2][i]);
-    myStorage->updateParameter(aParam);
-  }
-}
-
 void SketchSolver_ConstraintMirror::adjustConstraint()
 {
-  AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-      myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-  if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) {
-    myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
-    return;
-  }
-  ResultConstructionPtr aRC =
-      std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aMirLineAttr->object());
-  FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
-    std::dynamic_pointer_cast<ModelAPI_Feature>(aMirLineAttr->object());
-  std::map<FeaturePtr, Slvs_hEntity>::iterator aMirLineIter = myFeatureMap.find(aFeature);
-  if (aMirLineIter == myFeatureMap.end())
-    return;
-  Slvs_Entity aMirrorLine = myStorage->getEntity(aMirLineIter->second);
-
-  Slvs_Constraint aMirror;
-  double aStartEnd[4];
-  for (int i = 0; i < 2; i++) {
-    Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]);
-    for (int j = 0; j < 2; j++)
-      aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val;
-  }
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
 
-  // Calculate length of the mirror line and create temporary constraint
-  double aLength = sqrt((aStartEnd[2] - aStartEnd[0]) * (aStartEnd[2] - aStartEnd[0]) +
-                        (aStartEnd[3] - aStartEnd[1]) * (aStartEnd[3] - aStartEnd[1]));
-  if (aLength < tolerance) {
-    if (myMirrorLineLength < 1.0)
-      myMirrorLineLength = 1.0;
-  } else
-    myMirrorLineLength = aLength;
-  std::list<Slvs_Constraint> aDist = myStorage->getConstraintsByType(SLVS_C_PT_PT_DISTANCE);
-  std::list<Slvs_Constraint>::const_iterator aDIt = aDist.begin();
-  for (; aDIt != aDist.end(); ++aDIt)
-    if ((aDIt->ptA == aMirrorLine.point[0] && aDIt->ptB == aMirrorLine.point[1]) ||
-        (aDIt->ptA == aMirrorLine.point[1] && aDIt->ptB == aMirrorLine.point[0]))
-      break; // length of mirror line is already set
-  if (aDIt == aDist.end()) {
-    // check the points of mirror line is not fixed
-    Slvs_hConstraint aFixed;
-    if (!myStorage->isPointFixed(aMirrorLine.point[0], aFixed, true) ||
-        !myStorage->isPointFixed(aMirrorLine.point[1], aFixed, true)) {
-      // Add length constraint
-      aMirror = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_PT_DISTANCE,
-          myGroup->getWorkplaneId(), aLength, aMirrorLine.point[0], aMirrorLine.point[1],
-          SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-      aMirror.h = myStorage->addConstraint(aMirror);
-      myStorage->addTemporaryConstraint(aMirror.h);
-    }
-  }
-
-  // Search mirror between middle points on the arcs and recompute their coordinates
-  std::map<Slvs_hEntity, Slvs_hEntity> aPointsOnCircles;
-  std::list<Slvs_Constraint> aMirrorPonCirc;
-  std::list<Slvs_Constraint> aPonCirc = myStorage->getConstraintsByType(SLVS_C_PT_ON_CIRCLE);
-  std::vector<Slvs_hConstraint>::iterator aConstrIter = mySlvsConstraints.begin();
-  for (; aConstrIter != mySlvsConstraints.end(); aConstrIter++) {
-    aMirror = myStorage->getConstraint(*aConstrIter);
-    if (aMirror.type != SLVS_C_SYMMETRIC_LINE)
-      continue;
-    if (aMirror.entityA != aMirrorLine.h)
-      continue; // don't update another Mirror constraints
-    Slvs_Constraint aPonCircA, aPonCircB;
-    aPonCircA.h = SLVS_E_UNKNOWN;
-    aPonCircB.h = SLVS_E_UNKNOWN;
-    std::list<Slvs_Constraint>::iterator aPtIter = aPonCirc.begin();
-    for (; aPtIter != aPonCirc.end(); aPtIter++) {
-      if (aMirror.ptA == aPtIter->ptA)
-        aPonCircA = *aPtIter;
-      if (aMirror.ptB == aPtIter->ptA)
-        aPonCircB = *aPtIter;
-    }
-    if (aPonCircA.h == SLVS_E_UNKNOWN || aPonCircB.h == SLVS_E_UNKNOWN)
-      continue;
-    aMirrorPonCirc.push_back(aMirror);
-    // Store point IDs to avoid their recalculation twice
-    aPointsOnCircles[aPonCircA.ptA] = aPonCircA.entityA;
-    aPointsOnCircles[aPonCircB.ptA] = aPonCircB.entityA;
-  }
-
-  // Recalculate positions of mirroring points
-  std::list<Slvs_Constraint> aMirrorList = myStorage->getConstraintsByType(SLVS_C_SYMMETRIC_LINE);
-  std::list<Slvs_Constraint>::iterator aMirIter = aMirrorList.begin();
-  for (; aMirIter != aMirrorList.end(); aMirIter++) {
-    if (aMirIter->entityA != aMirrorLine.h)
-      continue; // don't update another Mirror constraints
-    if (aPointsOnCircles.find(aMirIter->ptA) != aPointsOnCircles.end())
-      continue; // Avoid mirroring points on circles
-    Slvs_Entity aBase = myStorage->getEntity(aMirIter->ptA);
-    Slvs_Entity aMirror = myStorage->getEntity(aMirIter->ptB);
-    makeMirrorEntity(aBase, aMirror, aStartEnd);
-  }
-
-  bool aNeedToResolve = myStorage->isNeedToResolve();
-  for (aMirIter = aMirrorPonCirc.begin(); aMirIter != aMirrorPonCirc.end(); aMirIter++) {
-    // Make centers of arcs symmetric
-    Slvs_Entity aBaseArc = myStorage->getEntity(aPointsOnCircles[aMirIter->ptA]);
-    Slvs_Entity aBasePoint = myStorage->getEntity(aBaseArc.point[0]);
-    Slvs_Entity aMirrorArc = myStorage->getEntity(aPointsOnCircles[aMirIter->ptB]);
-    Slvs_Entity aMirrorPoint = myStorage->getEntity(aMirrorArc.point[0]);
-    makeMirrorEntity(aBasePoint, aMirrorPoint, aStartEnd);
-    // Calculate middle point for base arc and mirrored point on mirror arc
-    aBasePoint = myStorage->getEntity(aMirIter->ptA);
-    Slvs_Param aParamX = myStorage->getParameter(aBasePoint.param[0]);
-    Slvs_Param aParamY = myStorage->getParameter(aBasePoint.param[1]);
-    calculateMiddlePoint(aBaseArc, 0.5, aParamX.val, aParamY.val);
-    myStorage->updateParameter(aParamX);
-    myStorage->updateParameter(aParamY);
-    aMirrorPoint = myStorage->getEntity(aMirIter->ptB);
-    aParamX = myStorage->getParameter(aMirrorPoint.param[0]);
-    aParamY = myStorage->getParameter(aMirrorPoint.param[1]);
-    calculateMiddlePoint(aMirrorArc, 0.5, aParamX.val, aParamY.val);
-    myStorage->updateParameter(aParamX);
-    myStorage->updateParameter(aParamY);
-  }
-  // Restore previous value to avoid looped recalculations of sketch
-  myStorage->setNeedToResolve(aNeedToResolve);
+  const std::list<ConstraintWrapperPtr>& aConstraints = myStorage->constraint(myBaseConstraint);
+  std::list<ConstraintWrapperPtr>::const_iterator aCIt = aConstraints.begin();
+  for (; aCIt != aConstraints.end(); ++aCIt)
+    if ((*aCIt)->type() == CONSTRAINT_SYMMETRIC)
+      aBuilder->adjustConstraint(*aCIt);
 }
index f6aa365eb616810b736c30d501cd36644449a985..9986fc2a07436a57bdd637f808fbb13eea1c271d 100644 (file)
@@ -20,60 +20,36 @@ public:
   /// Constructor based on SketchPlugin constraint
   SketchSolver_ConstraintMirror(ConstraintPtr theConstraint) :
       SketchSolver_Constraint(theConstraint),
-      myNumberOfObjects(0),
-      myMirrorLineLength(0.0)
+      myNumberOfObjects(0)
   {}
 
-  virtual int getType() const
-  { return SLVS_C_SYMMETRIC_LINE; }
-
   /// \brief Update constraint
-  virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
-
-  /// \brief Tries to remove constraint
-  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
-  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+  virtual void update();
 
 protected:
   /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
   virtual void process();
 
-  /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+  /// \brief Generate list of attributes of constraint in order useful for constraints
   /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
   /// \param[out] theAttributes list of attributes to be filled
-  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes)
+  virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes)
   { /* do nothing here */ }
 
-  /// \brief Verify the attributes of constraint are changed (and constraint need to rebuild)
-  /// \param[in] theConstraint constraint, which attributes should be checked (if NULL, the myBaseConstraint is used)
-  /// \return \c true if some attributes are changed
-  virtual bool checkAttributesChanged(ConstraintPtr theConstraint);
-
   /// \brief Generate list of entities of mirror constraint
   /// \param[out] theMirrorLine     entity corresponding to mirror line
   /// \param[out] theBaseEntities   list of entities to mirror
   /// \param[out] theMirrorEntities list of mirrored entities
-  void getAttributes(Slvs_Entity& theMirrorLine,
-                     std::vector<Slvs_Entity>& theBaseEntities,
-                     std::vector<Slvs_Entity>& theMirrorEntities);
+  void getAttributes(EntityWrapperPtr& theMirrorLine,
+                     std::vector<EntityWrapperPtr>& theBaseEntities,
+                     std::vector<EntityWrapperPtr>& theMirrorEntities);
 
   /// \brief This method is used in derived objects to check consistence of constraint.
   ///        E.g. the distance between line and point may be signed.
   virtual void adjustConstraint();
 
-private:
-  /// \brief Change parameters of entities to be symmetric relative a line,
-  ///        given by array of parameters (coordinates of first and last points)
-  void makeMirrorEntity(const Slvs_Entity& theBase,
-                        const Slvs_Entity& theMirror,
-                        const double theMirrorLine[]) const;
-
-  /// \brief Precisely update last point to be on arc
-  void adjustArcPoints(const Slvs_Entity& theArc) const;
-
 private:
   size_t myNumberOfObjects;  ///< number of previously mirrored objects
-  double myMirrorLineLength; ///< length of mirror line (should be always greater than 0)
 };
 
 #endif
index b97d1a754fde25fbc659b8bfa8e0e771e1502c48..85542cb42c7cad8c36e86a18530dc18c8479da23 100644 (file)
 #include <SketchSolver_ConstraintMovement.h>
 #include <SketchSolver_Error.h>
-#include <SketchSolver_Group.h>
+#include <SketchSolver_Manager.h>
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
 
-SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(FeaturePtr theFeature)
-  : SketchSolver_ConstraintRigid(theFeature)
-{
-  process();
-}
+#include <GeomDataAPI_Point2D.h>
+
 
 void SketchSolver_ConstraintMovement::process()
 {
   cleanErrorMsg();
-  if (!myBaseFeature || !myStorage || myGroup == 0) {
-    /// TODO: Put error message here
+  if (!myBaseFeature || !myStorage || myGroupID == GID_UNKNOWN) {
+    // Not enough parameters are initialized
     return;
   }
-  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-    update(myBaseConstraint);
 
-  double aValue;
-  std::vector<Slvs_hEntity> anEntities;
-  bool isFullyMoved;
-  getAttributes(aValue, anEntities, isFullyMoved);
-  if (!myErrorMsg.empty() || (myFeatureMap.empty() && myAttributeMap.empty()))
+  ParameterWrapperPtr aValue;
+  getAttributes(aValue, myMovedEntities);
+  if (!myErrorMsg.empty() || myMovedEntities.empty()) {
+    // Nothing to move, clear the feature to avoid changing its group
+    // after removing the Movement constraint.
+    myBaseFeature = FeaturePtr();
     return;
-
-  if (isFullyMoved)
-    fixFeature();
-  else {
-    std::vector<Slvs_hEntity>::iterator anEntIt = anEntities.begin();
-    for (; anEntIt != anEntities.end(); ++anEntIt)
-      fixPoint(*anEntIt);
   }
+
+  std::vector<EntityWrapperPtr>::iterator anEntIt = myMovedEntities.begin();
+  for (; anEntIt != myMovedEntities.end(); ++anEntIt)
+    fixFeature(*anEntIt);
 }
 
 
-void SketchSolver_ConstraintMovement::getAttributes(
-    double& theValue,
-    std::vector<Slvs_hEntity>& theAttributes,
-    bool& theIsFullyMoved)
+static std::list<EntityWrapperPtr> movedEntities(
+    EntityWrapperPtr theOld, StoragePtr theOldStorage,
+    EntityWrapperPtr theNew, StoragePtr theNewStorage)
 {
-  bool isComplexFeature = false;
-  theValue = 0.0;
-  theIsFullyMoved = true;
-  int aType = SLVS_E_UNKNOWN; // type of created entity
-  Slvs_hEntity anEntityID = SLVS_E_UNKNOWN;
-  Slvs_hEntity anEntMaxID = myStorage->entityMaxID();
-  anEntityID = myGroup->getFeatureId(myBaseFeature);
-  if (anEntityID == SLVS_E_UNKNOWN) {
-    anEntityID = changeEntity(myBaseFeature, aType);
-    if (anEntityID == SLVS_E_UNKNOWN) {
-      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
-      return;
-    }
-
-    // Check the entity is complex
-    Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
-    if (anEntity.point[0] != SLVS_E_UNKNOWN)
-      isComplexFeature = true;
-    else // simple entity
-      theAttributes.push_back(anEntityID);
+  bool isFullyMoved = true;
+  std::list<EntityWrapperPtr> aMoved;
+  if (theOld->isEqual(theNew))
+    return aMoved;
+
+  std::list<EntityWrapperPtr> anOldSubs = theOld->subEntities();
+  std::list<EntityWrapperPtr> aNewSubs = theNew->subEntities();
+  std::list<EntityWrapperPtr>::const_iterator anOldIt = anOldSubs.begin();
+  std::list<EntityWrapperPtr>::const_iterator aNewIt = aNewSubs.begin();
+  for (; anOldIt != anOldSubs.end() && aNewIt != aNewSubs.end(); ++anOldIt, ++aNewIt) {
+    std::list<EntityWrapperPtr> aMovedSubs = movedEntities(
+        *anOldIt, theOldStorage, *aNewIt, theNewStorage);
+    if (aMovedSubs.size() != 1 || aMovedSubs.front() != *anOldIt)
+      isFullyMoved = false;
+    aMoved.insert(aMoved.end(), aMovedSubs.begin(), aMovedSubs.end());
   }
-  else {
-     myFeatureMap[myBaseFeature] = anEntityID;
-     isComplexFeature = true;
-  }
-
-  int aNbOutOfGroup = 0;
-  if (isComplexFeature) {
-     std::list<AttributePtr> aPoints =
-        myBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
-     std::list<AttributePtr>::iterator anIt = aPoints.begin();
-     for (; anIt != aPoints.end(); ++anIt) {
-       std::map<AttributePtr, Slvs_hEntity>::const_iterator aFound = myAttributeMap.find(*anIt);
-       Slvs_hEntity anAttr = aFound != myAttributeMap.end() ?
-                             aFound->second : myGroup->getAttributeId(*anIt);
-       Slvs_Entity anAttrEnt = myStorage->getEntity(anAttr);
-
-       // Check the attribute changes coordinates
-       std::shared_ptr<GeomDataAPI_Point2D> aPt =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt);
-       // Check the entity is not lying in the current group or it is not moved
-       if (anAttr == SLVS_E_UNKNOWN || anAttrEnt.group != myGroup->getId() ||
-           (anAttr <= anEntMaxID && !isMoved(aPt, anAttrEnt))) {
-         if (anAttrEnt.group == SLVS_G_OUTOFGROUP)
-           ++aNbOutOfGroup;
-         theIsFullyMoved = false;
-       }
-       else {
-         theAttributes.push_back(anAttr);
-         // update point coordinates
-         Slvs_Entity anAttrEnt = myStorage->getEntity(anAttr);
-         double aNewPos[2] = {aPt->x(), aPt->y()};
-         for (int i = 0; i < 2; i++) {
-           Slvs_Param aParam = myStorage->getParameter(anAttrEnt.param[i]);
-           aParam.val = aNewPos[i];
-           myStorage->updateParameter(aParam);
-         }
-       }
-     }
-  }
-
-  // Additional checking, which leads to fix whole feature, if it has fixed points
-  if (!theIsFullyMoved) {
-    Slvs_Entity aFeature = myStorage->getEntity(anEntityID);
-    int aNbPoints = 4;
-    while (aNbPoints > 0 && aFeature.point[aNbPoints-1] == SLVS_E_UNKNOWN)
-      --aNbPoints;
-    if (aNbPoints == aNbOutOfGroup + (int)theAttributes.size()) {
-      theIsFullyMoved = true;
-      return;
-    }
-  }
-
-  // Leave only points which are used in constraints
-  if (myStorage->isUsedByConstraints(anEntityID))
-    return;
-  std::vector<Slvs_hEntity>::iterator anIt = theAttributes.begin();
-  while (anIt != theAttributes.end()) {
-    if (myStorage->isUsedByConstraints(*anIt))
-      ++anIt;
-    else {
-      int aShift = anIt - theAttributes.begin();
-      theAttributes.erase(anIt);
-      anIt = theAttributes.begin() + aShift;
-    }
+  if (isFullyMoved) {
+    aMoved.clear();
+    aMoved.push_back(theOld);
   }
+  return aMoved;
 }
 
-bool SketchSolver_ConstraintMovement::isMoved(
-    std::shared_ptr<GeomDataAPI_Point2D> thePoint, const Slvs_Entity& theEntity)
-{
-  double aDeltaX = myStorage->getParameter(theEntity.param[0]).val;
-  double aDeltaY = myStorage->getParameter(theEntity.param[1]).val;
-  aDeltaX -= thePoint->x();
-  aDeltaY -= thePoint->y();
-  return aDeltaX * aDeltaX + aDeltaY * aDeltaY >= tolerance * tolerance;
-}
 
-void SketchSolver_ConstraintMovement::fixFeature()
+void SketchSolver_ConstraintMovement::getAttributes(
+    ParameterWrapperPtr& theValue,
+    std::vector<EntityWrapperPtr>& theAttributes)
 {
-  Slvs_hEntity anEntID = fixedEntity();
-
-  std::string aKind;
-  std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFIt = myFeatureMap.begin();
-  for (; aFIt != myFeatureMap.end() && aKind.empty(); ++aFIt)
-    if (aFIt->second == anEntID)
-      aKind = aFIt->first->getKind();
-  std::map<AttributePtr, Slvs_hEntity>::const_iterator anAtIt = myAttributeMap.begin();
-  for (; anAtIt != myAttributeMap.end() && aKind.empty(); ++anAtIt)
-    if (anAtIt->second == anEntID)
-      aKind = anAtIt->first->attributeType();
+  // There will be build entities, according to the fixed feature, in the separate storage
+  // to check whether any point is moved
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+  StoragePtr anOtherStorage = aBuilder->createStorage(myGroupID);
+  anOtherStorage->setSketch(myStorage->sketch());
+  if (!anOtherStorage->update(myBaseFeature, myGroupID))
+    return;
+  EntityWrapperPtr aNewEntity = anOtherStorage->entity(myBaseFeature);
+  EntityWrapperPtr anOldEntity = myStorage->entity(myBaseFeature);
 
-  if (aKind == SketchPlugin_Line::ID()) {
-    Slvs_Entity aLine = myStorage->getEntity(anEntID);
-    fixLine(aLine);
-  }
-  else if (aKind == SketchPlugin_Arc::ID()) {
-    Slvs_Entity anArc = myStorage->getEntity(anEntID);
-    fixArc(anArc);
-  }
-  else if (aKind == SketchPlugin_Circle::ID()) {
-    Slvs_Entity aCirc = myStorage->getEntity(anEntID);
-    fixCircle(aCirc);
-  }
-  else if (aKind == SketchPlugin_Point::ID() || aKind == GeomDataAPI_Point2D::typeId()) {
-    fixPoint(anEntID);
+  std::list<EntityWrapperPtr> aMoved;
+  if (aNewEntity && anOldEntity)
+    aMoved = movedEntities(anOldEntity, myStorage, aNewEntity, anOtherStorage);
+  else {
+    // get attributes moved
+    std::list<AttributePtr> anAttrList =
+        myBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
+    std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
+    for (; anIt != anAttrList.end(); ++anIt) {
+      aNewEntity = anOtherStorage->entity(*anIt);
+      anOldEntity = myStorage->entity(*anIt);
+      if (!aNewEntity || !anOldEntity)
+        continue;
+      std::list<EntityWrapperPtr> aMovedAttr = movedEntities(
+          anOldEntity, myStorage, aNewEntity, anOtherStorage);
+      aMoved.insert(aMoved.end(), aMovedAttr.begin(), aMovedAttr.end());
+    }
   }
+  theAttributes.clear();
+  theAttributes.insert(theAttributes.begin(), aMoved.begin(), aMoved.end());
 }
-
index dbec1b020e25ea06bf4a910cb4431c84f5417e9d..ba119beaadf2f6bc7cab53469949838d3b9a19c3 100644 (file)
@@ -8,25 +8,25 @@
 #define SketchSolver_ConstraintMovement_H_
 
 #include "SketchSolver.h"
-#include <SketchSolver_ConstraintRigid.h>
-
-#include <GeomDataAPI_Point2D.h>
+#include <SketchSolver_ConstraintFixed.h>
 
 /** \class   SketchSolver_ConstraintMovement
  *  \ingroup Plugins
- *  \brief   Stores data of Rigid (Fixed) constraint for the moved feature only
+ *  \brief   Stores data to the Fixed constraint for the moved feature only
  */
-class SketchSolver_ConstraintMovement : public SketchSolver_ConstraintRigid
+class SketchSolver_ConstraintMovement : public SketchSolver_ConstraintFixed
 {
 private:
   /// Creates constraint to manage the given constraint from plugin
   SketchSolver_ConstraintMovement(ConstraintPtr theConstraint)
-    : SketchSolver_ConstraintRigid(theConstraint)
+    : SketchSolver_ConstraintFixed(theConstraint)
   {}
 
 public:
   /// Creates temporary constraint based on feature
-  SketchSolver_ConstraintMovement(FeaturePtr theFeature);
+  SketchSolver_ConstraintMovement(FeaturePtr theFeature)
+    : SketchSolver_ConstraintFixed(theFeature)
+  {}
 
 protected:
   /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
@@ -34,16 +34,11 @@ protected:
 
   /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
   /// \param[out] theValue        numerical characteristic of constraint (e.g. distance)
-  /// \param[out] theAttributes   list of attributes to be filled
-  /// \param[out] theIsFullyMoved shows that the feature is moved, in other case only one point of the feature is shifted
-  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes, bool& theIsFullyMoved);
-
-  /// \brief Fixed feature basing on its type
-  virtual void fixFeature();
+  /// \param[out] theAttributes   list of attributes to be filled (list of moved entities or attributes)
+  virtual void getAttributes(ParameterWrapperPtr& theValue, std::vector<EntityWrapperPtr>& theAttributes);
 
 private:
-  /// \brief Check the coordinates of point are differ than coordinates of correponding SolveSpace entity
-  bool isMoved(std::shared_ptr<GeomDataAPI_Point2D> thePoint, const Slvs_Entity& theEntity);
+  std::vector<EntityWrapperPtr> myMovedEntities; ///< list of entities that are moved
 };
 
 #endif
index 5be0d2fe596ce718db4c4217312f6c009b6d74f9..8f9e8c04697475a83a525739e76e483a4ea791bd 100644 (file)
 #include <SketchSolver_ConstraintMulti.h>
-#include <SketchSolver_Group.h>
 #include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
 
-#include <SketchPlugin_Arc.h>
-
-#include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeInteger.h>
 #include <ModelAPI_AttributeRefAttr.h>
 #include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_ResultConstruction.h>
-
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_XY.h>
 
-#include <math.h>
-
-void SketchSolver_ConstraintMulti::processEntities(const std::vector< std::vector<Slvs_hEntity> >& theEntAndCopies)
+void SketchSolver_ConstraintMulti::getEntitiesAndCopies(
+    std::list< std::list<EntityWrapperPtr> >& theEntAndCopies)
 {
-  // Keep all objects unchanged (only initial object may be changed by user)
-  myCircsAndCopies.clear();
-  std::vector<std::vector<Slvs_hEntity> >::const_iterator anEntIt = theEntAndCopies.begin();
-  std::vector<Slvs_hEntity>::const_iterator aCpIt;
-  for (; anEntIt != theEntAndCopies.end(); ++anEntIt) {
-    std::vector<Slvs_hEntity> aCircs;
-    aCpIt = anEntIt->begin();
-    // Obtain initial points
-    Slvs_Entity anInitial = myStorage->getEntity(*aCpIt);
-    if (anInitial.type == SLVS_E_POINT_IN_2D || anInitial.type == SLVS_E_POINT_IN_3D)
-      myInitialPoints.insert(anInitial.h);
-    else {
-      for (int i = 0; i < 4 && anInitial.point[i] != SLVS_E_UNKNOWN; i++)
-        myInitialPoints.insert(anInitial.point[i]);
-    }
-
-    // Fix the copies
-    for (++aCpIt; aCpIt != anEntIt->end(); ++aCpIt) {
-      const Slvs_Entity& anEntity = myStorage->getEntity(*aCpIt);
-      std::vector<Slvs_hConstraint> aNewConstr;
-      if (anEntity.type == SLVS_E_CIRCLE) {
-        aCircs.push_back(anEntity.distance);
-        // for circles we fix only center
-        aNewConstr = myStorage->fixEntity(anEntity.point[0]);
-      } else
-        aNewConstr = myStorage->fixEntity(*aCpIt);
-      if (anEntity.type == SLVS_E_ARC_OF_CIRCLE)
-        aCircs.push_back(anEntity.h);
-      mySlvsConstraints.insert(mySlvsConstraints.end(), aNewConstr.begin(), aNewConstr.end());
-    }
+  DataPtr aData = myBaseConstraint->data();
+
+  // Lists of objects and number of copies
+  AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+      aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
+  myNumberOfObjects = anInitialRefList->size();
+  myNumberOfCopies = aData->integer(nameNbObjects())->value() - 1;
+  if (myNumberOfCopies <= 0)
+    return;
 
-    if (!aCircs.empty()) {
-      if (anInitial.type == SLVS_E_CIRCLE)
-        aCircs.insert(aCircs.begin(), anInitial.distance);
-      else
-        aCircs.insert(aCircs.begin(), anInitial.h);
-      myCircsAndCopies.push_back(aCircs);
-    }
+  AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+      aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
+  if (!aRefList || aRefList->size() == 0) {
+    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+    return;
   }
-}
 
-void SketchSolver_ConstraintMulti::update(ConstraintPtr theConstraint)
-{
-  cleanErrorMsg();
-  if (!theConstraint || theConstraint == myBaseConstraint) {
-    AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-        myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-    AttributeIntegerPtr aNbObjects = myBaseConstraint->integer(nameNbObjects());
-    if (anInitialRefList->size() != myNumberOfObjects || aNbObjects->value()-1 != myNumberOfCopies) {
-      remove(myBaseConstraint);
-      process();
-      return;
+  FeaturePtr aFeature;
+  std::list<EntityWrapperPtr> anEntities; // list of transformed entities
+  std::list<ObjectPtr> anObjectList = aRefList->list();
+  std::list<ObjectPtr>::iterator anObjIt = anObjectList.begin();
+  while (anObjIt != anObjectList.end()) {
+    anEntities.clear();
+    for (int i = 0; i <= myNumberOfCopies && anObjIt != anObjectList.end(); ++i, ++anObjIt) {
+      aFeature = ModelAPI_Feature::feature(*anObjIt);
+      if (!aFeature)
+        continue;
+
+      myStorage->update(aFeature);
+      anEntities.push_back(myStorage->entity(aFeature));
     }
+    if (!anEntities.empty())
+      theEntAndCopies.push_back(anEntities);
   }
-
-  updateLocal();
-  SketchSolver_Constraint::update();
 }
 
-bool SketchSolver_ConstraintMulti::remove(ConstraintPtr theConstraint)
+void SketchSolver_ConstraintMulti::update()
 {
-  cleanErrorMsg();
-  if (theConstraint && theConstraint != myBaseConstraint)
-    return false;
-  bool isFullyRemoved = true;
-  std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
-  for (; aCIter != mySlvsConstraints.end(); aCIter++)
-   isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
-  mySlvsConstraints.clear();
-
-  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
-  for (; aFeatIt != myFeatureMap.end(); aFeatIt++)
-    myStorage->removeEntity(aFeatIt->second);
-  myStorage->removeUnusedEntities();
-
-  std::map<FeaturePtr, Slvs_hEntity> aFeatureMapCopy = myFeatureMap;
-
-  if (isFullyRemoved) {
-    myFeatureMap.clear();
-    myAttributeMap.clear();
-    myValueMap.clear();
-  } else
-    cleanRemovedEntities();
-
-  // Restore initial features
-  std::map<FeaturePtr, Slvs_hEntity>::iterator aFIter = aFeatureMapCopy.begin();
-  for (; aFIter != aFeatureMapCopy.end(); ++aFIter)
-  {
-    if (myFeatureMap.find(aFIter->first) != myFeatureMap.end())
-      continue; // the feature was not removed
-    Slvs_hEntity anEntity = myGroup->getFeatureId(aFIter->first);
-    if (anEntity != SLVS_E_UNKNOWN)
-      myFeatureMap[aFIter->first] = anEntity;
-  }
-
-  // Clear list of rotated points
-  myPointsAndCopies.clear();
-  myInitialPoints.clear();
-
-  return true;
+  update(false);
 }
 
-void SketchSolver_ConstraintMulti::addFeature(FeaturePtr theFeature)
-{
-  SketchSolver_Constraint::addFeature(theFeature);
 
-  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.find(theFeature);
-  if (aFeatIt == myFeatureMap.end())
+void SketchSolver_ConstraintMulti::update(bool isForce)
+{
+  cleanErrorMsg();
+  AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+      myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+  AttributeIntegerPtr aNbObjects = myBaseConstraint->integer(nameNbObjects());
+  if (anInitialRefList->size() != myNumberOfObjects || aNbObjects->value()-1 != myNumberOfCopies) {
+    remove();
+    process();
     return;
+  }
 
-  // store list of points of the feature
-  const Slvs_Entity& theEntity = myStorage->getEntity(aFeatIt->second);
-  for (int i = 0; i < 4; i++)
-    if (theEntity.point[i] != SLVS_E_UNKNOWN)
-      myPointsJustUpdated.insert(theEntity.point[i]);
+  // update derivative object
+  updateLocal();
+  if (isForce)
+    myAdjusted = false;
+  // update parent object
+  SketchSolver_Constraint::update();
 }
 
 void SketchSolver_ConstraintMulti::adjustConstraint()
@@ -139,172 +76,12 @@ void SketchSolver_ConstraintMulti::adjustConstraint()
   if (myAdjusted)
     return; // constraint already adjusted, don't do it once again
 
-  double aRelCoord[2]  = {0.0, 0.0}; // relative coordinates of point
-  double anAbsCoord[2] = {0.0, 0.0}; // absolute coordinates of point
-
-  std::list<Slvs_Constraint> aCoincident = myStorage->getConstraintsByType(SLVS_C_POINTS_COINCIDENT);
-  std::list<Slvs_Constraint>::const_iterator aCoIt;
-
-  // Update positions of all points to satisfy angles
-  std::vector< std::vector<Slvs_hEntity> >::const_iterator aPointsIter = myPointsAndCopies.begin();
-  std::vector<Slvs_hEntity>::const_iterator aCopyIter;
-  for (; aPointsIter != myPointsAndCopies.end(); ++aPointsIter) {
-    aCopyIter = aPointsIter->begin();
-    const Slvs_Entity& anInitial = myStorage->getEntity(*aCopyIter);
-    for (int i = 0; i < 2; i++)
-      anAbsCoord[i] = myStorage->getParameter(anInitial.param[i]).val;
-    getRelative(anAbsCoord[0], anAbsCoord[1], aRelCoord[0], aRelCoord[1]);
-
-    // if the point is coincident with another one which is temporary fixed (moved by user),
-    // we will update its position correspondingly
-    Slvs_hConstraint aFixed;
-    for (aCoIt = aCoincident.begin(); aCoIt != aCoincident.end(); ++aCoIt) {
-      if ((aCoIt->ptA == anInitial.h && myInitialPoints.find(aCoIt->ptB) != myInitialPoints.end()) ||
-          (aCoIt->ptB == anInitial.h && myInitialPoints.find(aCoIt->ptA) != myInitialPoints.end())) {
-        Slvs_hEntity anOtherId = aCoIt->ptA == anInitial.h ? aCoIt->ptB : aCoIt->ptA;
-        if (!myStorage->isTemporary(aFixed) &&
-            myPointsJustUpdated.find(anOtherId) == myPointsJustUpdated.end())
-          continue; // nothing to change
-
-        const Slvs_Entity& anOtherPnt = myStorage->getEntity(anOtherId);
-        for (int i = 0; i < 2; i++) {
-          Slvs_Param anInitParam = myStorage->getParameter(anInitial.param[i]);
-          const Slvs_Param& anOtherParam = myStorage->getParameter(anOtherPnt.param[i]);
-          anInitParam.val = anOtherParam.val;
-          myStorage->updateParameter(anInitParam);
-          anAbsCoord[i] = anOtherParam.val;
-        }
-        getRelative(anAbsCoord[0], anAbsCoord[1], aRelCoord[0], aRelCoord[1]);
-      }
-    }
-
-    // update copied points
-    aCopyIter = aPointsIter->begin();
-    for (++aCopyIter; aCopyIter != aPointsIter->end(); ++aCopyIter) {
-      // transform coordinates
-      transformRelative(aRelCoord[0], aRelCoord[1]);
-      getAbsolute(aRelCoord[0], aRelCoord[1], anAbsCoord[0], anAbsCoord[1]);
-
-      const Slvs_Entity& aTarget = myStorage->getEntity(*aCopyIter);
-      for (int i = 0; i < 2; i++) {
-        Slvs_Param aParam = myStorage->getParameter(aTarget.param[i]);
-        aParam.val = anAbsCoord[i];
-        myStorage->updateParameter(aParam);
-      }
-    }
-  }
-
-  std::list<Slvs_Constraint> aDiamConstr;
-  for (aPointsIter = myCircsAndCopies.begin(); aPointsIter != myCircsAndCopies.end(); ++aPointsIter) {
-    aCopyIter = aPointsIter->begin();
-    const Slvs_Entity& anInitial = myStorage->getEntity(*aCopyIter);
-    if (anInitial.type == SLVS_E_DISTANCE) {
-      const Slvs_Param& anInitRad = myStorage->getParameter(anInitial.param[0]);
-      for (++aCopyIter; aCopyIter != aPointsIter->end(); ++aCopyIter) {
-        const Slvs_Entity& aCopy = myStorage->getEntity(*aCopyIter);
-        Slvs_Param aCopyRad = myStorage->getParameter(aCopy.param[0]);
-        aCopyRad.val = anInitRad.val;
-        myStorage->updateParameter(aCopyRad);
-      }
-    } else if (anInitial.type == SLVS_E_ARC_OF_CIRCLE) {
-      const Slvs_Entity& aCenterEnt = myStorage->getEntity(anInitial.point[0]);
-      const Slvs_Entity& aStartEnt = myStorage->getEntity(anInitial.point[1]);
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
 
-      if (aDiamConstr.empty())
-        aDiamConstr = myStorage->getConstraintsByType(SLVS_C_DIAMETER);
-      // Calculate diameter of initial arc
-      double aDiam = 0.0;
-      for (int i = 0; i < 2; i++) {
-        double d = myStorage->getParameter(aStartEnt.param[i]).val -
-                   myStorage->getParameter(aCenterEnt.param[i]).val;
-        aDiam += d * d;
-      }
-      aDiam = sqrt(aDiam) * 2.0;
-      // Update the Diameter constraints of copied arcs
-      for (++aCopyIter; aCopyIter != aPointsIter->end(); ++aCopyIter) {
-        std::list<Slvs_Constraint>::iterator aDCIt = aDiamConstr.begin();
-        for (; aDCIt != aDiamConstr.end(); ++aDCIt)
-          if (aDCIt->entityA == *aCopyIter) {
-            aDCIt->valA = aDiam;
-            myStorage->updateConstraint(*aDCIt);
-            aDiamConstr.erase(aDCIt);
-            break;
-          }
-      }
-    }
-  }
-
-  myPointsJustUpdated.clear();
+  const std::list<ConstraintWrapperPtr>& aConstraints = myStorage->constraint(myBaseConstraint);
+  std::list<ConstraintWrapperPtr>::const_iterator anIt = aConstraints.begin();
+  for (; anIt != aConstraints.end(); ++anIt)
+    aBuilder->adjustConstraint(*anIt);
+  myStorage->addConstraint(myBaseConstraint, aConstraints);
   myAdjusted = true;
 }
-
-void SketchSolver_ConstraintMulti::checkCoincidence()
-{
-  std::vector< std::vector<Slvs_hEntity> > aFilteredPoints; // points are filtered by their positions
-
-  std::vector< std::vector<Slvs_hEntity> >::const_iterator aPCIt = myPointsAndCopies.begin();
-  std::vector<Slvs_hEntity>::const_iterator aCIt;
-  for (; aPCIt != myPointsAndCopies.end(); ++aPCIt) {
-    aCIt = aPCIt->begin();
-    // Skip first element, focus the copies only
-    for (++aCIt; aCIt != aPCIt->end(); ++aCIt) {
-      std::vector< std::vector<Slvs_hEntity> >::iterator aFilterIt = aFilteredPoints.begin();
-      for (; aFilterIt != aFilteredPoints.end(); ++aFilterIt)
-        if (myStorage->isEqual(*aCIt, aFilterIt->front())) {
-          aFilterIt->push_back(*aCIt);
-          break;
-        }
-      if (aFilterIt == aFilteredPoints.end()) {
-        std::vector<Slvs_hEntity> aNewFilter(1, *aCIt);
-        aFilteredPoints.push_back(aNewFilter);
-      }
-    }
-  }
-
-  // Check the coicidence of filtered points and remove extra fixation.
-  // Also check separated points which are not fixed.
-  std::vector< std::vector<Slvs_hEntity> >::iterator aFPIt = aFilteredPoints.begin();
-  for (; aFPIt != aFilteredPoints.end(); ++aFPIt) {
-    if (aFPIt->size() <= 1)
-      continue;
-    std::vector<Slvs_hEntity>::iterator anIt1, anIt2;
-    for (anIt1 = aFPIt->begin(); anIt1 != aFPIt->end(); ++anIt1) {
-      for (anIt2 = anIt1 + 1; anIt2 != aFPIt->end(); ++anIt2) {
-        Slvs_hConstraint aFixed1, aFixed2;
-        bool isFixed1 = myStorage->isPointFixed(*anIt1, aFixed1);
-        bool isFixed2 = myStorage->isPointFixed(*anIt2, aFixed2);
-        if (myStorage->isCoincident(*anIt1, *anIt2)) {
-          if (!isFixed1 && isFixed2) {
-            Slvs_hEntity aTmp = *anIt1;
-            *anIt1 = *anIt2;
-            *anIt2 = aTmp;
-          } else if (isFixed1 && isFixed2) {
-            // remove fixing of the second point
-            myStorage->removeConstraint(aFixed2);
-            std::vector<Slvs_hConstraint>::iterator aRemoveIt = mySlvsConstraints.begin();
-            for (; aRemoveIt != mySlvsConstraints.end(); ++aRemoveIt)
-              if (*aRemoveIt == aFixed2) {
-                mySlvsConstraints.erase(aRemoveIt);
-                break;
-              }
-          }
-        } else {
-          bool isFixed[2] = {
-              myStorage->isPointFixed(*anIt1, aFixed1, true),
-              myStorage->isPointFixed(*anIt2, aFixed2, true)
-          };
-
-          Slvs_hEntity aPoint[2] = {*anIt1, *anIt2};
-          for (int i = 0; i < 2; i++)
-            if (!isFixed[i]) {
-              Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
-                  SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
-                  aPoint[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-              aConstraint.h = myStorage->addConstraint(aConstraint);
-              mySlvsConstraints.push_back(aConstraint.h);
-            }
-        }
-      }
-    }
-  }
-}
index 4786ee430436040987a5dfe405366e9d8eff4892..70fe5e7817ab1ee6ffc82323be267486d5eb3ab8 100644 (file)
@@ -27,29 +27,10 @@ public:
       myAdjusted(false)
   {}
 
-  virtual int getType() const
-  { return SLVS_C_UNKNOWN; }
-
   /// \brief Update constraint
-  virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
-
-  /// \brief Tries to remove constraint
-  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
-  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
-
-  /// \brief Adds a feature to constraint and create its analogue in SolveSpace
-  virtual void addFeature(FeaturePtr theFeature);
-
-  /// \brief Update SketchPlugin attributes using the data obtained from SolveSpace entities
-  virtual void refresh()
-  {
-    myAdjusted = false;
-    SketchSolver_Constraint::refresh();
-  }
-
-  /// \brief Verifies, the coincidence between points of copied entities appears or disappears,
-  ///        and removes or adds fixing of corresponding points.
-  void checkCoincidence();
+  virtual void update();
+  /// \brief Update constraint
+  void update(bool isForce);
 
 protected:
   /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
@@ -57,12 +38,12 @@ protected:
   { /* do nothing here */ }
 
   /// \brief Collect entities and their copies, like circles and arcs
-  void processEntities(const std::vector< std::vector<Slvs_hEntity> >& theEntAndCopies);
+  void getEntitiesAndCopies(std::list< std::list<EntityWrapperPtr> >& theEntAndCopies);
 
   /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
   /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
   /// \param[out] theAttributes list of attributes to be filled
-  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes)
+  virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes)
   { /* do nothing here */ }
 
   /// \brief This method is used in derived objects to check consistence of constraint.
@@ -73,24 +54,10 @@ protected:
 
   /// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature
   virtual const std::string& nameNbObjects() = 0;
-  
-protected:
-  /// \brief Convert absolute coordinates to relative coordinates
-  virtual void getRelative(double theAbsX, double theAbsY, double& theRelX, double& theRelY) = 0;
-  /// \brief Convert relative coordinates to absolute coordinates
-  virtual void getAbsolute(double theRelX, double theRelY, double& theAbsX, double& theAbsY) = 0;
-  /// \brief Apply transformation for relative coordinates
-  virtual void transformRelative(double& theX, double& theY) = 0;
 
 protected:
-  size_t myNumberOfObjects; ///< number of previous initial objects
-  size_t myNumberOfCopies;  ///< number of previous copies of initial objects
-
-  std::vector< std::vector<Slvs_hEntity> > myPointsAndCopies; ///< list of initial points and their copies
-  std::vector< std::vector<Slvs_hEntity> > myCircsAndCopies;  ///< list of circles and their copies (to change their radii together)
-
-  std::set<Slvs_hEntity> myPointsJustUpdated; ///< list of points touched by user
-  std::set<Slvs_hEntity> myInitialPoints;     ///< list of points containing initial objects
+  int myNumberOfObjects; ///< number of previous initial objects
+  int myNumberOfCopies;  ///< number of previous copies of initial objects
 
   bool myAdjusted; ///< the constraint is already adjusted (to not do it several times)
 };
index 7608460c47d37f5bdcb2261f02843b2e92b8d08a..597d313ebf79306e38ac20356238b60596544528 100644 (file)
@@ -1,25 +1,14 @@
 #include <SketchSolver_ConstraintMultiRotation.h>
-#include <SketchSolver_Group.h>
 #include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
 
-#include <SketchPlugin_Arc.h>
 #include <SketchPlugin_MultiRotation.h>
 
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeInteger.h>
-#include <ModelAPI_AttributeRefAttr.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_ResultConstruction.h>
-
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_XY.h>
-
 #include <math.h>
 
 void SketchSolver_ConstraintMultiRotation::getAttributes(
-    Slvs_hEntity& theCenter, double& theAngle,
-    std::vector< std::vector<Slvs_hEntity> >& thePoints,
-    std::vector< std::vector<Slvs_hEntity> >& theEntities)
+    EntityWrapperPtr& theCenter, double& theAngle,
+    std::list< std::list<EntityWrapperPtr> >& theEntities)
 {
   DataPtr aData = myBaseConstraint->data();
   theAngle = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
@@ -30,106 +19,42 @@ void SketchSolver_ConstraintMultiRotation::getAttributes(
     myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
     return;
   }
-  int aType = SLVS_E_UNKNOWN; // type of created entity
-  Slvs_hEntity anEntityID = myGroup->getAttributeId(aCenterAttr);
-  if (anEntityID == SLVS_E_UNKNOWN)
-    anEntityID = changeEntity(aCenterAttr, aType);
-  theCenter = anEntityID;
-
-  // Lists of objects and number of copies
-  AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-      aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
-  myNumberOfObjects = anInitialRefList->size();
-  myNumberOfCopies = (size_t) aData->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID())->value() - 1;
-  if (myNumberOfCopies <= 0)
-    return;
-  AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-      myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
-  if (!aRefList) {
-    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
-    return;
-  }
 
-  // Obtain all points of initial features and store them into separate lists
-  // containing their translated copies.
-  // Also all circles and arc collected too, because they will be constrained by equal radii.
-  FeaturePtr aFeature;
-  ResultConstructionPtr aRC;
-  static const size_t MAX_POINTS = 3;
-  std::vector<Slvs_hEntity> aPoints[MAX_POINTS]; // lists of points of features
-  std::vector<Slvs_hEntity> anEntities;
-  std::list<ObjectPtr> anObjectList = aRefList->list();
-  std::list<ObjectPtr>::iterator anObjectIter = anObjectList.begin();
-  while (anObjectIter != anObjectList.end()) {
-    for (size_t i = 0; i < MAX_POINTS; ++i)
-      aPoints[i].clear();
-    anEntities.clear();
-
-    for (size_t i = 0; i <= myNumberOfCopies && anObjectIter != anObjectList.end(); i++, anObjectIter++) {
-      aFeature = ModelAPI_Feature::feature(*anObjectIter);
-      if (!aFeature)
-        continue;
-      anEntityID = changeEntity(aFeature, aType);
-      anEntities.push_back(anEntityID);
-      Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
-      switch (aType) {
-      case SLVS_E_POINT_IN_2D:
-      case SLVS_E_POINT_IN_3D:
-        aPoints[0].push_back(anEntityID);
-        break;
-      case SLVS_E_LINE_SEGMENT:
-        aPoints[0].push_back(anEntity.point[0]); // start point of line
-        aPoints[1].push_back(anEntity.point[1]); // end point of line
-        break;
-      case SLVS_E_CIRCLE:
-        aPoints[0].push_back(anEntity.point[0]); // center of circle
-        break;
-      case SLVS_E_ARC_OF_CIRCLE:
-        aPoints[0].push_back(anEntity.point[0]); // center of arc
-        aPoints[1].push_back(anEntity.point[1]); // start point of arc
-        aPoints[2].push_back(anEntity.point[2]); // end point of arc
-        break;
-      default:
-        myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
-        return;
-      }
-    }
-
-    for (size_t i = 0; i < MAX_POINTS; ++i)
-      if (!aPoints[i].empty())
-        thePoints.push_back(aPoints[i]);
-    if (!anEntities.empty())
-      theEntities.push_back(anEntities);
-  }
+  myType = CONSTRAINT_MULTI_ROTATION;
+
+  myStorage->update(aCenterAttr, GID_OUTOFGROUP);
+  theCenter = myStorage->entity(aCenterAttr);
+
+  getEntitiesAndCopies(theEntities);
 }
 
 void SketchSolver_ConstraintMultiRotation::process()
 {
   cleanErrorMsg();
-  if (!myBaseConstraint || !myStorage || myGroup == 0) {
+  if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) {
     /// TODO: Put error message here
     return;
   }
-  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-    update(myBaseConstraint);
 
-  std::vector<std::vector<Slvs_hEntity> > anEntitiesAndCopies;
-  getAttributes(myRotationCenter, myAngle, myPointsAndCopies, anEntitiesAndCopies);
+  EntityWrapperPtr aRotationCenter;
+  std::list<std::list<EntityWrapperPtr> > anEntitiesAndCopies;
+  getAttributes(aRotationCenter, myAngle, anEntitiesAndCopies);
   if (!myErrorMsg.empty())
     return;
 
-  // Set the rotation center unchanged during constraint recalculation
-  Slvs_Constraint aConstraint;
-  if (!myStorage->isPointFixed(myRotationCenter, aConstraint.h, true)) {
-    aConstraint = Slvs_MakeConstraint(
-        SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
-        myRotationCenter, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-    aConstraint.h = myStorage->addConstraint(aConstraint);
-    mySlvsConstraints.push_back(aConstraint.h);
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+  std::list<ConstraintWrapperPtr> aRotConstraints;
+
+  std::list< std::list<EntityWrapperPtr> >::iterator anEntIt = anEntitiesAndCopies.begin();
+  for (; anEntIt != anEntitiesAndCopies.end(); ++anEntIt) {
+    std::list<ConstraintWrapperPtr> aNewConstraints =
+        aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, myType,
+        myAngle, aRotationCenter, EntityWrapperPtr(), *anEntIt);
+    aRotConstraints.insert(aRotConstraints.end(), aNewConstraints.begin(), aNewConstraints.end());
   }
+  myStorage->addConstraint(myBaseConstraint, aRotConstraints);
 
   myAdjusted = false;
-  processEntities(anEntitiesAndCopies);
   adjustConstraint();
 }
 
@@ -141,6 +66,13 @@ void SketchSolver_ConstraintMultiRotation::updateLocal()
     myAdjusted = false;
   // update angle value
   myAngle = aValue;
+
+  // update center
+  AttributePtr aCenterAttr = myBaseConstraint->attribute(SketchPlugin_MultiRotation::CENTER_ID());
+  if (myStorage->update(aCenterAttr, myGroupID)) {
+    myStorage->update(aCenterAttr, GID_UNKNOWN);
+    myAdjusted = false;
+  }
 }
 
 void SketchSolver_ConstraintMultiRotation::adjustConstraint()
@@ -149,64 +81,15 @@ void SketchSolver_ConstraintMultiRotation::adjustConstraint()
     myStorage->setNeedToResolve(false);
     return;
   }
-  if (myAdjusted)
-    return;
 
-  std::list<Slvs_Constraint> aCoincident = myStorage->getConstraintsByType(SLVS_C_POINTS_COINCIDENT);
-  std::list<Slvs_Constraint>::const_iterator aCoIt;
-
-  // Check overconstrained on rotation center (if it is coincident with other fixed point)
-  Slvs_hConstraint aFixedCenter;
-  if (myStorage->isPointFixed(myRotationCenter, aFixedCenter, false)) {
-    Slvs_hConstraint aFixed;
-    for (aCoIt = aCoincident.begin(); aCoIt != aCoincident.end(); ++aCoIt)
-      if ((aCoIt->ptA == myRotationCenter && myStorage->isPointFixed(aCoIt->ptB, aFixed, true)) ||
-          (aCoIt->ptB == myRotationCenter && myStorage->isPointFixed(aCoIt->ptA, aFixed, true))) {
-        // Un-fix the center
-        myStorage->removeConstraint(aFixedCenter);
-        std::vector<Slvs_hConstraint>::iterator aSCIt = mySlvsConstraints.begin();
-        for (; aSCIt != mySlvsConstraints.end(); ++aSCIt)
-          if (*aSCIt == aFixedCenter) {
-            mySlvsConstraints.erase(aSCIt);
-            break;
-          }
-      }
-  }
-
-  // Obtain coordinates of rotation center
-  Slvs_Entity aRotCenter = myStorage->getEntity(myRotationCenter);
-  myCenterCoord[0] = myStorage->getParameter(aRotCenter.param[0]).val;
-  myCenterCoord[1] = myStorage->getParameter(aRotCenter.param[1]).val;
-
-  myRotationVal[0] = sin(myAngle * PI / 180.0);
-  myRotationVal[1] = cos(myAngle * PI / 180.0);
+  const std::list<ConstraintWrapperPtr>& aConstraints = myStorage->constraint(myBaseConstraint);
+  std::list<ConstraintWrapperPtr>::const_iterator aCIt = aConstraints.begin();
+  for (; aCIt != aConstraints.end(); ++aCIt)
+    (*aCIt)->setValue(myAngle);
 
   SketchSolver_ConstraintMulti::adjustConstraint();
 }
 
-void SketchSolver_ConstraintMultiRotation::getRelative(
-    double theAbsX, double theAbsY, double& theRelX, double& theRelY)
-{
-  theRelX = theAbsX - myCenterCoord[0];
-  theRelY = theAbsY - myCenterCoord[1];
-}
-
-void SketchSolver_ConstraintMultiRotation::getAbsolute(
-    double theRelX, double theRelY, double& theAbsX, double& theAbsY)
-{
-  theAbsX = theRelX + myCenterCoord[0];
-  theAbsY = theRelY + myCenterCoord[1];
-}
-
-void SketchSolver_ConstraintMultiRotation::transformRelative(double& theX, double& theY)
-{
-  // rotate direction
-  // myRotationVal[0] = sinA, myRotationVal[1] = cosA
-  double aTemp = theX * myRotationVal[1] - theY * myRotationVal[0];
-  theY = theX * myRotationVal[0] + theY * myRotationVal[1];
-  theX = aTemp;
-}
-
 const std::string& SketchSolver_ConstraintMultiRotation::nameNbObjects()
 {
   return SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID();
index 86966e522110d56d67cc83212aa824b9c77779be..6aad12d63d0ec244f42b662c571b54466fe74ae6 100644 (file)
@@ -22,21 +22,16 @@ public:
       SketchSolver_ConstraintMulti(theConstraint)
   {}
 
-  virtual int getType() const
-  { return SLVS_C_MULTI_ROTATION; }
-
 protected:
   /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
   virtual void process();
 
   /// \brief Generate list of rotated entities
-  /// \param[out] theCenter   ID of central point of rotation
+  /// \param[out] theCenter   central point of rotation
   /// \param[out] theAngle    rotation angle
-  /// \param[out] thePoints   list of IDs of initial points and their rotated copies
-  /// \param[out] theEntities list of IDs of entities and their rotated copies
-  void getAttributes(Slvs_hEntity& theCenter, double& theAngle,
-                     std::vector< std::vector<Slvs_hEntity> >& thePoints,
-                     std::vector< std::vector<Slvs_hEntity> >& theEntities);
+  /// \param[out] theEntities list of entities and their rotated copies
+  void getAttributes(EntityWrapperPtr& theCenter, double& theAngle,
+                     std::list< std::list<EntityWrapperPtr> >& theEntities);
 
   /// \brief This method is used in derived objects to check consistence of constraint.
   virtual void adjustConstraint();
@@ -44,24 +39,10 @@ protected:
   /// \brief Update parameters (called from base class)
   virtual void updateLocal();
 
-private:
-  /// \brief Convert absolute coordinates to relative coordinates
-  virtual void getRelative(double theAbsX, double theAbsY, double& theRelX, double& theRelY);
-  /// \brief Convert relative coordinates to absolute coordinates
-  virtual void getAbsolute(double theRelX, double theRelY, double& theAbsX, double& theAbsY);
-  /// \brief Apply transformation for relative coordinates
-  virtual void transformRelative(double& theX, double& theY);
-
 private:
   /// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature
   virtual const std::string& nameNbObjects();
-
-private:
-  Slvs_hEntity myRotationCenter; ///< ID of center of rotation
   double       myAngle;           ///< angle of rotation
-
-  double myCenterCoord[2]; ///< coordinates of rotation center
-  double myRotationVal[2]; ///< sinus and cosinus of rotation angle
 };
 
 #endif
index 02b872c6e549527f2bbdd56cb85c4a87707b5e9a..d6960c015b7996e1a380295b8960e25699567ae1 100644 (file)
@@ -1,27 +1,13 @@
 #include <SketchSolver_ConstraintMultiTranslation.h>
-#include <SketchSolver_Group.h>
 #include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
 
-#include <SketchPlugin_Arc.h>
 #include <SketchPlugin_MultiTranslation.h>
 
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeInteger.h>
-#include <ModelAPI_AttributeRefAttr.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_ResultConstruction.h>
-#include <ModelAPI_Data.h>
-
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_XY.h>
-
-#include <math.h>
-
 
 void SketchSolver_ConstraintMultiTranslation::getAttributes(
-    Slvs_hEntity& theStartPoint, Slvs_hEntity& theEndPoint,
-    std::vector< std::vector<Slvs_hEntity> >& thePoints,
-    std::vector< std::vector<Slvs_hEntity> >& theEntities)
+    EntityWrapperPtr& theStartPoint, EntityWrapperPtr& theEndPoint,
+    std::list< std::list<EntityWrapperPtr> >& theEntities)
 {
   DataPtr aData = myBaseConstraint->data();
   AttributePtr aStartPointAttr = aData->attribute(SketchPlugin_MultiTranslation::START_POINT_ID());
@@ -32,176 +18,47 @@ void SketchSolver_ConstraintMultiTranslation::getAttributes(
     return;
   }
 
-  int aType = SLVS_E_UNKNOWN; // type of created entity
-  Slvs_hEntity anEntityID = myGroup->getAttributeId(aStartPointAttr);
-  if (anEntityID == SLVS_E_UNKNOWN)
-    anEntityID = changeEntity(aStartPointAttr, aType);
-  theStartPoint = anEntityID;
-  anEntityID = myGroup->getAttributeId(aEndPointAttr);
-  if (anEntityID == SLVS_E_UNKNOWN)
-    anEntityID = changeEntity(aEndPointAttr, aType);
-  theEndPoint = anEntityID;
-
-  // Lists of objects and number of copies
-  AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-      aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
-  myNumberOfObjects = anInitialRefList->size();
-  myNumberOfCopies = (size_t) aData->integer(SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID())->value() - 1;
-  if (myNumberOfCopies <= 0)
-    return;
-
-  AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-      myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
-  if (!aRefList) {
-    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
-    return;
-  }
+  myType = CONSTRAINT_MULTI_TRANSLATION;
 
-  // Obtain all points of initial features and store them into separate lists
-  // containing their translated copies.
-  // Also all circles and arc collected too, because they will be constrained by equal radii.
-  FeaturePtr aFeature;
-  ResultConstructionPtr aRC;
-  static const size_t MAX_POINTS = 3;
-  std::vector<Slvs_hEntity> aPoints[MAX_POINTS]; // lists of points of features
-  std::vector<Slvs_hEntity> anEntities;          // list of translated entities
-  std::list<ObjectPtr> anObjectList = aRefList->list();
-  std::list<ObjectPtr>::iterator anObjectIter = anObjectList.begin();
-  while (anObjectIter != anObjectList.end()) {
-    for (size_t i = 0; i < MAX_POINTS; i++)
-      aPoints[i].clear();
-    anEntities.clear();
+  myStorage->update(aStartPointAttr);
+  theStartPoint = myStorage->entity(aStartPointAttr);
+  myStorage->update(aEndPointAttr);
+  theEndPoint = myStorage->entity(aEndPointAttr);
 
-    for (size_t i = 0; i <= myNumberOfCopies && anObjectIter != anObjectList.end(); i++, anObjectIter++) {
-      aFeature = ModelAPI_Feature::feature(*anObjectIter);
-      if (!aFeature)
-        continue;
-      anEntityID = changeEntity(aFeature, aType);
-      anEntities.push_back(anEntityID);
-      Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
-      switch (aType) {
-      case SLVS_E_POINT_IN_2D:
-      case SLVS_E_POINT_IN_3D:
-        aPoints[0].push_back(anEntityID);
-        break;
-      case SLVS_E_LINE_SEGMENT:
-        aPoints[0].push_back(anEntity.point[0]); // start point of line
-        aPoints[1].push_back(anEntity.point[1]); // end point of line
-        break;
-      case SLVS_E_CIRCLE:
-        aPoints[0].push_back(anEntity.point[0]); // center of circle
-        break;
-      case SLVS_E_ARC_OF_CIRCLE:
-        aPoints[0].push_back(anEntity.point[0]); // center of arc
-        aPoints[1].push_back(anEntity.point[1]); // start point of arc
-        aPoints[2].push_back(anEntity.point[2]); // end point of arc
-        break;
-      default:
-        myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
-        return;
-      }
-    }
+  getEntitiesAndCopies(theEntities);
 
-    for (size_t i = 0; i < MAX_POINTS; ++i)
-      if (!aPoints[i].empty())
-        thePoints.push_back(aPoints[i]);
-    if (!anEntities.empty())
-      theEntities.push_back(anEntities);
-  }
 }
 
 void SketchSolver_ConstraintMultiTranslation::process()
 {
   cleanErrorMsg();
-  if (!myBaseConstraint || !myStorage || myGroup == 0) {
+  if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) {
     /// TODO: Put error message here
     return;
   }
-  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-    update(myBaseConstraint);
 
-  Slvs_hEntity aStartPoint, aEndPoint;
-  std::vector<std::vector<Slvs_hEntity> > anEntitiesAndCopies;
-  getAttributes(aStartPoint, aEndPoint, myPointsAndCopies, anEntitiesAndCopies);
+  EntityWrapperPtr aStartPoint, aEndPoint;
+  std::list<std::list<EntityWrapperPtr> > anEntitiesAndCopies;
+  getAttributes(aStartPoint, aEndPoint, anEntitiesAndCopies);
   if (!myErrorMsg.empty())
     return;
 
-  // Create translation line
-  if (myTranslationLine == SLVS_E_UNKNOWN) {
-    Slvs_Entity aTranslationLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
-        myGroup->getWorkplaneId(), aStartPoint, aEndPoint);
-    aTranslationLine.h = myStorage->addEntity(aTranslationLine);
-    myTranslationLine = aTranslationLine.h;
-  } else {
-    Slvs_Entity aTranslationLine = myStorage->getEntity(myTranslationLine);
-    if (aTranslationLine.point[0] != aStartPoint || aTranslationLine.point[1] != aEndPoint) {
-      aTranslationLine.point[0] = aStartPoint;
-      aTranslationLine.point[1] = aEndPoint;
-      myStorage->updateEntity(aTranslationLine);
-    }
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+  std::list<ConstraintWrapperPtr> aTransConstraints;
+
+  std::list< std::list<EntityWrapperPtr> >::iterator anEntIt = anEntitiesAndCopies.begin();
+  for (; anEntIt != anEntitiesAndCopies.end(); ++anEntIt) {
+    std::list<ConstraintWrapperPtr> aNewConstraints =
+        aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, myType,
+        0.0, aStartPoint, aEndPoint, *anEntIt);
+    aTransConstraints.insert(aTransConstraints.end(), aNewConstraints.begin(), aNewConstraints.end());
   }
+  myStorage->addConstraint(myBaseConstraint, aTransConstraints);
 
   myAdjusted = false;
-  processEntities(anEntitiesAndCopies);
   adjustConstraint();
 }
 
-void SketchSolver_ConstraintMultiTranslation::adjustConstraint()
-{
-  if (myAdjusted)
-    return;
-
-  Slvs_Entity aTranslationLine = myStorage->getEntity(myTranslationLine);
-  Slvs_hConstraint aFixed; // temporary variable
-  // Set the translation line unchanged during constraint recalculation
-  for (int i = 0; i < 2; i++) {
-    if (myStorage->isPointFixed(aTranslationLine.point[i], aFixed, true))
-      continue;
-    Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-        SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
-        aTranslationLine.point[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-    aConstraint.h = myStorage->addConstraint(aConstraint);
-    myStorage->addTemporaryConstraint(aConstraint.h);
-  }
-
-  // Check if the distance between point is 0, no need to resolve constraints (just wait another values)
-  double aXY[4];
-  for (int i = 0; i < 2; i++) {
-    Slvs_Entity aPnt = myStorage->getEntity(aTranslationLine.point[i]);
-    aXY[2*i] = myStorage->getParameter(aPnt.param[0]).val;
-    aXY[2*i+1] = myStorage->getParameter(aPnt.param[1]).val;
-  }
-  myDelta[0] = aXY[2] - aXY[0];
-  myDelta[1] = aXY[3] - aXY[1];
-  if (fabs(myDelta[0]) + fabs(myDelta[1]) < tolerance) {
-    myStorage->setNeedToResolve(false);
-    return;
-  }
-
-  SketchSolver_ConstraintMulti::adjustConstraint();
-}
-
-void SketchSolver_ConstraintMultiTranslation::getRelative(
-    double theAbsX, double theAbsY, double& theRelX, double& theRelY)
-{
-  theRelX = theAbsX;
-  theRelY = theAbsY;
-}
-
-void SketchSolver_ConstraintMultiTranslation::getAbsolute(
-    double theRelX, double theRelY, double& theAbsX, double& theAbsY)
-{
-  theAbsX = theRelX;
-  theAbsY = theRelY;
-}
-
-void SketchSolver_ConstraintMultiTranslation::transformRelative(double& theX, double& theY)
-{
-  // translate coordinates
-  theX += myDelta[0];
-  theY += myDelta[1];
-}
-
 const std::string& SketchSolver_ConstraintMultiTranslation::nameNbObjects()
 {
   return SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID();
index c9f10147def434dcc90e67d1937686b2e1bcf17b..0e0c2faf1697375a72740fea634225a7c1fa48a1 100644 (file)
@@ -19,49 +19,27 @@ class SketchSolver_ConstraintMultiTranslation : public SketchSolver_ConstraintMu
 public:
   /// Constructor based on SketchPlugin constraint
   SketchSolver_ConstraintMultiTranslation(ConstraintPtr theConstraint) :
-      SketchSolver_ConstraintMulti(theConstraint),
-      myTranslationLine(SLVS_E_UNKNOWN)
+      SketchSolver_ConstraintMulti(theConstraint)
   {}
 
-  virtual int getType() const
-  { return SLVS_C_MULTI_TRANSLATION; }
-
 protected:
   /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
   virtual void process();
 
   /// \brief Generate list of translated entities
-  /// \param[out] theStartPoint ID of start point of translation
-  /// \param[out] theEndPoint   ID of final point of translation
-  /// \param[out] thePoints     list of IDs of initial points and their translated copies
-  /// \param[out] theEntities   list of IDs of entities and their translated copies
-  void getAttributes(Slvs_hEntity& theStartPoint, Slvs_hEntity& theEndPoint,
-                     std::vector< std::vector<Slvs_hEntity> >& thePoints,
-                     std::vector< std::vector<Slvs_hEntity> >& theEntities);
-
-  /// \brief This method is used in derived objects to check consistence of constraint.
-  virtual void adjustConstraint();
+  /// \param[out] theStartPoint start point of translation
+  /// \param[out] theEndPoint   final point of translation
+  /// \param[out] theEntities   list of entities and their translated copies
+  void getAttributes(EntityWrapperPtr& theStartPoint, EntityWrapperPtr& theEndPoint,
+                     std::list< std::list<EntityWrapperPtr> >& theEntities);
 
   /// \brief Update parameters (called from base class)
   virtual void updateLocal()
   {}
 
-private:
-  /// \brief Convert absolute coordinates to relative coordinates
-  virtual void getRelative(double theAbsX, double theAbsY, double& theRelX, double& theRelY);
-  /// \brief Convert relative coordinates to absolute coordinates
-  virtual void getAbsolute(double theRelX, double theRelY, double& theAbsX, double& theAbsY);
-  /// \brief Apply transformation for relative coordinates
-  virtual void transformRelative(double& theX, double& theY);
-
 private:
   /// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature
   virtual const std::string& nameNbObjects();
-
-private:
-  Slvs_hEntity myTranslationLine; ///< ID of translation line
-
-  double myDelta[2]; ///< increment of translation
 };
 
 #endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintParametric.cpp b/src/SketchSolver/SketchSolver_ConstraintParametric.cpp
deleted file mode 100644 (file)
index bd533ce..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-#include <SketchSolver_ConstraintParametric.h>
-#include <SketchSolver_Error.h>
-#include <SketchSolver_Group.h>
-
-#include <GeomDataAPI_Point2D.h>
-
-SketchSolver_ConstraintParametric::SketchSolver_ConstraintParametric(AttributePtr theAttribute)
-  : SketchSolver_ConstraintRigid(ConstraintPtr()),
-    myBaseAttribute(theAttribute)
-{
-  process();
-}
-
-void SketchSolver_ConstraintParametric::process()
-{
-  cleanErrorMsg();
-  if (!myBaseAttribute || !myStorage || myGroup == 0) {
-    /// TODO: Put error message here
-    return;
-  }
-  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-    update(myBaseConstraint);
-
-  Slvs_hEntity anAttrID;
-  getAttributes(anAttrID);
-  if (!myErrorMsg.empty() || (myFeatureMap.empty() && myAttributeMap.empty()))
-    return;
-
-  myHorizLineID = SLVS_E_UNKNOWN;
-  myVertLineID = SLVS_E_UNKNOWN;
-
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(myBaseAttribute);
-  if (!aPoint)
-    return;
-  if (!aPoint->textX().empty()) {
-    // Create vertical line with fixed boundary point
-    Slvs_Entity aLine = createLine(aPoint->x(), -100.0, aPoint->x(), 100.0);
-    // Place point on line
-    Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
-        SLVS_C_PT_ON_LINE, myGroup->getWorkplaneId(), 0.0, anAttrID, SLVS_E_UNKNOWN,
-        aLine.h, SLVS_E_UNKNOWN);
-    aConstraint.h = myStorage->addConstraint(aConstraint);
-    mySlvsConstraints.push_back(aConstraint.h);
-    myVertLineID = aLine.h;
-    myX = aPoint->x();
-  }
-  if (!aPoint->textY().empty()) {
-    // Create horizontal line with fixed boundary points
-    Slvs_Entity aLine = createLine(-100.0, aPoint->y(), 100.0, aPoint->y());
-    // Place point on line
-    Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
-        SLVS_C_PT_ON_LINE, myGroup->getWorkplaneId(), 0.0, anAttrID, SLVS_E_UNKNOWN,
-        aLine.h, SLVS_E_UNKNOWN);
-    aConstraint.h = myStorage->addConstraint(aConstraint);
-    mySlvsConstraints.push_back(aConstraint.h);
-    myHorizLineID = aLine.h;
-    myY = aPoint->y();
-  }
-}
-
-
-void SketchSolver_ConstraintParametric::getAttributes(Slvs_hEntity& theAttributeID)
-{
-  int aType = SLVS_E_UNKNOWN; // type of created entity
-  theAttributeID = SLVS_E_UNKNOWN;
-  theAttributeID = myGroup->getAttributeId(myBaseAttribute);
-  if (theAttributeID == SLVS_E_UNKNOWN) {
-    theAttributeID = changeEntity(myBaseAttribute, aType);
-    if (theAttributeID == SLVS_E_UNKNOWN) {
-      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
-      return;
-    }
-  }
-  else
-     myAttributeMap[myBaseAttribute] = theAttributeID;
-}
-
-
-void SketchSolver_ConstraintParametric::update(ConstraintPtr theConstraint)
-{
-  cleanErrorMsg();
-  if (!theConstraint || theConstraint == myBaseConstraint) {
-    std::shared_ptr<GeomDataAPI_Point2D> aPoint =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(myBaseAttribute);
-    if (aPoint && ((!aPoint->textX().empty() && myVertLineID == SLVS_E_UNKNOWN) || 
-        (!aPoint->textY().empty() && myHorizLineID == SLVS_E_UNKNOWN))) {
-      remove();
-      process();
-      return;
-    }
-  }
-  adjustConstraint();
-}
-
-void SketchSolver_ConstraintParametric::refresh()
-{
-  Slvs_hEntity aBasePointID = myAttributeMap[myBaseAttribute];
-  const Slvs_Entity& aBasePoint = myStorage->getEntity(aBasePointID);
-  double aXY[2];
-  aXY[0] = myVertLineID  != SLVS_E_UNKNOWN ? myX : myStorage->getParameter(aBasePoint.param[0]).val;
-  aXY[1] = myHorizLineID != SLVS_E_UNKNOWN ? myY : myStorage->getParameter(aBasePoint.param[1]).val;
-
-  std::list<Slvs_Constraint> aCoincidence = myStorage->getConstraintsByType(SLVS_C_POINTS_COINCIDENT);
-  std::list<Slvs_Constraint>::const_iterator aCIt = aCoincidence.begin();
-  for (; aCIt != aCoincidence.end(); ++aCIt) {
-    if (aCIt->ptA != aBasePointID && aCIt->ptB != aBasePointID)
-      continue;
-    Slvs_hEntity anOtherPointID = aCIt->ptA == aBasePointID ? aCIt->ptB : aCIt->ptA;
-    const Slvs_Entity& aPoint = myStorage->getEntity(anOtherPointID);
-    for (int i = 0; i < 2; i++) {
-      Slvs_Param aParam = myStorage->getParameter(aPoint.param[i]);
-      aParam.val = aXY[i];
-      myStorage->updateParameter(aParam);
-    }
-  }
-}
-
-void SketchSolver_ConstraintParametric::adjustConstraint()
-{
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(myBaseAttribute);
-  if (!aPoint)
-    return;
-
-  if (!aPoint->textX().empty()) {
-    const Slvs_Entity& aLine = myStorage->getEntity(myVertLineID);
-    const Slvs_Entity& aStartPoint = myStorage->getEntity(aLine.point[0]);
-    Slvs_Param aParX = myStorage->getParameter(aStartPoint.param[0]);
-    aParX.val = aPoint->x();
-    myStorage->updateParameter(aParX);
-    myX = aParX.val;
-  }
-  if (!aPoint->textY().empty()) {
-    const Slvs_Entity& aLine = myStorage->getEntity(myHorizLineID);
-    const Slvs_Entity& aStartPoint = myStorage->getEntity(aLine.point[0]);
-    Slvs_Param aParY = myStorage->getParameter(aStartPoint.param[1]);
-    aParY.val = aPoint->y();
-    myStorage->updateParameter(aParY);
-    myY = aParY.val;
-  }
-}
-
-
-Slvs_Entity SketchSolver_ConstraintParametric::createLine(
-    double theStartX, double theStartY, double theEndX, double theEndY)
-{
-  // Start point
-  Slvs_Param aParX = Slvs_MakeParam(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, theStartX);
-  Slvs_Param aParY = Slvs_MakeParam(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, theStartY);
-  aParX.h = myStorage->addParameter(aParX);
-  aParY.h = myStorage->addParameter(aParY);
-  Slvs_Entity aStartPoint = Slvs_MakePoint2d(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP,
-    myGroup->getWorkplaneId(), aParX.h, aParY.h);
-  aStartPoint.h = myStorage->addEntity(aStartPoint);
-
-  // End point
-  aParX = Slvs_MakeParam(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, theEndX);
-  aParY = Slvs_MakeParam(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, theEndY);
-  aParX.h = myStorage->addParameter(aParX);
-  aParY.h = myStorage->addParameter(aParY);
-  Slvs_Entity aEndPoint = Slvs_MakePoint2d(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP,
-    myGroup->getWorkplaneId(), aParX.h, aParY.h);
-  aEndPoint.h = myStorage->addEntity(aEndPoint);
-
-  // Line
-  Slvs_Entity aLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP,
-    myGroup->getWorkplaneId(), aStartPoint.h, aEndPoint.h);
-  aLine.h = myStorage->addEntity(aLine);
-  return aLine;
-}
diff --git a/src/SketchSolver/SketchSolver_ConstraintParametric.h b/src/SketchSolver/SketchSolver_ConstraintParametric.h
deleted file mode 100644 (file)
index 3a25d96..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_ConstraintParametric.h
-// Created: 15 Jun 2015
-// Author:  Artem ZHIDKOV
-
-#ifndef SketchSolver_ConstraintParametric_H_
-#define SketchSolver_ConstraintParametric_H_
-
-#include "SketchSolver.h"
-#include <SketchSolver_ConstraintRigid.h>
-
-/** \class   SketchSolver_ConstraintParametric
- *  \ingroup Plugins
- *  \brief   Stores data of Rigid (Fixed) constraint for the attribute
- *           which coordinates are given by parametric expression
- */
-class SketchSolver_ConstraintParametric : public SketchSolver_ConstraintRigid
-{
-private:
-  /// Creates constraint to manage the given constraint from plugin
-  SketchSolver_ConstraintParametric()
-    : SketchSolver_ConstraintRigid(ConstraintPtr())
-  {}
-
-public:
-  /// Creates temporary constraint based on feature
-  SketchSolver_ConstraintParametric(AttributePtr theAttribute);
-
-  /// \brief Update constraint
-  virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
-
-  /// \brief Update points coincident with parametric one
-  virtual void refresh();
-
-protected:
-  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
-  virtual void process();
-
-  /// \brief Convert attribute to the entity
-  /// \param[out] theAttributeID   identifier of the entity related to the attribute
-  virtual void getAttributes(Slvs_hEntity& theAttributeID);
-
-  /// \brief This method is used in derived objects to check consistence of constraint.
-  virtual void adjustConstraint();
-
-private:
-  /// \brief Create SolveSpace line with given coordinates
-  /// \return created line
-  Slvs_Entity createLine(double theStartX, double theStartY, double theEndX, double theEndY);
-
-private:
-  AttributePtr myBaseAttribute; ///< attribute given by expression
-  Slvs_hEntity myHorizLineID;   ///< identifier of horizontal line, containing the point
-  Slvs_hEntity myVertLineID;    ///< identifier of vertical line, containing the point
-  double myX, myY;
-};
-
-#endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.cpp b/src/SketchSolver/SketchSolver_ConstraintRigid.cpp
deleted file mode 100644 (file)
index ed8ae37..0000000
+++ /dev/null
@@ -1,393 +0,0 @@
-#include <SketchSolver_ConstraintRigid.h>
-#include <SketchSolver_Error.h>
-#include <SketchSolver_Group.h>
-
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_ConstraintRigid.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
-
-#include <GeomAPI_Pnt2d.h>
-#include <GeomAPI_XY.h>
-#include <GeomDataAPI_Point2D.h>
-#include <ModelAPI_AttributeDouble.h>
-
-#include <math.h>
-
-SketchSolver_ConstraintRigid::SketchSolver_ConstraintRigid(FeaturePtr theFeature)
-  : SketchSolver_Constraint(),
-    myBaseFeature(theFeature)
-{
-  process();
-}
-
-void SketchSolver_ConstraintRigid::process()
-{
-  cleanErrorMsg();
-  if ((!myBaseConstraint && !myBaseFeature) || !myStorage || myGroup == 0) {
-    /// TODO: Put error message here
-    return;
-  }
-  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-    update(myBaseConstraint);
-
-  double aValue;
-  std::vector<Slvs_hEntity> anEntities;
-  getAttributes(aValue, anEntities);
-  if (!myErrorMsg.empty() || (myFeatureMap.empty() && myAttributeMap.empty()))
-    return;
-  fixFeature();
-}
-
-void SketchSolver_ConstraintRigid::update(ConstraintPtr theConstraint)
-{
-  cleanErrorMsg();
-  if (theConstraint && theConstraint == myBaseConstraint &&
-      theConstraint->getKind() == myBaseConstraint->getKind() &&
-      checkAttributesChanged(theConstraint)) {
-    // remove previous constraint and set the given one
-    remove(myBaseConstraint);
-    myBaseConstraint = theConstraint;
-    process();
-  }
-}
-
-static void fixEntity(StoragePtr theStorage, const Slvs_hEntity& theEntID)
-{
-  Slvs_Entity anEntity = theStorage->getEntity(theEntID);
-  anEntity.group = SLVS_G_OUTOFGROUP;
-  theStorage->updateEntity(anEntity);
-  // move out of group all sub-entities
-  for (int i = 0; i < 4; ++i)
-    if (anEntity.point[i] != SLVS_E_UNKNOWN)
-      fixEntity(theStorage, anEntity.point[i]);
-  // move out of group the radius of circle
-  if (anEntity.distance != SLVS_E_UNKNOWN)
-    fixEntity(theStorage, anEntity.distance);
-  // move out of group parameters
-  for (int i = 0; i < 4; ++i)
-    if (anEntity.param[i] != SLVS_E_UNKNOWN) {
-      Slvs_Param aParam = theStorage->getParameter(anEntity.param[i]);
-      aParam.group = SLVS_G_OUTOFGROUP;
-      theStorage->updateParameter(aParam);
-    }
-}
-
-void SketchSolver_ConstraintRigid::fixFeature()
-{
-  Slvs_hEntity anEntID = fixedEntity();
-  if (anEntID != SLVS_E_UNKNOWN)
-    fixEntity(myStorage, anEntID);
-}
-
-Slvs_hEntity SketchSolver_ConstraintRigid::fixedEntity() const
-{
-  Slvs_hEntity anEntID = SLVS_E_UNKNOWN;
-  if (myBaseConstraint) {
-    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-        myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-    if (aRefAttr->isObject()) {
-      FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
-      std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFound = myFeatureMap.find(aFeature);
-      if (aFound != myFeatureMap.end())
-        anEntID = aFound->second;
-    } else {
-      std::map<AttributePtr, Slvs_hEntity>::const_iterator aFound = myAttributeMap.find(aRefAttr->attr());
-      if (aFound != myAttributeMap.end())
-        anEntID = aFound->second;
-    }
-  }
-  else if (myBaseFeature) {
-    std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFound = myFeatureMap.find(myBaseFeature);
-    if (aFound != myFeatureMap.end())
-      anEntID = aFound->second;
-  }
-  return anEntID;
-}
-
-void SketchSolver_ConstraintRigid::getAttributes(
-    double& theValue,
-    std::vector<Slvs_hEntity>& theAttributes)
-{
-  theValue = 0.0;
-  int aType = SLVS_E_UNKNOWN; // type of created entity
-  Slvs_hEntity anEntityID = SLVS_E_UNKNOWN;
-  if (myBaseConstraint) {
-    // Get the attribute of constraint
-    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-        myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
-    if (!aRefAttr || !aRefAttr->isInitialized()) {
-      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
-      return;
-    }
-    anEntityID = myGroup->getAttributeId(aRefAttr);
-    if (anEntityID == SLVS_E_UNKNOWN)
-      anEntityID = changeEntity(aRefAttr, aType);
-  } else {
-    anEntityID = myGroup->getFeatureId(myBaseFeature);
-    if (anEntityID == SLVS_E_UNKNOWN)
-      anEntityID = changeEntity(myBaseFeature, aType);
-    else
-      myFeatureMap[myBaseFeature] = anEntityID;
-  }
-
-  if (anEntityID == SLVS_E_UNKNOWN) {
-    myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
-    return;
-  }
-
-  // Check the entity is complex
-  Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
-  if (anEntity.point[0] != SLVS_E_UNKNOWN) {
-    for (int i = 0; i < 4 && anEntity.point[i]; i++)
-      theAttributes.push_back(anEntity.point[i]);
-  } else // simple entity
-    theAttributes.push_back(anEntityID);
-}
-
-
-bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint)
-{
-  cleanErrorMsg();
-  if (theConstraint && theConstraint != myBaseConstraint)
-    return false;
-  bool isFullyRemoved = true;
-
-  std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
-  for (; aCIter != mySlvsConstraints.end(); ++aCIter)
-    isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
-
-  std::map<FeaturePtr, Slvs_hEntity>::iterator aFIter = myFeatureMap.begin();
-  for (; aFIter != myFeatureMap.end(); ++aFIter)
-    isFullyRemoved = myStorage->removeEntity(aFIter->second) && isFullyRemoved;
-
-  std::map<AttributePtr, Slvs_hEntity>::iterator anAtIter = myAttributeMap.begin();
-  for (; anAtIter != myAttributeMap.end(); ++anAtIter)
-    isFullyRemoved = myStorage->removeEntity(anAtIter->second) && isFullyRemoved;
-
-  if (isFullyRemoved) {
-    myFeatureMap.clear();
-    myAttributeMap.clear();
-    myValueMap.clear();
-    mySlvsConstraints.clear();
-  } else
-    cleanRemovedEntities();
-  return true;
-}
-
-Slvs_hConstraint SketchSolver_ConstraintRigid::fixPoint(const Slvs_hEntity& thePointID)
-{
-  if (thePointID == SLVS_E_UNKNOWN)
-    return SLVS_C_UNKNOWN;
-
-  Slvs_Constraint aConstraint;
-  Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN;
-  bool isFixed = myStorage->isPointFixed(thePointID, aConstrID, true);
-  bool isForceUpdate = (isFixed && !myBaseConstraint &&
-                        myStorage->isTemporary(aConstrID));
-  if (!isForceUpdate) { // create new constraint
-    if (isFixed) return aConstrID;
-    aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
-        0.0, thePointID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-    aConstraint.h = myStorage->addConstraint(aConstraint);
-    mySlvsConstraints.push_back(aConstraint.h);
-    if (!myBaseConstraint)
-      myStorage->addConstraintWhereDragged(aConstraint.h);
-  } else { // update already existent constraint
-    if (!isFixed || aConstrID == SLVS_C_UNKNOWN || myBaseConstraint)
-      return SLVS_C_UNKNOWN;
-    aConstraint = myStorage->getConstraint(aConstrID);
-    aConstraint.ptA = thePointID;
-    myStorage->addConstraint(aConstraint);
-    if (!myBaseConstraint)
-      myStorage->addConstraintWhereDragged(aConstraint.h);
-  }
-  return aConstraint.h;
-}
-
-void SketchSolver_ConstraintRigid::fixLine(const Slvs_Entity& theLine)
-{
-  Slvs_Constraint anEqual;
-  if (myStorage->isAxisParallel(theLine.h)) {
-    // Fix one point and a line length
-    Slvs_hConstraint aFixed;
-    if (!myStorage->isPointFixed(theLine.point[0], aFixed, true) &&
-        !myStorage->isPointFixed(theLine.point[1], aFixed, true))
-      fixPoint(theLine.point[0]);
-    if (!myStorage->isUsedInEqual(theLine.h, anEqual)) {
-      // Check the distance is not set yet
-      std::list<Slvs_Constraint> aDistConstr = myStorage->getConstraintsByType(SLVS_C_PT_PT_DISTANCE);
-      std::list<Slvs_Constraint>::const_iterator aDIt = aDistConstr.begin();
-      for (; aDIt != aDistConstr.end(); aDIt++)
-        if ((aDIt->ptA == theLine.point[0] && aDIt->ptB == theLine.point[1]) ||
-            (aDIt->ptA == theLine.point[1] && aDIt->ptB == theLine.point[0]))
-          return;
-      // Calculate distance between points on the line
-      double aCoords[4];
-      for (int i = 0; i < 2; i++) {
-        Slvs_Entity aPnt = myStorage->getEntity(theLine.point[i]);
-        for (int j = 0; j < 2; j++) {
-          Slvs_Param aParam = myStorage->getParameter(aPnt.param[j]);
-          aCoords[2*i+j] = aParam.val;
-        }
-      }
-      double aLength = sqrt((aCoords[2] - aCoords[0]) * (aCoords[2] - aCoords[0]) + 
-                            (aCoords[3] - aCoords[1]) * (aCoords[3] - aCoords[1]));
-      // fix line length
-      Slvs_Constraint aDistance = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
-          SLVS_C_PT_PT_DISTANCE, myGroup->getWorkplaneId(), aLength,
-          theLine.point[0], theLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-      aDistance.h = myStorage->addConstraint(aDistance);
-      mySlvsConstraints.push_back(aDistance.h);
-    }
-    return;
-  }
-  else if (myStorage->isUsedInEqual(theLine.h, anEqual)) {
-    // Check another entity of Equal is already fixed
-    Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA;
-    if (myStorage->isEntityFixed(anOtherEntID, true)) {
-      // Fix start point of the line (if end point is not fixed yet) ...
-      Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN;
-      bool isFixed = myStorage->isPointFixed(theLine.point[1], anEndFixedID, true);
-      if (isFixed == SLVS_E_UNKNOWN)
-        fixPoint(theLine.point[0]);
-      // ...  and create fixed point lying on this line
-      Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0];
-      // Firstly, search already fixed point on line
-      bool isPonLineFixed = false;
-      Slvs_hEntity aFixedPoint;
-      std::list<Slvs_Constraint> aPonLineList = myStorage->getConstraintsByType(SLVS_C_PT_ON_LINE);
-      std::list<Slvs_Constraint>::const_iterator aPLIter = aPonLineList.begin();
-      for (; aPLIter != aPonLineList.end() && !isPonLineFixed; aPLIter++)
-        if (aPLIter->entityA == theLine.h) {
-          isPonLineFixed = myStorage->isPointFixed(aPLIter->ptA, anEndFixedID);
-          aFixedPoint = aPLIter->ptA;
-        }
-
-      if (isPonLineFixed) { // update existent constraint
-        myStorage->copyEntity(aPointToCopy, aFixedPoint);
-      } else { // create new constraint
-        Slvs_hEntity aCopied = myStorage->copyEntity(aPointToCopy);
-        Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_LINE,
-            myGroup->getWorkplaneId(), 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN);
-        aPonLine.h = myStorage->addConstraint(aPonLine);
-        mySlvsConstraints.push_back(aPonLine.h);
-        fixPoint(aCopied);
-      }
-      return;
-    }
-  }
-
-  for (int i = 0; i < 2; i++)
-    fixPoint(theLine.point[i]);
-}
-
-void SketchSolver_ConstraintRigid::fixCircle(const Slvs_Entity& theCircle)
-{
-  bool isFixRadius = true;
-  // Verify the arc is under Equal constraint
-  Slvs_Constraint anEqual;
-  if (myStorage->isUsedInEqual(theCircle.h, anEqual)) {
-    // Check another entity of Equal is already fixed
-    Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA;
-    if (myStorage->isEntityFixed(anOtherEntID, true))
-      isFixRadius = false;
-  }
-
-  fixPoint(theCircle.point[0]);
-
-  if (isFixRadius) {
-    // Search the radius is already fixed
-    std::list<Slvs_Constraint> aDiamConstr = myStorage->getConstraintsByType(SLVS_C_DIAMETER);
-    std::list<Slvs_Constraint>::const_iterator aDiamIter = aDiamConstr.begin();
-    for (; aDiamIter != aDiamConstr.end(); aDiamIter++)
-      if (aDiamIter->entityA == theCircle.h)
-        return;
-
-    // Fix radius of a circle
-    AttributeDoublePtr aRadiusAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-        myFeatureMap.begin()->first->attribute(SketchPlugin_Circle::RADIUS_ID()));
-    Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER,
-        myGroup->getWorkplaneId(), aRadiusAttr->value() * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
-        myFeatureMap.begin()->second, SLVS_E_UNKNOWN);
-    aFixedR.h = myStorage->addConstraint(aFixedR);
-    mySlvsConstraints.push_back(aFixedR.h);
-  }
-}
-
-void SketchSolver_ConstraintRigid::fixArc(const Slvs_Entity& theArc)
-{
-  bool isFixRadius = true;
-  std::list<Slvs_hEntity> aPointsToFix;
-  aPointsToFix.push_back(theArc.point[1]);
-  aPointsToFix.push_back(theArc.point[2]);
-
-  // Verify the arc is under Equal constraint
-  Slvs_Constraint anEqual;
-  if (myStorage->isUsedInEqual(theArc.h, anEqual)) {
-    // Check another entity of Equal is already fixed
-    Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA;
-    if (myStorage->isEntityFixed(anOtherEntID, true)) {
-      isFixRadius = false;
-      Slvs_Entity anOtherEntity = myStorage->getEntity(anOtherEntID);
-      if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) {
-        aPointsToFix.pop_back();
-        aPointsToFix.push_back(theArc.point[0]);
-      }
-    }
-  }
-
-  Slvs_hConstraint aConstrID;
-  int aNbPointsToFix = 2; // number of fixed points for the arc
-  if (myStorage->isPointFixed(theArc.point[0], aConstrID, true))
-    aNbPointsToFix--;
-
-  // Radius of the arc
-  FeaturePtr aFeature = myFeatureMap.begin()->first;
-  std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-    aFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
-  std::shared_ptr<GeomAPI_Pnt2d> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-    aFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
-  double aRadius = aCenter->distance(aStart);
-
-  // Update end point of the arc to be on a curve
-  std::shared_ptr<GeomAPI_Pnt2d> anEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-    aFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
-  double aDistance = anEnd->distance(aCenter);
-  std::shared_ptr<GeomAPI_XY> aDir = anEnd->xy()->decreased(aCenter->xy());
-  if (aDistance < tolerance)
-    aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0);
-  else
-    aDir = aDir->multiplied(aRadius / aDistance);
-  double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()};
-  Slvs_Entity aEndPoint = myStorage->getEntity(theArc.point[2]);
-  for (int i = 0; i < 2; i++) {
-    Slvs_Param aParam = myStorage->getParameter(aEndPoint.param[i]);
-    aParam.val = xy[i];
-    myStorage->updateParameter(aParam);
-  }
-
-  std::list<Slvs_hEntity>::iterator aPtIt = aPointsToFix.begin();
-  for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--)
-    fixPoint(*aPtIt);
-
-  if (isFixRadius) {
-    // Fix radius of the arc
-    bool isExists = false;
-    std::list<Slvs_Constraint> aDiamConstraints = myStorage->getConstraintsByType(SLVS_C_DIAMETER);
-    std::list<Slvs_Constraint>::iterator anIt = aDiamConstraints.begin();
-    for (; anIt != aDiamConstraints.end() && !isExists; anIt++)
-      if (anIt->entityA == theArc.h)
-        isExists = true;
-    if (!isExists) {
-      Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER,
-          myGroup->getWorkplaneId(), aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
-          myFeatureMap.begin()->second, SLVS_E_UNKNOWN);
-      aFixedR.h = myStorage->addConstraint(aFixedR);
-      mySlvsConstraints.push_back(aFixedR.h);
-      if (!myBaseConstraint)
-        myStorage->addConstraintWhereDragged(aFixedR.h);
-    }
-  }
-}
diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.h b/src/SketchSolver/SketchSolver_ConstraintRigid.h
deleted file mode 100644 (file)
index adac8c6..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_ConstraintRigid.h
-// Created: 30 Mar 2015
-// Author:  Artem ZHIDKOV
-
-#ifndef SketchSolver_ConstraintRigid_H_
-#define SketchSolver_ConstraintRigid_H_
-
-#include "SketchSolver.h"
-#include <SketchSolver_Constraint.h>
-
-/** \class   SketchSolver_ConstraintRigid
- *  \ingroup Plugins
- *  \brief   Stores data of Rigid (Fixed) constraint
- *
- *  Rigid constraint may have NULL basic SketchPlugin constraint,
- *  because the Rigid constraint may be temporary for correct moving of objects.
- *
- *  Rigid constraint does not create a constraint, but builds the entities in separate group,
- *  so they will not be moved while resolving the set of constraints.
- */
-class SketchSolver_ConstraintRigid : public SketchSolver_Constraint
-{
-public:
-  /// Creates constraint to manage the given constraint from plugin
-  SketchSolver_ConstraintRigid(ConstraintPtr theConstraint)
-    : SketchSolver_Constraint(theConstraint)
-  {}
-  /// Creates temporary constraint based on feature
-  SketchSolver_ConstraintRigid(FeaturePtr theFeature);
-
-  /// \brief Update constraint
-  virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
-
-  /// \brief Tries to remove constraint
-  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
-  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
-
-  /// \brief Returns the type of constraint
-  virtual int getType() const
-  { return SLVS_C_WHERE_DRAGGED; }
-
-protected:
-  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
-  virtual void process();
-
-  /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
-  /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
-  /// \param[out] theAttributes list of attributes to be filled
-  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
-
-  /// \brief Fixed feature basing on its type
-  virtual void fixFeature();
-
-  /// \brief Fix given point
-  /// \return ID of the Fixed constraint
-  Slvs_hConstraint fixPoint(const Slvs_hEntity& thePointID);
-
-  /// \brief Returns ID of fixed entity
-  Slvs_hEntity fixedEntity() const;
-
-  /// \brief Fixing line position (start and end points)
-  void fixLine(const Slvs_Entity& theLine);
-  /// \brief Fixing circle (center and radius)
-  void fixCircle(const Slvs_Entity& theCircle);
-  /// \brief The arc is fixed differently to avoid SolveSpace problems (overconstraint)
-  ///
-  /// There will be fixed start and end points and the radius of the arc.
-  void fixArc(const Slvs_Entity& theArc);
-
-protected:
-  FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL)
-};
-
-#endif
index 865065411596d9e96ec503398675a63f43cf78a3..bf551e43c27dc156663e6cbe472b9b7c0ecabc66 100644 (file)
@@ -1,84 +1,80 @@
 #include <SketchSolver_ConstraintTangent.h>
-#include <SketchSolver_Group.h>
 #include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
 
+#include <GeomAPI_Pnt2d.h>
 
-void SketchSolver_ConstraintTangent::process()
+
+/// \brief Check whether the entities has only one shared point
+static bool hasSingleCoincidence(EntityWrapperPtr theEntity1, EntityWrapperPtr theEntity2)
 {
-  cleanErrorMsg();
-  if (!myBaseConstraint || !myStorage || myGroup == 0) {
-    /// TODO: Put error message here
-    return;
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+
+  const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
+  const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
+
+  std::list<EntityWrapperPtr>::const_iterator aStartIt1 = aPoints1.begin();
+  if (theEntity1->type() == ENTITY_ARC) ++aStartIt1; // skip center of arc
+  std::list<EntityWrapperPtr>::const_iterator aStartIt2 = aPoints2.begin();
+  if (theEntity2->type() == ENTITY_ARC) ++aStartIt2; // skip center of arc
+
+  int aNbCoinc = 0;
+  std::list<EntityWrapperPtr>::const_iterator anIt1, anIt2;
+  for (anIt1 = aStartIt1; anIt1 != aPoints1.end(); ++anIt1) {
+    std::shared_ptr<GeomAPI_Pnt2d> aPt1 = aBuilder->point(*anIt1);
+    for (anIt2 = aStartIt2; anIt2 != aPoints2.end(); ++anIt2) {
+      std::shared_ptr<GeomAPI_Pnt2d> aPt2 = aBuilder->point(*anIt2);
+      if (aPt1->distance(aPt2) < tolerance)
+        ++aNbCoinc;
+    }
   }
-  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-    update(myBaseConstraint);
+  return aNbCoinc == 1;
+}
+
 
-  double aValue;
-  std::vector<Slvs_hEntity> anEntID;
-  getAttributes(aValue, anEntID);
-  if (!myErrorMsg.empty())
+void SketchSolver_ConstraintTangent::getAttributes(
+    double& theValue,
+    std::vector<EntityWrapperPtr>& theAttributes)
+{
+  SketchSolver_Constraint::getAttributes(theValue, theAttributes);
+  if (!myErrorMsg.empty() || !theAttributes[2] || !theAttributes[3]) {
+    theAttributes.clear();
     return;
+  }
+
   // Check the quantity of entities of each type and their order (arcs first)
   int aNbLines = 0;
   int aNbArcs = 0;
-  Slvs_Entity anEntities[2];
-  myType = SLVS_C_CURVE_CURVE_TANGENT;
-  std::vector<Slvs_hEntity>::iterator anEntIter = anEntID.begin();
-  for (; anEntIter != anEntID.end(); anEntIter++) {
-    Slvs_Entity anEnt = myStorage->getEntity(*anEntIter);
-    if (anEnt.type == SLVS_E_LINE_SEGMENT) {
-      if (aNbLines == 0)
-        anEntities[1 + aNbLines] = anEnt;
-      aNbLines++;
-      myType = SLVS_C_ARC_LINE_TANGENT;
-    }
-    else if (anEnt.type == SLVS_E_ARC_OF_CIRCLE) {
-      if (aNbArcs < 2)
-        anEntities[aNbArcs] = anEnt;
-      aNbArcs++;
+  bool isSwap = false; // whether need to swap arguments (arc goes before line)
+  std::vector<EntityWrapperPtr>::iterator anEntIt = theAttributes.begin() + 2;
+  for (; anEntIt != theAttributes.end(); ++anEntIt) {
+    if ((*anEntIt)->type() == ENTITY_LINE)
+      ++aNbLines;
+    else if ((*anEntIt)->type() == ENTITY_ARC) {
+      ++aNbArcs;
+      isSwap = aNbLines > 0;
     }
   }
 
-  if (aNbLines + aNbArcs != 2) {
-    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
-    return;
-  } else if (aNbArcs < 1) {
+  if (aNbArcs < 1) {
     myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
     return;
   }
-
-  // It is necessary to identify which points of entities are coincident
-  int aSlvsOtherFlag = 0;
-  int aSlvsOther2Flag = 0;
-  // Obtain start and end points of entities
-  Slvs_hEntity aPointsToFind[4];
-  for (int i = 0; i < 2; i++) {
-    int aShift = anEntities[i].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
-    aPointsToFind[2*i]  = anEntities[i].point[aShift];
-    aPointsToFind[2*i+1]= anEntities[i].point[aShift+1];
-  }
-  // Search coincident points
-  bool isPointFound = false;
-  for (int i = 0; i < 2 && !isPointFound; i++)
-    for (int j = 2; j < 4 && !isPointFound; j++)
-      if (myStorage->isEqual(aPointsToFind[i], aPointsToFind[j])) {
-        aSlvsOtherFlag = i;
-        aSlvsOther2Flag = j - 2;
-        isPointFound = true;
-      }
-  if (!isPointFound) {
-    // There is no coincident points between tangential objects. Generate error message
-    myErrorMsg = SketchSolver_Error::NO_COINCIDENT_POINTS();
+  if (aNbLines == 1 && aNbArcs == 1)
+    myType = CONSTRAINT_TANGENT_ARC_LINE;
+  else if (aNbArcs == 2)
+    myType = CONSTRAINT_TANGENT_ARC_ARC;
+  else {
+    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
     return;
   }
 
-  Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
-      getType(), myGroup->getWorkplaneId(), aValue,
-      SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, anEntities[0].h, anEntities[1].h);
-  aConstraint.other = aSlvsOtherFlag;
-  aConstraint.other2 = aSlvsOther2Flag;
-  aConstraint.h = myStorage->addConstraint(aConstraint);
-  mySlvsConstraints.push_back(aConstraint.h);
-  adjustConstraint();
-}
+  if (!hasSingleCoincidence(theAttributes[2], theAttributes[3]))
+    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
 
+  if (isSwap) {
+    EntityWrapperPtr aTemp = theAttributes[2];
+    theAttributes[2] = theAttributes[3];
+    theAttributes[3] = aTemp;
+  }
+}
index a6c744e44e7ff7718981433fa52674a6fbc17bb2..e1716bf74b5c4c493d20ec4c6a298c101b684122 100644 (file)
@@ -22,15 +22,11 @@ public:
       SketchSolver_Constraint(theConstraint)
   {}
 
-  virtual int getType() const
-  { return myType; }
-
 protected:
-  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
-  virtual void process();
-
-private:
-  int myType; ///< type of constraint (applicable: SLVS_C_ARC_LINE_TANGENT, SLVS_C_CURVE_CURVE_TANGENT)
+  /// \brief Generate list of attributes of constraint in order useful for constraints
+  /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
+  /// \param[out] theAttributes list of attributes to be filled
+  virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
 };
 
 #endif
diff --git a/src/SketchSolver/SketchSolver_FeatureStorage.cpp b/src/SketchSolver/SketchSolver_FeatureStorage.cpp
deleted file mode 100644 (file)
index 34d07b2..0000000
+++ /dev/null
@@ -1,418 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_FeatureStorage.cpp
-// Created: 23 Mar 2015
-// Author:  Artem ZHIDKOV
-
-#include <SketchSolver_FeatureStorage.h>
-
-#include <ModelAPI_AttributeRefAttr.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_ResultConstruction.h>
-#include <GeomDataAPI_Point2D.h>
-
-void SketchSolver_FeatureStorage::changeConstraint(ConstraintPtr theConstraint)
-{
-  std::list<AttributePtr> anAttributes = theConstraint->data()->attributes(std::string());
-  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
-  for (; anIter != anAttributes.end(); anIter++) {
-    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
-    if (aRefAttr) {
-      if (!aRefAttr->isObject()) {
-        changeAttribute(aRefAttr->attr(), theConstraint);
-        continue;
-      }
-      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-          aRefAttr->object());
-      FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
-          std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
-      if (aFeature)
-        changeFeature(aFeature, theConstraint);
-      continue;
-    }
-    AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
-    if (aRefList) {
-      std::list<ObjectPtr> aList = aRefList->list();
-      std::list<ObjectPtr>::iterator aListIter = aList.begin();
-      for (; aListIter != aList.end(); aListIter++) {
-        ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-            *aListIter);
-        FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
-            std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
-        if (aFeature)
-          changeFeature(aFeature, theConstraint);
-      }
-      continue;
-    }
-    changeAttribute(*anIter, theConstraint);
-  }
-  myConstraints.insert(theConstraint);
-}
-
-void SketchSolver_FeatureStorage::removeConstraint(ConstraintPtr theConstraint)
-{
-  DataPtr aData = theConstraint->data();
-  if (aData) { // Constraint has data. Iterate through its attributes and remove them
-    std::list<AttributePtr> anAttributes = aData->attributes(std::string());
-    std::list<AttributePtr>::iterator anIter = anAttributes.begin();
-    for (; anIter != anAttributes.end(); anIter++) {
-      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
-      if (aRefAttr) {
-        if (!aRefAttr->isObject()) {
-          removeAttribute(aRefAttr->attr(), theConstraint);
-          continue;
-        }
-        ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-            aRefAttr->object());
-        FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
-            std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
-        if (aFeature)
-          removeFeature(aFeature, theConstraint);
-        continue;
-      }
-      AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
-      if (aRefList) {
-        std::list<ObjectPtr> aList = aRefList->list();
-        std::list<ObjectPtr>::iterator aListIter = aList.begin();
-        for (; aListIter != aList.end(); aListIter++) {
-          ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-              *aListIter);
-          FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
-              std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
-          if (aFeature)
-            removeFeature(aFeature, theConstraint);
-        }
-        continue;
-      }
-      removeAttribute(*anIter, theConstraint);
-    }
-  } else { // Constraint has no data. Search the links on it in the lists of back references for features and attributes
-    std::set<ConstraintPtr>::iterator aCIter;
-    MapFeatureConstraint::iterator aFeatIter = myFeatures.begin();
-    while (aFeatIter != myFeatures.end()) {
-      aCIter = aFeatIter->second.find(theConstraint);
-      if (aCIter != aFeatIter->second.end()) {
-        FeaturePtr aFeature = aFeatIter->first;
-        aFeatIter++;
-        removeFeature(aFeature, theConstraint);
-        continue;
-      }
-      aFeatIter++;
-    }
-    std::set<FeaturePtr>::iterator aFIter;
-    MapAttributeFeature::iterator anAttrIter = myAttributes.begin();
-    while (anAttrIter != myAttributes.end()) {
-      aFIter = anAttrIter->second.find(theConstraint);
-      if (aFIter != anAttrIter->second.end()) {
-        anAttrIter->second.erase(aFIter);
-        if (anAttrIter->second.empty()) {
-          MapAttributeFeature::iterator aTmpIter = anAttrIter; // stores iterator for the next element, while the current is deleting
-          aTmpIter++;
-          myAttributes.erase(anAttrIter);
-          anAttrIter = aTmpIter;
-          continue;
-        }
-      }
-      anAttrIter++;
-    }
-  }
-  myConstraints.erase(theConstraint);
-}
-
-bool SketchSolver_FeatureStorage::isInteract(ConstraintPtr theConstraint) const
-{
-  if (myConstraints.empty() || myConstraints.find(theConstraint) != myConstraints.end())
-    return true;
-
-  DataPtr aData = theConstraint->data();
-  if (!aData)
-    return false;
-
-  std::list<AttributePtr> anAttributes = aData->attributes(std::string());
-  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
-  for (; anIter != anAttributes.end(); anIter++) {
-    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
-    if (aRefAttr) {
-      if (!aRefAttr->isObject()) {
-        if (isInteract(aRefAttr->attr()))
-          return true;
-        continue;
-      }
-      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-          aRefAttr->object());
-      FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
-          std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
-      if (aFeature)
-        if (isInteract(aFeature))
-          return true;
-      continue;
-    }
-    AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
-    if (aRefList) {
-      std::list<ObjectPtr> aList = aRefList->list();
-      std::list<ObjectPtr>::iterator aListIter = aList.begin();
-      for (; aListIter != aList.end(); aListIter++) {
-        ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-            *aListIter);
-        FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
-            std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
-        if (aFeature)
-          if (isInteract(aFeature))
-            return true;
-      }
-      continue;
-    }
-    if (isInteract(*anIter))
-      return true;
-  }
-  return false;
-}
-
-
-void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature)
-{
-  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
-  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
-  for (; anIter != anAttributes.end(); anIter++) {
-    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
-    if (aRefAttr) {
-      if (!aRefAttr->isObject())
-        changeAttribute(aRefAttr->attr(), theFeature);
-      continue;
-    }
-    changeAttribute(*anIter, theFeature);
-  }
-  if (myFeatures.find(theFeature) == myFeatures.end())
-    myFeatures[theFeature] = std::set<ConstraintPtr>();
-}
-
-void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint)
-{
-  // Change all attributes of the feature
-  changeFeature(theFeature);
-  // Add back reference feature to constraint
-  myFeatures[theFeature].insert(theConstraint);
-}
-
-void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature)
-{
-  MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature);
-  if (aFeatIter == myFeatures.end())
-    return; // no such feature
-
-  std::set<ConstraintPtr> aConstraints = aFeatIter->second;
-  std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
-  for (; aCIter != aConstraints.end(); aCIter++)
-    removeFeature(theFeature, *aCIter);
-}
-
-void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint)
-{
-  MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature);
-  if (aFeatIter == myFeatures.end())
-    return; // no such feature
-
-  if (theFeature->data()) {
-    std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
-    std::list<AttributePtr>::iterator anIter = anAttributes.begin();
-    for (; anIter != anAttributes.end(); anIter++) {
-      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
-      if (aRefAttr) {
-        if (!aRefAttr->isObject())
-          removeAttribute(aRefAttr->attr(), theFeature);
-        continue;
-      }
-      removeAttribute(*anIter, theFeature);
-    }
-  } else {
-    // iterate on attributes to find items refered to theFeature
-    MapAttributeFeature::iterator anIter = myAttributes.begin();
-    while (anIter != myAttributes.end()) {
-      if (anIter->second.find(theFeature) != anIter->second.end()) {
-        anIter->second.erase(theFeature);
-        if (anIter->second.empty()) {
-          MapAttributeFeature::iterator aDeadIter = anIter++;
-          myAttributes.erase(aDeadIter);
-          continue;
-        }
-      }
-      anIter++;
-    }
-  }
-
-  aFeatIter->second.erase(theConstraint);
-  if (aFeatIter->second.empty())
-    myFeatures.erase(aFeatIter);
-}
-
-bool SketchSolver_FeatureStorage::isInteract(FeaturePtr theFeature) const
-{
-  if (myFeatures.find(theFeature) != myFeatures.end())
-    return true;
-  if (!theFeature->data() || !theFeature->data()->isValid())
-    return false;
-
-  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
-  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
-  for (; anIter != anAttributes.end(); anIter++) {
-    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
-    if (aRefAttr) {
-      if (!aRefAttr->isObject())
-        if (isInteract(aRefAttr->attr()))
-          return true;
-      continue;
-    }
-    if (isInteract(*anIter))
-      return true;
-  }
-  return false;
-}
-
-
-void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute)
-{
-  if (myAttributes.find(theAttribute) == myAttributes.end())
-    myAttributes[theAttribute] = std::set<FeaturePtr>();
-}
-
-void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature)
-{
-  MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
-  if (anAttrIter == myAttributes.end()) {
-    std::set<FeaturePtr> aFeatures;
-    aFeatures.insert(theFeature);
-    myAttributes[theAttribute] = aFeatures;
-    return;
-  }
-  anAttrIter->second.insert(theFeature);
-}
-
-void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute)
-{
-  MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
-  if (anAttrIter == myAttributes.end())
-    return;
-
-  std::set<FeaturePtr> aFeatures = anAttrIter->second;
-  std::set<FeaturePtr>::iterator aFeatIter = aFeatures.begin();
-  for (; aFeatIter != aFeatures.end(); aFeatIter++)
-    removeAttribute(theAttribute, *aFeatIter);
-}
-
-void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature)
-{
-  MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
-  if (anAttrIter == myAttributes.end())
-    return; // no such attribute
-
-  anAttrIter->second.erase(theFeature);
-  if (!anAttrIter->second.empty())
-    return;
-
-  // Check there is no features containing such attribute
-  MapFeatureConstraint::iterator aFeatIter = myFeatures.begin();
-  for (; aFeatIter != myFeatures.end(); aFeatIter++) {
-    DataPtr aData = aFeatIter->first->data();
-    if (!aData || !aData->isValid())
-      continue;
-    std::list<AttributePtr> anAttrList = aData->attributes(GeomDataAPI_Point2D::typeId());
-    std::list<AttributePtr>::iterator anAtIt = anAttrList.begin();
-    for (; anAtIt != anAttrList.end(); anAtIt++) {
-      std::shared_ptr<GeomDataAPI_Point2D> aPoint =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anAtIt);
-      if (aPoint == theAttribute)
-        anAttrIter->second.insert(aFeatIter->first);
-    }
-  }
-  if (anAttrIter->second.empty())
-    myAttributes.erase(anAttrIter);
-}
-
-bool SketchSolver_FeatureStorage::isInteract(AttributePtr theAttribute) const
-{
-  return myAttributes.find(theAttribute) != myAttributes.end();
-}
-
-
-bool SketchSolver_FeatureStorage::isConsistent() const
-{
-  // Check the constraints are valid
-  std::set<ConstraintPtr>::const_iterator aCIter = myConstraints.begin();
-  for (; aCIter != myConstraints.end(); aCIter++)
-    if (!(*aCIter)->data() || !(*aCIter)->data()->isValid())
-      return false;
-  // Check the features are valid
-  MapFeatureConstraint::const_iterator aFIter = myFeatures.begin();
-  for (; aFIter != myFeatures.end(); aFIter++)
-    if (!aFIter->first->data() || !aFIter->first->data()->isValid())
-      return false;
-  return true;
-}
-
-std::set<ConstraintPtr> SketchSolver_FeatureStorage::getConstraints(FeaturePtr theFeature) const
-{
-  std::set<ConstraintPtr> aResult;
-  MapFeatureConstraint::const_iterator aFeatIter = myFeatures.find(theFeature);
-  if (aFeatIter != myFeatures.end())
-    aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
-
-  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
-  std::list<AttributePtr>::const_iterator anAttrIter = anAttributes.begin();
-  for (; anAttrIter != anAttributes.end(); anAttrIter++) {
-    MapAttributeFeature::const_iterator anIt = myAttributes.find(*anAttrIter);
-    if (anIt == myAttributes.end())
-      continue;
-    std::set<FeaturePtr>::const_iterator aFIter = anIt->second.begin();
-    for (; aFIter != anIt->second.end(); aFIter++) {
-      aFeatIter = myFeatures.find(*aFIter);
-      if (aFeatIter != myFeatures.end())
-        aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
-      else {
-        ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFIter);
-        if (aConstraint)
-          aResult.insert(aConstraint);
-      }
-    }
-  }
-  return aResult;
-}
-
-std::set<ConstraintPtr> SketchSolver_FeatureStorage::getConstraints(AttributePtr theAttribute) const
-{
-  std::set<ConstraintPtr> aResult;
-  MapAttributeFeature::const_iterator anIt = myAttributes.find(theAttribute);
-  if (anIt == myAttributes.end())
-    return aResult;
-  std::set<FeaturePtr>::const_iterator aFIter = anIt->second.begin();
-  MapFeatureConstraint::const_iterator aFeatIter;
-  for (; aFIter != anIt->second.end(); aFIter++) {
-    aFeatIter = myFeatures.find(*aFIter);
-    if (aFeatIter != myFeatures.end())
-      aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
-    else {
-      ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFIter);
-      if (aConstraint)
-        aResult.insert(aConstraint);
-    }
-  }
-  return aResult;
-}
-
-void SketchSolver_FeatureStorage::blockEvents(bool isBlocked) const
-{
-  std::set<ConstraintPtr>::iterator aCIter = myConstraints.begin();
-  for (; aCIter != myConstraints.end(); aCIter++)
-    if ((*aCIter)->data() && (*aCIter)->data()->isValid())
-      (*aCIter)->data()->blockSendAttributeUpdated(isBlocked);
-
-  MapFeatureConstraint::const_iterator aFIter = myFeatures.begin();
-  for (; aFIter != myFeatures.end(); aFIter++)
-    if (aFIter->first->data() && aFIter->first->data()->isValid())
-      aFIter->first->data()->blockSendAttributeUpdated(isBlocked);
-
-  MapAttributeFeature::const_iterator anAtIter = myAttributes.begin();
-  for (; anAtIter != myAttributes.end(); anAtIter++)
-    if (anAtIter->first->owner() && anAtIter->first->owner()->data() &&
-        anAtIter->first->owner()->data()->isValid())
-      anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked);
-}
diff --git a/src/SketchSolver/SketchSolver_FeatureStorage.h b/src/SketchSolver/SketchSolver_FeatureStorage.h
deleted file mode 100644 (file)
index 2cb36ba..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_FeatureStorage.h
-// Created: 23 Mar 2015
-// Author:  Artem ZHIDKOV
-
-#ifndef SketchSolver_FeatureStorage_H_
-#define SketchSolver_FeatureStorage_H_
-
-#include <SketchSolver.h>
-#include <SketchPlugin_Feature.h>
-#include <SketchPlugin_Constraint.h>
-
-#include <set>
-#include <map>
-
-typedef std::map<FeaturePtr, std::set<ConstraintPtr> > MapFeatureConstraint;
-typedef std::map<AttributePtr, std::set<FeaturePtr> >  MapAttributeFeature;
-
-/** \class   SketchSolver_FeatureStorage
- *  \ingroup Plugins
- *  \brief   Collects information about SketchPlugin constraints used in specific group
- */
-class SketchSolver_FeatureStorage
-{
-public:
-  SketchSolver_FeatureStorage() {}
-
-  /// \brief Adds or changes a constraint and all features it uses in the storage
-  void changeConstraint(ConstraintPtr theConstraint);
-  /// \brief Removes a constraint and all its features not used by other constraints
-  void removeConstraint(ConstraintPtr theConstraint);
-  /// \brief Verifies a constraint is used in the current storage
-  bool isInteract(ConstraintPtr theConstraint) const;
-
-  /// \brief Adds or changes a feature in the storage
-  void changeFeature(FeaturePtr theFeature);
-  /// \brief Adds or changes a feature in the storage. The feature is used in specified constraint
-  void changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint);
-  /// \brief Removes a feature
-  void removeFeature(FeaturePtr theFeature);
-  /// \brief Removes a feature according to a given constraint
-  void removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint);
-  /// \brief Verifies a feature is used in the current storage
-  bool isInteract(FeaturePtr theFeature) const;
-
-  /// \brief Adds or changes an attribute in the storage
-  void changeAttribute(AttributePtr theAttribute);
-  /// \brief Adds or changes a attribute in the storage.
-  ///        The attribute is used in specified feature or constraint (theFeature)
-  void changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature);
-  /// \brief Removes an attribute
-  void removeAttribute(AttributePtr theAttribute);
-  /// \brief Removes an attribute according to a given feature
-  void removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature);
-  /// \brief Verifies an attribute is used in the current storage
-  bool isInteract(AttributePtr theAttribute) const;
-
-  /// \brief Check the features is not removed
-  bool isConsistent() const;
-
-  /// \brief Prepares list of constraints, which using specified feature or its attributes
-  std::set<ConstraintPtr> getConstraints(FeaturePtr theFeature) const;
-  /// \brief Prepares list of constraints, which using specified attribute
-  std::set<ConstraintPtr> getConstraints(AttributePtr theAttribute) const;
-
-  /// \brief Block/unblock events of changing attributes of the features
-  void blockEvents(bool isBlocked) const;
-
-private:
-  std::set<ConstraintPtr> myConstraints; ///< list of SketchPlugin constraints used in the current group
-  MapFeatureConstraint myFeatures; ///< list of features used in the group and corresponding constraints which use the feature
-  MapAttributeFeature myAttributes; ///< list of attributes used in the group and corresponding features which are based on the attribute
-};
-
-typedef std::shared_ptr<SketchSolver_FeatureStorage> FeatureStoragePtr;
-
-#endif // SketchSolver_FeatureStorage_H_
index 9ad17d7508f15014737c74e2dbe5357fffea7b1e..5b242b63264e460bb16445454c7be0bfe5fe4d10 100644 (file)
@@ -6,29 +6,19 @@
 
 #include "SketchSolver_Group.h"
 
-#include <SketchSolver_Builder.h>
 #include <SketchSolver_Constraint.h>
 #include <SketchSolver_ConstraintCoincidence.h>
 #include <SketchSolver_ConstraintMulti.h>
 #include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
 
 #include <Events_Error.h>
 #include <Events_Loop.h>
-#include <GeomAPI_XY.h>
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_Pnt2d.h>
-#include <GeomDataAPI_Dir.h>
-#include <GeomDataAPI_Point.h>
-#include <GeomDataAPI_Point2D.h>
-#include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeString.h>
-#include <ModelAPI_Document.h>
 #include <ModelAPI_Events.h>
-#include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Validator.h>
 
-#include <SketchPlugin_Constraint.h>
 #include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
 #include <SketchPlugin_ConstraintDistance.h>
 #include <SketchPlugin_ConstraintRigid.h>
 #include <SketchPlugin_ConstraintTangent.h>
 #include <SketchPlugin_ConstraintVertical.h>
-#include <SketchPlugin_Feature.h>
 #include <SketchPlugin_MultiRotation.h>
 #include <SketchPlugin_MultiTranslation.h>
-#include <SketchPlugin_Sketch.h>
-
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Sketch.h>
 
 #include <math.h>
 #include <assert.h>
@@ -63,9 +45,9 @@ class GroupIndexer
 {
 public:
   /// \brief Return vacant index
-  static Slvs_hGroup NEW_GROUP() { return ++myGroupIndex; }
+  static GroupID NEW_GROUP() { return ++myGroupIndex; }
   /// \brief Removes the index
-  static void REMOVE_GROUP(const Slvs_hGroup& theIndex) {
+  static void REMOVE_GROUP(const GroupID& theIndex) {
     if (myGroupIndex == theIndex)
       myGroupIndex--;
   }
@@ -73,10 +55,10 @@ public:
 private:
   GroupIndexer() {};
 
-  static Slvs_hGroup myGroupIndex; ///< index of the group
+  static GroupID myGroupIndex; ///< index of the group
 };
 
-Slvs_hGroup GroupIndexer::myGroupIndex = SLVS_G_OUTOFGROUP;
+GroupID GroupIndexer::myGroupIndex = GID_OUTOFGROUP;
 
 
 static void sendMessage(const char* theMessageName)
@@ -98,12 +80,8 @@ SketchSolver_Group::SketchSolver_Group(
       myPrevSolved(true)
 {
   // Initialize workplane
-  myWorkplaneID = SLVS_E_UNKNOWN;
-#ifndef NDEBUG
-  assert(addWorkplane(theWorkplane));
-#else
+  myWorkplaneID = EID_UNKNOWN;
   addWorkplane(theWorkplane);
-#endif
 }
 
 SketchSolver_Group::~SketchSolver_Group()
@@ -127,85 +105,13 @@ bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const
 //  Class:    SketchSolver_Group
 //  Purpose:  verify are there any entities in the group used by given constraint
 // ============================================================================
-bool SketchSolver_Group::isInteract(
-    std::shared_ptr<SketchPlugin_Feature> theFeature) const
+bool SketchSolver_Group::isInteract(FeaturePtr theFeature) const
 {
   // Empty group interacts with everything
-  if (isEmpty()) return true;
-  ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
-  if (aConstraint)
-    return myFeatureStorage->isInteract(aConstraint);
-  return myFeatureStorage->isInteract(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
-}
-
-// check the entity is really exists
-static void checkEntity(StoragePtr theStorage, Slvs_hEntity& theEntity)
-{
-  if (theEntity == SLVS_E_UNKNOWN)
-    return;
-  Slvs_Entity anEnt = theStorage->getEntity(theEntity);
-  theEntity = anEnt.h;
-}
-
-// ============================================================================
-//  Function: getFeatureId
-//  Class:    SketchSolver_Group
-//  Purpose:  Find the identifier of the feature, if it already exists in the group
-// ============================================================================
-Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const
-{
-  Slvs_hEntity aResult = SLVS_E_UNKNOWN;
-  if (!myFeatureStorage)
-    return aResult;
-  // Obtain regular constraints interacting with the feature and find its ID
-  ConstraintConstraintMap::const_iterator aCIter = myConstraints.begin();
-  for (; aCIter != myConstraints.end(); ++aCIter) {
-    aResult = aCIter->second->getId(theFeature);
-    checkEntity(myStorage, aResult);
-    if (aResult != SLVS_E_UNKNOWN)
-      return aResult;
-  }
-  // The feature is not found, check it in the temporary constraints
-  std::set<SolverConstraintPtr>::iterator aTmpCIter = myTempConstraints.begin();
-  for (; aTmpCIter != myTempConstraints.end() && aResult == SLVS_E_UNKNOWN; ++aTmpCIter) {
-    aResult = (*aTmpCIter)->getId(theFeature);
-    checkEntity(myStorage, aResult);
-  }
-  return aResult;
-}
-
-// ============================================================================
-//  Function: getAttributeId
-//  Class:    SketchSolver_Group
-//  Purpose:  Find the identifier of the attribute, if it already exists in the group
-// ============================================================================
-Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const
-{
-  Slvs_hEntity aResult = SLVS_E_UNKNOWN;
-  if (!myFeatureStorage)
-    return aResult;
-  // Obtain regular constraints interacting with the attribute and find its ID
-  ConstraintConstraintMap::const_iterator aCIter = myConstraints.begin();
-  for (; aCIter != myConstraints.end(); ++aCIter) {
-    aResult = aCIter->second->getId(theAttribute);
-    checkEntity(myStorage, aResult);
-    if (aResult != SLVS_E_UNKNOWN)
-      return aResult;
-  }
-  // The attribute is not found, check it in the temporary constraints
-  std::set<SolverConstraintPtr>::const_iterator aTmpCIter = myTempConstraints.begin();
-  for (; aTmpCIter != myTempConstraints.end() && aResult == SLVS_E_UNKNOWN; ++aTmpCIter) {
-    aResult = (*aTmpCIter)->getId(theAttribute);
-    checkEntity(myStorage, aResult);
-  }
-  // Last chance to find attribute in parametric constraints
-  std::map<AttributePtr, SolverConstraintPtr>::const_iterator aParIter =
-      myParametricConstraints.find(theAttribute);
-  if (aParIter != myParametricConstraints.end()) {
-    aResult = aParIter->second->getId(theAttribute);
-    checkEntity(myStorage, aResult);
-  }
-  return aResult;
+  if (isEmpty())
+    return true;
+  // Check interaction with the storage
+  return myStorage->isInteract(theFeature);
 }
 
 // ============================================================================
@@ -217,7 +123,7 @@ bool SketchSolver_Group::changeConstraint(
     std::shared_ptr<SketchPlugin_Constraint> theConstraint)
 {
   // There is no workplane yet, something wrong
-  if (myWorkplaneID == SLVS_E_UNKNOWN)
+  if (myWorkplaneID == EID_UNKNOWN)
     return false;
 
   if (!theConstraint || !theConstraint->data())
@@ -226,131 +132,42 @@ bool SketchSolver_Group::changeConstraint(
   if (!checkFeatureValidity(theConstraint))
     return false;
 
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+
   bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end();
   if (isNewConstraint) {
     // Add constraint to the current group
-    SolverConstraintPtr aConstraint =
-        SketchSolver_Builder::getInstance()->createConstraint(theConstraint);
+    SolverConstraintPtr aConstraint = aBuilder->createConstraint(theConstraint);
     if (!aConstraint)
       return false;
-    aConstraint->setGroup(this);
-    aConstraint->setStorage(myStorage);
+    aConstraint->process(myStorage, getId(), getWorkplaneId());
     if (!aConstraint->error().empty()) {
       if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
         return false; // some attribute are not initialized yet, don't show message
       Events_Error::send(aConstraint->error(), this);
     }
-
-    // Additional verification of coincidence of several points
-    if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
-      bool hasMultiCoincidence = false;
-      ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
-      for (; aCIter != myConstraints.end(); ++aCIter) {
-        std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoincidence =
-          std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aCIter->second);
-        if (!aCoincidence)
-          continue;
-        std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoinc2 =
-          std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aConstraint);
-        if (aCoincidence != aCoinc2 && aCoincidence->isCoincide(aCoinc2)) {
-          aCoinc2->attach(aCoincidence);
-          // update other coincidences
-          ConstraintConstraintMap::iterator anIt = aCIter;
-          for (++anIt; anIt != myConstraints.end(); ++anIt)
-            if (anIt->second == aCIter->second)
-              anIt->second = aCoinc2;
-          aCIter->second = aCoinc2;
-          hasMultiCoincidence = true;
-        }
-      }
-
-      if (hasMultiCoincidence)
-        notifyMultiConstraints();
-    }
     myConstraints[theConstraint] = aConstraint;
   }
   else
     myConstraints[theConstraint]->update();
 
-  // Fix base features for fillet
-  if (isNewConstraint && theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
-    std::list<AttributePtr> anAttrList =
-        theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
-    std::list<AttributePtr>::iterator anAttrIter = anAttrList.begin();
-    for (; anAttrIter != anAttrList.end(); anAttrIter++) {
-      AttributeRefAttrPtr aRefAttr =
-          std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
-      if (!aRefAttr || !aRefAttr->isObject())
-        continue;
-      FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
-      SolverConstraintPtr aConstraint =
-          SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
-      if (!aConstraint)
-        continue;
-      aConstraint->setGroup(this);
-      aConstraint->setStorage(myStorage);
-      setTemporary(aConstraint);
-    }
-  }
   // Fix mirror line
   if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
         theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_A()));
     if (aRefAttr && aRefAttr->isObject()) {
-      FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+      std::shared_ptr<SketchPlugin_Feature> aFeature =
+          std::dynamic_pointer_cast<SketchPlugin_Feature>(
+          ModelAPI_Feature::feature(aRefAttr->object()));
       if (aFeature) {
-        SolverConstraintPtr aConstraint =
-            SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
+        SolverConstraintPtr aConstraint = aBuilder->createFixedConstraint(aFeature);
         if (aConstraint) {
-          aConstraint->setGroup(this);
-          aConstraint->setStorage(myStorage);
+          aConstraint->process(myStorage, getId(), getWorkplaneId());
           setTemporary(aConstraint);
         }
       }
     }
   }
-
-  if (!myFeatureStorage)
-    myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
-  myFeatureStorage->changeConstraint(theConstraint);
-
-  // Check the attributes of constraint are given by parametric expression
-  std::list<AttributePtr> anAttributes =
-      theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
-  std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
-  for (; anAttrIt != anAttributes.end(); ++anAttrIt) {
-    AttributeRefAttrPtr aRefAttr =
-        std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIt);
-    if (!aRefAttr)
-      continue;
-
-    std::shared_ptr<GeomDataAPI_Point2D> aPoint;
-    if (aRefAttr->isObject()) {
-      FeaturePtr aFeat = ModelAPI_Feature::feature(aRefAttr->object());
-      if (aFeat->getKind() != SketchPlugin_Point::ID())
-        continue;
-      aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aFeat->attribute(SketchPlugin_Point::COORD_ID()));
-    } else
-      aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
-
-    if (!aPoint || (aPoint->textX().empty() && aPoint->textY().empty()))
-      continue;
-
-    std::map<AttributePtr, SolverConstraintPtr>::iterator aFound =
-        myParametricConstraints.find(aPoint);
-    if (aFound == myParametricConstraints.end()) {
-      SolverConstraintPtr aConstraint =
-          SketchSolver_Builder::getInstance()->createParametricConstraint(aPoint);
-      if (!aConstraint)
-        continue;
-      aConstraint->setGroup(this);
-      aConstraint->setStorage(myStorage);
-      myParametricConstraints[aPoint] = aConstraint;
-    } else
-      aFound->second->update();
-  }
-
   return true;
 }
 
@@ -378,105 +195,37 @@ void SketchSolver_Group::updateConstraints()
   myChangedConstraints.clear();
 }
 
-bool SketchSolver_Group::updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
+bool SketchSolver_Group::updateFeature(FeaturePtr theFeature)
 {
   if (!checkFeatureValidity(theFeature))
     return false;
-
-  std::set<ConstraintPtr> aConstraints =
-      myFeatureStorage->getConstraints(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
-  if (aConstraints.empty())
-    return false;
-  std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
-  for (; aCIter != aConstraints.end(); aCIter++) {
-    ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter);
-    if (aSolConIter == myConstraints.end() || !aSolConIter->first->data() ||
-        !aSolConIter->first->data()->isValid())
-      continue;
-    myFeatureStorage->changeFeature(theFeature, aSolConIter->first);
-
-    aSolConIter->second->addFeature(theFeature);
-    myChangedConstraints.insert(aSolConIter->first);
-  }
-
-  // Search attributes of the feature in the set of parametric constraints and update them
-  std::list<AttributePtr> anAttrList =
-      theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
-  std::list<AttributePtr>::iterator anAttrIt = anAttrList.begin();
-  for (; anAttrIt != anAttrList.end(); ++anAttrIt) {
-    std::map<AttributePtr, SolverConstraintPtr>::iterator aFound =
-        myParametricConstraints.find(*anAttrIt);
-    if (aFound != myParametricConstraints.end())
-      aFound->second->update();
-    else {
-      std::shared_ptr<GeomDataAPI_Point2D> aPoint =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anAttrIt);
-      if (aPoint && (!aPoint->textX().empty() || !aPoint->textY().empty())) {
-        // Create new parametric constraint
-        SolverConstraintPtr aConstraint =
-            SketchSolver_Builder::getInstance()->createParametricConstraint(*anAttrIt);
-        if (!aConstraint)
-          continue;
-        aConstraint->setGroup(this);
-        aConstraint->setStorage(myStorage);
-        myParametricConstraints[*anAttrIt] = aConstraint;
-      }
-    }
-  }
-  return true;
+  myStorage->refresh(true);
+  return myStorage->update(theFeature);
 }
 
-void SketchSolver_Group::moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
+void SketchSolver_Group::moveFeature(FeaturePtr theFeature)
 {
-  // Firstly, create temporary rigid constraint
-  SolverConstraintPtr aConstraint =
-      SketchSolver_Builder::getInstance()->createMovementConstraint(theFeature);
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+
+  // Firstly, revert changes in the fixed entities
+  myStorage->refresh(true);
+
+  // Secondly, search attributes of the feature in the list of the Multi constraints and update them
+  ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
+  for (; aCIt != myConstraints.end(); ++aCIt) {
+    if ((aCIt->second->getType() == CONSTRAINT_MULTI_ROTATION ||
+         aCIt->second->getType() == CONSTRAINT_MULTI_TRANSLATION)
+        && aCIt->second->isUsed(theFeature))
+      std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIt->second)->update(true);
+  }
+
+  // Then, create temporary rigid constraint
+  SolverConstraintPtr aConstraint = aBuilder->createMovementConstraint(theFeature);
   if (!aConstraint)
     return;
-  aConstraint->setGroup(this);
-  aConstraint->setStorage(myStorage);
+  aConstraint->process(myStorage, getId(), getWorkplaneId());
   if (aConstraint->error().empty())
     setTemporary(aConstraint);
-  // Secondly, update the feature
-  updateFeature(theFeature);
-}
-
-// ============================================================================
-//  Function: fixFeaturesList
-//  Class:    SketchSolver_Group
-//  Purpose:  Apply temporary rigid constraints for the list of features
-// ============================================================================
-void SketchSolver_Group::fixFeaturesList(AttributeRefListPtr theList)
-{
-  std::list<ObjectPtr> aList = theList->list();
-  std::list<ObjectPtr>::iterator anIt = aList.begin();
-  std::list<FeaturePtr> aFeatures;
-  // Sort features, at begining there are features used by Equal constraint
-  for (; anIt != aList.end(); anIt++) {
-    if (!(*anIt))
-      continue;
-    FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
-    std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(aFeature);
-    std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
-    for (; aCIter != aConstraints.end(); aCIter++)
-      if ((*aCIter)->getKind() == SketchPlugin_ConstraintEqual::ID())
-        break;
-    if (aCIter != aConstraints.end())
-      aFeatures.push_front(aFeature);
-    else
-      aFeatures.push_back(aFeature);
-  }
-
-  std::list<FeaturePtr>::iterator aFeatIter = aFeatures.begin();
-  for (; aFeatIter != aFeatures.end(); aFeatIter++) {
-    SolverConstraintPtr aConstraint =
-        SketchSolver_Builder::getInstance()->createRigidConstraint(*aFeatIter);
-    if (!aConstraint)
-      continue;
-    aConstraint->setGroup(this);
-    aConstraint->setStorage(myStorage);
-    setTemporary(aConstraint);
-  }
 }
 
 // ============================================================================
@@ -486,11 +235,14 @@ void SketchSolver_Group::fixFeaturesList(AttributeRefListPtr theList)
 // ============================================================================
 bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch)
 {
-  if (myWorkplaneID != SLVS_E_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID())
+  if (myWorkplaneID != EID_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID())
     return false;  // the workplane already exists or the function parameter is not Sketch
 
   mySketch = theSketch;
-  updateWorkplane();
+  if (!updateWorkplane()) {
+    mySketch = CompositeFeaturePtr();
+    return false;
+  }
   return true;
 }
 
@@ -501,55 +253,17 @@ bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch)
 // ============================================================================
 bool SketchSolver_Group::updateWorkplane()
 {
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
   if (!myStorage) // Create storage if not exists
-    myStorage = StoragePtr(new SketchSolver_Storage);
-  SketchSolver_Builder* aBuilder = SketchSolver_Builder::getInstance();
+    myStorage = aBuilder->createStorage(getId());
 
-  std::vector<Slvs_Entity> anEntities;
-  std::vector<Slvs_Param> aParams;
-  if (!aBuilder->createWorkplane(mySketch, anEntities, aParams))
-    return false;
-
-  if (myWorkplaneID == SLVS_E_UNKNOWN) {
-    myWorkplaneID = anEntities.back().h;
-    // Add new workplane elements
-    std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
-    for (; aParIter != aParams.end(); aParIter++) {
-      aParIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
-      aParIter->group = SLVS_G_OUTOFGROUP;
-      aParIter->h = myStorage->addParameter(*aParIter);
-    }
-    std::vector<Slvs_Entity>::iterator anEntIter = anEntities.begin();
-    for (; anEntIter != anEntities.end(); anEntIter++) {
-      anEntIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
-      anEntIter->group = SLVS_G_OUTOFGROUP;
-      anEntIter->wrkpl = myWorkplaneID;
-      for (int i = 0; i < 4; i++)
-        if (anEntIter->param[i] != SLVS_E_UNKNOWN)
-          anEntIter->param[i] = aParams[anEntIter->param[i]-1].h;
-      for (int i = 0; i < 4; i++)
-        if (anEntIter->point[i] != SLVS_E_UNKNOWN)
-          anEntIter->point[i] = anEntities[anEntIter->point[i]-1].h;
-      anEntIter->h = myStorage->addEntity(*anEntIter);
-    }
-  } else {
-    // Update existent workplane
-    const Slvs_Entity& aWP = myStorage->getEntity(myWorkplaneID);
-    const Slvs_Entity& anOrigin = myStorage->getEntity(aWP.point[0]);
-    const Slvs_Entity& aNormal = myStorage->getEntity(aWP.normal);
-    // Get parameters and update them
-    Slvs_hParam aWPParams[7] = {
-        anOrigin.param[0], anOrigin.param[1], anOrigin.param[2],
-        aNormal.param[0], aNormal.param[1], aNormal.param[2], aNormal.param[3]
-      };
-    std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
-    for (int i = 0; aParIter != aParams.end(); aParIter++, i++) {
-      Slvs_Param aParam = myStorage->getParameter(aWPParams[i]);
-      aParam.val = aParIter->val;
-      myStorage->updateParameter(aParam);
-    }
+  // sketch should be unchanged, set it out of current group
+  bool isUpdated = myStorage->update(FeaturePtr(mySketch), GID_OUTOFGROUP);
+  if (isUpdated) {
+    EntityWrapperPtr anEntity = myStorage->entity(FeaturePtr(mySketch));
+    myWorkplaneID = anEntity->id();
   }
-  return myWorkplaneID > 0;
+  return isUpdated;
 }
 
 // ============================================================================
@@ -565,33 +279,36 @@ bool SketchSolver_Group::resolveConstraints()
   bool aResolved = false;
   bool isGroupEmpty = isEmpty();
   if (myStorage->isNeedToResolve() && !isGroupEmpty) {
-    myConstrSolver.setGroupID(myID);
-    myConstrSolver.calculateFailedConstraints(false);
-    myStorage->initializeSolver(myConstrSolver);
+    if (!mySketchSolver)
+      mySketchSolver = SketchSolver_Manager::instance()->builder()->createSolver();
 
-    int aResult = SLVS_RESULT_OKAY;
+    mySketchSolver->setGroup(myID);
+    mySketchSolver->calculateFailedConstraints(false);
+    myStorage->initializeSolver(mySketchSolver);
+
+    SketchSolver_SolveStatus aResult = STATUS_OK;
     try {
       if (myStorage->hasDuplicatedConstraint())
-        aResult = SLVS_RESULT_INCONSISTENT;
+        aResult = STATUS_INCONSISTENT;
       else {
         // To avoid overconstraint situation, we will remove temporary constraints one-by-one
         // and try to find the case without overconstraint
         bool isLastChance = false;
-        int aNbTemp = myStorage->numberTemporary();
+        size_t aNbTemp = myStorage->nbTemporary();
         while (true) {
-          aResult = myConstrSolver.solve();
-          if (aResult == SLVS_RESULT_OKAY || isLastChance)
+          aResult = mySketchSolver->solve();
+          if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET || isLastChance)
             break;
-          if (aNbTemp <= 0) {
+          if (aNbTemp == 0) {
             // try to update parameters and resolve once again
             ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin();
             for (; aConstrIt != myConstraints.end(); ++aConstrIt)
               aConstrIt->second->update();
             isLastChance = true;
           } else
-            aNbTemp = myStorage->deleteTemporaryConstraint();
-          myConstrSolver.calculateFailedConstraints(true); // something failed => need to find it
-          myStorage->initializeSolver(myConstrSolver);
+            aNbTemp = myStorage->removeTemporary();
+          mySketchSolver->calculateFailedConstraints(true); // something failed => need to find it
+          myStorage->initializeSolver(mySketchSolver);
         }
       }
     } catch (...) {
@@ -604,17 +321,8 @@ bool SketchSolver_Group::resolveConstraints()
       }
       return false;
     }
-    if (aResult == SLVS_RESULT_OKAY) {  // solution succeeded, store results into correspondent attributes
-      myFeatureStorage->blockEvents(true);
-      // First refresh parametric constraints to satisfy parameters
-      std::map<AttributePtr, SolverConstraintPtr>::iterator aParIter = myParametricConstraints.begin();
-      for (; aParIter != myParametricConstraints.end(); ++aParIter)
-        aParIter->second->refresh();
-      // Update all other constraints
-      ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
-      for (; aConstrIter != myConstraints.end(); ++aConstrIter)
-        aConstrIter->second->refresh();
-      myFeatureStorage->blockEvents(false);
+    if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET) {  // solution succeeded, store results into correspondent attributes
+      myStorage->refresh();
       if (!myPrevSolved) {
         getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue("");
         // the error message should be changed before sending the message
@@ -633,15 +341,15 @@ bool SketchSolver_Group::resolveConstraints()
 
     aResolved = true;
   } else if (!isGroupEmpty) {
-    myFeatureStorage->blockEvents(true);
     // Check there are constraints Fixed. If they exist, update parameters by stored values
     ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
     for (; aCIt != myConstraints.end(); ++aCIt)
       if (aCIt->first->getKind() == SketchPlugin_ConstraintRigid::ID()) {
-        aCIt->second->refresh();
         aResolved = true;
+        break;
       }
-     myFeatureStorage->blockEvents(false);
+    if (aCIt != myConstraints.end())
+      myStorage->refresh();
   }
   removeTemporaryConstraints();
   myStorage->setNeedToResolve(false);
@@ -658,8 +366,6 @@ void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
   // If specified group is empty, no need to merge
   if (theGroup.isEmpty())
     return;
-  if (!myFeatureStorage)
-    myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
 
   std::set<ObjectPtr> aConstraints;
   ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
@@ -681,27 +387,27 @@ void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
 //  Class:    SketchSolver_Group
 //  Purpose:  divide the group into several subgroups
 // ============================================================================
-void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
+void SketchSolver_Group::splitGroup(std::list<SketchSolver_Group*>& theCuts)
 {
+  // New storage will be used in trimmed way to store the list of constraint interacted together.
+  StoragePtr aNewStorage = SketchSolver_Manager::instance()->builder()->createStorage(getId());
+  std::list<ConstraintWrapperPtr> aDummyVec; // empty vector to avoid creation of solver's constraints
+
   // Obtain constraints, which should be separated
-  FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage);
-  std::vector<ConstraintPtr> anUnusedConstraints;
+  std::list<ConstraintPtr> anUnusedConstraints;
   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
   for ( ; aCIter != myConstraints.end(); aCIter++) {
-    std::list<ConstraintPtr> aBaseConstraints = aCIter->second->constraints();
-    std::list<ConstraintPtr>::iterator anIter = aBaseConstraints.begin();
-    for (; anIter != aBaseConstraints.end(); anIter++)
-      if (aNewFeatStorage->isInteract(*anIter)) {
-        aNewFeatStorage->changeConstraint(*anIter);
-      } else
-        anUnusedConstraints.push_back(*anIter);
+    if (aNewStorage->isInteract(FeaturePtr(aCIter->first)))
+      aNewStorage->addConstraint(aCIter->first, aDummyVec);
+    else
+      anUnusedConstraints.push_back(aCIter->first);
   }
 
   // Check the unused constraints once again, because they may become interacted with new storage since adding constraints
-  std::vector<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
+  std::list<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
   while (aUnuseIt != anUnusedConstraints.end()) {
-    if (aNewFeatStorage->isInteract(*aUnuseIt)) {
-      aNewFeatStorage->changeConstraint(*aUnuseIt);
+    if (aNewStorage->isInteract(FeaturePtr(*aUnuseIt))) {
+      aNewStorage->addConstraint(*aUnuseIt, aDummyVec);
       anUnusedConstraints.erase(aUnuseIt);
       aUnuseIt = anUnusedConstraints.begin();
       continue;
@@ -709,13 +415,13 @@ void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
     aUnuseIt++;
   }
 
-  std::vector<SketchSolver_Group*>::iterator aCutsIter;
+  std::list<SketchSolver_Group*>::iterator aCutsIter;
   aUnuseIt = anUnusedConstraints.begin();
-  for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) {
+  for ( ; aUnuseIt != anUnusedConstraints.end(); ++aUnuseIt) {
     // Remove unused constraints
     removeConstraint(*aUnuseIt);
     // Try to append constraint to already existent group
-    for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); aCutsIter++)
+    for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); ++aCutsIter)
       if ((*aCutsIter)->isInteract(*aUnuseIt)) {
         (*aCutsIter)->changeConstraint(*aUnuseIt);
         break;
@@ -725,11 +431,17 @@ void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
       SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch);
       aGroup->changeConstraint(*aUnuseIt);
       theCuts.push_back(aGroup);
+    } else {
+      // Find other groups interacting with constraint
+      std::list<SketchSolver_Group*>::iterator aBaseGroupIt = aCutsIter;
+      for (++aCutsIter; aCutsIter != theCuts.end(); ++aCutsIter)
+        if ((*aCutsIter)->isInteract(*aUnuseIt)) {
+          (*aBaseGroupIt)->mergeGroups(**aCutsIter);
+          std::list<SketchSolver_Group*>::iterator aRemoveIt = aCutsIter--;
+          theCuts.erase(aRemoveIt);
+        }
     }
   }
-
-  // Update feature storage
-  myFeatureStorage = aNewFeatStorage;
 }
 
 // ============================================================================
@@ -739,12 +451,24 @@ void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
 // ============================================================================
 bool SketchSolver_Group::isConsistent()
 {
-  if (!myFeatureStorage) // no one constraint is initialized yet
+  if (isEmpty()) // no one constraint is initialized yet
     return true;
 
-  bool aResult = myFeatureStorage->isConsistent();
+  // Check the features and constraint is the storage are valid
+  bool aResult = myStorage->isConsistent();
+  if (aResult) {
+    // additional check of consistency of the Fixed constraint,
+    // because they are not added to the storage
+    ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+    for (; aCIter != myConstraints.end(); ++aCIter)
+      if (aCIter->first->getKind() == SketchPlugin_ConstraintRigid::ID() &&
+         (!aCIter->first->data() || !aCIter->first->data()->isValid())) {
+        aResult = false;
+        break;
+      }
+  }
   if (!aResult) {
-    // remove invalid entities
+    // remove invalid constraints
     std::set<ConstraintPtr> anInvalidConstraints;
     ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
     for (; aCIter != myConstraints.end(); ++aCIter) {
@@ -754,6 +478,8 @@ bool SketchSolver_Group::isConsistent()
     std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
     for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
       removeConstraint(*aRemoveIt);
+    // remove invalid features
+    myStorage->removeInvalidEntities();
   }
   return aResult;
 }
@@ -769,16 +495,15 @@ void SketchSolver_Group::removeTemporaryConstraints()
   std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
   for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
     (*aTmpIt)->remove();
-  myTempConstraints.clear();
 
-  while (myStorage->numberTemporary())
-    myStorage->deleteTemporaryConstraint();
-  // Clean lists of removed entities in the storage
-  std::set<Slvs_hParam> aRemPar;
-  std::set<Slvs_hEntity> aRemEnt;
-  std::set<Slvs_hConstraint> aRemCon;
-  myStorage->getRemoved(aRemPar, aRemEnt, aRemCon);
+  size_t aNbTemp = myStorage->nbTemporary();
+  if (aNbTemp > 0)
+    myStorage->removeTemporary(aNbTemp);
+
+  if (!myTempConstraints.empty())
+    myStorage->verifyFixed();
   myStorage->setNeedToResolve(false);
+  myTempConstraints.clear();
 }
 
 // ============================================================================
@@ -789,20 +514,16 @@ void SketchSolver_Group::removeTemporaryConstraints()
 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
 {
   bool isFullyRemoved = true;
-  myFeatureStorage->removeConstraint(theConstraint);
   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
   for (; aCIter != myConstraints.end(); aCIter++)
-    if (aCIter->second->hasConstraint(theConstraint)) {
-      if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed
+    if (aCIter->first == theConstraint) {
+      if (!aCIter->second->remove()) // the constraint is not fully removed
         isFullyRemoved = false;
       break;
     }
   if (aCIter == myConstraints.end())
     return;
 
-  // Remove entities not used by constraints
-  myStorage->removeUnusedEntities();
-
   if (isFullyRemoved)
     myConstraints.erase(aCIter);
   else if (aCIter != myConstraints.end() &&
@@ -817,7 +538,7 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
       }
       if (aCIter->first != theConstraint)
         aMultiCoinc.push_back(aCIter->first);
-      aCIter->second->remove(aCIter->first);
+      aCIter->second->remove();
       ConstraintConstraintMap::iterator aRemoveIt = aCIter++;
       myConstraints.erase(aRemoveIt);
     }
@@ -825,8 +546,6 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
     std::list<ConstraintPtr>::iterator anIt = aMultiCoinc.begin();
     for (; anIt != aMultiCoinc.end(); ++anIt)
       changeConstraint(*anIt);
-
-    notifyMultiConstraints();
   }
 }
 
@@ -845,7 +564,7 @@ bool SketchSolver_Group::isComplexConstraint(FeaturePtr theConstraint)
 // ============================================================================
 //  Function: setTemporary
 //  Class:    SketchSolver_Group
-//  Purpose:  append given constraint to th group of temporary constraints
+//  Purpose:  append given constraint to the group of temporary constraints
 // ============================================================================
 void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
 {
@@ -869,24 +588,6 @@ bool SketchSolver_Group::checkFeatureValidity(FeaturePtr theFeature)
   return aFactory->validate(theFeature);
 }
 
-// ============================================================================
-//  Function: notifyMultiConstraints
-//  Class:    SketchSolver_Group
-//  Purpose:  Update Multi-Translation/-Rotation constraints due to multi coincidence appears/disappears
-// ============================================================================
-void SketchSolver_Group::notifyMultiConstraints()
-{
-  ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
-  for (; aCIter != myConstraints.end(); ++aCIter) {
-    if (aCIter->first->getKind() == SketchPlugin_MultiRotation::ID() ||
-        aCIter->first->getKind() == SketchPlugin_MultiTranslation::ID()) {
-      std::shared_ptr<SketchSolver_ConstraintMulti> aMulti = 
-          std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIter->second);
-      aMulti->checkCoincidence();
-    }
-  }
-}
-
 
 
 
index 507386d03e9928b83b0c578333422b25ec10b097..4eb67e619784c0fa56daabd6d6679f4834e92635 100644 (file)
 #include "SketchSolver.h"
 #include <SketchSolver_Constraint.h>
 #include <SketchSolver_Storage.h>
-#include <SketchSolver_FeatureStorage.h>
-#include <SketchSolver_Solver.h>
+#include <SketchSolver_ISolver.h>
 
 #include <SketchPlugin_Constraint.h>
-#include <ModelAPI_Data.h>
 #include <ModelAPI_Feature.h>
-#include <ModelAPI_AttributeRefList.h>
 
 #include <memory>
 #include <list>
 #include <map>
-#include <vector>
 #include <set>
 
 typedef std::map<ConstraintPtr, SolverConstraintPtr> ConstraintConstraintMap;
@@ -42,22 +38,17 @@ class SketchSolver_Group
   ~SketchSolver_Group();
 
   /// \brief Returns group's unique identifier
-  inline const Slvs_hGroup& getId() const
+  inline const GroupID& getId() const
   {
     return myID;
   }
 
   /// \brief Returns identifier of the workplane
-  inline const Slvs_hEntity& getWorkplaneId() const
+  inline const EntityID& getWorkplaneId() const
   {
     return myWorkplaneID;
   }
 
-  /// \brief Find the identifier of the feature, if it already exists in the group
-  Slvs_hEntity getFeatureId(FeaturePtr theFeature) const;
-  /// \brief Find the identifier of the attribute, if it already exists in the group
-  Slvs_hEntity getAttributeId(AttributePtr theAttribute) const;
-
   /// \brief Returns true if the group has no constraints yet
   inline bool isEmpty() const
   {
@@ -82,19 +73,19 @@ class SketchSolver_Group
   /** \brief Updates the data corresponding the specified feature
    *  \param[in] theFeature the feature to be updated
    */
-  bool updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature);
+  bool updateFeature(FeaturePtr theFeature);
 
   /** \brief Updates the data corresponding the specified feature moved in GUI.
    *         Additional Fixed constraints are created.
    *  \param[in] theFeature the feature to be updated
    */
-  void moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature);
+  void moveFeature(FeaturePtr theFeature);
 
   /** \brief Verifies the feature attributes are used in this group
    *  \param[in] theFeature constraint or any other object for verification of interaction
    *  \return \c true if some of attributes are used in current group
    */
-  bool isInteract(std::shared_ptr<SketchPlugin_Feature> theFeature) const;
+  bool isInteract(FeaturePtr theFeature) const;
 
   /** \brief Verifies the specified feature is equal to the base workplane for this group
    *  \param[in] theWorkplane the feature to be compared with base workplane
@@ -126,7 +117,7 @@ class SketchSolver_Group
   /** \brief Cut from the group several subgroups, which are not connected to the current one by any constraint
    *  \param[out] theCuts enlarge this list by newly created groups
    */
-  void splitGroup(std::vector<SketchSolver_Group*>& theCuts);
+  void splitGroup(std::list<SketchSolver_Group*>& theCuts);
 
   /** \brief Start solution procedure if necessary and update attributes of features
    *  \return \c false when no need to solve constraints
@@ -155,10 +146,7 @@ private:
    */
   bool addWorkplane(CompositeFeaturePtr theSketch);
 
-  /// \brief Apply temporary rigid constraints for the list of features
-  void fixFeaturesList(AttributeRefListPtr theList);
-
-  /// \brief Append given constraint to th group of temporary constraints
+  /// \brief Append given constraint to the group of temporary constraints
   void setTemporary(SolverConstraintPtr theConstraint);
 
   /// \brief Verifies is the feature valid
@@ -167,12 +155,9 @@ private:
   /// \brief Update just changed constraints
   void updateConstraints();
 
-  /// \brief Update Multi-Translation/-Rotation constraints due to multi coincidence appears/disappears
-  void notifyMultiConstraints();
-
 private:
-  Slvs_hGroup myID; ///< Index of the group
-  Slvs_hEntity myWorkplaneID; ///< Index of workplane, the group is based on
+  GroupID  myID; ///< Index of the group
+  EntityID myWorkplaneID; ///< Index of workplane, the group is based on
   CompositeFeaturePtr mySketch; ///< Sketch is equivalent to workplane
   ConstraintConstraintMap myConstraints; ///< List of constraints
   std::set<SolverConstraintPtr> myTempConstraints; ///< List of temporary constraints
@@ -180,9 +165,8 @@ private:
   std::set<ConstraintPtr> myChangedConstraints; ///< List of just updated constraints
 
   StoragePtr myStorage; ///< Container for the set of SolveSpace constraints and their entities
-  FeatureStoragePtr myFeatureStorage; ///< Container for the set of SketchPlugin features and their dependencies
 
-  SketchSolver_Solver myConstrSolver;  ///< Solver for set of equations obtained by constraints
+  SolverPtr mySketchSolver;  ///< Solver for set of equations obtained by constraints
 
   bool myPrevSolved; ///< Indicates that previous solving was done correctly
 };
diff --git a/src/SketchSolver/SketchSolver_IConstraintWrapper.h b/src/SketchSolver/SketchSolver_IConstraintWrapper.h
new file mode 100644 (file)
index 0000000..a0dd526
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_IConstraintWrapper.h
+// Created: 30 Nov 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_IConstraintWrapper_H_
+#define SketchSolver_IConstraintWrapper_H_
+
+#include <SketchSolver_IEntityWrapper.h>
+
+#include <SketchPlugin_Constraint.h>
+
+#include <list>
+#include <memory>
+
+/// Types of constraints
+enum SketchSolver_ConstraintType {
+  CONSTRAINT_UNKNOWN = 0,
+  CONSTRAINT_COINCIDENCE,      // base coincidence if we don't know exact type yet
+  CONSTRAINT_PT_PT_COINCIDENT,
+  CONSTRAINT_PT_ON_LINE,
+  CONSTRAINT_PT_ON_CIRCLE,
+  CONSTRAINT_DISTANCE,         // base distance if we don't know the measured objects yet
+  CONSTRAINT_PT_PT_DISTANCE,
+  CONSTRAINT_PT_LINE_DISTANCE,
+  CONSTRAINT_RADIUS,
+  CONSTRAINT_ANGLE,
+  CONSTRAINT_FIXED,
+  CONSTRAINT_HORIZONTAL,
+  CONSTRAINT_VERTICAL,
+  CONSTRAINT_PARALLEL,
+  CONSTRAINT_PERPENDICULAR,
+  CONSTRAINT_SYMMETRIC,
+  CONSTRAINT_EQUAL,           // base equality if we don't know the measured objects yet
+  CONSTRAINT_EQUAL_LINES,
+  CONSTRAINT_EQUAL_LINE_ARC,
+  CONSTRAINT_EQUAL_RADIUS,
+  CONSTRAINT_TANGENT,         // base tangency if we don't know the measured objects yet
+  CONSTRAINT_TANGENT_ARC_LINE,
+  CONSTRAINT_TANGENT_ARC_ARC,
+  CONSTRAINT_MULTI_TRANSLATION,
+  CONSTRAINT_MULTI_ROTATION
+};
+
+/**
+ *  Wrapper providing operations with constraints regardless the solver.
+ */
+class SketchSolver_IConstraintWrapper
+{
+public:
+  virtual ~SketchSolver_IConstraintWrapper() {}
+
+  /// \brief Return base feature
+  const ConstraintPtr& baseConstraint() const
+  { return myBaseConstraint; }
+
+  /// \brief Return ID of current entity
+  virtual ConstraintID id() const = 0;
+
+  /// \brief Change group for the constraint
+  virtual void setGroup(const GroupID& theGroup) = 0;
+  /// \brief Return identifier of the group the constraint belongs to
+  virtual GroupID group() const = 0;
+
+  /// \brief Return type of current entity
+  virtual SketchSolver_ConstraintType type() const = 0;
+
+  /// \brief Assign list of constrained objects
+  void setEntities(const std::list<EntityWrapperPtr>& theEntities)
+  { myConstrained = theEntities; }
+  /// \brief Return list of constrained objects
+  const std::list<EntityWrapperPtr>& entities() const
+  { return myConstrained; }
+
+  /// \brief Assign numeric parameter of constraint
+  virtual void setValue(const double& theValue)
+  { myValue = theValue; }
+  /// \brief Return numeric parameter of constraint
+  const double& value() const
+  { return myValue; }
+
+  /// \brief Verify the feature is used in the constraint
+  virtual bool isUsed(FeaturePtr theFeature) const = 0;
+  /// \brief Verify the attribute is used in the constraint
+  virtual bool isUsed(AttributePtr theAttribute) const = 0;
+
+  /// \brief Compare current constraint with other
+  virtual bool isEqual(const std::shared_ptr<SketchSolver_IConstraintWrapper>& theOther) = 0;
+
+  /// \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) = 0;
+
+protected:
+  ConstraintPtr               myBaseConstraint;
+  std::list<EntityWrapperPtr> myConstrained;
+  double                      myValue;
+};
+
+typedef std::shared_ptr<SketchSolver_IConstraintWrapper> ConstraintWrapperPtr;
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_IEntityWrapper.h b/src/SketchSolver/SketchSolver_IEntityWrapper.h
new file mode 100644 (file)
index 0000000..49f4d79
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_IEntityWrapper.h
+// Created: 30 Nov 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_IEntityWrapper_H_
+#define SketchSolver_IEntityWrapper_H_
+
+#include <SketchSolver.h>
+#include <SketchSolver_IParameterWrapper.h>
+
+#include <ModelAPI_Attribute.h>
+#include <ModelAPI_Feature.h>
+
+#include <list>
+#include <memory>
+
+/// Types of entities
+enum SketchSolver_EntityType {
+  ENTITY_UNKNOWN = 0,
+  ENTITY_SCALAR,
+  ENTITY_POINT,
+  ENTITY_NORMAL,
+  ENTITY_LINE,
+  ENTITY_CIRCLE,
+  ENTITY_ARC,
+  ENTITY_SKETCH
+};
+
+/**
+ *  Wrapper providing operations with entities regardless the solver.
+ */
+class SketchSolver_IEntityWrapper
+{
+public:
+  virtual ~SketchSolver_IEntityWrapper() {}
+
+  /// \brief Return base feature
+  const FeaturePtr& baseFeature() const
+  { return myBaseFeature; }
+  /// \brief Return base attribute
+  const AttributePtr& baseAttribute() const
+  { return myBaseAttribute; }
+
+  /// \brief Check the feature is basis for this wrapper
+  bool isBase(FeaturePtr theFeature) const
+  { return myBaseFeature && myBaseFeature == theFeature; }
+  /// \brief Check the attribute is basis for this wrapper
+  bool isBase(AttributePtr theAttribute) const
+  { return myBaseAttribute && myBaseAttribute == theAttribute; }
+
+  /// \brief Assign list of parameters for this entity
+  void setParameters(const std::list<ParameterWrapperPtr>& theParams)
+  { myParameters = theParams; }
+  /// \brief Return list of parameters
+  const std::list<ParameterWrapperPtr>& parameters() const
+  { return myParameters; }
+
+  /// \brief Assign list of sub-entities
+  void setSubEntities(const std::list<std::shared_ptr<SketchSolver_IEntityWrapper> >& theEntities)
+  { mySubEntities = theEntities; }
+  /// \brief Return list of sub-entities
+  const std::list<std::shared_ptr<SketchSolver_IEntityWrapper> >& subEntities() const
+  { return mySubEntities; }
+
+  /// \brief Return ID of current entity
+  virtual EntityID id() const = 0;
+
+  /// \brief Change group for the entity
+  virtual void setGroup(const GroupID& theGroup) = 0;
+  /// \brief Return identifier of the group the entity belongs to
+  virtual GroupID group() const = 0;
+
+  /// \brief Return type of current entity
+  virtual SketchSolver_EntityType type() const = 0;
+
+  /// \brief Verify the feature is used in the entity
+  virtual bool isUsed(FeaturePtr theFeature) const = 0;
+  /// \brief Verify the attribute is used in the entity
+  virtual bool isUsed(AttributePtr theAttribute) const = 0;
+
+  /// \brief Compare current entity with other
+  virtual bool isEqual(const std::shared_ptr<SketchSolver_IEntityWrapper>& theOther) = 0;
+
+  /// \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 std::shared_ptr<SketchSolver_IEntityWrapper>& theOther) = 0;
+
+protected:
+  FeaturePtr   myBaseFeature;
+  AttributePtr myBaseAttribute;
+
+  std::list<ParameterWrapperPtr>                            myParameters;
+  std::list<std::shared_ptr<SketchSolver_IEntityWrapper> >  mySubEntities;
+};
+
+typedef std::shared_ptr<SketchSolver_IEntityWrapper> EntityWrapperPtr;
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_IParameterWrapper.h b/src/SketchSolver/SketchSolver_IParameterWrapper.h
new file mode 100644 (file)
index 0000000..751e346
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_IParameterWrapper.h
+// Created: 1 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_IParameterWrapper_H_
+#define SketchSolver_IParameterWrapper_H_
+
+#include <SketchSolver.h>
+
+#include <memory>
+
+/**
+ *  Wrapper providing operations with parameters regardless the solver.
+ */
+class SketchSolver_IParameterWrapper
+{
+public:
+  virtual ~SketchSolver_IParameterWrapper() {}
+
+  /// \brief Return ID of current parameter
+  virtual ParameterID id() const = 0;
+
+  /// \brief Change group for the parameter
+  virtual void setGroup(const GroupID& theGroup) = 0;
+  /// \brief Return identifier of the group the parameter belongs to
+  virtual GroupID group() const = 0;
+
+  /// \brief Change value of parameter
+  virtual void setValue(double theValue) = 0;
+  /// \brief Return value of parameter
+  virtual double value() const = 0;
+
+  /// \brief Set or unset flag the parameter is given by expression
+  void setIsParametric(bool isParametric)
+  { myIsParametric = isParametric; }
+  /// \brief Show the parameter is an expression
+  bool isParametric() const
+  { return myIsParametric; }
+
+  /// \brief Compare current parameter with other
+  virtual bool isEqual(const std::shared_ptr<SketchSolver_IParameterWrapper>& theOther) = 0;
+
+  /// \brief Update value of parameter by the given one
+  /// \return \c true if the value of parameter is changed
+  virtual bool update(const std::shared_ptr<SketchSolver_IParameterWrapper>& theOther) = 0;
+
+protected:
+  bool myIsParametric; ///< indicate the parameter is given by parametric expression
+};
+
+typedef std::shared_ptr<SketchSolver_IParameterWrapper> ParameterWrapperPtr;
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_ISolver.h b/src/SketchSolver/SketchSolver_ISolver.h
new file mode 100644 (file)
index 0000000..75ddbfd
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_ISolver.h
+// Created: 30 Nov 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ISolver_H_
+#define SketchSolver_ISolver_H_
+
+#include <SketchSolver.h>
+
+#include <memory>
+
+/// The result of constraints solution
+enum SketchSolver_SolveStatus {
+  STATUS_OK,
+  STATUS_INCONSISTENT,
+  STATUS_EMPTYSET,
+  STATUS_FAILED // set if no one other status is applicable
+};
+
+
+/**
+ *  Interface providing operations to solve sketches.
+ */
+class SketchSolver_ISolver
+{
+public:
+  virtual ~SketchSolver_ISolver() {}
+
+  /// \brief Changes the ID of the group to solve
+  void setGroup(const GroupID& theGroupID)
+  { myGroup = theGroupID; }
+
+  /// \brief Set or unset the flag which allows to find all failed constraints
+  void calculateFailedConstraints(bool theSic)
+  { myFindFaileds = theSic; }
+
+  /// \brief Solve the set of equations
+  /// \return identifier whether solution succeeded
+  virtual SketchSolver_SolveStatus solve() = 0;
+
+protected:
+  GroupID myGroup;       ///< ID of the group to be solved
+  bool    myFindFaileds; ///< flag to find conflicting or inappropriate constraints
+};
+
+typedef std::shared_ptr<SketchSolver_ISolver> SolverPtr;
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_Manager.cpp b/src/SketchSolver/SketchSolver_Manager.cpp
new file mode 100644 (file)
index 0000000..442cf15
--- /dev/null
@@ -0,0 +1,366 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Manager.cpp
+// Created: 08 May 2014
+// Author:  Artem ZHIDKOV
+
+#include "SketchSolver_Manager.h"
+
+#include <Events_Loop.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Object.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Attribute.h>
+
+#include <SketchPlugin_Constraint.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Sketch.h>
+#include <SketchPlugin_Feature.h>
+
+#include <list>
+#include <set>
+#include <memory>
+
+// Initialization of constraint manager self pointer
+SketchSolver_Manager* SketchSolver_Manager::mySelf = 0;
+
+/// Global constraint manager object
+SketchSolver_Manager* myManager = SketchSolver_Manager::instance();
+
+
+// ========================================================
+// ========= SketchSolver_Manager ===============
+// ========================================================
+SketchSolver_Manager* SketchSolver_Manager::instance()
+{
+  if (!mySelf)
+    mySelf = new SketchSolver_Manager();
+  return mySelf;
+}
+
+SketchSolver_Manager::SketchSolver_Manager()
+{
+  myGroups.clear();
+  myIsComputed = false;
+
+  // Register in event loop
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
+}
+
+SketchSolver_Manager::~SketchSolver_Manager()
+{
+  myGroups.clear();
+}
+
+void SketchSolver_Manager::setBuilder(BuilderPtr theBuilder)
+{
+  myBuilder = theBuilder;
+}
+
+BuilderPtr SketchSolver_Manager::builder()
+{
+  return myBuilder;
+}
+
+// ============================================================================
+//  Function: processEvent
+//  Purpose:  listen the event loop and process the message
+// ============================================================================
+void SketchSolver_Manager::processEvent(
+  const std::shared_ptr<Events_Message>& theMessage)
+{
+  if (myIsComputed)
+    return;
+  if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
+      || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)
+      || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
+    std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
+        std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
+    std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
+
+    // Shows the message has at least one feature applicable for solver
+    bool hasProperFeature = false;
+
+    bool isMovedEvt = theMessage->eventID()
+          == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
+    if (isMovedEvt) {
+      std::set<ObjectPtr>::iterator aFeatIter;
+      for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
+        std::shared_ptr<SketchPlugin_Feature> aSFeature = 
+            std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+        if (aSFeature) {
+          moveEntity(aSFeature);
+          hasProperFeature = true;
+        }
+      }
+    } else {
+      std::list<FeaturePtr> aSketchFeatures = SketchSolver_Group::selectApplicableFeatures(aFeatures);
+      std::list<FeaturePtr>::iterator aFeatIter = aSketchFeatures.begin();
+      for (; aFeatIter != aSketchFeatures.end(); ++aFeatIter) {
+        if ((*aFeatIter)->getKind() == SketchPlugin_Sketch::ID()) {
+          std::shared_ptr<ModelAPI_CompositeFeature> aSketch = 
+              std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFeatIter);
+          hasProperFeature = changeWorkplane(aSketch) || hasProperFeature;
+          continue;
+        }
+        std::shared_ptr<SketchPlugin_Feature> aFeature = 
+            std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+        if (!aFeature)
+          continue;
+        hasProperFeature = changeFeature(aFeature) || hasProperFeature;
+      }
+    }
+
+    // Solve the set of constraints
+    if (hasProperFeature)
+      resolveConstraints(isMovedEvt); // send update for movement in any case
+  } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
+    std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
+      std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
+    const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
+
+    // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch
+    std::set<std::string>::const_iterator aFGrIter;
+    for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
+      if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 ||
+        aFGrIter->compare(ModelAPI_Feature::group()) == 0)
+        break;
+
+    if (aFGrIter != aFeatureGroups.end()) {
+      std::vector<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
+      std::list<SketchSolver_Group*> aSeparatedGroups;
+      while (aGroupIter != myGroups.end()) {
+        if (!(*aGroupIter)->isWorkplaneValid()) {  // the group should be removed
+          delete *aGroupIter;
+          int aShift = aGroupIter - myGroups.begin();
+          myGroups.erase(aGroupIter);
+          aGroupIter = myGroups.begin() + aShift;
+          continue;
+        }
+        if (!(*aGroupIter)->isConsistent()) {  // some constraints were removed, try to split the group
+          (*aGroupIter)->splitGroup(aSeparatedGroups);
+        }
+        aGroupIter++;
+      }
+      if (aSeparatedGroups.size() > 0)
+        myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
+    }
+  }
+}
+
+// ============================================================================
+//  Function: changeWorkplane
+//  Purpose:  update workplane by given parameters of the sketch
+// ============================================================================
+bool SketchSolver_Manager::changeWorkplane(CompositeFeaturePtr theSketch)
+{
+  bool aResult = true;  // changed when a workplane wrongly updated
+  bool isUpdated = false;
+  // Try to update specified workplane in all groups
+  std::vector<SketchSolver_Group*>::iterator aGroupIter;
+  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+    if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
+      isUpdated = true;
+      aResult = false;
+    }
+  // If the workplane is not updated, so this is a new workplane
+  if (!isUpdated) {
+    SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch);
+    // Verify that the group is created successfully
+    if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) {
+      delete aNewGroup;
+      return false;
+    }
+    myGroups.push_back(aNewGroup);
+  }
+  return aResult;
+}
+
+// ============================================================================
+//  Function: changeConstraintOrEntity
+//  Purpose:  create/update the constraint or the feature and place it into appropriate group
+// ============================================================================
+bool SketchSolver_Manager::changeFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
+{
+  // Search the groups which this feature touches
+  std::set<GroupID> aGroups;
+  findGroups(theFeature, aGroups);
+
+  std::shared_ptr<SketchPlugin_Constraint> aConstraint = 
+      std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
+
+  // Process the groups list
+  if (aGroups.size() == 0) {
+    // There are no groups applicable for this constraint => create new one
+    // The group will be created only for constraints, not for features
+    if (!aConstraint) return false;
+    std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(aConstraint);
+    if (!aWP)
+      return false;
+    SketchSolver_Group* aGroup = new SketchSolver_Group(aWP);
+    if (!aGroup->changeConstraint(aConstraint)) {
+      delete aGroup;
+      return false;
+    }
+    myGroups.push_back(aGroup);
+    return true;
+  } else if (aGroups.size() == 1) {  // Only one group => add feature into it
+    GroupID aGroupId = *(aGroups.begin());
+    std::vector<SketchSolver_Group*>::iterator aGroupIter;
+    for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+      if ((*aGroupIter)->getId() == aGroupId) {
+        // If the group is empty, the feature is not added (the constraint only)
+        if (!aConstraint && !(*aGroupIter)->isEmpty())
+          return (*aGroupIter)->updateFeature(theFeature);
+        return (*aGroupIter)->changeConstraint(aConstraint);
+      }
+  } else if (aGroups.size() > 1) {  // Several groups applicable for this feature => need to merge them
+    std::set<GroupID>::const_iterator aGroupsIter = aGroups.begin();
+
+    // Search first group
+    std::vector<SketchSolver_Group*>::iterator aFirstGroupIter;
+    for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
+      if ((*aFirstGroupIter)->getId() == *aGroupsIter)
+        break;
+    if (aFirstGroupIter == myGroups.end())
+      return false;
+
+    // Append other groups to the first one
+    std::vector<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
+    for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
+      for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
+        if ((*anOtherGroupIter)->getId() == *aGroupsIter)
+          break;
+      if (anOtherGroupIter == myGroups.end()) {  // Group disappears
+        anOtherGroupIter = aFirstGroupIter + 1;
+        continue;
+      }
+
+      (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
+      int aShiftFirst = aFirstGroupIter - myGroups.begin();
+      int aShiftOther = anOtherGroupIter - myGroups.begin();
+      delete *anOtherGroupIter;
+      myGroups.erase(anOtherGroupIter);
+      aFirstGroupIter = myGroups.begin() + aShiftFirst;
+      anOtherGroupIter = myGroups.begin() + aShiftOther;
+    }
+
+    if (aConstraint)
+      return (*aFirstGroupIter)->changeConstraint(aConstraint);
+    return (*aFirstGroupIter)->updateFeature(theFeature);
+  }
+
+  // Something goes wrong
+  return false;
+}
+
+// ============================================================================
+//  Function: moveEntity
+//  Purpose:  update element moved on the sketch, which is used by constraints
+// ============================================================================
+void SketchSolver_Manager::moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature)
+{
+  std::vector<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
+  for (; aGroupIt != myGroups.end(); aGroupIt++)
+    if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature))
+      (*aGroupIt)->moveFeature(theFeature);
+}
+
+// ============================================================================
+//  Function: findGroups
+//  Purpose:  search groups of entities interacting with given feature
+// ============================================================================
+void SketchSolver_Manager::findGroups(
+    std::shared_ptr<SketchPlugin_Feature> theFeature,
+    std::set<GroupID>& theGroupIDs) const
+{
+  std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(theFeature);
+
+  SketchSolver_Group* anEmptyGroup = 0;  // appropriate empty group for specified constraint
+  std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
+  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+    if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) {
+      if (!(*aGroupIter)->isEmpty())
+        theGroupIDs.insert((*aGroupIter)->getId());
+      else if (!anEmptyGroup)
+        anEmptyGroup = *aGroupIter;
+    }
+
+  // When only empty group is found, use it
+  if (anEmptyGroup && theGroupIDs.empty())
+    theGroupIDs.insert(anEmptyGroup->getId());
+}
+
+// ============================================================================
+//  Function: findWorkplane
+//  Purpose:  search workplane containing given feature
+// ============================================================================
+std::shared_ptr<ModelAPI_CompositeFeature> SketchSolver_Manager
+::findWorkplane(std::shared_ptr<SketchPlugin_Feature> theFeature) const
+{
+  // Already verified workplanes
+  std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
+
+  std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
+  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
+    std::shared_ptr<ModelAPI_CompositeFeature> aWP = (*aGroupIter)->getWorkplane();
+    if (aVerified.find(aWP) != aVerified.end())
+      continue;
+
+    DataPtr aData = aWP->data();
+    if (aData->isValid()) {
+      std::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures = std::dynamic_pointer_cast<
+          ModelAPI_AttributeRefList>(aData->attribute(SketchPlugin_Sketch::FEATURES_ID()));
+      std::list<ObjectPtr> aFeaturesList = aWPFeatures->list();
+      std::list<ObjectPtr>::const_iterator anIter;
+      for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
+        if (*anIter == theFeature)
+          return aWP;  // workplane is found
+    }
+    aVerified.insert(aWP);
+  }
+
+  return std::shared_ptr<ModelAPI_CompositeFeature>();
+}
+
+// ============================================================================
+//  Function: resolveConstraints
+//  Purpose:  change entities according to available constraints
+// ============================================================================
+void SketchSolver_Manager::resolveConstraints(const bool theForceUpdate)
+{
+  myIsComputed = true;
+  bool needToUpdate = false;
+  static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+  // to avoid redisplay of each segment on update by solver one by one in the viewer
+  bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
+  if (isUpdateFlushed) {
+    Events_Loop::loop()->setFlushed(anUpdateEvent, false);
+  }
+
+  std::vector<SketchSolver_Group*>::iterator aGroupIter;
+  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+    if ((*aGroupIter)->resolveConstraints())
+      needToUpdate = true;
+
+  // Features may be updated => now send events, but for all changed at once
+  if (isUpdateFlushed) {
+    Events_Loop::loop()->setFlushed(anUpdateEvent, true);
+  }
+  // Must be before flush because on "Updated" flush the results may be produced
+  // and the creation event is appeared with many new objects. If myIsComputed these
+  // events are missed in processEvents and some elements are not added.
+  myIsComputed = false;
+  if (needToUpdate || theForceUpdate)
+    Events_Loop::loop()->flush(anUpdateEvent);
+}
diff --git a/src/SketchSolver/SketchSolver_Manager.h b/src/SketchSolver/SketchSolver_Manager.h
new file mode 100644 (file)
index 0000000..8ceddc7
--- /dev/null
@@ -0,0 +1,114 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Manager.h
+// Created: 08 May 2014
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_Manager_H_
+#define SketchSolver_Manager_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Builder.h>
+
+#include <Events_Listener.h>
+#include <SketchPlugin_Constraint.h>
+
+#include <vector>
+#include <set>
+
+/** \class   SketchSolver_Manager
+ *  \ingroup Plugins
+ *  \brief   Listens the changes of SketchPlugin features and transforms the Constraint
+ *           feature into the format understandable by SolveSpace library.
+ *
+ *  Constraints created for SolveSpace library are divided into the groups.
+ *  The division order based on connectedness of the features by the constraints.
+ *  The groups may be fused or separated according to the new constraints.
+ *
+ *  \remark This is a singleton.
+ */
+class SketchSolver_Manager : public Events_Listener
+{
+public:
+  /** \brief Main method to create constraint manager
+   *  \return pointer to the singleton
+   */
+  SKETCHSOLVER_EXPORT static SketchSolver_Manager* instance();
+
+  /** \brief Implementation of Event Listener method
+   *  \param[in] theMessage the data of the event
+   */
+  virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
+
+  /// \brief Initialize builder for solver's data structure entities
+  /// \param theBuilder [in]  solver's specific builder
+  SKETCHSOLVER_EXPORT void setBuilder(BuilderPtr theBuilder);
+  /// \brief Returns the builder specific for the solver
+  BuilderPtr builder();
+
+protected:
+  SketchSolver_Manager();
+  ~SketchSolver_Manager();
+
+  /** \brief Adds or updates a constraint or an entity in the suitable group
+   *  \param[in] theFeature sketch feature to be changed
+   *  \return \c true if the feature changed successfully
+   */
+  bool changeFeature(std::shared_ptr<SketchPlugin_Feature> theFeature);
+
+  /** \brief Removes a constraint from the manager
+   *  \param[in] theConstraint constraint to be removed
+   *  \return \c true if the constraint removed successfully
+   */
+  bool removeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
+
+  /** \brief Adds or updates a workplane in the manager
+   *  \param[in] theSketch the feature to create or update workplane
+   *  \return \c true if the workplane changed successfully
+   *  \remark Type of theSketch is not verified inside
+   */
+  bool changeWorkplane(CompositeFeaturePtr theSketch);
+
+  /** \brief Removes a workplane from the manager.
+   *         All groups based on such workplane will be removed too.
+   *  \param[in] theSketch the feature to be removed
+   *  \return \c true if the workplane removed successfully
+   */
+  bool removeWorkplane(std::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+  /** \brief Updates entity which is moved in GUI
+   *  \param[in] theFeature entity to be updated
+   */
+  void moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
+
+  /** \brief Goes through the list of groups and solve the constraints
+   *  \param theForceUpdate flushes the update event in any case: something changed or not
+   */
+  void resolveConstraints(const bool theForceUpdate);
+
+private:
+  /** \brief Searches list of groups which interact with specified feature
+   *  \param[in]  theFeature  object to be found
+   *  \param[out] theGroups   list of group indexes interacted with the feature
+   */
+  void findGroups(std::shared_ptr<SketchPlugin_Feature> theFeature,
+                  std::set<GroupID>& theGroupIDs) const;
+
+  /** \brief Searches in the list of groups the workplane which contains specified feature
+   *  \param[in] theFeature object to be found
+   *  \return workplane containing the feature
+   */
+  std::shared_ptr<ModelAPI_CompositeFeature> findWorkplane(
+      std::shared_ptr<SketchPlugin_Feature> theFeature) const;
+
+private:
+  static SketchSolver_Manager*     mySelf;    ///< Self pointer to implement singleton functionality
+  std::vector<SketchSolver_Group*> myGroups;  ///< Groups of constraints
+  BuilderPtr                       myBuilder; ///< Builder for solver's entities
+  /// true if computation is performed and all "updates" are generated by this algo
+  /// and needs no recomputation
+  bool myIsComputed;
+};
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_Solver.cpp b/src/SketchSolver/SketchSolver_Solver.cpp
deleted file mode 100644 (file)
index 36979d7..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_Solver.cpp
-// Created: 07 May 2014
-// Author:  Artem ZHIDKOV
-
-#include "SketchSolver_Solver.h"
-#include <Events_LongOp.h>
-
-SketchSolver_Solver::SketchSolver_Solver()
-{
-  myGroupID = 0;
-  // Nullify all elements of the set of equations
-  myEquationsSystem.param = 0;
-  myEquationsSystem.params = 0;
-  myEquationsSystem.entity = 0;
-  myEquationsSystem.entities = 0;
-  myEquationsSystem.constraint = 0;
-  myEquationsSystem.constraints = 0;
-  myEquationsSystem.failed = 0;
-  myEquationsSystem.faileds = 0;
-
-  myEquationsSystem.dragged[0] = 0;
-  myEquationsSystem.dragged[1] = 0;
-  myEquationsSystem.dragged[2] = 0;
-  myEquationsSystem.dragged[3] = 0;
-
-  // If the set of constraints is inconsistent,
-  // the failed field will contain wrong constraints
-  myEquationsSystem.calculateFaileds = 0;
-}
-
-SketchSolver_Solver::~SketchSolver_Solver()
-{
-  if (myEquationsSystem.constraint)
-    delete[] myEquationsSystem.constraint;
-  myEquationsSystem.constraint = 0;
-  if (myEquationsSystem.failed)
-    delete[] myEquationsSystem.failed;
-  myEquationsSystem.failed = 0;
-}
-
-void SketchSolver_Solver::setParameters(Slvs_Param* theParameters, int theSize)
-{
-  myEquationsSystem.param = theParameters;
-  myEquationsSystem.params = theSize;
-}
-
-
-void SketchSolver_Solver::setDraggedParameters(const Slvs_hParam* theDragged)
-{
-  for (unsigned int i = 0; i < 4; i++)
-    myEquationsSystem.dragged[i] = theDragged[i];
-}
-
-void SketchSolver_Solver::setEntities(Slvs_Entity* theEntities, int theSize)
-{
-  myEquationsSystem.entity = theEntities;
-  myEquationsSystem.entities = theSize;
-}
-
-void SketchSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize)
-{
-  if (!myEquationsSystem.constraint) {
-    myEquationsSystem.constraint = new Slvs_Constraint[theSize];
-    myEquationsSystem.constraints = theSize;
-    myEquationsSystem.failed = new Slvs_hConstraint[theSize];
-  }
-  else if (myEquationsSystem.constraints != theSize) {
-    if (theSize > myEquationsSystem.constraints) {
-      delete[] myEquationsSystem.constraint;
-      myEquationsSystem.constraint = new Slvs_Constraint[theSize];
-      if (myEquationsSystem.failed)
-        delete[] myEquationsSystem.failed;
-      myEquationsSystem.failed = new Slvs_hConstraint[theSize];
-    }
-    myEquationsSystem.constraints = theSize;
-  }
-  memcpy(myEquationsSystem.constraint, theConstraints, theSize * sizeof(Slvs_Constraint));
-  memset(myEquationsSystem.failed, SLVS_C_UNKNOWN, theSize * sizeof(Slvs_hConstraint));
-}
-
-
-int SketchSolver_Solver::solve()
-{
-  if (myEquationsSystem.constraints <= 0)
-    return SLVS_RESULT_EMPTY_SET;
-
-  Events_LongOp::start(this);
-  Slvs_Solve(&myEquationsSystem, myGroupID);
-  Events_LongOp::end(this);
-
-  return myEquationsSystem.result;
-}
-
-bool SketchSolver_Solver::getResult(std::vector<Slvs_Param>& theParameters)
-{
-  if (myEquationsSystem.result != SLVS_RESULT_OKAY)
-    return false;
-
-  if (theParameters.size() != myEquationsSystem.params)
-    return false;  // number of parameters is not the same
-
-  std::vector<Slvs_Param>::iterator aParamIter = theParameters.begin();
-  for (int i = 0; i < myEquationsSystem.params; i++, aParamIter++) {
-    if (myEquationsSystem.param[i].h != aParamIter->h)
-      return false;  // sequence of parameters was changed
-    aParamIter->val = myEquationsSystem.param[i].val;
-  }
-
-  return true;
-}
diff --git a/src/SketchSolver/SketchSolver_Solver.h b/src/SketchSolver/SketchSolver_Solver.h
deleted file mode 100644 (file)
index 52ac18f..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_Solver.h
-// Created: 07 May 2014
-// Author:  Artem ZHIDKOV
-
-#ifndef SketchSolver_Solver_H_
-#define SketchSolver_Solver_H_
-
-#include "SketchSolver.h"
-
-// Need to be defined before including SolveSpace to avoid additional dependances on Windows platform
-#if defined(WIN32) && !defined(HAVE_C99_INTEGER_TYPES)
-typedef unsigned int UINT32;
-#else
-#include <stdint.h>
-#endif
-#include <string.h>
-#include <slvs.h>
-
-#include <vector>
-
-#define SLVS_RESULT_EMPTY_SET -1
-
-// Unknown constraint (for error reporting)
-#define SLVS_C_UNKNOWN 0
-// Fillet constraint identifier
-#define SLVS_C_FILLET            100100
-// Multi-rotation constraint identifier
-#define SLVS_C_MULTI_ROTATION    100101
-// Multi-translation constraint identifier
-#define SLVS_C_MULTI_TRANSLATION 100102
-// Unknown entity
-#define SLVS_E_UNKNOWN 0
-// Unknown group
-#define SLVS_G_UNKNOWN 0
-// Group ID to store external objects
-#define SLVS_G_OUTOFGROUP 1
-
-/**
- * The main class that performs the high-level operations for connection to the SolveSpace.
- */
-class SketchSolver_Solver
-{
- public:
-  SketchSolver_Solver();
-  ~SketchSolver_Solver();
-
-  /** \brief Initialize the ID of the group
-   */
-  inline void setGroupID(Slvs_hGroup theGroupID)
-  {
-    myGroupID = theGroupID;
-  }
-
-  /** \brief Change array of parameters
-   *  \param[in] theParameters pointer to the array of parameters
-   *  \param[in] theSize       size of this array
-   */
-  void setParameters(Slvs_Param* theParameters, int theSize);
-
-  /** \brief Change array of entities
-   *  \param[in] theEntities pointer to the array of entities
-   *  \param[in] theSize     size of this array
-   */
-  void setEntities(Slvs_Entity* theEntities, int theSize);
-
-  /** \brief Change array of constraints
-   *  \param[in] theConstraints pointer to the array of constraints
-   *  \param[in] theSize        size of this array
-   */
-  void setConstraints(Slvs_Constraint* theConstraints, int theSize);
-
-  /** \brief Store the parameters of the point which was moved by user.
-   *         The solver will watch this items to be constant
-   *  \param[in] theDragged list of parameters (not more than 4) which should not be changed during solving
-   */
-  void setDraggedParameters(const Slvs_hParam* theDragged);
-
-  /** \brief Set or unset the flag which allows to find all failed constraints
-   */
-  void calculateFailedConstraints(bool theSic)
-  { myEquationsSystem.calculateFaileds = theSic ? 1 : 0; }
-
-  /** \brief Solve the set of equations
-   *  \return identifier whether solution succeeded
-   */
-  int solve();
-
-  /** \brief Updates the list of parameters by calculated values
-   *  \param[in,out] theParameters parameters to be updated
-   *  \return \c true if parameters are updated correctly
-   */
-  bool getResult(std::vector<Slvs_Param>& theParameters);
-
- private:
-  Slvs_hGroup myGroupID;         ///< identifier of the group to be solved
-  Slvs_System myEquationsSystem;  ///< set of equations for solving in SolveSpace
-};
-
-#endif
index 58cd67418755730d3f169b6bdde4c3f020c8db65..eecc86653a9c66fc4041ba9c3eb28ce5602686ce 100644 (file)
 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
 
 // File:    SketchSolver_Storage.cpp
-// Created: 18 Mar 2015
+// Created: 30 Nov 2015
 // Author:  Artem ZHIDKOV
 
 #include <SketchSolver_Storage.h>
+#include <SketchSolver_Manager.h>
 
-#include <GeomAPI_Pnt2d.h>
-#include <GeomAPI_XY.h>
-#include <math.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
 
-/** \brief Search the entity/parameter with specified ID in the list of elements
- *  \param[in] theEntityID unique ID of the element
- *  \param[in] theEntities list of elements
- *  \return position of the found element or -1 if the element is not found
- */
-template<typename T>
-static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
 
-/// \brief Compare two parameters to be different
-static bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2);
-/// \brief Compare two entities to be different
-static bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2);
-/// \brief Compare two constriants to be different
-static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2);
+/// \brief Verify two vectors of constraints are equal.
+///        Vectors differ by the order of elements are equal.
+static bool isEqual(const std::list<ConstraintWrapperPtr>& theCVec1,
+                    const std::list<ConstraintWrapperPtr>& theCVec2);
 
 
-SketchSolver_Storage::SketchSolver_Storage()
-  : myParamMaxID(SLVS_E_UNKNOWN),
-    myEntityMaxID(SLVS_E_UNKNOWN),
-    myConstrMaxID(SLVS_C_UNKNOWN),
-    myFixed(SLVS_E_UNKNOWN),
-    myNeedToResolve(false),
-    myDuplicatedConstraint(false)
+void SketchSolver_Storage::addConstraint(ConstraintPtr        theConstraint,
+                                         ConstraintWrapperPtr theSolverConstraint)
 {
+  std::list<ConstraintWrapperPtr> aConstrList(1, theSolverConstraint);
+  addConstraint(theConstraint, aConstrList);
 }
 
-Slvs_hParam SketchSolver_Storage::addParameter(const Slvs_Param& theParam)
+void SketchSolver_Storage::addConstraint(
+    ConstraintPtr                   theConstraint,
+    std::list<ConstraintWrapperPtr> theSolverConstraints)
 {
-  if (theParam.h > 0 && theParam.h <= myParamMaxID) {
-    // parameter is already used, rewrite it
-    return updateParameter(theParam);
-  }
-
-  Slvs_Param aParam = theParam;
-  if (aParam.h > myParamMaxID)
-    myParamMaxID = aParam.h;
-  else
-    aParam.h = ++myParamMaxID;
-  myParameters.push_back(aParam);
-  myNeedToResolve = true;
-  return aParam.h;
-}
+  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+      aFound = myConstraintMap.find(theConstraint);
+  if (aFound == myConstraintMap.end() || !isEqual(aFound->second, theSolverConstraints))
+    setNeedToResolve(true);
 
-Slvs_hParam SketchSolver_Storage::updateParameter(const Slvs_Param& theParam)
-{
-  if (theParam.h > 0 && theParam.h <= myParamMaxID) {
-    // parameter already used, rewrite it
-    int aPos = Search(theParam.h, myParameters);
-    if (aPos >= 0 && aPos < (int)myParameters.size()) {
-      if (IsNotEqual(myParameters[aPos], theParam))
-        myUpdatedParameters.insert(theParam.h);
-      myParameters[aPos] = theParam;
-      return theParam.h;
-    }
+  // Do not add point-point coincidence, because it is already made by setting
+  // the same parameters for both points
+  if (!theSolverConstraints.empty() &&
+      theSolverConstraints.front()->type() != CONSTRAINT_PT_PT_COINCIDENT) {
+    std::list<ConstraintWrapperPtr>::iterator aCIt = theSolverConstraints.begin();
+    for (; aCIt != theSolverConstraints.end(); ++aCIt)
+      update(*aCIt);
   }
-
-  // Parameter is not found, add new one
-  Slvs_Param aParam = theParam;
-  aParam.h = 0;
-  return addParameter(aParam);
+  myConstraintMap[theConstraint] = theSolverConstraints;
 }
 
-bool SketchSolver_Storage::removeParameter(const Slvs_hParam& theParamID)
+void SketchSolver_Storage::addEntity(FeaturePtr       theFeature,
+                                     EntityWrapperPtr theSolverEntity)
 {
-  int aPos = Search(theParamID, myParameters);
-  if (aPos >= 0 && aPos < (int)myParameters.size()) {
-    // Firstly, search the parametes is not used elsewhere
-    std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
-    for (; anEntIter != myEntities.end(); anEntIter++) {
-      for (int i = 0; i < 4; i++)
-        if (anEntIter->param[i] == theParamID)
-          return false;
-    }
-    // Remove parameter
-    myParameters.erase(myParameters.begin() + aPos);
-    myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h;
-    myNeedToResolve = true;
-    myRemovedParameters.insert(theParamID);
-    return true;
-  }
-  return false;
-}
-
-const Slvs_Param& SketchSolver_Storage::getParameter(const Slvs_hParam& theParamID) const
-{
-  int aPos = Search(theParamID, myParameters);
-  if (aPos >= 0 && aPos < (int)myParameters.size())
-    return myParameters[aPos];
+  std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFound = myFeatureMap.find(theFeature);
+  if (aFound == myFeatureMap.end() || !aFound->second->isEqual(theSolverEntity))
+    setNeedToResolve(true); // the entity is new or modified
 
-  // Parameter is not found, return empty object
-  static Slvs_Param aDummy;
-  aDummy.h = 0;
-  return aDummy;
+  myFeatureMap[theFeature] = theSolverEntity;
 }
 
-
-Slvs_hEntity SketchSolver_Storage::addEntity(const Slvs_Entity& theEntity)
+void SketchSolver_Storage::addEntity(AttributePtr     theAttribute,
+                                     EntityWrapperPtr theSolverEntity)
 {
-  if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
-    // Entity is already used, rewrite it
-    return updateEntity(theEntity);
-  }
+  std::map<AttributePtr, EntityWrapperPtr>::const_iterator aFound = myAttributeMap.find(theAttribute);
+  if (aFound == myAttributeMap.end() || !aFound->second->isEqual(theSolverEntity))
+    setNeedToResolve(true); // the entity is new or modified
 
-  Slvs_Entity aEntity = theEntity;
-  if (aEntity.h > myEntityMaxID)
-    myEntityMaxID = aEntity.h;
-  else
-    aEntity.h = ++myEntityMaxID;
-  myEntities.push_back(aEntity);
-  myNeedToResolve = true;
-  return aEntity.h;
+  myAttributeMap[theAttribute] = theSolverEntity;
 }
 
-Slvs_hEntity SketchSolver_Storage::updateEntity(const Slvs_Entity& theEntity)
-{
-  if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
-    // Entity already used, rewrite it
-    int aPos = Search(theEntity.h, myEntities);
-    if (aPos >= 0 && aPos < (int)myEntities.size()) {
-      myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity);
-      myEntities[aPos] = theEntity;
-      return theEntity.h;
-    }
-  }
-
-  // Entity is not found, add new one
-  Slvs_Entity aEntity = theEntity;
-  aEntity.h = 0;
-  return addEntity(aEntity);
-}
-
-bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
-{
-  bool aResult = true;
-  int aPos = Search(theEntityID, myEntities);
-  if (aPos >= 0 && aPos < (int)myEntities.size()) {
-    // Firstly, check the entity and its attributes is not used elsewhere
-    std::set<Slvs_hEntity> anEntAndSubs;
-    anEntAndSubs.insert(theEntityID);
-    for (int i = 0; i < 4; i++)
-      if (myEntities[aPos].point[i] != SLVS_E_UNKNOWN)
-        anEntAndSubs.insert(myEntities[aPos].point[i]);
-
-    std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
-    for (; anEntIter != myEntities.end(); anEntIter++) {
-      for (int i = 0; i < 4; i++)
-        if (anEntAndSubs.find(anEntIter->point[i]) != anEntAndSubs.end())
-          return false;
-      if (anEntAndSubs.find(anEntIter->distance) != anEntAndSubs.end())
-        return false;
-    }
-    std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-    for (; aConstrIter != myConstraints.end(); aConstrIter++) {
-      Slvs_hEntity anEntIDs[6] = {aConstrIter->ptA, aConstrIter->ptB,
-          aConstrIter->entityA, aConstrIter->entityB,
-          aConstrIter->entityC, aConstrIter->entityD};
-      for (int i = 0; i < 6; i++)
-        if (anEntAndSubs.find(anEntIDs[i]) != anEntAndSubs.end())
-          return false;
-    }
-    // The entity is not used, remove it and its parameters
-    Slvs_Entity anEntity = myEntities[aPos];
-    myEntities.erase(myEntities.begin() + aPos);
-    myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
-    if (anEntity.distance != SLVS_E_UNKNOWN)
-      aResult = aResult && removeParameter(anEntity.distance);
-    for (int i = 0; i < 4; i++)
-      if (anEntity.param[i] != SLVS_E_UNKNOWN)
-        aResult = removeParameter(anEntity.param[i]) && aResult;
-    for (int i = 0; i < 4; i++)
-      if (anEntity.point[i] != SLVS_E_UNKNOWN)
-        aResult = removeEntity(anEntity.point[i]) && aResult;
-    myNeedToResolve = true;
-    myRemovedEntities.insert(theEntityID);
-    if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D)
-      removeCoincidentPoint(theEntityID);
-  }
-  return aResult;
-}
 
-void SketchSolver_Storage::removeUnusedEntities()
+bool SketchSolver_Storage::update(FeaturePtr theFeature, const GroupID& theGroup)
 {
-  std::set<Slvs_hEntity> anUnusedEntities;
-  std::vector<Slvs_Entity>::const_iterator aEIt = myEntities.begin();
-  for (; aEIt != myEntities.end(); ++aEIt) {
-    if (aEIt->h == aEIt->wrkpl) {
-      // don't remove workplane
-      anUnusedEntities.erase(aEIt->point[0]);
-      anUnusedEntities.erase(aEIt->normal);
-      continue;
+  bool isUpdated = false;
+  EntityWrapperPtr aRelated = entity(theFeature);
+  if (!aRelated) { // Feature is not exist, create it
+    std::list<EntityWrapperPtr> aSubs;
+    // Firstly, create/update its attributes
+    std::list<AttributePtr> anAttrs =
+        theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
+    std::list<AttributePtr>::const_iterator anIt = anAttrs.begin();
+    for (; anIt != anAttrs.end(); ++anIt) {
+      isUpdated = update(*anIt, theGroup) || isUpdated;
+      aSubs.push_back(entity(*anIt));
     }
-    anUnusedEntities.insert(aEIt->h);
-  }
-
-  std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
-  for (; aCIt != myConstraints.end(); ++aCIt) {
-    Slvs_hEntity aSubs[6] = {
-        aCIt->entityA, aCIt->entityB,
-        aCIt->entityC, aCIt->entityD,
-        aCIt->ptA,     aCIt->ptB};
-    for (int i = 0; i < 6; i++) {
-      if (aSubs[i] != SLVS_E_UNKNOWN) {
-        anUnusedEntities.erase(aSubs[i]);
-        int aPos = Search(aSubs[i], myEntities);
-        if (aPos >= 0 && aPos < (int)myEntities.size()) {
-          for (int j = 0; j < 4; j++)
-            if (myEntities[aPos].point[j] != SLVS_E_UNKNOWN)
-              anUnusedEntities.erase(myEntities[aPos].point[j]);
-          if (myEntities[aPos].distance != SLVS_E_UNKNOWN)
-            anUnusedEntities.erase(myEntities[aPos].distance);
-        }
-      }
+    // If the feature is a circle, add its radius as a sub
+    if (theFeature->getKind() == SketchPlugin_Circle::ID()) {
+      AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
+      isUpdated = update(aRadius, theGroup) || isUpdated;
+      aSubs.push_back(entity(aRadius));
     }
-  }
-
-  std::set<Slvs_hEntity>::const_iterator anEntIt = anUnusedEntities.begin();
-  while (anEntIt != anUnusedEntities.end()) {
-    int aPos = Search(*anEntIt, myEntities);
-    if (aPos < 0 && aPos >= (int)myEntities.size())
-      continue;
-    Slvs_Entity anEntity = myEntities[aPos];
-    // Remove entity if and only if all its parameters unused
-    bool isUsed = false;
-    if (anEntity.distance != SLVS_E_UNKNOWN && 
-      anUnusedEntities.find(anEntity.distance) == anUnusedEntities.end())
-      isUsed = true;
-    for (int i = 0; i < 4 && !isUsed; i++)
-      if (anEntity.point[i] != SLVS_E_UNKNOWN &&
-          anUnusedEntities.find(anEntity.point[i]) == anUnusedEntities.end())
-        isUsed = true;
-    if (isUsed) {
-      anUnusedEntities.erase(anEntity.distance);
-      for (int i = 0; i < 4; i++)
-        if (anEntity.point[i] != SLVS_E_UNKNOWN)
-          anUnusedEntities.erase(anEntity.point[i]);
-      std::set<Slvs_hEntity>::iterator aRemoveIt = anEntIt++;
-      anUnusedEntities.erase(aRemoveIt);
-      continue;
+    // If the feature if circle or arc, we need to add normal of the sketch to the list of subs
+    if (theFeature->getKind() == SketchPlugin_Arc::ID() ||
+        theFeature->getKind() == SketchPlugin_Circle::ID()) {
+      EntityWrapperPtr aNormal = getNormal();
+      if (aNormal) aSubs.push_back(aNormal);
     }
-    ++anEntIt;
-  }
-
-  for (anEntIt = anUnusedEntities.begin(); anEntIt != anUnusedEntities.end(); ++anEntIt) {
-    int aPos = Search(*anEntIt, myEntities);
-    if (aPos >= 0 && aPos < (int)myEntities.size()) {
-      // Remove entity and its parameters
-      Slvs_Entity anEntity = myEntities[aPos];
-      myEntities.erase(myEntities.begin() + aPos);
-      myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
-      if (anEntity.distance != SLVS_E_UNKNOWN)
-        removeParameter(anEntity.distance);
-      for (int i = 0; i < 4; i++)
-        if (anEntity.param[i] != SLVS_E_UNKNOWN)
-          removeParameter(anEntity.param[i]);
-      for (int i = 0; i < 4; i++)
-        if (anEntity.point[i] != SLVS_E_UNKNOWN)
-          removeEntity(anEntity.point[i]);
-      myRemovedEntities.insert(*anEntIt);
-      if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D)
-        removeCoincidentPoint(*anEntIt);
-    }
-  }
-
-  if (!anUnusedEntities.empty())
-    myNeedToResolve = true;
-}
-
-bool SketchSolver_Storage::isUsedByConstraints(const Slvs_hEntity& theEntityID) const
-{
-  std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
-  for (; aCIt != myConstraints.end(); ++aCIt) {
-    Slvs_hEntity aSubs[6] = {
-        aCIt->entityA, aCIt->entityB,
-        aCIt->entityC, aCIt->entityD,
-        aCIt->ptA,     aCIt->ptB};
-    for (int i = 0; i < 6; i++)
-      if (aSubs[i] != SLVS_E_UNKNOWN && aSubs[i] == theEntityID)
-        return true;
-  }
-  return false;
-}
-
-const Slvs_Entity& SketchSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const
-{
-  int aPos = Search(theEntityID, myEntities);
-  if (aPos >= 0 && aPos < (int)myEntities.size())
-    return myEntities[aPos];
-
-  // Entity is not found, return empty object
-  static Slvs_Entity aDummy;
-  aDummy.h = SLVS_E_UNKNOWN;
-  return aDummy;
-}
-
-Slvs_hEntity SketchSolver_Storage::copyEntity(const Slvs_hEntity& theCopied)
-{
-  int aPos = Search(theCopied, myEntities);
-  if (aPos < 0 || aPos >= (int)myEntities.size())
-    return SLVS_E_UNKNOWN;
-
-  Slvs_Entity aCopy = myEntities[aPos];
-  aCopy.h = SLVS_E_UNKNOWN;
-  int i = 0;
-  while (aCopy.point[i] != SLVS_E_UNKNOWN) {
-    aCopy.point[i] = copyEntity(aCopy.point[i]);
-    i++;
-  }
-  if (aCopy.param[0] != SLVS_E_UNKNOWN) {
-    aPos = Search(aCopy.param[0], myParameters);
-    i = 0;
-    while (aCopy.param[i] != SLVS_E_UNKNOWN) {
-      Slvs_Param aNewParam = myParameters[aPos];
-      aNewParam.h = SLVS_E_UNKNOWN;
-      aCopy.param[i] = addParameter(aNewParam);
-      i++;
-      aPos++;
-    }
-  }
-  return addEntity(aCopy);
-}
-
-void SketchSolver_Storage::copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo)
-{
-  int aPosFrom = Search(theFrom, myEntities);
-  int aPosTo = Search(theTo, myEntities);
-  if (aPosFrom < 0 || aPosFrom >= (int)myEntities.size() || 
-      aPosTo < 0 || aPosTo >= (int)myEntities.size())
-    return;
-
-  Slvs_Entity aEntFrom = myEntities[aPosFrom];
-  Slvs_Entity aEntTo = myEntities[aPosTo];
-  int i = 0;
-  while (aEntFrom.point[i] != SLVS_E_UNKNOWN) {
-    copyEntity(aEntFrom.point[i], aEntTo.point[i]);
-    i++;
-  }
-  if (aEntFrom.param[0] != SLVS_E_UNKNOWN) {
-    aPosFrom = Search(aEntFrom.param[0], myParameters);
-    aPosTo = Search(aEntTo.param[0], myParameters);
-    i = 0;
-    while (aEntFrom.param[i] != SLVS_E_UNKNOWN) {
-      myParameters[aPosTo++].val = myParameters[aPosFrom++].val;
-      i++;
-    }
-  }
-}
-
-
-bool SketchSolver_Storage::isPointFixed(
-    const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate) const
-{
-  // Search the set of coincident points
-  std::set<Slvs_hEntity> aCoincident;
-  aCoincident.insert(thePointID);
-  std::vector< std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
-  for (; aCPIter != myCoincidentPoints.end(); aCPIter++)
-    if (aCPIter->find(thePointID) != aCPIter->end()) {
-      aCoincident = *aCPIter;
-      break;
-    }
-
-  // Check whether one of coincident points is out-of-group
-  std::set<Slvs_hEntity>::const_iterator aCoincIt = aCoincident.begin();
-  for (; aCoincIt != aCoincident.end(); ++aCoincIt) {
-    Slvs_Entity aPoint = getEntity(*aCoincIt);
-    if (aPoint.group == SLVS_G_OUTOFGROUP)
-      return true;
-  }
-
-  // Search the Rigid constraint
-  theFixed = SLVS_C_UNKNOWN;
-  std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-  for (; aConstrIter != myConstraints.end(); aConstrIter++)
-    if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
-        aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
-      theFixed = aConstrIter->h;
-      if (aConstrIter->ptA == thePointID)
-        return true;
-    }
-  if (theFixed != SLVS_C_UNKNOWN)
-    return true;
-
-  if (theAccurate) {
-    // Try to find the fixed entity which uses such point or its coincidence
-    std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
-    for (; anEntIter != myEntities.end(); anEntIter++) {
-      for (int i = 0; i < 4; i++) {
-        Slvs_hEntity aPt = anEntIter->point[i];
-        if (aPt != SLVS_E_UNKNOWN &&
-            (aPt == thePointID || aCoincident.find(aPt) != aCoincident.end())) {
-          if (isEntityFixed(anEntIter->h, true))
-            return true;
-        }
-      }
-    }
-  }
-  return SLVS_E_UNKNOWN;
-}
-
-bool SketchSolver_Storage::isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate) const
-{
-  int aPos = Search(theEntityID, myEntities);
-  if (aPos < 0 || aPos >= (int)myEntities.size())
-    return false;
-
-  // Firstly, find how many points are under Rigid constraint
-  int aNbFixed = 0;
-  for (int i = 0; i < 4; i++) {
-    Slvs_hEntity aPoint = myEntities[aPos].point[i];
-    if (aPoint == SLVS_E_UNKNOWN)
-      continue;
-
-    std::set<Slvs_hEntity> aCoincident;
-    aCoincident.insert(aPoint);
-    std::vector< std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
-    for (; aCPIter != myCoincidentPoints.end(); aCPIter++)
-      if (aCPIter->find(aPoint) != aCPIter->end()) {
-        aCoincident = *aCPIter;
-        break;
-      }
-
-    // Search the Rigid constraint
-    std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-    for (; aConstrIter != myConstraints.end(); aConstrIter++)
-      if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
-          aCoincident.find(aConstrIter->ptA) != aCoincident.end())
-        aNbFixed++;
-  }
-
-  std::list<Slvs_Constraint> aList;
-  std::list<Slvs_Constraint>::iterator anIt;
-  Slvs_hConstraint aTempID; // used in isPointFixed() method
-
-  if (myEntities[aPos].type == SLVS_E_LINE_SEGMENT) {
-    if (aNbFixed == 2)
-      return true;
-    else if (aNbFixed == 0 || !theAccurate)
-      return false;
-    // Additional check (the line may be fixed if it is used by different constraints):
-    // 1. The line is used in Equal constraint, another entity is fixed and there is a fixed point on line
-    aList = getConstraintsByType(SLVS_C_PT_ON_LINE);
-    for (anIt = aList.begin(); anIt != aList.end(); anIt++)
-      if (anIt->entityA == theEntityID && isPointFixed(anIt->ptA, aTempID))
-        break;
-    if (anIt != aList.end()) {
-      aList = getConstraintsByType(SLVS_C_EQUAL_LENGTH_LINES);
-      aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
-      for (anIt = aList.begin(); anIt != aList.end(); anIt++)
-        if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
-          Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
-          if (isEntityFixed(anOther, false))
-            return true;
-        }
-    }
-    // 2. The line is used in Parallel/Perpendicular/Vertical/Horizontal and Length constraints
-    aList = getConstraintsByType(SLVS_C_PARALLEL);
-    aList.splice(aList.end(), getConstraintsByType(SLVS_C_PERPENDICULAR));
-    aList.splice(aList.end(), getConstraintsByType(SLVS_C_VERTICAL));
-    aList.splice(aList.end(), getConstraintsByType(SLVS_C_HORIZONTAL));
-    for (anIt = aList.begin(); anIt != aList.end(); anIt++)
-      if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
-        Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
-        if (isEntityFixed(anOther, false))
-          break;
-      }
-    if (anIt != aList.end()) {
-      aList = getConstraintsByType(SLVS_C_PT_PT_DISTANCE);
-      for (anIt = aList.begin(); anIt != aList.end(); anIt++)
-        if ((anIt->ptA == myEntities[aPos].point[0] && anIt->ptB == myEntities[aPos].point[1]) ||
-            (anIt->ptA == myEntities[aPos].point[1] && anIt->ptB == myEntities[aPos].point[0]))
-          return true;
-    }
-    // 3. Another verifiers ...
-  } else if (myEntities[aPos].type == SLVS_E_CIRCLE) {
-    if (aNbFixed == 0)
+    // Secondly, convert feature
+    BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+    aRelated = aBuilder->createFeature(theFeature, aSubs, theGroup);
+    if (!aRelated)
       return false;
-    // Search for Diameter constraint
-    aList = getConstraintsByType(SLVS_C_DIAMETER);
-    for (anIt = aList.begin(); anIt != aList.end(); anIt++)
-      if (anIt->entityA == theEntityID)
-        return true;
-    if (!theAccurate)
-      return false;
-    // Additional check (the circle may be fixed if it is used by different constraints):
-    // 1. The circle is used in Equal constraint and another entity is fixed
-    aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
-    for (anIt = aList.begin(); anIt != aList.end(); anIt++)
-      if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
-        Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
-        if (isEntityFixed(anOther, false))
-          return true;
-      }
-    // 2. Another verifiers ...
-  } else if (myEntities[aPos].type == SLVS_E_ARC_OF_CIRCLE) {
-    if (aNbFixed > 2)
-      return true;
-    else if (aNbFixed <= 1)
-      return false;
-    // Search for Diameter constraint
-    aList = getConstraintsByType(SLVS_C_DIAMETER);
-    for (anIt = aList.begin(); anIt != aList.end(); anIt++)
-      if (anIt->entityA == theEntityID)
-        return true;
-    if (!theAccurate)
-      return false;
-    // Additional check (the arc may be fixed if it is used by different constraints):
-    // 1. The arc is used in Equal constraint and another entity is fixed
-    aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
-    aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
-    for (anIt = aList.begin(); anIt != aList.end(); anIt++)
-      if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
-        Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
-        if (isEntityFixed(anOther, false))
-          return true;
-      }
-    // 2. Another verifiers ...
-  }
-  return false;
-}
-
-
-Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
-{
-  if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
-    // Constraint is already used, rewrite it
-    return updateConstraint(theConstraint);
-  }
-
-  Slvs_Constraint aConstraint = theConstraint;
-
-  // Find a constraint with same type uses same arguments to show user overconstraint situation
-  std::vector<Slvs_Constraint>::iterator aCIt = myConstraints.begin();
-  for (; aCIt != myConstraints.end(); aCIt++) {
-    if (aConstraint.type != aCIt->type)
-      continue;
-    if (aConstraint.ptA == aCIt->ptA && aConstraint.ptB == aCIt->ptB &&
-        aConstraint.entityA == aCIt->entityA && aConstraint.entityB == aCIt->entityB &&
-        aConstraint.entityC == aCIt->entityC && aConstraint.entityD == aCIt->entityD)
-      myDuplicatedConstraint = true;
-  }
-
-  if (aConstraint.h > myConstrMaxID)
-    myConstrMaxID = aConstraint.h;
-  else
-    aConstraint.h = ++myConstrMaxID;
-  myConstraints.push_back(aConstraint);
-  myNeedToResolve = true;
-  if (aConstraint.type == SLVS_C_POINTS_COINCIDENT)
-    addCoincidentPoints(aConstraint.ptA, aConstraint.ptB);
-  return aConstraint.h;
+    addEntity(theFeature, aRelated);
+  } else if (theGroup != GID_UNKNOWN)
+    changeGroup(aRelated, theGroup);
+  return update(aRelated) || isUpdated;
 }
 
-Slvs_hConstraint SketchSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint)
+bool SketchSolver_Storage::update(AttributePtr theAttribute, const GroupID& theGroup)
 {
-  if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
-    // Constraint already used, rewrite it
-    int aPos = Search(theConstraint.h, myConstraints);
-    if (aPos >= 0 && aPos < (int)myConstraints.size()) {
-      myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint);
-      myConstraints[aPos] = theConstraint;
-      if (theConstraint.type == SLVS_C_POINTS_COINCIDENT)
-        addCoincidentPoints(theConstraint.ptA, theConstraint.ptB);
-      return theConstraint.h;
-    }
+  AttributePtr anAttribute = theAttribute;
+  AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
+  if (aRefAttr) {
+    if (aRefAttr->isObject()) {
+      FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+      return update(aFeature, theGroup);
+    } else
+      anAttribute = aRefAttr->attr();
   }
 
-  // Constraint is not found, add new one
-  Slvs_Constraint aConstraint = theConstraint;
-  aConstraint.h = 0;
-  return addConstraint(aConstraint);
+  EntityWrapperPtr aRelated = entity(anAttribute);
+  if (!aRelated) { // Attribute is not exist, create it
+    BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+    aRelated = aBuilder->createAttribute(anAttribute, theGroup);
+    if (!aRelated)
+      return false;
+    addEntity(anAttribute, aRelated);
+  } else if (theGroup != GID_UNKNOWN)
+    changeGroup(aRelated, theGroup);
+  return update(aRelated);
 }
 
-bool SketchSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID)
-{
-  bool aResult = true;
-  int aPos = Search(theConstraintID, myConstraints);
-  if (aPos >= 0 && aPos < (int)myConstraints.size()) {
-    Slvs_Constraint aConstraint = myConstraints[aPos];
-    myConstraints.erase(myConstraints.begin() + aPos);
-    myConstrMaxID = myConstraints.empty() ? SLVS_E_UNKNOWN : myConstraints.back().h;
-    myNeedToResolve = true;
-    myRemovedConstraints.insert(theConstraintID);
-    if (aConstraint.type == SLVS_C_POINTS_COINCIDENT)
-      removeCoincidence(aConstraint);
 
-    // Remove all entities
-    Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB,
-        aConstraint.entityA, aConstraint.entityB,
-        aConstraint.entityC, aConstraint.entityD};
-    for (int i = 0; i < 6; i++)
-      if (anEntities[i] != SLVS_E_UNKNOWN)
-        aResult = removeEntity(anEntities[i]) && aResult;
-    // remove temporary fixed point, if available
-    if (myFixed == theConstraintID)
-      myFixed = SLVS_E_UNKNOWN;
-    if (myDuplicatedConstraint) {
-      // Check the duplicated constraints are still available
-      myDuplicatedConstraint = false;
-      std::vector<Slvs_Constraint>::const_iterator anIt1 = myConstraints.begin();
-      std::vector<Slvs_Constraint>::const_iterator anIt2 = myConstraints.begin();
-      for (; anIt1 != myConstraints.end() && !myDuplicatedConstraint; anIt1++)
-        for (anIt2 = anIt1+1; anIt2 != myConstraints.end() && !myDuplicatedConstraint; anIt2++) {
-          if (anIt1->type != anIt2->type)
-            continue;
-          if (anIt1->ptA == anIt2->ptA && anIt1->ptB == anIt2->ptB &&
-              anIt1->entityA == anIt2->entityA && anIt1->entityB == anIt2->entityB &&
-              anIt1->entityC == anIt2->entityC && anIt1->entityD == anIt2->entityD)
-            myDuplicatedConstraint = true;
-        }
-    }
-  }
-  return aResult;
-}
 
-const Slvs_Constraint& SketchSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const
+const std::list<ConstraintWrapperPtr>& SketchSolver_Storage::constraint(
+    const ConstraintPtr& theConstraint) const
 {
-  int aPos = Search(theConstraintID, myConstraints);
-  if (aPos >= 0 && aPos < (int)myConstraints.size())
-    return myConstraints[aPos];
+  static std::list<ConstraintWrapperPtr> aDummy;
 
-  // Constraint is not found, return empty object
-  static Slvs_Constraint aDummy;
-  aDummy.h = 0;
+  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr>>::const_iterator
+      aFound = myConstraintMap.find(theConstraint);
+  if (aFound != myConstraintMap.end())
+    return aFound->second;
   return aDummy;
 }
 
-std::list<Slvs_Constraint> SketchSolver_Storage::getConstraintsByType(int theConstraintType) const
-{
-  std::list<Slvs_Constraint> aResult;
-  std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
-  for (; aCIter != myConstraints.end(); aCIter++)
-    if (aCIter->type == theConstraintType)
-      aResult.push_back(*aCIter);
-  return aResult;
-}
-
-
-void SketchSolver_Storage::addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID)
-{
-  if (myFixed != SLVS_E_UNKNOWN)
-    return; // the point is already fixed
-  int aPos = Search(theConstraintID, myConstraints);
-  if (aPos >= 0 && aPos < (int)myConstraints.size())
-    myFixed = theConstraintID;
-}
-
-void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
+const EntityWrapperPtr& SketchSolver_Storage::entity(const FeaturePtr& theFeature) const
 {
-  myTemporaryConstraints.insert(theConstraintID);
-}
+  static EntityWrapperPtr aDummy;
 
-void SketchSolver_Storage::removeTemporaryConstraints()
-{
-  myTemporaryConstraints.clear();
-}
-
-int SketchSolver_Storage::deleteTemporaryConstraint()
-{
-  if (myTemporaryConstraints.empty())
-    return 0;
-  // Search the point-on-line or a non-rigid constraint
-  std::set<Slvs_hConstraint>::iterator aCIt = myTemporaryConstraints.begin();
-  for (; aCIt != myTemporaryConstraints.end(); aCIt++) {
-    int aPos = Search(*aCIt, myConstraints);
-    if (aPos >= (int)myConstraints.size() || myConstraints[aPos].type != SLVS_C_WHERE_DRAGGED)
-      break;
-    std::vector<Slvs_Constraint>::iterator anIt = myConstraints.begin();
-    for (; anIt != myConstraints.end(); anIt++)
-      if (anIt->type == SLVS_C_PT_ON_LINE && anIt->ptA == myConstraints[aPos].ptA)
-        break;
-    if (anIt != myConstraints.end())
-      break;
-  }
-  if (aCIt == myTemporaryConstraints.end())
-    aCIt = myTemporaryConstraints.begin();
-  bool aNewFixed = (*aCIt == myFixed);
-  removeConstraint(*aCIt);
-  myTemporaryConstraints.erase(aCIt);
-  if (aNewFixed) {
-    for (aCIt = myTemporaryConstraints.begin(); aCIt != myTemporaryConstraints.end(); aCIt++) {
-      int aPos = Search(*aCIt, myConstraints);
-      if (myConstraints[aPos].type == SLVS_C_WHERE_DRAGGED) {
-        myFixed = *aCIt;
-        break;
-      }
-    }
-  }
-  return (int)myTemporaryConstraints.size();
-}
-
-bool SketchSolver_Storage::isTemporary(const Slvs_hConstraint& theConstraintID) const
-{
-  return myTemporaryConstraints.find(theConstraintID) != myTemporaryConstraints.end();
-}
-
-
-void SketchSolver_Storage::getRemoved(
-    std::set<Slvs_hParam>& theParameters,
-    std::set<Slvs_hEntity>& theEntities,
-    std::set<Slvs_hConstraint>& theConstraints)
-{
-  theParameters = myRemovedParameters;
-  theEntities = myRemovedEntities;
-  theConstraints = myRemovedConstraints;
-
-  myRemovedParameters.clear();
-  myRemovedEntities.clear();
-  myRemovedConstraints.clear();
+  std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFound = myFeatureMap.find(theFeature);
+  if (aFound != myFeatureMap.end())
+    return aFound->second;
+  return aDummy;
 }
 
-void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver)
+const EntityWrapperPtr& SketchSolver_Storage::entity(const AttributePtr& theAttribute) const
 {
-  theSolver.setParameters(myParameters.data(), (int)myParameters.size());
-  theSolver.setEntities(myEntities.data(), (int)myEntities.size());
+  static EntityWrapperPtr aDummy;
 
-  // Copy constraints excluding the fixed one
-  std::vector<Slvs_Constraint> aConstraints = myConstraints;
-  if (myFixed != SLVS_E_UNKNOWN) {
-    Slvs_hEntity aFixedPoint = SLVS_E_UNKNOWN;
-    std::vector<Slvs_Constraint>::iterator anIt = aConstraints.begin();
-    for (; anIt != aConstraints.end(); anIt++)
-      if (anIt->h == myFixed) {
-        aFixedPoint = anIt->ptA;
-        aConstraints.erase(anIt);
-        break;
-      }
-    // set dragged parameters
-    int aPos = Search(aFixedPoint, myEntities);
-    theSolver.setDraggedParameters(myEntities[aPos].param);
-  }
-  theSolver.setConstraints(aConstraints.data(), (int)aConstraints.size());
-}
+  std::map<AttributePtr, EntityWrapperPtr>::const_iterator
+      aFound = myAttributeMap.find(theAttribute);
+  if (aFound != myAttributeMap.end())
+    return aFound->second;
 
-void SketchSolver_Storage::addCoincidentPoints(
-    const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2)
-{
-  std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
-  std::vector< std::set<Slvs_hEntity> >::iterator aFoundIter = myCoincidentPoints.end(); // already found coincidence
-  bool isFound = false;
-  for (; aCIter != myCoincidentPoints.end(); aCIter++) {
-    bool isFirstFound = aCIter->find(thePoint1) != aCIter->end();
-    bool isSecondFound = aCIter->find(thePoint2) != aCIter->end();
-    isFound = isFound || isFirstFound || isSecondFound;
-    if (isFirstFound && isSecondFound)
-      break; // already coincident
-    else if (isFirstFound || isSecondFound) {
-      if (aFoundIter != myCoincidentPoints.end()) {
-        // merge two sets
-        aFoundIter->insert(aCIter->begin(), aCIter->end());
-        myCoincidentPoints.erase(aCIter);
-        break;
-      } else
-        aFoundIter = aCIter;
-      aCIter->insert(thePoint1);
-      aCIter->insert(thePoint2);
-    }
-  }
-  // coincident points not found
-  if (!isFound) {
-    std::set<Slvs_hEntity> aNewSet;
-    aNewSet.insert(thePoint1);
-    aNewSet.insert(thePoint2);
-    myCoincidentPoints.push_back(aNewSet);
+  AttributeRefAttrPtr aRefAttr =
+      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+  if (aRefAttr) {
+    if (aRefAttr->isObject()) {
+      FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+      return entity(aFeature);
+    } else
+      return entity(aRefAttr->attr());
   }
+  return aDummy;
 }
 
-void SketchSolver_Storage::removeCoincidentPoint(const Slvs_hEntity& thePoint)
-{
-  std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
-  for (; aCIter != myCoincidentPoints.end(); aCIter++)
-    if (aCIter->find(thePoint) != aCIter->end()) {
-      aCIter->erase(thePoint);
-      if (aCIter->size() <= 1)
-        myCoincidentPoints.erase(aCIter);
-      break;
-    }
-}
-
-void SketchSolver_Storage::removeCoincidence(const Slvs_Constraint& theCoincidence)
+bool SketchSolver_Storage::isInteract(const FeaturePtr& theFeature) const
 {
-  // Find set of coincident points
-  std::vector< std::set<Slvs_hEntity> >::iterator aCIt = myCoincidentPoints.begin();
-  for (; aCIt != myCoincidentPoints.end(); ++aCIt)
-    if (aCIt->find(theCoincidence.ptA) != aCIt->end() ||
-        aCIt->find(theCoincidence.ptB) != aCIt->end())
-      break;
-  if (aCIt == myCoincidentPoints.end())
-    return;
-
-  // Leave only the points which are still coincident
-  std::set<Slvs_hEntity> aRemainCoincidence;
-  std::vector<Slvs_Constraint>::const_iterator aConstrIt = myConstraints.begin();
-  for (; aConstrIt != myConstraints.end(); ++aConstrIt) {
-    if (aConstrIt->type != SLVS_C_POINTS_COINCIDENT)
-      continue;
-    if (aCIt->find(aConstrIt->ptA) != aCIt->end() ||
-        aCIt->find(aConstrIt->ptB) != aCIt->end()) {
-      aRemainCoincidence.insert(aConstrIt->ptA);
-      aRemainCoincidence.insert(aConstrIt->ptB);
-    }
-  }
-  if (aRemainCoincidence.size() <= 1)
-    myCoincidentPoints.erase(aCIt);
-  else
-    aCIt->swap(aRemainCoincidence);
-}
+  if (!theFeature)
+    return false;
+  if (myConstraintMap.empty())
+    return true; // empty storage interacts with each feature
 
-bool SketchSolver_Storage::isCoincident(
-    const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const
-{
-  std::vector< std::set<Slvs_hEntity> >::const_iterator aCIter = myCoincidentPoints.begin();
-  for (; aCIter != myCoincidentPoints.end(); aCIter++)
-    if (aCIter->find(thePoint1) != aCIter->end() && aCIter->find(thePoint2) != aCIter->end())
+  ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
+  if (aConstraint) {
+    if (myConstraintMap.find(aConstraint) != myConstraintMap.end())
       return true;
-  return false;
-}
-
-bool SketchSolver_Storage::isEqual(
-    const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const
-{
-  if (isCoincident(thePoint1, thePoint2))
+  } else if (myFeatureMap.find(theFeature) != myFeatureMap.end())
     return true;
 
-  // Precise checking of coincidence: verify that points have equal coordinates
-  int aEnt1Pos = Search(thePoint1, myEntities);
-  int aEnt2Pos = Search(thePoint2, myEntities);
-  if (aEnt1Pos >= 0 && aEnt1Pos < (int)myEntities.size() &&
-      aEnt2Pos >= 0 && aEnt2Pos < (int)myEntities.size()) {
-    double aDist[2];
-    int aParamPos;
-    for (int i = 0; i < 2; i++) {
-      aParamPos = Search(myEntities[aEnt1Pos].param[i], myParameters);
-      aDist[i] = myParameters[aParamPos].val;
-      aParamPos = Search(myEntities[aEnt2Pos].param[i], myParameters);
-      aDist[i] -= myParameters[aParamPos].val;
-    }
-    if (aDist[0] * aDist[0] + aDist[1] * aDist[1] < tolerance * tolerance)
+  std::list<AttributePtr> anAttrList = theFeature->data()->attributes(std::string());
+  std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
+  for (; anIt != anAttrList.end(); ++anIt)
+    if (isInteract(*anIt))
       return true;
-  }
+
   return false;
 }
 
-
-std::vector<Slvs_hConstraint> SketchSolver_Storage::fixEntity(const Slvs_hEntity& theEntity)
+bool SketchSolver_Storage::isInteract(const AttributePtr& theAttribute) const
 {
-  std::vector<Slvs_hConstraint> aNewConstraints;
+  if (!theAttribute)
+    return false;
 
-  int aPos = Search(theEntity, myEntities);
-  if (aPos >= 0 && aPos < (int)myEntities.size()) {
-    switch (myEntities[aPos].type) {
-    case SLVS_E_POINT_IN_2D:
-    case SLVS_E_POINT_IN_3D:
-      fixPoint(myEntities[aPos], aNewConstraints);
-      break;
-    case SLVS_E_LINE_SEGMENT:
-      fixLine(myEntities[aPos], aNewConstraints);
-      break;
-    case SLVS_E_CIRCLE:
-      fixCircle(myEntities[aPos], aNewConstraints);
-      break;
-    case SLVS_E_ARC_OF_CIRCLE:
-      fixArc(myEntities[aPos], aNewConstraints);
-      break;
-    default:
-      break;
-    }
-  }
+  AttributeRefAttrPtr aRefAttr =
+      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+  if (!aRefAttr)
+    return myAttributeMap.find(theAttribute) != myAttributeMap.end();
+  if (!aRefAttr->isObject())
+    return myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end();
 
-  return aNewConstraints;
+  FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+  return isInteract(aFeature);
 }
 
-void SketchSolver_Storage::fixPoint(const Slvs_Entity& thePoint,
-    std::vector<Slvs_hConstraint>& theCreated)
+bool SketchSolver_Storage::isConsistent() const
 {
-  Slvs_Constraint aConstraint;
-  Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN;
-  bool isFixed = isPointFixed(thePoint.h, aConstrID, true);
-  bool isForceUpdate = (isFixed && isTemporary(aConstrID));
-  if (!isForceUpdate) { // create new constraint
-    if (isFixed) return;
-    aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, thePoint.group, SLVS_C_WHERE_DRAGGED, thePoint.wrkpl,
-        0.0, thePoint.h, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-    aConstraint.h = addConstraint(aConstraint);
-    theCreated.push_back(aConstraint.h);
-  } else { // update already existent constraint
-    if (!isFixed || aConstrID == SLVS_E_UNKNOWN)
-      return;
-    int aPos = Search(aConstrID, myConstraints);
-    if (aPos >= 0 && aPos < (int)myConstraints.size())
-      myConstraints[aPos].ptA = thePoint.h;
-  }
+  // Check the constraints are valid
+  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+      aCIter = myConstraintMap.begin();
+  for (; aCIter != myConstraintMap.end(); ++aCIter)
+    if (!aCIter->first->data() || !aCIter->first->data()->isValid())
+      return false;
+  // Check the features are valid
+  std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
+  for (; aFIter != myFeatureMap.end(); aFIter++)
+    if (!aFIter->first->data() || !aFIter->first->data()->isValid())
+      return false;
+  return true;
+}
+
+void SketchSolver_Storage::removeInvalidEntities()
+{
+  // Remove invalid constraints
+  std::list<ConstraintPtr> anInvalidConstraints;
+  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+      aCIter = myConstraintMap.begin();
+  for (; aCIter != myConstraintMap.end(); ++aCIter)
+    if (!aCIter->first->data() || !aCIter->first->data()->isValid())
+      anInvalidConstraints.push_back(aCIter->first);
+  std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
+  for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
+    removeConstraint(*anInvCIt);
+  // Remove invalid features
+  std::list<FeaturePtr> anInvalidFeatures;
+  std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
+  for (; aFIter != myFeatureMap.end(); aFIter++)
+    if (!aFIter->first->data() || !aFIter->first->data()->isValid())
+      anInvalidFeatures.push_back(aFIter->first);
+  std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
+  for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
+    removeEntity(*anInvFIt);
+}
+
+EntityWrapperPtr SketchSolver_Storage::getNormal() const
+{
+  EntityWrapperPtr aSketch = sketch();
+  if (!aSketch)
+    return aSketch;
+
+  // Find normal entity
+  const std::list<EntityWrapperPtr>& aSketchSubs = aSketch->subEntities();
+  std::list<EntityWrapperPtr>::const_iterator aSIt = aSketchSubs.begin();
+  for (; aSIt != aSketchSubs.end(); ++aSIt)
+    if ((*aSIt)->type() == ENTITY_NORMAL)
+      return *aSIt;
+  return EntityWrapperPtr();
+}
+
+const EntityWrapperPtr& SketchSolver_Storage::sketch() const
+{
+  static EntityWrapperPtr aDummySketch;
+
+  std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
+  for (; aFIt != myFeatureMap.end(); ++aFIt)
+    if (aFIt->second->type() == ENTITY_SKETCH)
+      break;
+  if (aFIt == myFeatureMap.end())
+    return aDummySketch;
+  return aFIt->second;
 }
 
-void SketchSolver_Storage::fixLine(const Slvs_Entity& theLine,
-    std::vector<Slvs_hConstraint>& theCreated)
+void SketchSolver_Storage::setSketch(const EntityWrapperPtr& theSketch)
 {
-  Slvs_Entity aPoint[2] = {
-      getEntity(theLine.point[0]),
-      getEntity(theLine.point[1])
-  };
-
-  Slvs_Constraint anEqual;
-  if (isAxisParallel(theLine.h)) {
-    // Fix one point and a line length
-    Slvs_hConstraint aFixed;
-    if (!isPointFixed(theLine.point[0], aFixed, true) &&
-        !isPointFixed(theLine.point[1], aFixed, true))
-      fixPoint(aPoint[0], theCreated);
-    if (!isUsedInEqual(theLine.h, anEqual)) {
-      // Check the distance is not set yet
-      std::vector<Slvs_Constraint>::const_iterator aDistIt = myConstraints.begin();
-      for (; aDistIt != myConstraints.end(); ++aDistIt)
-        if ((aDistIt->type == SLVS_C_PT_PT_DISTANCE) &&
-           ((aDistIt->ptA == theLine.point[0] && aDistIt->ptB == theLine.point[1]) ||
-            (aDistIt->ptA == theLine.point[1] && aDistIt->ptB == theLine.point[0])))
-          return;
-      // Calculate distance between points on the line
-      double aCoords[4];
-      for (int i = 0; i < 2; i++)
-        for (int j = 0; j < 2; j++) {
-          Slvs_Param aParam = getParameter(aPoint[i].param[j]);
-          aCoords[2*i+j] = aParam.val;
-        }
-
-      double aLength = sqrt((aCoords[2] - aCoords[0]) * (aCoords[2] - aCoords[0]) + 
-                            (aCoords[3] - aCoords[1]) * (aCoords[3] - aCoords[1]));
-      // fix line length
-      Slvs_Constraint aDistance = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group,
-          SLVS_C_PT_PT_DISTANCE, theLine.wrkpl, aLength,
-          theLine.point[0], theLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-      aDistance.h = addConstraint(aDistance);
-      theCreated.push_back(aDistance.h);
-    }
+  if (sketch())
     return;
-  }
-  else if (isUsedInEqual(theLine.h, anEqual)) {
-    // Check another entity of Equal is already fixed
-    Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA;
-    if (isEntityFixed(anOtherEntID, true)) {
-      // Fix start point of the line (if end point is not fixed yet) ...
-      Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN;
-      bool isFixed = isPointFixed(theLine.point[1], anEndFixedID, true);
-      if (isFixed == SLVS_E_UNKNOWN)
-        fixPoint(aPoint[0], theCreated);
-      // ...  and create fixed point lying on this line
-      Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0];
-      // Firstly, search already fixed point on line
-      bool isPonLineFixed = false;
-      Slvs_hEntity aFixedPoint;
-      std::vector<Slvs_Constraint>::const_iterator aPLIter = myConstraints.begin();
-      for (; aPLIter != myConstraints.end() && !isPonLineFixed; ++aPLIter)
-        if (aPLIter->type == SLVS_C_PT_ON_LINE && aPLIter->entityA == theLine.h) {
-          isPonLineFixed = isPointFixed(aPLIter->ptA, anEndFixedID);
-          aFixedPoint = aPLIter->ptA;
-        }
-
-      if (isPonLineFixed) { // update existent constraint
-        copyEntity(aPointToCopy, aFixedPoint);
-      } else { // create new constraint
-        Slvs_hEntity aCopied = copyEntity(aPointToCopy);
-        Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group, SLVS_C_PT_ON_LINE,
-            theLine.wrkpl, 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN);
-        aPonLine.h = addConstraint(aPonLine);
-        theCreated.push_back(aPonLine.h);
-        fixPoint(getEntity(aCopied), theCreated);
-      }
-      return;
-    }
-  }
-
-  // Fix both points
-  for (int i = 0; i < 2; i++)
-    fixPoint(aPoint[i], theCreated);
+  addEntity(FeaturePtr(), theSketch);
 }
 
-void SketchSolver_Storage::fixCircle(const Slvs_Entity& theCircle,
-    std::vector<Slvs_hConstraint>& theCreated)
+void SketchSolver_Storage::blockEvents(bool isBlocked) const
 {
-  bool isFixRadius = true;
-  // Verify the arc is under Equal constraint
-  Slvs_Constraint anEqual;
-  if (isUsedInEqual(theCircle.h, anEqual)) {
-    // Check another entity of Equal is already fixed
-    Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA;
-    if (isEntityFixed(anOtherEntID, true))
-      isFixRadius = false;
-  }
+  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+      aCIter = myConstraintMap.begin();
+  for (; aCIter != myConstraintMap.end(); aCIter++)
+    if (aCIter->first->data() && aCIter->first->data()->isValid())
+      aCIter->first->data()->blockSendAttributeUpdated(isBlocked);
 
-  fixPoint(getEntity(theCircle.point[0]), theCreated);
+  std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
+  for (; aFIter != myFeatureMap.end(); aFIter++)
+    if (aFIter->first->data() && aFIter->first->data()->isValid())
+      aFIter->first->data()->blockSendAttributeUpdated(isBlocked);
 
-  if (isFixRadius) {
-    // Search the radius is already fixed
-    std::vector<Slvs_Constraint>::const_iterator aDiamIter = myConstraints.begin();
-    for (; aDiamIter != myConstraints.end(); ++aDiamIter)
-      if (aDiamIter->type == SLVS_C_DIAMETER && aDiamIter->entityA == theCircle.h)
-        return;
-
-    // Fix radius of a circle
-    const Slvs_Entity& aRadEnt = getEntity(theCircle.distance);
-    double aRadius = getParameter(aRadEnt.param[0]).val;
-    Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theCircle.group, SLVS_C_DIAMETER,
-        theCircle.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theCircle.h, SLVS_E_UNKNOWN);
-    aFixedR.h = addConstraint(aFixedR);
-    theCreated.push_back(aFixedR.h);
-  }
+  std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAtIter = myAttributeMap.begin();
+  for (; anAtIter != myAttributeMap.end(); anAtIter++)
+    if (anAtIter->first->owner() && anAtIter->first->owner()->data() &&
+        anAtIter->first->owner()->data()->isValid())
+      anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked);
 }
 
-void SketchSolver_Storage::fixArc(const Slvs_Entity& theArc,
-    std::vector<Slvs_hConstraint>& theCreated)
-{
-  Slvs_Entity aPoint[3] = {
-      getEntity(theArc.point[0]),
-      getEntity(theArc.point[1]),
-      getEntity(theArc.point[2])
-  };
-
-  bool isFixRadius = true;
-  std::list<Slvs_Entity> aPointsToFix;
-  aPointsToFix.push_back(aPoint[1]);
-  aPointsToFix.push_back(aPoint[2]);
-
-  // Verify the arc is under Equal constraint
-  Slvs_Constraint anEqual;
-  if (isUsedInEqual(theArc.h, anEqual)) {
-    // Check another entity of Equal is already fixed
-    Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA;
-    if (isEntityFixed(anOtherEntID, true)) {
-      isFixRadius = false;
-      Slvs_Entity anOtherEntity = getEntity(anOtherEntID);
-      if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) {
-        aPointsToFix.pop_back();
-        aPointsToFix.push_back(aPoint[0]);
-      }
-    }
-  }
-
-  Slvs_hConstraint aConstrID;
-  int aNbPointsToFix = 2; // number of fixed points for the arc
-  if (isPointFixed(theArc.point[0], aConstrID, true))
-    aNbPointsToFix--;
-
-  double anArcPoints[3][2];
-  for (int i = 0; i < 3; i++) {
-    const Slvs_Entity& aPointOnArc = getEntity(theArc.point[i]);
-    for (int j = 0; j < 2; j++)
-      anArcPoints[i][j] = getParameter(aPointOnArc.param[j]).val;
-  }
-
-  // Radius of the arc
-  std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(anArcPoints[0][0], anArcPoints[0][1]));
-  std::shared_ptr<GeomAPI_Pnt2d> aStart(new GeomAPI_Pnt2d(anArcPoints[1][0], anArcPoints[1][1]));
-  double aRadius = aCenter->distance(aStart);
 
-  // Update end point of the arc to be on a curve
-  std::shared_ptr<GeomAPI_Pnt2d> anEnd(new GeomAPI_Pnt2d(anArcPoints[2][0], anArcPoints[2][1]));
-  double aDistance = anEnd->distance(aCenter);
-  std::shared_ptr<GeomAPI_XY> aDir = anEnd->xy()->decreased(aCenter->xy());
-  if (aDistance < tolerance)
-    aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0);
-  else
-    aDir = aDir->multiplied(aRadius / aDistance);
-  double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()};
-  const Slvs_Entity& aEndPoint = getEntity(theArc.point[2]);
-  for (int i = 0; i < 2; i++) {
-    Slvs_Param aParam = getParameter(aEndPoint.param[i]);
-    aParam.val = xy[i];
-    updateParameter(aParam);
-  }
-
-  std::list<Slvs_Entity>::iterator aPtIt = aPointsToFix.begin();
-  for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--)
-    fixPoint(*aPtIt, theCreated);
-
-  if (isFixRadius) {
-    // Fix radius of the arc
-    bool isExists = false;
-    std::vector<Slvs_Constraint>::iterator anIt = myConstraints.begin();
-    for (; anIt != myConstraints.end() && !isExists; ++anIt)
-      if (anIt->type == SLVS_C_DIAMETER && anIt->entityA == theArc.h)
-        isExists = true;
-    if (!isExists) {
-      Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theArc.group, SLVS_C_DIAMETER,
-          theArc.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theArc.h, SLVS_E_UNKNOWN);
-      aFixedR.h = addConstraint(aFixedR);
-      theCreated.push_back(aFixedR.h);
-    }
-  }
-}
 
 
-bool SketchSolver_Storage::isAxisParallel(const Slvs_hEntity& theEntity) const
-{
-  std::vector<Slvs_Constraint>::const_iterator anIter = myConstraints.begin();
-  for (; anIter != myConstraints.end(); anIter++)
-    if ((anIter->type == SLVS_C_HORIZONTAL || anIter->type == SLVS_C_VERTICAL) && 
-        anIter->entityA == theEntity)
-      return true;
-  return false;
-}
 
-bool SketchSolver_Storage::isUsedInEqual(
-    const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const
-{
-  // Check the entity is used in Equal constraint
-  std::vector<Slvs_Constraint>::const_iterator anEqIter = myConstraints.begin();
-  for (; anEqIter != myConstraints.end(); anEqIter++)
-    if ((anEqIter->type == SLVS_C_EQUAL_LENGTH_LINES ||
-         anEqIter->type == SLVS_C_EQUAL_LINE_ARC_LEN ||
-         anEqIter->type == SLVS_C_EQUAL_RADIUS) &&
-       (anEqIter->entityA == theEntity || anEqIter->entityB == theEntity)) {
-      theEqual = *anEqIter;
-      return true;
-    }
-  return false;
-}
 
-bool SketchSolver_Storage::isNeedToResolve()
+// ==============   Auxiliary functions   ====================================
+bool isEqual(const std::list<ConstraintWrapperPtr>& theCVec1,
+             const std::list<ConstraintWrapperPtr>& theCVec2)
 {
-  if (myConstraints.empty())
+  if (theCVec1.size() != theCVec2.size())
     return false;
 
-  if (!myNeedToResolve) {
-    // Verify the updated parameters are used in constraints
-    std::set<Slvs_hEntity> aPoints;
-    std::vector<Slvs_Entity>::const_iterator anEntIt = myEntities.begin();
-    for (; anEntIt != myEntities.end(); ++anEntIt) {
-      for (int i = 0; i < 4 && anEntIt->param[i] != SLVS_E_UNKNOWN; ++i)
-        if (myUpdatedParameters.find(anEntIt->param[i]) != myUpdatedParameters.end()) {
-          aPoints.insert(anEntIt->h);
-          break;
-        }
-    }
-    std::set<Slvs_hEntity> anEntities = aPoints;
-    for (anEntIt = myEntities.begin(); anEntIt != myEntities.end(); ++anEntIt) {
-      for (int i = 0; i < 4 && anEntIt->point[i] != SLVS_E_UNKNOWN; ++i)
-        if (aPoints.find(anEntIt->point[i]) != aPoints.end()) {
-          anEntities.insert(anEntIt->h);
-          break;
-        }
-    }
-
-    std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
-    for (; aCIt != myConstraints.end() && !myNeedToResolve; ++aCIt) {
-      Slvs_hEntity anAttrs[6] =
-        {aCIt->ptA, aCIt->ptB, aCIt->entityA, aCIt->entityB, aCIt->entityC, aCIt->entityD};
-      for (int i = 0; i < 6; i++)
-        if (anAttrs[i] != SLVS_E_UNKNOWN && anEntities.find(anAttrs[i]) != anEntities.end()) {
-          myNeedToResolve = true;
-          break;
-        }
-    }
+  std::list<bool> aChecked(theCVec2.size(), false);
+  std::list<ConstraintWrapperPtr>::const_iterator anIt1 = theCVec1.begin();
+  for (; anIt1 != theCVec1.end(); ++anIt1) {
+    std::list<ConstraintWrapperPtr>::const_iterator anIt2 = theCVec2.begin();
+    std::list<bool>::iterator aCheckIt = aChecked.begin();
+    while (aCheckIt != aChecked.end() && *aCheckIt) {
+      ++aCheckIt;
+      ++anIt2;
+    }
+    for (; anIt2 != theCVec2.end(); ++anIt2, ++aCheckIt)
+      if (!(*aCheckIt) && (*anIt1)->isEqual(*anIt2)) {
+        *aCheckIt = true;
+        break;
+      }
+    // the same constraint is not found
+    if (anIt2 == theCVec2.end())
+      return false;
   }
-
-  myUpdatedParameters.clear();
-  return myNeedToResolve;
-}
-
-
-
-
-
-
-// ========================================================
-// =========      Auxiliary functions       ===============
-// ========================================================
-
-template<typename T>
-int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
-{
-  int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
-  int aVecSize = theEntities.size();
-  if (theEntities.empty())
-    return 1;
-  while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
-    aResIndex--;
-  while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
-    aResIndex++;
-  if (aResIndex == -1 || (aResIndex < aVecSize && theEntities[aResIndex].h != theEntityID))
-    aResIndex = aVecSize;
-  return aResIndex;
-}
-
-bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2)
-{
-  return fabs(theParam1.val - theParam2.val) > tolerance;
-}
-
-bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2)
-{
-  int i = 0;
-  for (; theEntity1.param[i] != 0 && i < 4; i++)
-    if (theEntity1.param[i] != theEntity2.param[i])
-      return true;
-  i = 0;
-  for (; theEntity1.point[i] != 0 && i < 4; i++)
-    if (theEntity1.point[i] != theEntity2.point[i])
-      return true;
-  return false;
-}
-
-bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2)
-{
-  return theConstraint1.ptA != theConstraint2.ptA ||
-         theConstraint1.ptB != theConstraint2.ptB ||
-         theConstraint1.entityA != theConstraint2.entityA ||
-         theConstraint1.entityB != theConstraint2.entityB ||
-         theConstraint1.entityC != theConstraint2.entityC ||
-         theConstraint1.entityD != theConstraint2.entityD ||
-         fabs(theConstraint1.valA - theConstraint2.valA) > tolerance;
+  return true;
 }
index bb270d77d191a1083c0b9d53e6f03898a4b09ee9..3369fc7ae725ab5781b77ec3bdc980afa8a9c204 100644 (file)
 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
 
 // File:    SketchSolver_Storage.h
-// Created: 18 Mar 2015
+// Created: 30 Nov 2015
 // Author:  Artem ZHIDKOV
 
 #ifndef SketchSolver_Storage_H_
 #define SketchSolver_Storage_H_
 
-#include "SketchSolver.h"
-#include <SketchSolver_Solver.h>
+#include <SketchSolver.h>
+#include <SketchSolver_IConstraintWrapper.h>
+#include <SketchSolver_IEntityWrapper.h>
+#include <SketchSolver_IParameterWrapper.h>
+#include <SketchSolver_ISolver.h>
 
-#include <list>
-#include <memory>
-#include <set>
-#include <vector>
+#include <ModelAPI_Attribute.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_Feature.h>
+#include <SketchPlugin_Constraint.h>
 
 /** \class   SketchSolver_Storage
  *  \ingroup Plugins
- *  \brief   Contains all necessary data in SolveSpace format to solve a single group of constraints
+ *  \brief   Interface to map SketchPlugin features to the entities of corresponding solver.
  */
 class SketchSolver_Storage
 {
-public:
+private:
   SketchSolver_Storage();
+  SketchSolver_Storage(const SketchSolver_Storage&);
+  SketchSolver_Storage& operator=(const SketchSolver_Storage&);
 
-  /** \brief Add new parameter to the current group
-   *  \param[in] theParam  SolveSpace parameter
-   *  \return the ID of added parameter
-   */
-  Slvs_hParam addParameter(const Slvs_Param& theParam);
-  /** \brief Updates parameter in the current group. If the ID of parameter is zero, the new item will be added
-   *  \param[in] theParam  SolveSpace parameter
-   *  \return the ID of updated/added parameter
-   */
-  Slvs_hParam updateParameter(const Slvs_Param& theParam);
-  /** \brief Removes the parameter by its ID
-   *  \param[in] theParamID  index of parameter to be removed
-   *  \return \c true if the parameter was successfully removed
-   */
-  bool removeParameter(const Slvs_hParam& theParamID);
-  /// \brief Returns the parameter by its ID
-  const Slvs_Param& getParameter(const Slvs_hParam& theParamID) const;
-
-  /** \brief Add new entity to the current group
-   *  \param[in] theEntity  SolveSpace entity
-   *  \return the ID of added entity
-   */
-  Slvs_hEntity addEntity(const Slvs_Entity& theEntity);
-  /** \brief Updates entity in the current group. If the ID of entity is zero, the new item will be added
-   *  \param[in] theEntity  SolveSpace entity
-   *  \return the ID of updated/added entity
-   */
-  Slvs_hEntity updateEntity(const Slvs_Entity& theEntity);
-  /** \brief Removes the entity by its ID. All parameters used in this entity,
-   *         and not used in other constraints, will be removed too.
-   *  \param[in] theEntityID  index of entity to be removed
-   *  \return \c true if the entity was successfully removed
-   */
-  bool removeEntity(const Slvs_hEntity& theEntityID);
-  /** \brief 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 Returns maximal ID of entities in this storage
-  const Slvs_hEntity& entityMaxID() const
-  { return myEntityMaxID; }
-
-  /// \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 Returns quantity of constraints in this storage
-  size_t nbConstraints() const
-  { return myConstraints.size(); }
-
-  /// \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(); }
+public:
+  SketchSolver_Storage(const GroupID& theGroup)
+    : myGroupID(theGroup),
+      myNeedToResolve(false)
+  {}
+
+  /// \brief Change mapping between constraint from SketchPlugin and
+  ///        a constraint applicable for corresponding solver.
+  /// \param theConstraint       [in]   original SketchPlugin constraint
+  /// \param theSolverConstraint [in]   solver's constraints
+  SKETCHSOLVER_EXPORT void addConstraint(ConstraintPtr        theConstraint,
+                                         ConstraintWrapperPtr theSolverConstraints);
+  /// \brief Change mapping between constraint from SketchPlugin and
+  ///        the list of constraints applicable for corresponding solver.
+  /// \param theConstraint        [in]   original SketchPlugin constraint
+  /// \param theSolverConstraints [in]   list of solver's constraints
+  SKETCHSOLVER_EXPORT
+    void addConstraint(ConstraintPtr                   theConstraint,
+                       std::list<ConstraintWrapperPtr> theSolverConstraints);
+
+  /// \brief Convert feature to the form applicable for specific solver and map it
+  /// \param theFeature [in]  feature to convert
+  /// \param theGroup   [in]  id of the group where the feature should be placed
+  /// \return \c true if the feature has been created or updated
+  SKETCHSOLVER_EXPORT bool update(FeaturePtr theFeature, const GroupID& theGroup = GID_UNKNOWN);
+  /// \brief Convert attribute to the form applicable for specific solver and map it
+  /// \param theFeature [in]  feature to convert
+  /// \return \c true if the attribute has been created or updated
+  SKETCHSOLVER_EXPORT bool update(AttributePtr theAttribute, const GroupID& theGroup = GID_UNKNOWN);
+
+  /// \brief Returns constraint related to corresponding constraint
+  SKETCHSOLVER_EXPORT
+    const std::list<ConstraintWrapperPtr>& constraint(const ConstraintPtr& theConstraint) const;
+
+  /// \brief Returns entity related to corresponding feature
+  SKETCHSOLVER_EXPORT const EntityWrapperPtr& entity(const FeaturePtr& theFeature) const;
+  /// \brief Returns entity related to corresponding attribute
+  SKETCHSOLVER_EXPORT const EntityWrapperPtr& entity(const AttributePtr& theAttribute) const;
+
+  /// \brief Return parsed sketch entity
+  const EntityWrapperPtr& sketch() const;
+  /// \brief Set parsed sketch entity.
+  /// Be careful, this method does not update fields of the storage specific for the solver.
+  /// Does not update if the sketch already exists.
+  void setSketch(const EntityWrapperPtr& theSketch);
+
+  /// \brief Mark two points as coincident
+  virtual void addCoincidentPoints(EntityWrapperPtr theMaster, EntityWrapperPtr theSlave) = 0;
+
+  /// \brief Shows the storage has any constraint twice
+  virtual bool hasDuplicatedConstraint() const = 0;
+
+  /// \brief Removes constraint from the storage
+  /// \return \c true if the constraint and all its parameters are removed successfully
+  virtual bool removeConstraint(ConstraintPtr theConstraint) = 0;
+  /// \brief Removes feature from the storage
+  /// \return \c true if the feature and its attributes are removed successfully;
+  ///         \c false if the feature or any it attribute is used by remaining constraints.
+  virtual bool removeEntity(FeaturePtr theFeature) = 0;
+  /// \brief Removes attribute from the storage
+  /// \return \c true if the attribute is not used by remaining features and constraints
+  virtual bool removeEntity(AttributePtr theAttribute) = 0;
+
+  /// \brief Remove all features became invalid
+  SKETCHSOLVER_EXPORT void removeInvalidEntities();
+
+  /// \brief Mark specified constraint as temporary
+  virtual void setTemporary(ConstraintPtr theConstraint) = 0;
+  /// \brief Returns number of temporary constraints
+  virtual size_t nbTemporary() const = 0;
+  /// \brief Remove temporary constraints
+  /// \param theNbConstraints [in]  number of temporary constraints to be deleted
+  /// \return number of remaining temporary constraints
+  virtual size_t removeTemporary(size_t theNbConstraints = 1) = 0;
+
+  /// \brief Check whether the feature or its attributes are used by this storage
+  /// \param theFeature [in]  feature to be checked
+  /// \return \c true if the feature interacts with the storage
+  bool isInteract(const FeaturePtr& theFeature) const;
+  /// \brief Check whether the attribute is used by this storage
+  /// \param theAttribute [in]  attribute to be checked
+  /// \return \c true if the attribute interacts with the storage
+  bool isInteract(const AttributePtr& theAttribute) const;
+
+  /// \brief Check the features is not removed
+  bool isConsistent() const;
 
   /// \brief Shows the sketch should be resolved
-  bool isNeedToResolve();
-
-  /// \brief Shows the storage has the same constraint twice
-  bool hasDuplicatedConstraint() const
-  { return myDuplicatedConstraint; }
-
+  virtual bool isNeedToResolve()
+  { return myNeedToResolve; }
   /// \brief Changes the flag of group to be resolved
   void setNeedToResolve(bool theFlag)
   { myNeedToResolve = theFlag; }
 
-  /// \brief Returns lists of removed elements
-  void getRemoved(std::set<Slvs_hParam>& theParameters,
-                  std::set<Slvs_hEntity>& theEntities,
-                  std::set<Slvs_hConstraint>& theConstraints);
-
-  /// \brief Initialize constraint solver by the entities collected by current storage
-  void initializeSolver(SketchSolver_Solver& theSolver);
-
-private:
-  /// \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);
+  /// \brief Initialize solver by constraints, entities and parameters
+  virtual void initializeSolver(SolverPtr theSolver) = 0;
+
+  /// \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 = 0;
+
+  /// \brief Check if some parameters or entities are returned
+  ///        to the current group after removing temporary constraints
+  virtual void verifyFixed() = 0;
+
+  /// \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) = 0;
+
+protected:
+  /// \brief Change mapping feature from SketchPlugin and
+  ///        the entity applicable for corresponding solver.
+  /// \param theFeature      [in]  original SketchPlugin feature
+  /// \param theSolverEntity [in]  solver's entity, created outside
+  SKETCHSOLVER_EXPORT
+    void addEntity(FeaturePtr       theFeature,
+                   EntityWrapperPtr theSolverEntity);
+
+  /// \brief Change mapping attribute of a feature and the entity applicable for corresponding solver.
+  /// \param theAttribute    [in]  original attribute
+  /// \param theSolverEntity [in]  solver's entity, created outside
+  SKETCHSOLVER_EXPORT
+    void addEntity(AttributePtr     theAttribute,
+                   EntityWrapperPtr theSolverEntity);
+
+  /// \brief Update constraint's data
+  /// \return \c true if any value is updated
+  virtual bool update(ConstraintWrapperPtr& theConstraint) = 0;
+  /// \brief Update entity's data
+  /// \return \c true if any value is updated
+  virtual bool update(EntityWrapperPtr& theEntity) = 0;
+  /// \brief Update parameter's data
+  /// \return \c true if the value of parameter is updated
+  virtual bool update(ParameterWrapperPtr& theParameter) = 0;
+
+  /// \brief Remove constraint
+  /// \return \c true if the constraint and all its parameters are removed successfully
+  virtual bool remove(ConstraintWrapperPtr theConstraint) = 0;
+  /// \brief Remove entity
+  /// \return \c true if the entity and all its parameters are removed successfully
+  virtual bool remove(EntityWrapperPtr theEntity) = 0;
+  /// \brief Remove parameter
+  /// \return \c true if the parameter has been removed
+  virtual bool remove(ParameterWrapperPtr theParameter) = 0;
+
+  /// \brief Update the group for the given entity, its sub-entities and parameters
+  virtual void changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup) = 0;
+  /// \brief Update the group for the given parameter
+  virtual void changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup) = 0;
+
+  /// \brief Block or unblock events when refreshing features
+  SKETCHSOLVER_EXPORT void blockEvents(bool isBlocked) const;
 
 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);
+  /// \brief Find the normal of the sketch
+  EntityWrapperPtr getNormal() const;
 
-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)
+protected:
+  GroupID myGroupID; ///< identifier of the group, this storage belongs to
 
-  std::vector< std::set<Slvs_hEntity> > myCoincidentPoints; ///< lists of coincident points
-  Slvs_hConstraint myFixed; ///< identifier of one of temporary constraints to fix separate point
+  /// map SketchPlugin constraint to a list of solver's constraints
+  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> > myConstraintMap;
+  /// map SketchPlugin feature to solver's entity
+  std::map<FeaturePtr, EntityWrapperPtr>                    myFeatureMap;
+  /// map attribute to solver's entity
+  std::map<AttributePtr, EntityWrapperPtr>                  myAttributeMap;
 
   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)
 };
 
 typedef std::shared_ptr<SketchSolver_Storage> StoragePtr;
diff --git a/src/SketchSolver/SolveSpaceSolver/CMakeLists.txt b/src/SketchSolver/SolveSpaceSolver/CMakeLists.txt
new file mode 100644 (file)
index 0000000..cda6e3b
--- /dev/null
@@ -0,0 +1,42 @@
+## Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+FIND_PACKAGE(SolveSpace REQUIRED)
+
+SET(PROJECT_HEADERS
+    SolveSpaceSolver_Solver.h
+    SolveSpaceSolver_Builder.h
+    SolveSpaceSolver_Storage.h
+    SolveSpaceSolver_EntityWrapper.h
+    SolveSpaceSolver_ParameterWrapper.h
+    SolveSpaceSolver_ConstraintWrapper.h
+    SolveSpaceSolver_ConstraintType.h
+)
+
+SET(PROJECT_SOURCES
+    SolveSpaceSolver_Solver.cpp
+    SolveSpaceSolver_Builder.cpp
+    SolveSpaceSolver_Storage.cpp
+    SolveSpaceSolver_EntityWrapper.cpp
+    SolveSpaceSolver_ParameterWrapper.cpp
+    SolveSpaceSolver_ConstraintWrapper.cpp
+)
+
+SET(PROJECT_LIBRARIES
+    ${SOLVESPACE_LIBRARIES}
+    SketchSolver
+    ModelAPI
+    GeomAPI
+)
+
+INCLUDE_DIRECTORIES(
+    ${SOLVESPACE_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(SolveSpaceSolver MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS})
+TARGET_LINK_LIBRARIES(SolveSpaceSolver ${PROJECT_LIBRARIES})
+INSTALL(TARGETS SolveSpaceSolver DESTINATION plugins)
diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.cpp
new file mode 100644 (file)
index 0000000..eabf9f6
--- /dev/null
@@ -0,0 +1,845 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SolveSpaceSolver_Builder.cpp
+// Created: 25 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#include <SolveSpaceSolver_Builder.h>
+#include <SolveSpaceSolver_Solver.h>
+#include <SolveSpaceSolver_Storage.h>
+#include <SolveSpaceSolver_ParameterWrapper.h>
+#include <SolveSpaceSolver_EntityWrapper.h>
+#include <SolveSpaceSolver_ConstraintWrapper.h>
+#include <SolveSpaceSolver_ConstraintType.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 <math.h>
+
+
+static EntityWrapperPtr createLine(FeaturePtr theFeature,
+                                   const std::list<EntityWrapperPtr>& theAttributes,
+                                   const GroupID& theGroupID,
+                                   const EntityID& theSketchID);
+static EntityWrapperPtr createCircle(FeaturePtr theFeature,
+                                     const std::list<EntityWrapperPtr>& theAttributes,
+                                     const GroupID& theGroupID,
+                                     const EntityID& theSketchID);
+static EntityWrapperPtr createArc(FeaturePtr theFeature,
+                                  const std::list<EntityWrapperPtr>& theAttributes,
+                                  const GroupID& theGroupID,
+                                  const EntityID& theSketchID);
+
+/// \brief Set flags of constraint to identify which points are coincident in the Tangency
+///        (for more information, see SolveSpace documentation)
+static void adjustTangency(ConstraintWrapperPtr theConstraint);
+/// \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 SolveSpaceSolver_Builder::mySelf = SolveSpaceSolver_Builder::getInstance();
+
+BuilderPtr SolveSpaceSolver_Builder::getInstance()
+{
+  if (!mySelf) {
+    mySelf = BuilderPtr(new SolveSpaceSolver_Builder);
+    SketchSolver_Manager::instance()->setBuilder(mySelf);
+  }
+  return mySelf;
+}
+
+StoragePtr SolveSpaceSolver_Builder::createStorage(const GroupID& theGroup) const
+{
+  return StoragePtr(new SolveSpaceSolver_Storage(theGroup));
+}
+
+SolverPtr SolveSpaceSolver_Builder::createSolver() const
+{
+  return SolverPtr(new SolveSpaceSolver_Solver);
+}
+
+
+std::list<ConstraintWrapperPtr> SolveSpaceSolver_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
+{
+  if (theType == CONSTRAINT_SYMMETRIC)
+    return createMirror(theConstraint, theGroupID, theSketchID,
+                        thePoint1, thePoint2, theEntity1);
+
+  int aType = ConstraintType::toSolveSpace(theType);
+  if (aType == SLVS_C_UNKNOWN)
+    return std::list<ConstraintWrapperPtr>();
+
+  Slvs_hEntity aSlvsEntities[4] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
+  EntityWrapperPtr anOriginal[4] = {thePoint1, thePoint2, theEntity1, theEntity2};
+  std::list<EntityWrapperPtr> aConstrAttrList; // to be filled
+  for (int i = 0; i < 4; ++i) {
+    if (!anOriginal[i])
+      continue;
+    aSlvsEntities[i] = (Slvs_hEntity)anOriginal[i]->id();
+    if (aSlvsEntities[i] == SLVS_E_UNKNOWN)
+      return std::list<ConstraintWrapperPtr>(); // entity is not added into a storage, constraint can not be created
+    aConstrAttrList.push_back(anOriginal[i]);
+  }
+
+  Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+      SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
+      theValue, aSlvsEntities[0], aSlvsEntities[1], aSlvsEntities[2], aSlvsEntities[3]);
+  ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
+  aResult->setValue(theValue);
+  aResult->setEntities(aConstrAttrList);
+  adjustConstraint(aResult);
+
+  return std::list<ConstraintWrapperPtr>(1, aResult);
+}
+
+std::list<ConstraintWrapperPtr> SolveSpaceSolver_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
+{
+  if (theType != CONSTRAINT_MULTI_ROTATION && theType != CONSTRAINT_MULTI_TRANSLATION)
+    return std::list<ConstraintWrapperPtr>();
+
+  int aType = ConstraintType::toSolveSpace(theType);
+  if (aType == SLVS_C_UNKNOWN)
+    return std::list<ConstraintWrapperPtr>();
+
+  Slvs_Constraint aConstraint =
+      Slvs_MakeConstraint(SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
+      theValue, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+
+  std::list<EntityWrapperPtr> aConstrAttrList = theTrsfEnt;
+  if (thePoint2)
+    aConstrAttrList.push_front(thePoint2);
+  aConstrAttrList.push_front(thePoint1);
+
+  ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
+  aResult->setValue(theValue);
+  aResult->setEntities(aConstrAttrList);
+  return std::list<ConstraintWrapperPtr>(1, aResult);
+}
+
+
+std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    const EntityID& theSketchID,
+    const EntityWrapperPtr& theEntity1,
+    const EntityWrapperPtr& theEntity2,
+    const EntityWrapperPtr& theMirrorLine) const
+{
+  Slvs_Constraint aConstraint;
+  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);
+
+    aConstraint = Slvs_MakeConstraint(
+        SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, SLVS_C_SYMMETRIC_LINE, (Slvs_hEntity)theSketchID,
+        0.0, (Slvs_hEntity)theEntity1->id(), (Slvs_hEntity)theEntity2->id(),
+        (Slvs_hEntity)theMirrorLine->id(), SLVS_E_UNKNOWN);
+
+    aConstrAttrList.push_back(theEntity1);
+    aConstrAttrList.push_back(theEntity2);
+    aConstrAttrList.push_back(theMirrorLine);
+
+    ConstraintWrapperPtr aWrapper(new SolveSpaceSolver_ConstraintWrapper(
+        theConstraint, aConstraint));
+    aWrapper->setEntities(aConstrAttrList);
+    aResult.push_back(aWrapper);
+  }
+  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);
+
+    std::list<ConstraintWrapperPtr> aMrrList;
+    std::list<EntityWrapperPtr>::const_iterator anIt1 = theEntity1->subEntities().begin();
+    std::list<EntityWrapperPtr>::const_iterator anIt2 = theEntity2->subEntities().begin();
+    if ((*anIt2)->group() == theGroupID) // mirrored point is not fixed
+      makeMirrorPoints(theEntity1->subEntities().front(),
+          theEntity2->subEntities().front(), theMirrorLine);
+
+    // Workaround to avoid problems in SolveSpace.
+    // The symmetry of two arcs will be done using symmetry of three points on these arcs:
+    // start point, end point, and any other point on the arc
+    std::list<EntityWrapperPtr> aBaseArcPoints(++anIt1, theEntity1->subEntities().end());
+    std::list<EntityWrapperPtr> aMirrorArcPoints(++anIt2, theEntity2->subEntities().end());
+    // indices of points of arc, center corresponds center, first point corresponds last point
+    aMirrorArcPoints.reverse();
+
+    anIt1 = aBaseArcPoints.begin();
+    anIt2 = aMirrorArcPoints.begin();
+    for (; anIt1 != aBaseArcPoints.end(); ++anIt1, ++anIt2) {
+      aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
+      aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
+    }
+    // Restore event sending
+    aMirrArc->data()->blockSendAttributeUpdated(false);
+  }
+  return aResult;
+}
+
+void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const
+{
+  SketchSolver_ConstraintType aType = theConstraint->type();
+  // Update flags in constraints
+  if (aType == CONSTRAINT_TANGENT_ARC_ARC || aType == CONSTRAINT_TANGENT_ARC_LINE)
+    adjustTangency(theConstraint);
+  else 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 SolveSpaceSolver_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, theSketchID);
+  // Circle
+  else if (aFeatureKind == SketchPlugin_Circle::ID())
+    return createCircle(theFeature, theAttributes,theGroupID, theSketchID);
+  // Arc
+  else if (aFeatureKind == SketchPlugin_Arc::ID())
+    return createArc(theFeature, theAttributes,theGroupID, theSketchID);
+  // 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, theSketchID);
+    if (!aSub)
+      return aDummy;
+
+    const Slvs_Entity& aSubEnt =
+        std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(aSub)->entity();
+    EntityWrapperPtr aNewEntity(new SolveSpaceSolver_EntityWrapper(theFeature, aSubEnt));
+    aNewEntity->setSubEntities(std::list<EntityWrapperPtr>(1, aSub));
+    return aNewEntity;
+  }
+
+  // wrong entity
+  return aDummy;
+}
+
+EntityWrapperPtr SolveSpaceSolver_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;
+  Slvs_Entity anEntity;
+  anEntity.type = 0;
+
+  // Point in 3D
+  std::shared_ptr<GeomDataAPI_Point> aPoint =
+      std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
+  if (aPoint) {
+    aParameters.push_back(createParameter(theGroupID, aPoint->x(), !aPoint->textX().empty()));
+    aParameters.push_back(createParameter(theGroupID, aPoint->y(), !aPoint->textY().empty()));
+    aParameters.push_back(createParameter(theGroupID, aPoint->z(), !aPoint->textZ().empty()));
+    // Create entity (parameters are not filled)
+    anEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+        SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+  } else {
+    // 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()));
+      // Create entity (parameters are not filled)
+      anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+          (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+    } else {
+      // Scalar value (used for the distance entities)
+      AttributeDoublePtr aScalar =
+          std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+      if (aScalar) {
+        aParameters.push_back(createParameter(theGroupID, aScalar->value(), !aScalar->text().empty()));
+        // Create entity (parameter is not filled)
+        anEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+          (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN);
+      }
+    }
+  }
+
+  if (anEntity.type == 0) {
+    // unknown attribute type
+    return EntityWrapperPtr();
+  }
+
+  EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theAttribute, anEntity));
+  aResult->setParameters(aParameters);
+  return aResult;
+}
+
+
+
+EntityWrapperPtr SolveSpaceSolver_Builder::createSketchEntity(
+    CompositeFeaturePtr theSketch,
+    const GroupID& theGroupID) const
+{
+  DataPtr aSketchData = theSketch->data();
+  if (!aSketchData || !aSketchData->isValid())
+    return EntityWrapperPtr(); // the sketch is incorrect
+
+  // Get parameters of workplane
+  AttributePtr aDirX    = aSketchData->attribute(SketchPlugin_Sketch::DIRX_ID());
+  AttributePtr aNorm    = aSketchData->attribute(SketchPlugin_Sketch::NORM_ID());
+  AttributePtr anOrigin = aSketchData->attribute(SketchPlugin_Sketch::ORIGIN_ID());
+  if (!anOrigin->isInitialized() || !aNorm->isInitialized() || !aDirX->isInitialized())
+    return EntityWrapperPtr();
+
+  EntityWrapperPtr aNewEnt;
+  std::list<EntityWrapperPtr> aSubs;
+
+  // Create SolveSpace entity corresponding to the sketch origin
+  aNewEnt = createAttribute(anOrigin, theGroupID);
+  if (!aNewEnt)
+    return EntityWrapperPtr();
+  aSubs.push_back(aNewEnt);
+
+  // Create SolveSpace entity corresponding the the sketch normal
+  aNewEnt = createNormal(aNorm, aDirX, theGroupID);
+  if (!aNewEnt)
+    return EntityWrapperPtr();
+  aSubs.push_back(aNewEnt);
+
+  // Create workplane
+  Slvs_Entity aWorkplane = Slvs_MakeWorkplane(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+      SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+
+  aNewEnt = EntityWrapperPtr(
+      new SolveSpaceSolver_EntityWrapper(FeaturePtr(theSketch), aWorkplane));
+  aNewEnt->setSubEntities(aSubs);
+  return aNewEnt;
+}
+
+EntityWrapperPtr SolveSpaceSolver_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;
+}
+
+ParameterWrapperPtr SolveSpaceSolver_Builder::createParameter(
+    const GroupID& theGroup, const double theValue, const bool theExpr) const
+{
+  Slvs_Param aParam = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroup, theValue);
+  ParameterWrapperPtr aWrapper(new SolveSpaceSolver_ParameterWrapper(aParam));
+  aWrapper->setIsParametric(theExpr);
+  return aWrapper;
+}
+
+
+
+
+
+// ================   Auxiliary functions   ==========================
+EntityWrapperPtr createLine(FeaturePtr theFeature,
+                            const std::list<EntityWrapperPtr>& theAttributes,
+                            const GroupID& theGroupID,
+                            const EntityID& theSketchID)
+{
+  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;
+
+  EntityWrapperPtr aStartEnt, aEndEnt;
+  std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
+  for (; anIt != theAttributes.end(); ++anIt) {
+    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity = 
+        std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
+    if (aSlvsEntity->isBase(aStart))
+      aStartEnt = aSlvsEntity;
+    else if (aSlvsEntity->isBase(aEnd))
+      aEndEnt = aSlvsEntity;
+  }
+  if (!aStartEnt || !aEndEnt)
+    return aNewEntity;
+
+  aSubs.push_back(aStartEnt);
+  aSubs.push_back(aEndEnt);
+  Slvs_Entity anEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+      (Slvs_hEntity)theSketchID, (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
+
+  aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
+  aNewEntity->setSubEntities(aSubs);
+  return aNewEntity;
+}
+
+EntityWrapperPtr createCircle(FeaturePtr theFeature,
+                              const std::list<EntityWrapperPtr>& theAttributes,
+                              const GroupID& theGroupID,
+                              const EntityID& theSketchID)
+{
+  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;
+
+  EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt;
+  std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
+  for (; anIt != theAttributes.end(); ++anIt) {
+    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity = 
+        std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
+    if (aSlvsEntity->isBase(aCenter))
+      aCenterEnt = aSlvsEntity;
+    else if (aSlvsEntity->isBase(aRadius))
+      aRadiusEnt = aSlvsEntity;
+    else if (aSlvsEntity->type() == ENTITY_NORMAL)
+      aNormalEnt = aSlvsEntity;
+  }
+  if (!aCenterEnt || !aRadiusEnt || !aNormalEnt)
+    return aNewEntity;
+
+  aSubs.push_back(aCenterEnt);
+  aSubs.push_back(aRadiusEnt);
+  Slvs_Entity anEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+      (Slvs_hEntity)theSketchID, (Slvs_hEntity)aCenterEnt->id(),
+      (Slvs_hEntity)aNormalEnt->id(), (Slvs_hEntity)aRadiusEnt->id());
+
+  aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
+  aNewEntity->setSubEntities(aSubs);
+  return aNewEntity;
+}
+
+EntityWrapperPtr createArc(FeaturePtr theFeature,
+                           const std::list<EntityWrapperPtr>& theAttributes,
+                           const GroupID& theGroupID,
+                           const EntityID& theSketchID)
+{
+  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;
+
+  EntityWrapperPtr aCenterEnt, aStartEnt, aEndEnt, aNormalEnt;
+  std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
+  for (; anIt != theAttributes.end(); ++anIt) {
+    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity = 
+        std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
+    if (aSlvsEntity->isBase(aCenter))
+      aCenterEnt = aSlvsEntity;
+    else if (aSlvsEntity->isBase(aStart))
+      aStartEnt = aSlvsEntity;
+    else if (aSlvsEntity->isBase(aEnd))
+      aEndEnt = aSlvsEntity;
+    else if (aSlvsEntity->type() == ENTITY_NORMAL)
+      aNormalEnt = aSlvsEntity;
+  }
+  if (!aCenterEnt || !aStartEnt || !aEndEnt || !aNormalEnt)
+    return aNewEntity;
+
+  aSubs.push_back(aCenterEnt);
+  aSubs.push_back(aStartEnt);
+  aSubs.push_back(aEndEnt);
+  Slvs_Entity anEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+      (Slvs_hEntity)theSketchID, (Slvs_hEntity)aNormalEnt->id(),
+      (Slvs_hEntity)aCenterEnt->id(), (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
+
+  aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
+  aNewEntity->setSubEntities(aSubs);
+  return aNewEntity;
+}
+
+
+void adjustTangency(ConstraintWrapperPtr theConstraint)
+{
+  BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
+
+  std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
+    std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
+
+  // Collect start, end points of entities
+  std::shared_ptr<GeomAPI_Pnt2d> aStartEntPoints[2][2];
+  bool isCoinc[2][2] = {false};
+  const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
+  std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+  for (int i = 0; aSIt != aSubs.end(); ++aSIt, ++i) {
+    const std::list<EntityWrapperPtr>& aPoints = (*aSIt)->subEntities();
+    std::list<EntityWrapperPtr>::const_iterator aPIt = aPoints.begin();
+    if ((*aSIt)->type() == ENTITY_ARC)
+      ++aPIt;
+    for (int j = 0; aPIt != aPoints.end(); ++aPIt, ++j) {
+      aStartEntPoints[i][j] = aBuilder->point(*aPIt);
+      if (i > 0) { // check coincidence
+        for (int k = 0; k < 2; ++k)
+          if (aStartEntPoints[i][j]->distance(aStartEntPoints[0][k]) < tolerance)
+            isCoinc[0][k] = isCoinc[i][j] = true;
+      }
+    }
+  }
+
+  Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
+  if (isCoinc[0][0] == false && isCoinc[0][1] == true)
+    aSlvsConstraint.other = 1;
+  else aSlvsConstraint.other = 0;
+  if (isCoinc[1][0] == false && isCoinc[1][1] == true)
+    aSlvsConstraint.other2 = 1;
+  else aSlvsConstraint.other2 = 0;
+}
+
+void adjustAngle(ConstraintWrapperPtr theConstraint)
+{
+  BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
+
+  std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
+    std::dynamic_pointer_cast<SolveSpaceSolver_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;
+      }
+    }
+  }
+
+  Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
+  aSlvsConstraint.other = false;
+  for (int i = 0; i < 2; i++)
+    if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
+      aSlvsConstraint.other = !aSlvsConstraint.other;
+}
+
+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 = SolveSpaceSolver_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<SolveSpaceSolver_EntityWrapper>(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)
+{
+  std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
+      std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
+  std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
+      std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
+
+  if (theSource->type() == ENTITY_POINT) {
+    // Rotate single point
+    std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
+    std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->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 = aDest->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)
+{
+  std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
+      std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
+  std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
+      std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
+
+  if (theSource->type() == ENTITY_POINT) {
+    // Translate single point
+    std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
+    std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->baseAttribute());
+    if (aSrcAttr && aDstAttr)
+      aDstAttr->setValue(aSrcAttr->x() + theDelta->x(), aSrcAttr->y() + theDelta->y());
+    return;
+  }
+
+  FeaturePtr aDestFeature = aDest->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 = SolveSpaceSolver_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 = SolveSpaceSolver_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/SolveSpaceSolver/SolveSpaceSolver_Builder.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.h
new file mode 100644 (file)
index 0000000..f55330a
--- /dev/null
@@ -0,0 +1,140 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SolveSpaceSolver_Builder.h
+// Created: 25 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_Builder_H_
+#define SolveSpaceSolver_Builder_H_
+
+#include <SketchSolver_Builder.h>
+#include <SketchSolver_Constraint.h>
+
+#include <SketchPlugin_Constraint.h>
+
+#include <ModelAPI_CompositeFeature.h>
+
+/** \class   SolveSpaceSolver_Builder
+ *  \ingroup Plugins
+ *  \brief   Create bridges between SketchPlugin constraints and SolveSpace constraints
+ */
+class SolveSpaceSolver_Builder : public SketchSolver_Builder
+{
+private:
+  /// Default constructor
+  SolveSpaceSolver_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;
+
+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;
+
+  /// \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
+  ParameterWrapperPtr createParameter(const GroupID& theGroup,
+                                      const double theValue = 0.0,
+                                      const bool theExpr = false) const;
+
+private:
+  static BuilderPtr mySelf;
+};
+
+#endif
diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintType.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintType.h
new file mode 100644 (file)
index 0000000..a38939b
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SolveSpaceSolver_ConstraintType.h
+// Created: 8 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_ConstraintType_H_
+#define SolveSpaceSolver_ConstraintType_H_
+
+#include <SketchSolver_IConstraintWrapper.h>
+#include <SolveSpaceSolver_Solver.h>
+
+namespace ConstraintType
+{
+  /// \brief Convert constraint type from SketchSolver to SolveSpace
+  static int toSolveSpace(SketchSolver_ConstraintType theType)
+  {
+    switch (theType) {
+    case CONSTRAINT_PT_PT_COINCIDENT:   return SLVS_C_POINTS_COINCIDENT;
+    case CONSTRAINT_PT_ON_LINE:         return SLVS_C_PT_ON_LINE;
+    case CONSTRAINT_PT_ON_CIRCLE:       return SLVS_C_PT_ON_CIRCLE;
+    case CONSTRAINT_PT_PT_DISTANCE:     return SLVS_C_PT_PT_DISTANCE;
+    case CONSTRAINT_PT_LINE_DISTANCE:   return SLVS_C_PT_LINE_DISTANCE;
+    case CONSTRAINT_ANGLE:              return SLVS_C_ANGLE;
+    case CONSTRAINT_RADIUS:             return SLVS_C_DIAMETER;
+    case CONSTRAINT_FIXED:              return SLVS_C_WHERE_DRAGGED;
+    case CONSTRAINT_HORIZONTAL:         return SLVS_C_HORIZONTAL;
+    case CONSTRAINT_VERTICAL:           return SLVS_C_VERTICAL;
+    case CONSTRAINT_PARALLEL:           return SLVS_C_PARALLEL;
+    case CONSTRAINT_PERPENDICULAR:      return SLVS_C_PERPENDICULAR;
+    case CONSTRAINT_SYMMETRIC:          return SLVS_C_SYMMETRIC_LINE;
+    case CONSTRAINT_EQUAL_LINES:        return SLVS_C_EQUAL_LENGTH_LINES;
+    case CONSTRAINT_EQUAL_LINE_ARC:     return SLVS_C_EQUAL_LINE_ARC_LEN;
+    case CONSTRAINT_EQUAL_RADIUS:       return SLVS_C_EQUAL_RADIUS;
+    case CONSTRAINT_TANGENT_ARC_LINE:   return SLVS_C_ARC_LINE_TANGENT;
+    case CONSTRAINT_TANGENT_ARC_ARC:    return SLVS_C_CURVE_CURVE_TANGENT;
+    case CONSTRAINT_MULTI_ROTATION:     return SLVS_C_MULTI_ROTATION;
+    case CONSTRAINT_MULTI_TRANSLATION:  return SLVS_C_MULTI_TRANSLATION;
+    default: break;
+    }
+    return SLVS_C_UNKNOWN;
+  }
+
+  /// \brief Convert constraint type from SolveSpace to SketchSolver
+  static SketchSolver_ConstraintType fromSolveSpace(int theType)
+  {
+    switch (theType) {
+    case SLVS_C_POINTS_COINCIDENT:    return CONSTRAINT_PT_PT_COINCIDENT;
+    case SLVS_C_PT_ON_LINE:           return CONSTRAINT_PT_ON_LINE;
+    case SLVS_C_PT_ON_CIRCLE:         return CONSTRAINT_PT_ON_CIRCLE;
+    case SLVS_C_PT_PT_DISTANCE:       return CONSTRAINT_PT_PT_DISTANCE;
+    case SLVS_C_PT_LINE_DISTANCE:     return CONSTRAINT_PT_LINE_DISTANCE;
+    case SLVS_C_EQUAL_LENGTH_LINES:   return CONSTRAINT_EQUAL_LINES;
+    case SLVS_C_EQUAL_LINE_ARC_LEN:   return CONSTRAINT_EQUAL_LINE_ARC;
+    case SLVS_C_SYMMETRIC_LINE:       return CONSTRAINT_SYMMETRIC;
+    case SLVS_C_HORIZONTAL:           return CONSTRAINT_HORIZONTAL;
+    case SLVS_C_VERTICAL:             return CONSTRAINT_VERTICAL;
+    case SLVS_C_DIAMETER:             return CONSTRAINT_RADIUS;
+    case SLVS_C_ANGLE:                return CONSTRAINT_ANGLE;
+    case SLVS_C_PARALLEL:             return CONSTRAINT_PARALLEL;
+    case SLVS_C_PERPENDICULAR:        return CONSTRAINT_PERPENDICULAR;
+    case SLVS_C_ARC_LINE_TANGENT:     return CONSTRAINT_TANGENT_ARC_LINE;
+    case SLVS_C_EQUAL_RADIUS:         return CONSTRAINT_EQUAL_RADIUS;
+    case SLVS_C_WHERE_DRAGGED:        return CONSTRAINT_FIXED;
+    case SLVS_C_CURVE_CURVE_TANGENT:  return CONSTRAINT_TANGENT_ARC_ARC;
+    case SLVS_C_MULTI_ROTATION:       return CONSTRAINT_MULTI_ROTATION;
+    case SLVS_C_MULTI_TRANSLATION:    return CONSTRAINT_MULTI_TRANSLATION;
+    default: break;
+    }
+    return CONSTRAINT_UNKNOWN;
+  }
+}
+
+
+#endif
diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.cpp
new file mode 100644 (file)
index 0000000..8419b9a
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SolveSpaceSolver_ConstraintWrapper.cpp
+// Created: 2 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#include <SolveSpaceSolver_ConstraintWrapper.h>
+#include <SolveSpaceSolver_ConstraintType.h>
+#include <math.h>
+
+SolveSpaceSolver_ConstraintWrapper::SolveSpaceSolver_ConstraintWrapper(
+    const ConstraintPtr&    theOriginal,
+    const Slvs_Constraint& theConstraint)
+  : mySlvsConstraint(theConstraint)
+{
+  myBaseConstraint = theOriginal;
+  myValue = mySlvsConstraint.valA;
+}
+
+ConstraintID SolveSpaceSolver_ConstraintWrapper::id() const
+{
+  return (ConstraintID)mySlvsConstraint.h;
+}
+
+void SolveSpaceSolver_ConstraintWrapper::setGroup(const GroupID& theGroup)
+{
+  mySlvsConstraint.group = (Slvs_hGroup)theGroup;
+  std::list<EntityWrapperPtr>::iterator aSubsIt = myConstrained.begin();
+  for (; aSubsIt != myConstrained.end(); ++aSubsIt)
+    (*aSubsIt)->setGroup(theGroup);
+}
+
+SketchSolver_ConstraintType SolveSpaceSolver_ConstraintWrapper::type() const
+{
+  return ConstraintType::fromSolveSpace(mySlvsConstraint.type);
+}
+
+void SolveSpaceSolver_ConstraintWrapper::setValue(const double& theValue)
+{
+  double aValue = theValue;
+  if (type() == CONSTRAINT_RADIUS)
+    aValue *= 2.0; // NOTE: SolveSpace uses constraint DIAMETER
+
+  SketchSolver_IConstraintWrapper::setValue(aValue);
+}
+
+bool SolveSpaceSolver_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 SolveSpaceSolver_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 SolveSpaceSolver_ConstraintWrapper::isEqual(const ConstraintWrapperPtr& theOther)
+{
+  const Slvs_Constraint anOtherConstraint = 
+    std::dynamic_pointer_cast<SolveSpaceSolver_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 SolveSpaceSolver_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/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.h
new file mode 100644 (file)
index 0000000..b7ff499
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SolveSpaceSolver_ConstraintWrapper.h
+// Created: 2 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_ConstraintWrapper_H_
+#define SolveSpaceSolver_ConstraintWrapper_H_
+
+#include <SketchSolver_IConstraintWrapper.h>
+#include <SolveSpaceSolver_Solver.h>
+
+
+/**
+ *  Wrapper providing operations with SovleSpace constraints.
+ */
+class SolveSpaceSolver_ConstraintWrapper : public SketchSolver_IConstraintWrapper
+{
+public:
+  SolveSpaceSolver_ConstraintWrapper(const ConstraintPtr&   theOriginal,
+                                     const Slvs_Constraint& theConstraint);
+
+  /// \brief Return SolveSpace constraint
+  const Slvs_Constraint& constraint() const
+  { return mySlvsConstraint; }
+  /// \brief Return SolveSpace constraint to change
+  Slvs_Constraint& changeConstraint()
+  { return mySlvsConstraint; }
+
+  /// \brief Return ID of current entity
+  virtual ConstraintID id() const;
+
+  /// \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 (GroupID)mySlvsConstraint.group; }
+
+  /// \brief Return type of current entity
+  virtual SketchSolver_ConstraintType type() const;
+
+  /// \brief Assign numeric parameter of constraint
+  virtual void setValue(const double& theValue);
+
+  /// \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:
+  Slvs_Constraint mySlvsConstraint;
+};
+
+#endif
diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.cpp
new file mode 100644 (file)
index 0000000..1cb8115
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SolveSpaceSolver_EntityWrapper.cpp
+// Created: 2 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#include <SolveSpaceSolver_EntityWrapper.h>
+
+SolveSpaceSolver_EntityWrapper::SolveSpaceSolver_EntityWrapper(
+    const FeaturePtr theFeature, const Slvs_Entity& theEntity)
+  : myEntity(theEntity)
+{
+  myBaseFeature = theFeature;
+}
+
+SolveSpaceSolver_EntityWrapper::SolveSpaceSolver_EntityWrapper(
+    const AttributePtr theAttribute, const Slvs_Entity& theEntity)
+  : myEntity(theEntity)
+{
+  myBaseAttribute = theAttribute;
+}
+
+EntityID SolveSpaceSolver_EntityWrapper::id() const
+{
+  return (EntityID)myEntity.h;
+}
+
+void SolveSpaceSolver_EntityWrapper::setGroup(const GroupID& theGroup)
+{
+  myEntity.group = (Slvs_hGroup)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);
+}
+
+SketchSolver_EntityType SolveSpaceSolver_EntityWrapper::type() const
+{
+  switch (myEntity.type) {
+  case SLVS_E_POINT_IN_3D:
+  case SLVS_E_POINT_IN_2D:    return ENTITY_POINT;
+  case SLVS_E_LINE_SEGMENT:   return ENTITY_LINE;
+  case SLVS_E_CIRCLE:         return ENTITY_CIRCLE;
+  case SLVS_E_ARC_OF_CIRCLE:  return ENTITY_ARC;
+  case SLVS_E_NORMAL_IN_3D:
+  case SLVS_E_NORMAL_IN_2D:   return ENTITY_NORMAL;
+  case SLVS_E_DISTANCE:       return ENTITY_SCALAR;
+  case SLVS_E_WORKPLANE:      return ENTITY_SKETCH;
+  default: break;
+  }
+  return ENTITY_UNKNOWN;
+}
+
+bool SolveSpaceSolver_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 SolveSpaceSolver_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 SolveSpaceSolver_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 SolveSpaceSolver_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/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.h
new file mode 100644 (file)
index 0000000..566625f
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SolveSpaceSolver_EntityWrapper.h
+// Created: 2 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_EntityWrapper_H_
+#define SolveSpaceSolver_EntityWrapper_H_
+
+#include <SketchSolver_IEntityWrapper.h>
+#include <SolveSpaceSolver_Solver.h>
+
+/**
+ *  Wrapper providing operations with SolveSpace entities.
+ */
+class SolveSpaceSolver_EntityWrapper : public SketchSolver_IEntityWrapper
+{
+public:
+  SolveSpaceSolver_EntityWrapper(const FeaturePtr theFeature, const Slvs_Entity& theEntity);
+  SolveSpaceSolver_EntityWrapper(const AttributePtr theAttribute, const Slvs_Entity& theEntity);
+
+  /// \brief Return SolveSpace entity
+  const Slvs_Entity& entity() const
+  { return myEntity; }
+  /// \brief Return SolveSpace entity to change
+  Slvs_Entity& changeEntity()
+  { return myEntity; }
+
+  /// \brief Return ID of current entity
+  virtual EntityID id() const;
+
+  /// \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 (GroupID)myEntity.group; }
+
+  /// \brief Return type of current entity
+  virtual SketchSolver_EntityType type() const;
+
+  /// \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 std::shared_ptr<SketchSolver_IEntityWrapper>& theOther);
+
+private:
+  Slvs_Entity  myEntity;
+};
+
+#endif
diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.cpp
new file mode 100644 (file)
index 0000000..1f2c7d4
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SolveSpaceSolver_ParameterWrapper.cpp
+// Created: 2 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#include <SolveSpaceSolver_ParameterWrapper.h>
+
+#include <math.h>
+
+SolveSpaceSolver_ParameterWrapper::SolveSpaceSolver_ParameterWrapper(const Slvs_Param& theParam)
+  : myParameter(theParam)
+{
+}
+
+ParameterID SolveSpaceSolver_ParameterWrapper::id() const
+{
+  return (ParameterID)myParameter.h;
+}
+
+void SolveSpaceSolver_ParameterWrapper::setValue(double theValue)
+{
+  myParameter.val = theValue;
+}
+
+double SolveSpaceSolver_ParameterWrapper::value() const
+{
+  return myParameter.val;
+}
+
+bool SolveSpaceSolver_ParameterWrapper::isEqual(const ParameterWrapperPtr& theOther)
+{
+  std::shared_ptr<SolveSpaceSolver_ParameterWrapper> anOtherParam = 
+      std::dynamic_pointer_cast<SolveSpaceSolver_ParameterWrapper>(theOther);
+  return anOtherParam && fabs(value() - anOtherParam->value()) < tolerance;
+}
+
+bool SolveSpaceSolver_ParameterWrapper::update(const ParameterWrapperPtr& theOther)
+{
+  std::shared_ptr<SolveSpaceSolver_ParameterWrapper> anOther =
+      std::dynamic_pointer_cast<SolveSpaceSolver_ParameterWrapper>(theOther);
+  if (fabs(value() - anOther->value()) < tolerance)
+    return false;
+  myParameter.val = anOther->value();
+  myIsParametric = theOther->isParametric();
+  return true;
+}
diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.h
new file mode 100644 (file)
index 0000000..da82e65
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SolveSpaceSolver_ParameterWrapper.h
+// Created: 2 Dec 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_ParameterWrapper_H_
+#define SolveSpaceSolver_ParameterWrapper_H_
+
+#include <SketchSolver_IParameterWrapper.h>
+#include <SolveSpaceSolver_Solver.h>
+
+/**
+ *  Wrapper providing operations with parameters in SolveSpace.
+ */
+class SolveSpaceSolver_ParameterWrapper : public SketchSolver_IParameterWrapper
+{
+public:
+  SolveSpaceSolver_ParameterWrapper(const Slvs_Param& theParam);
+
+  /// \brief Return SolveSpace parameter
+  const Slvs_Param& parameter() const
+  { return myParameter; }
+  /// \brief Return SolveSpace parameter to change
+  Slvs_Param& changeParameter()
+  { return myParameter; }
+
+  /// \brief Return ID of current parameter
+  virtual ParameterID id() const;
+
+  /// \brief Change group for the parameter
+  virtual void setGroup(const GroupID& theGroup)
+  { myParameter.group = (Slvs_hGroup)theGroup; }
+
+  /// \brief Return identifier of the group the parameter belongs to
+  virtual GroupID group() const
+  { return (GroupID)myParameter.group; }
+
+  /// \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 std::shared_ptr<SketchSolver_IParameterWrapper>& theOther);
+
+private:
+  Slvs_Param myParameter;
+};
+
+#endif
diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.cpp
new file mode 100644 (file)
index 0000000..de1cc3e
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SolveSpaceSolver_Solver.cpp
+// Created: 07 May 2014
+// Author:  Artem ZHIDKOV
+
+#include "SolveSpaceSolver_Solver.h"
+#include <Events_LongOp.h>
+
+SolveSpaceSolver_Solver::SolveSpaceSolver_Solver()
+{
+  // Nullify all elements of the set of equations
+  myEquationsSystem.param = 0;
+  myEquationsSystem.params = 0;
+  myEquationsSystem.entity = 0;
+  myEquationsSystem.entities = 0;
+  myEquationsSystem.constraint = 0;
+  myEquationsSystem.constraints = 0;
+  myEquationsSystem.failed = 0;
+  myEquationsSystem.faileds = 0;
+
+  myEquationsSystem.dragged[0] = 0;
+  myEquationsSystem.dragged[1] = 0;
+  myEquationsSystem.dragged[2] = 0;
+  myEquationsSystem.dragged[3] = 0;
+
+  // If the set of constraints is inconsistent,
+  // the failed field will contain wrong constraints
+  myEquationsSystem.calculateFaileds = 0;
+}
+
+SolveSpaceSolver_Solver::~SolveSpaceSolver_Solver()
+{
+  if (myEquationsSystem.constraint)
+    delete[] myEquationsSystem.constraint;
+  myEquationsSystem.constraint = 0;
+  if (myEquationsSystem.failed)
+    delete[] myEquationsSystem.failed;
+  myEquationsSystem.failed = 0;
+}
+
+void SolveSpaceSolver_Solver::setParameters(Slvs_Param* theParameters, int theSize)
+{
+  myEquationsSystem.param = theParameters;
+  myEquationsSystem.params = theSize;
+}
+
+
+void SolveSpaceSolver_Solver::setDraggedParameters(const Slvs_hParam* theDragged)
+{
+  for (unsigned int i = 0; i < 4; i++)
+    myEquationsSystem.dragged[i] = theDragged[i];
+}
+
+void SolveSpaceSolver_Solver::setEntities(Slvs_Entity* theEntities, int theSize)
+{
+  myEquationsSystem.entity = theEntities;
+  myEquationsSystem.entities = theSize;
+}
+
+void SolveSpaceSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize)
+{
+  if (!myEquationsSystem.constraint) {
+    myEquationsSystem.constraint = new Slvs_Constraint[theSize];
+    myEquationsSystem.constraints = theSize;
+    myEquationsSystem.failed = new Slvs_hConstraint[theSize];
+  }
+  else if (myEquationsSystem.constraints != theSize) {
+    if (theSize > myEquationsSystem.constraints) {
+      delete[] myEquationsSystem.constraint;
+      myEquationsSystem.constraint = new Slvs_Constraint[theSize];
+      if (myEquationsSystem.failed)
+        delete[] myEquationsSystem.failed;
+      myEquationsSystem.failed = new Slvs_hConstraint[theSize];
+    }
+    myEquationsSystem.constraints = theSize;
+  }
+  memcpy(myEquationsSystem.constraint, theConstraints, theSize * sizeof(Slvs_Constraint));
+  memset(myEquationsSystem.failed, SLVS_C_UNKNOWN, theSize * sizeof(Slvs_hConstraint));
+}
+
+
+SketchSolver_SolveStatus SolveSpaceSolver_Solver::solve()
+{
+  if (myEquationsSystem.constraints <= 0)
+    return STATUS_EMPTYSET;
+
+  myEquationsSystem.calculateFaileds = myFindFaileds ? 1 : 0;
+
+  Events_LongOp::start(this);
+  Slvs_Solve(&myEquationsSystem, myGroup);
+  Events_LongOp::end(this);
+
+  SketchSolver_SolveStatus aStatus;
+  switch (myEquationsSystem.result) {
+  case SLVS_RESULT_OKAY:
+    aStatus = STATUS_OK;
+    break;
+  case SLVS_RESULT_INCONSISTENT:
+  case SLVS_RESULT_DIDNT_CONVERGE:
+  case SLVS_RESULT_TOO_MANY_UNKNOWNS:
+    aStatus = STATUS_INCONSISTENT;
+    break;
+  default:
+    aStatus = STATUS_FAILED;
+  }
+  return aStatus;
+}
diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.h
new file mode 100644 (file)
index 0000000..c853970
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SolveSpaceSolver_Solver.h
+// Created: 07 May 2014
+// Author:  Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_Solver_H_
+#define SolveSpaceSolver_Solver_H_
+
+#include <SketchSolver_ISolver.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 <slvs.h>
+
+#include <vector>
+
+// Unknown constraint (for error reporting)
+#define SLVS_C_UNKNOWN 0
+// Fillet constraint identifier
+#define SLVS_C_FILLET            100100
+// Multi-rotation constraint identifier
+#define SLVS_C_MULTI_ROTATION    100101
+// Multi-translation constraint identifier
+#define SLVS_C_MULTI_TRANSLATION 100102
+// Unknown entity
+#define SLVS_E_UNKNOWN 0
+// Unknown group
+#define SLVS_G_UNKNOWN 0
+// Group ID to store external objects
+#define SLVS_G_OUTOFGROUP 1
+
+/** \class SolveSpaceSolver_Solver
+ *  \ingroup Plugins
+ *  \brief Performs high-level operations to solve sketch in SolveSpace.
+ */
+class SolveSpaceSolver_Solver : public SketchSolver_ISolver
+{
+ public:
+  SolveSpaceSolver_Solver();
+  virtual ~SolveSpaceSolver_Solver();
+
+  /** \brief Change array of parameters
+   *  \param[in] theParameters pointer to the array of parameters
+   *  \param[in] theSize       size of this array
+   */
+  void setParameters(Slvs_Param* theParameters, int theSize);
+
+  /** \brief Change array of entities
+   *  \param[in] theEntities pointer to the array of entities
+   *  \param[in] theSize     size of this array
+   */
+  void setEntities(Slvs_Entity* theEntities, int theSize);
+
+  /** \brief Change array of constraints
+   *  \param[in] theConstraints pointer to the array of constraints
+   *  \param[in] theSize        size of this array
+   */
+  void setConstraints(Slvs_Constraint* theConstraints, int theSize);
+
+  /** \brief Store the parameters of the point which was moved by user.
+   *         The solver will watch this items to be constant
+   *  \param[in] theDragged list of parameters (not more than 4) which should not be changed during solving
+   */
+  void setDraggedParameters(const Slvs_hParam* theDragged);
+
+  /** \brief Solve the set of equations
+   *  \return identifier whether solution succeeded
+   */
+  virtual SketchSolver_SolveStatus solve();
+
+ private:
+  Slvs_System myEquationsSystem; ///< set of equations for solving in SolveSpace
+};
+
+#endif
diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.cpp
new file mode 100644 (file)
index 0000000..2a6fb95
--- /dev/null
@@ -0,0 +1,1879 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SolveSpaceSolver_Storage.cpp
+// Created: 18 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#include <SolveSpaceSolver_Storage.h>
+#include <SolveSpaceSolver_ConstraintWrapper.h>
+#include <SolveSpaceSolver_EntityWrapper.h>
+#include <SolveSpaceSolver_ParameterWrapper.h>
+#include <SolveSpaceSolver_Builder.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+#include <math.h>
+#include <assert.h>
+
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeDouble.h>
+
+/** \brief Search the entity/parameter with specified ID in the list of elements
+ *  \param[in] theEntityID unique ID of the element
+ *  \param[in] theEntities list of elements
+ *  \return position of the found element or -1 if the element is not found
+ */
+template<typename T>
+static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
+
+/// \brief Compare two parameters to be different
+static bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2);
+/// \brief Compare two entities to be different
+static bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2);
+/// \brief Compare two constraints to be different
+static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2);
+
+
+SolveSpaceSolver_Storage::SolveSpaceSolver_Storage(const GroupID& theGroup)
+  : SketchSolver_Storage(theGroup),
+    myWorkplaneID(SLVS_E_UNKNOWN),
+    myParamMaxID(SLVS_E_UNKNOWN),
+    myEntityMaxID(SLVS_E_UNKNOWN),
+    myConstrMaxID(SLVS_C_UNKNOWN),
+    myFixed(SLVS_E_UNKNOWN),
+    myDuplicatedConstraint(false)
+{
+}
+
+bool SolveSpaceSolver_Storage::update(ConstraintWrapperPtr& theConstraint)
+{
+  bool isUpdated = false;
+  std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
+      std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
+  Slvs_Constraint aSlvsConstr = getConstraint((Slvs_hConstraint)aConstraint->id());
+  if (aSlvsConstr.h == SLVS_C_UNKNOWN)
+    aSlvsConstr = aConstraint->constraint();
+
+  // update value of constraint if exist
+  if (fabs(aSlvsConstr.valA - theConstraint->value()) > tolerance) {
+    aSlvsConstr.valA = theConstraint->value();
+    isUpdated = true;
+  }
+
+  // update constrained entities
+  Slvs_hEntity* aPnts[2] = {&aSlvsConstr.ptA, &aSlvsConstr.ptB};
+  Slvs_hEntity* anEnts[4] = {&aSlvsConstr.entityA, &aSlvsConstr.entityB,
+                             &aSlvsConstr.entityC, &aSlvsConstr.entityD};
+  int aPtInd = 0;
+  int aEntInd = 0;
+
+  std::list<EntityWrapperPtr> anEntities = theConstraint->entities();
+  std::list<EntityWrapperPtr>::iterator anIt = anEntities.begin();
+  for (; anIt != anEntities.end(); ++anIt) {
+    isUpdated = update(*anIt) || isUpdated;
+
+    Slvs_hEntity anID = (Slvs_hEntity)(*anIt)->id();
+    if ((*anIt)->type() == ENTITY_POINT) {
+      if (*(aPnts[aPtInd]) != anID) {
+        *(aPnts[aPtInd]) = anID;
+        isUpdated = true;
+      }
+      ++aPtInd;
+    } else {
+      if (*(anEnts[aEntInd]) != anID) {
+        *(anEnts[aEntInd]) = anID;
+        isUpdated = true;
+      }
+      ++aEntInd;
+    }
+  }
+
+  // update constraint itself (do not update constraints Multi)
+  if (aSlvsConstr.type != SLVS_C_MULTI_ROTATION && aSlvsConstr.type != SLVS_C_MULTI_TRANSLATION) {
+    if (aSlvsConstr.wrkpl == SLVS_E_UNKNOWN && myWorkplaneID != SLVS_E_UNKNOWN)
+      aSlvsConstr.wrkpl = myWorkplaneID;
+    if (aSlvsConstr.group == SLVS_G_UNKNOWN)
+      aSlvsConstr.group = (Slvs_hGroup)myGroupID;
+    Slvs_hConstraint aConstrID = updateConstraint(aSlvsConstr);
+    if (aSlvsConstr.h == SLVS_C_UNKNOWN) {
+      aConstraint->changeConstraint() = getConstraint(aConstrID);
+      isUpdated = true;
+    }
+  }
+  return isUpdated;
+}
+
+bool SolveSpaceSolver_Storage::update(EntityWrapperPtr& theEntity)
+{
+  bool isUpdated = false;
+  std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity = 
+      std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theEntity);
+  Slvs_Entity aSlvsEnt = getEntity((Slvs_hEntity)anEntity->id());
+  if (aSlvsEnt.h == SLVS_E_UNKNOWN)
+    aSlvsEnt = anEntity->entity();
+
+  std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
+  std::list<ParameterWrapperPtr>::iterator aPIt;
+  // if the entity is an attribute, need to update its coordinates
+  if (anEntity->baseAttribute()) {
+    BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
+    EntityWrapperPtr anUpdAttr = aBuilder->createAttribute(anEntity->baseAttribute(), GID_UNKNOWN);
+    if (anUpdAttr) {
+      std::list<ParameterWrapperPtr> anUpdParams = anUpdAttr->parameters();
+      std::list<ParameterWrapperPtr>::iterator anUpdIt = anUpdParams.begin();
+      for (aPIt = aParams.begin(); aPIt != aParams.end() && anUpdIt != anUpdParams.end();
+          ++aPIt, ++anUpdIt) {
+        (*aPIt)->update(*anUpdIt);
+      }
+    }
+  }
+
+  // update parameters
+  int anInd = 0;
+  for (aPIt = aParams.begin(); aPIt != aParams.end(); ++aPIt, ++anInd) {
+    assert(anInd < 4);
+    isUpdated = update(*aPIt) || isUpdated;
+    if (aSlvsEnt.param[anInd] != (Slvs_hEntity)(*aPIt)->id()) {
+      isUpdated = true;
+      aSlvsEnt.param[anInd] = (Slvs_hEntity)(*aPIt)->id();
+    }
+  }
+
+  // update sub-entities
+  std::list<EntityWrapperPtr> aSubEntities = theEntity->subEntities();
+  std::list<EntityWrapperPtr>::iterator aSIt = aSubEntities.begin();
+  for (anInd = 0; aSIt != aSubEntities.end(); ++aSIt, ++anInd) {
+    assert(anInd < 4);
+    isUpdated = update(*aSIt) || isUpdated;
+
+    Slvs_hEntity anID = Slvs_hEntity((*aSIt)->id());
+    if ((*aSIt)->type() == ENTITY_NORMAL)
+      aSlvsEnt.normal = anID;
+    else if ((*aSIt)->type() == ENTITY_SCALAR)
+      aSlvsEnt.distance = anID;
+    else if (aSlvsEnt.point[anInd] != anID) {
+      aSlvsEnt.point[anInd] = anID;
+      isUpdated = true;
+    }
+  }
+
+  // update entity itself
+  if (aSlvsEnt.wrkpl == SLVS_E_UNKNOWN && myWorkplaneID != SLVS_E_UNKNOWN)
+    aSlvsEnt.wrkpl = myWorkplaneID;
+  if (aSlvsEnt.group == SLVS_G_UNKNOWN)
+    aSlvsEnt.group = (Slvs_hGroup)myGroupID;
+  Slvs_hEntity anEntID = updateEntity(aSlvsEnt);
+  if (aSlvsEnt.h == SLVS_E_UNKNOWN) {
+    anEntity->changeEntity() = getEntity(anEntID);
+    isUpdated = true;
+
+    if (anEntity->type() == ENTITY_SKETCH)
+      storeWorkplane(anEntity);
+  }
+  return isUpdated;
+}
+
+bool SolveSpaceSolver_Storage::update(ParameterWrapperPtr& theParameter)
+{
+  std::shared_ptr<SolveSpaceSolver_ParameterWrapper> aParameter = 
+      std::dynamic_pointer_cast<SolveSpaceSolver_ParameterWrapper>(theParameter);
+  const Slvs_Param& aParam = getParameter((Slvs_hParam)aParameter->id());
+  if (aParam.h != SLVS_E_UNKNOWN && fabs(aParam.val - aParameter->value()) < tolerance)
+    return false;
+  Slvs_Param aParamToUpd = aParameter->parameter();
+  if (aParamToUpd.group == SLVS_G_UNKNOWN)
+    aParamToUpd.group = aParameter->isParametric() ? (Slvs_hGroup)GID_OUTOFGROUP : (Slvs_hGroup)myGroupID;
+  Slvs_hParam anID = updateParameter(aParamToUpd);
+  if (aParam.h == SLVS_E_UNKNOWN) // new parameter
+    aParameter->changeParameter() = getParameter(anID);
+  return true;
+}
+
+void SolveSpaceSolver_Storage::storeWorkplane(EntityWrapperPtr theSketch)
+{
+  myWorkplaneID = (Slvs_hEntity)theSketch->id();
+
+  // Update sub-entities of the sketch
+  std::list<EntityWrapperPtr> aSubEntities = theSketch->subEntities();
+  std::list<EntityWrapperPtr>::iterator aSIt = aSubEntities.begin();
+  for (; aSIt != aSubEntities.end(); ++aSIt) {
+    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSub =
+        std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*aSIt);
+    aSub->changeEntity().wrkpl = myWorkplaneID;
+  }
+
+  // Update all stored entities
+  std::vector<Slvs_Entity>::iterator anIt = myEntities.begin();
+  for (; anIt != myEntities.end(); ++anIt)
+    anIt->wrkpl = myWorkplaneID;
+}
+
+void SolveSpaceSolver_Storage::changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup)
+{
+  std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
+  std::list<ParameterWrapperPtr>::iterator aPIt = aParams.begin();
+  for (; aPIt != aParams.end(); ++aPIt)
+    changeGroup(*aPIt, theGroup);
+
+  std::list<EntityWrapperPtr> aSubs = theEntity->subEntities();
+  std::list<EntityWrapperPtr>::iterator aSIt = aSubs.begin();
+  for (; aSIt != aSubs.end(); ++aSIt)
+    changeGroup(*aSIt, theGroup);
+
+  if (theEntity->group() != theGroup) {
+    theEntity->setGroup(theGroup);
+    int aPos = Search((Slvs_hEntity)theEntity->id(), myEntities);
+    if (aPos >= 0 && aPos < (int)myEntities.size()) {
+      myEntities[aPos].group = (Slvs_hGroup)theGroup;
+      setNeedToResolve(true);
+    }
+  }
+}
+
+void SolveSpaceSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup)
+{
+  GroupID aGroup = theGroup;
+  if (theParam->isParametric())
+    aGroup = GID_OUTOFGROUP;
+  if (theParam->group() == aGroup)
+    return;
+
+  theParam->setGroup(aGroup);
+  int aPos = Search((Slvs_hParam)theParam->id(), myParameters);
+  if (aPos >= 0 && aPos < (int)myParameters.size()) {
+    myParameters[aPos].group = (Slvs_hGroup)aGroup;
+    setNeedToResolve(true);
+  }
+}
+
+void SolveSpaceSolver_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 {
+    // Update the slave if it was used in constraints and features
+    replaceInFeatures(theSlave, theMaster);
+    replaceInConstraints(theSlave, theMaster);
+
+    // Remove slave entity
+    removeEntity((Slvs_hEntity)theSlave->id());
+
+    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aPointMaster = 
+        std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMaster);
+    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aPointSlave = 
+        std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSlave);
+    aPointSlave->changeEntity() = aPointMaster->entity();
+    aPointSlave->setParameters(aPointMaster->parameters());
+
+    aMasterFound->second.insert(theSlave);
+  }
+}
+
+void SolveSpaceSolver_Storage::replaceInFeatures(
+    EntityWrapperPtr theSource, EntityWrapperPtr theDest)
+{
+  std::map<FeaturePtr, EntityWrapperPtr>::const_iterator anIt = myFeatureMap.begin();
+  for (; anIt != myFeatureMap.end(); ++anIt) {
+    bool isUpdated = false;
+    std::list<EntityWrapperPtr> aSubs = anIt->second->subEntities();
+    std::list<EntityWrapperPtr>::iterator aSubIt = aSubs.begin();
+    for (; aSubIt != aSubs.end(); ++aSubIt)
+      if ((*aSubIt)->id() == theSource->id()) {
+        (*aSubIt)->update(theDest);
+        isUpdated = true;
+      }
+
+    if (!isUpdated)
+      continue;
+
+    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aWrapper =
+        std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(anIt->second);
+    // update SolveSpace entity
+    Slvs_Entity anEnt = aWrapper->entity();
+    for (int i = 0; i < 4; ++i)
+      if (anEnt.point[i] == (Slvs_hEntity)theSource->id())
+        anEnt.point[i] = (Slvs_hEntity)theDest->id();
+    anEnt.h = updateEntity(anEnt);
+    aWrapper->changeEntity() = anEnt;
+
+    // update sub-entities
+    aWrapper->setSubEntities(aSubs);
+  }
+}
+
+void SolveSpaceSolver_Storage::replaceInConstraints(
+    EntityWrapperPtr theSource, EntityWrapperPtr theDest)
+{
+  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+      anIt = myConstraintMap.begin();
+  std::list<ConstraintWrapperPtr>::const_iterator aCIt;
+  for (; anIt != myConstraintMap.end(); ++anIt)
+    for (aCIt = anIt->second.begin(); aCIt != anIt->second.end(); ++aCIt) {
+      // Do not process coincidence between points
+      // (these constraints are stored to keep the structure of constraints).
+      if ((*aCIt)->type() == CONSTRAINT_PT_PT_COINCIDENT)
+        continue;
+
+      bool isUpdated = false;
+      std::list<EntityWrapperPtr> aSubs = (*aCIt)->entities();
+      std::list<EntityWrapperPtr>::iterator aSubIt = aSubs.begin();
+      for (; aSubIt != aSubs.end(); ++aSubIt)
+        if ((*aSubIt)->id() == theSource->id()) {
+          (*aSubIt)->update(theDest);
+          isUpdated = true;
+        }
+
+      if (!isUpdated)
+        continue;
+
+      std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aWrapper =
+          std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(*aCIt);
+      // change constraint entities
+      Slvs_Constraint aConstr = aWrapper->constraint();
+      if (aConstr.ptA == (Slvs_hEntity)theSource->id())
+        aConstr.ptA = (Slvs_hEntity)theDest->id();
+      if (aConstr.ptB == (Slvs_hEntity)theSource->id())
+        aConstr.ptB = (Slvs_hEntity)theDest->id();
+
+      // check the constraint is duplicated
+      std::vector<Slvs_Constraint>::const_iterator aSlvsCIt = myConstraints.begin();
+      for (; aSlvsCIt != myConstraints.end(); ++aSlvsCIt)
+        if (aConstr.h != aSlvsCIt->h &&
+            aConstr.type == aSlvsCIt->type &&
+            aConstr.ptA == aSlvsCIt->ptA && aConstr.ptB == aSlvsCIt->ptB &&
+            aConstr.entityA == aSlvsCIt->entityA && aConstr.entityB == aSlvsCIt->entityB &&
+            aConstr.entityC == aSlvsCIt->entityC && aConstr.entityD == aSlvsCIt->entityD) {
+          removeConstraint(aConstr.h);
+          aConstr = *aSlvsCIt;
+          break;
+        }
+
+      if (aSlvsCIt != myConstraints.end()) {
+        // constraint is duplicated, search its wrapper to add the mapping
+        std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+            anIt2 = myConstraintMap.begin();
+        std::list<ConstraintWrapperPtr>::const_iterator aCIt2;
+        for (; anIt2 != myConstraintMap.end(); ++anIt2)
+          for (aCIt2 = anIt2->second.begin(); aCIt2 != anIt2->second.end(); ++aCIt2)
+            if ((Slvs_hConstraint)(*aCIt2)->id() == aConstr.h) {
+              addSameConstraints(*aCIt2, aWrapper);
+              break;
+            }
+      } else 
+        aConstr.h = updateConstraint(aConstr);
+      aWrapper->changeConstraint() = aConstr;
+
+      // update sub-entities
+      aWrapper->setEntities(aSubs);
+    }
+}
+
+void SolveSpaceSolver_Storage::addSameConstraints(ConstraintWrapperPtr theConstraint1,
+                                                  ConstraintWrapperPtr theConstraint2)
+{
+  SameConstraintMap::iterator anIt = myEqualConstraints.begin();
+  for (; anIt != myEqualConstraints.end(); ++anIt) {
+    if (anIt->find(theConstraint1) != anIt->end()) {
+      anIt->insert(theConstraint2);
+      return;
+    }
+    else if (anIt->find(theConstraint2) != anIt->end()) {
+      anIt->insert(theConstraint1);
+      return;
+    }
+  }
+  // group not found => create new one
+  std::set<ConstraintWrapperPtr> aNewGroup;
+  aNewGroup.insert(theConstraint1);
+  aNewGroup.insert(theConstraint2);
+  myEqualConstraints.push_back(aNewGroup);
+}
+
+
+EntityWrapperPtr SolveSpaceSolver_Storage::calculateMiddlePoint(
+    EntityWrapperPtr theBase, double theCoeff)
+{
+  BuilderPtr aBuilder = SolveSpaceSolver_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;
+  Slvs_Param aParam1 = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID, aMidPoint->x());
+  aParam1.h = addParameter(aParam1);
+  aParameters.push_back(ParameterWrapperPtr(new SolveSpaceSolver_ParameterWrapper(aParam1)));
+  Slvs_Param aParam2 = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID, aMidPoint->y());
+  aParam2.h = addParameter(aParam2);
+  aParameters.push_back(ParameterWrapperPtr(new SolveSpaceSolver_ParameterWrapper(aParam2)));
+  // Create entity (parameters are not filled)
+  Slvs_Entity anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID,
+      (Slvs_hEntity)myWorkplaneID, aParam1.h, aParam2.h);
+  anEntity.h = addEntity(anEntity);
+
+  EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(AttributePtr(), anEntity));
+  aResult->setParameters(aParameters);
+  return aResult;
+}
+
+
+
+
+
+
+Slvs_hParam SolveSpaceSolver_Storage::addParameter(const Slvs_Param& theParam)
+{
+  if (theParam.h > 0 && theParam.h <= myParamMaxID) {
+    // parameter is already used, rewrite it
+    return updateParameter(theParam);
+  }
+
+  Slvs_Param aParam = theParam;
+  if (aParam.h > myParamMaxID)
+    myParamMaxID = aParam.h;
+  else
+    aParam.h = ++myParamMaxID;
+  myParameters.push_back(aParam);
+  myNeedToResolve = true;
+  return aParam.h;
+}
+
+Slvs_hParam SolveSpaceSolver_Storage::updateParameter(const Slvs_Param& theParam)
+{
+  if (theParam.h > 0 && theParam.h <= myParamMaxID) {
+    // parameter already used, rewrite it
+    int aPos = Search(theParam.h, myParameters);
+    if (aPos >= 0 && aPos < (int)myParameters.size()) {
+      if (IsNotEqual(myParameters[aPos], theParam)) {
+        myUpdatedParameters.insert(theParam.h);
+        setNeedToResolve(true);
+      }
+      myParameters[aPos] = theParam;
+      return theParam.h;
+    }
+  }
+
+  // Parameter is not found, add new one
+  Slvs_Param aParam = theParam;
+  aParam.h = 0;
+  return addParameter(aParam);
+}
+
+bool SolveSpaceSolver_Storage::removeParameter(const Slvs_hParam& theParamID)
+{
+  int aPos = Search(theParamID, myParameters);
+  if (aPos >= 0 && aPos < (int)myParameters.size()) {
+    // Firstly, search the parameter is not used elsewhere
+    std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+    for (; anEntIter != myEntities.end(); anEntIter++) {
+      for (int i = 0; i < 4; i++)
+        if (anEntIter->param[i] == theParamID)
+          return false;
+    }
+    // Remove parameter
+    myParameters.erase(myParameters.begin() + aPos);
+    myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h;
+    myNeedToResolve = true;
+  }
+  return true;
+}
+
+const Slvs_Param& SolveSpaceSolver_Storage::getParameter(const Slvs_hParam& theParamID) const
+{
+  int aPos = Search(theParamID, myParameters);
+  if (aPos >= 0 && aPos < (int)myParameters.size())
+    return myParameters[aPos];
+
+  // Parameter is not found, return empty object
+  static Slvs_Param aDummy;
+  aDummy.h = 0;
+  return aDummy;
+}
+
+
+Slvs_hEntity SolveSpaceSolver_Storage::addEntity(const Slvs_Entity& theEntity)
+{
+  if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
+    // Entity is already used, rewrite it
+    return updateEntity(theEntity);
+  }
+
+  Slvs_Entity aEntity = theEntity;
+  if (aEntity.h > myEntityMaxID)
+    myEntityMaxID = aEntity.h;
+  else
+    aEntity.h = ++myEntityMaxID;
+  myEntities.push_back(aEntity);
+  myNeedToResolve = true;
+  return aEntity.h;
+}
+
+Slvs_hEntity SolveSpaceSolver_Storage::updateEntity(const Slvs_Entity& theEntity)
+{
+  if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
+    // Entity already used, rewrite it
+    int aPos = Search(theEntity.h, myEntities);
+    if (aPos >= 0 && aPos < (int)myEntities.size()) {
+      myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity);
+      myEntities[aPos] = theEntity;
+      return theEntity.h;
+    }
+  }
+
+  // Entity is not found, add new one
+  Slvs_Entity aEntity = theEntity;
+  aEntity.h = 0;
+  return addEntity(aEntity);
+}
+
+bool SolveSpaceSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
+{
+  bool aResult = true;
+  int aPos = Search(theEntityID, myEntities);
+  if (aPos >= 0 && aPos < (int)myEntities.size()) {
+    // Firstly, check the entity and its attributes is not used elsewhere
+    std::set<Slvs_hEntity> anEntAndSubs;
+    anEntAndSubs.insert(theEntityID);
+    for (int i = 0; i < 4; i++)
+      if (myEntities[aPos].point[i] != SLVS_E_UNKNOWN)
+        anEntAndSubs.insert(myEntities[aPos].point[i]);
+
+    std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+    for (; anEntIter != myEntities.end(); anEntIter++) {
+      if (anEntAndSubs.find(anEntIter->h) != anEntAndSubs.end())
+        continue;
+      for (int i = 0; i < 4; i++)
+        if (anEntAndSubs.find(anEntIter->point[i]) != anEntAndSubs.end())
+          return false;
+      if (anEntAndSubs.find(anEntIter->distance) != anEntAndSubs.end())
+        return false;
+    }
+    std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+    for (; aConstrIter != myConstraints.end(); aConstrIter++) {
+      Slvs_hEntity anEntIDs[6] = {aConstrIter->ptA, aConstrIter->ptB,
+          aConstrIter->entityA, aConstrIter->entityB,
+          aConstrIter->entityC, aConstrIter->entityD};
+      for (int i = 0; i < 6; i++)
+        if (anEntAndSubs.find(anEntIDs[i]) != anEntAndSubs.end())
+          return false;
+    }
+    // The entity is not used, remove it and its parameters
+    Slvs_Entity anEntity = myEntities[aPos];
+    myEntities.erase(myEntities.begin() + aPos);
+    myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
+    if (anEntity.distance != SLVS_E_UNKNOWN)
+      aResult = aResult && removeParameter(anEntity.distance);
+    for (int i = 0; i < 4; i++)
+      if (anEntity.param[i] != SLVS_E_UNKNOWN)
+        aResult = removeParameter(anEntity.param[i]) && aResult;
+    for (int i = 0; i < 4; i++)
+      if (anEntity.point[i] != SLVS_E_UNKNOWN)
+        aResult = removeEntity(anEntity.point[i]) && aResult;
+    myNeedToResolve = true;
+  }
+  return aResult;
+}
+
+void SolveSpaceSolver_Storage::removeUnusedEntities()
+{
+  std::set<Slvs_hEntity> anUnusedEntities;
+  std::vector<Slvs_Entity>::const_iterator aEIt = myEntities.begin();
+  for (; aEIt != myEntities.end(); ++aEIt) {
+    if (aEIt->h == aEIt->wrkpl) {
+      // don't remove workplane
+      anUnusedEntities.erase(aEIt->point[0]);
+      anUnusedEntities.erase(aEIt->normal);
+      continue;
+    }
+    anUnusedEntities.insert(aEIt->h);
+  }
+
+  std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
+  for (; aCIt != myConstraints.end(); ++aCIt) {
+    Slvs_hEntity aSubs[6] = {
+        aCIt->entityA, aCIt->entityB,
+        aCIt->entityC, aCIt->entityD,
+        aCIt->ptA,     aCIt->ptB};
+    for (int i = 0; i < 6; i++) {
+      if (aSubs[i] != SLVS_E_UNKNOWN) {
+        anUnusedEntities.erase(aSubs[i]);
+        int aPos = Search(aSubs[i], myEntities);
+        if (aPos >= 0 && aPos < (int)myEntities.size()) {
+          for (int j = 0; j < 4; j++)
+            if (myEntities[aPos].point[j] != SLVS_E_UNKNOWN)
+              anUnusedEntities.erase(myEntities[aPos].point[j]);
+          if (myEntities[aPos].distance != SLVS_E_UNKNOWN)
+            anUnusedEntities.erase(myEntities[aPos].distance);
+        }
+      }
+    }
+  }
+
+  std::set<Slvs_hEntity>::const_iterator anEntIt = anUnusedEntities.begin();
+  while (anEntIt != anUnusedEntities.end()) {
+    int aPos = Search(*anEntIt, myEntities);
+    if (aPos < 0 && aPos >= (int)myEntities.size())
+      continue;
+    Slvs_Entity anEntity = myEntities[aPos];
+    // Remove entity if and only if all its parameters unused
+    bool isUsed = false;
+    if (anEntity.distance != SLVS_E_UNKNOWN && 
+      anUnusedEntities.find(anEntity.distance) == anUnusedEntities.end())
+      isUsed = true;
+    for (int i = 0; i < 4 && !isUsed; i++)
+      if (anEntity.point[i] != SLVS_E_UNKNOWN &&
+          anUnusedEntities.find(anEntity.point[i]) == anUnusedEntities.end())
+        isUsed = true;
+    if (isUsed) {
+      anUnusedEntities.erase(anEntity.distance);
+      for (int i = 0; i < 4; i++)
+        if (anEntity.point[i] != SLVS_E_UNKNOWN)
+          anUnusedEntities.erase(anEntity.point[i]);
+      std::set<Slvs_hEntity>::iterator aRemoveIt = anEntIt++;
+      anUnusedEntities.erase(aRemoveIt);
+      continue;
+    }
+    ++anEntIt;
+  }
+
+  for (anEntIt = anUnusedEntities.begin(); anEntIt != anUnusedEntities.end(); ++anEntIt) {
+    int aPos = Search(*anEntIt, myEntities);
+    if (aPos >= 0 && aPos < (int)myEntities.size()) {
+      // Remove entity and its parameters
+      Slvs_Entity anEntity = myEntities[aPos];
+      myEntities.erase(myEntities.begin() + aPos);
+      myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
+      if (anEntity.distance != SLVS_E_UNKNOWN)
+        removeParameter(anEntity.distance);
+      for (int i = 0; i < 4; i++)
+        if (anEntity.param[i] != SLVS_E_UNKNOWN)
+          removeParameter(anEntity.param[i]);
+      for (int i = 0; i < 4; i++)
+        if (anEntity.point[i] != SLVS_E_UNKNOWN)
+          removeEntity(anEntity.point[i]);
+    }
+  }
+
+  if (!anUnusedEntities.empty())
+    myNeedToResolve = true;
+}
+
+bool SolveSpaceSolver_Storage::isUsedByConstraints(const Slvs_hEntity& theEntityID) const
+{
+  std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
+  for (; aCIt != myConstraints.end(); ++aCIt) {
+    Slvs_hEntity aSubs[6] = {
+        aCIt->entityA, aCIt->entityB,
+        aCIt->entityC, aCIt->entityD,
+        aCIt->ptA,     aCIt->ptB};
+    for (int i = 0; i < 6; i++)
+      if (aSubs[i] != SLVS_E_UNKNOWN && aSubs[i] == theEntityID)
+        return true;
+  }
+  return false;
+}
+
+const Slvs_Entity& SolveSpaceSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const
+{
+  int aPos = Search(theEntityID, myEntities);
+  if (aPos >= 0 && aPos < (int)myEntities.size())
+    return myEntities[aPos];
+
+  // Entity is not found, return empty object
+  static Slvs_Entity aDummy;
+  aDummy.h = SLVS_E_UNKNOWN;
+  return aDummy;
+}
+
+Slvs_hEntity SolveSpaceSolver_Storage::copyEntity(const Slvs_hEntity& theCopied)
+{
+  int aPos = Search(theCopied, myEntities);
+  if (aPos < 0 || aPos >= (int)myEntities.size())
+    return SLVS_E_UNKNOWN;
+
+  Slvs_Entity aCopy = myEntities[aPos];
+  aCopy.h = SLVS_E_UNKNOWN;
+  int i = 0;
+  while (aCopy.point[i] != SLVS_E_UNKNOWN) {
+    aCopy.point[i] = copyEntity(aCopy.point[i]);
+    i++;
+  }
+  if (aCopy.param[0] != SLVS_E_UNKNOWN) {
+    aPos = Search(aCopy.param[0], myParameters);
+    i = 0;
+    while (aCopy.param[i] != SLVS_E_UNKNOWN) {
+      Slvs_Param aNewParam = myParameters[aPos];
+      aNewParam.h = SLVS_E_UNKNOWN;
+      aCopy.param[i] = addParameter(aNewParam);
+      i++;
+      aPos++;
+    }
+  }
+  return addEntity(aCopy);
+}
+
+void SolveSpaceSolver_Storage::copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo)
+{
+  int aPosFrom = Search(theFrom, myEntities);
+  int aPosTo = Search(theTo, myEntities);
+  if (aPosFrom < 0 || aPosFrom >= (int)myEntities.size() || 
+      aPosTo < 0 || aPosTo >= (int)myEntities.size())
+    return;
+
+  Slvs_Entity aEntFrom = myEntities[aPosFrom];
+  Slvs_Entity aEntTo = myEntities[aPosTo];
+  int i = 0;
+  while (aEntFrom.point[i] != SLVS_E_UNKNOWN) {
+    copyEntity(aEntFrom.point[i], aEntTo.point[i]);
+    i++;
+  }
+  if (aEntFrom.param[0] != SLVS_E_UNKNOWN) {
+    aPosFrom = Search(aEntFrom.param[0], myParameters);
+    aPosTo = Search(aEntTo.param[0], myParameters);
+    i = 0;
+    while (aEntFrom.param[i] != SLVS_E_UNKNOWN) {
+      myParameters[aPosTo++].val = myParameters[aPosFrom++].val;
+      i++;
+    }
+  }
+}
+
+
+bool SolveSpaceSolver_Storage::isPointFixed(
+    const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate) const
+{
+  // Search the set of coincident points
+  std::set<Slvs_hEntity> aCoincident;
+  aCoincident.insert(thePointID);
+
+  // Check whether one of coincident points is out-of-group
+  std::set<Slvs_hEntity>::const_iterator aCoincIt = aCoincident.begin();
+  for (; aCoincIt != aCoincident.end(); ++aCoincIt) {
+    Slvs_Entity aPoint = getEntity(*aCoincIt);
+    if (aPoint.group == SLVS_G_OUTOFGROUP)
+      return true;
+  }
+
+  // Search the Rigid constraint
+  theFixed = SLVS_C_UNKNOWN;
+  std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+  for (; aConstrIter != myConstraints.end(); aConstrIter++)
+    if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
+        aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
+      theFixed = aConstrIter->h;
+      if (aConstrIter->ptA == thePointID)
+        return true;
+    }
+  if (theFixed != SLVS_C_UNKNOWN)
+    return true;
+
+  if (theAccurate) {
+    // Try to find the fixed entity which uses such point or its coincidence
+    std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+    for (; anEntIter != myEntities.end(); anEntIter++) {
+      for (int i = 0; i < 4; i++) {
+        Slvs_hEntity aPt = anEntIter->point[i];
+        if (aPt != SLVS_E_UNKNOWN &&
+            (aPt == thePointID || aCoincident.find(aPt) != aCoincident.end())) {
+          if (isEntityFixed(anEntIter->h, true))
+            return true;
+        }
+      }
+    }
+  }
+  return SLVS_E_UNKNOWN;
+}
+
+bool SolveSpaceSolver_Storage::isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate) const
+{
+  int aPos = Search(theEntityID, myEntities);
+  if (aPos < 0 || aPos >= (int)myEntities.size())
+    return false;
+
+  // Firstly, find how many points are under Rigid constraint
+  int aNbFixed = 0;
+  for (int i = 0; i < 4; i++) {
+    Slvs_hEntity aPoint = myEntities[aPos].point[i];
+    if (aPoint == SLVS_E_UNKNOWN)
+      continue;
+
+    std::set<Slvs_hEntity> aCoincident;
+    aCoincident.insert(aPoint);
+
+    // Search the Rigid constraint
+    std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+    for (; aConstrIter != myConstraints.end(); aConstrIter++)
+      if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
+          aCoincident.find(aConstrIter->ptA) != aCoincident.end())
+        aNbFixed++;
+  }
+
+  std::list<Slvs_Constraint> aList;
+  std::list<Slvs_Constraint>::iterator anIt;
+  Slvs_hConstraint aTempID; // used in isPointFixed() method
+
+  if (myEntities[aPos].type == SLVS_E_LINE_SEGMENT) {
+    if (aNbFixed == 2)
+      return true;
+    else if (aNbFixed == 0 || !theAccurate)
+      return false;
+    // Additional check (the line may be fixed if it is used by different constraints):
+    // 1. The line is used in Equal constraint, another entity is fixed and there is a fixed point on line
+    aList = getConstraintsByType(SLVS_C_PT_ON_LINE);
+    for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+      if (anIt->entityA == theEntityID && isPointFixed(anIt->ptA, aTempID))
+        break;
+    if (anIt != aList.end()) {
+      aList = getConstraintsByType(SLVS_C_EQUAL_LENGTH_LINES);
+      aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
+      for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+        if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
+          Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
+          if (isEntityFixed(anOther, false))
+            return true;
+        }
+    }
+    // 2. The line is used in Parallel/Perpendicular/Vertical/Horizontal and Length constraints
+    aList = getConstraintsByType(SLVS_C_PARALLEL);
+    aList.splice(aList.end(), getConstraintsByType(SLVS_C_PERPENDICULAR));
+    aList.splice(aList.end(), getConstraintsByType(SLVS_C_VERTICAL));
+    aList.splice(aList.end(), getConstraintsByType(SLVS_C_HORIZONTAL));
+    for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+      if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
+        Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
+        if (isEntityFixed(anOther, false))
+          break;
+      }
+    if (anIt != aList.end()) {
+      aList = getConstraintsByType(SLVS_C_PT_PT_DISTANCE);
+      for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+        if ((anIt->ptA == myEntities[aPos].point[0] && anIt->ptB == myEntities[aPos].point[1]) ||
+            (anIt->ptA == myEntities[aPos].point[1] && anIt->ptB == myEntities[aPos].point[0]))
+          return true;
+    }
+    // 3. Another verifiers ...
+  } else if (myEntities[aPos].type == SLVS_E_CIRCLE) {
+    if (aNbFixed == 0)
+      return false;
+    // Search for Diameter constraint
+    aList = getConstraintsByType(SLVS_C_DIAMETER);
+    for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+      if (anIt->entityA == theEntityID)
+        return true;
+    if (!theAccurate)
+      return false;
+    // Additional check (the circle may be fixed if it is used by different constraints):
+    // 1. The circle is used in Equal constraint and another entity is fixed
+    aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
+    for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+      if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
+        Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
+        if (isEntityFixed(anOther, false))
+          return true;
+      }
+    // 2. Another verifiers ...
+  } else if (myEntities[aPos].type == SLVS_E_ARC_OF_CIRCLE) {
+    if (aNbFixed > 2)
+      return true;
+    else if (aNbFixed <= 1)
+      return false;
+    // Search for Diameter constraint
+    aList = getConstraintsByType(SLVS_C_DIAMETER);
+    for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+      if (anIt->entityA == theEntityID)
+        return true;
+    if (!theAccurate)
+      return false;
+    // Additional check (the arc may be fixed if it is used by different constraints):
+    // 1. The arc is used in Equal constraint and another entity is fixed
+    aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
+    aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
+    for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+      if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
+        Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
+        if (isEntityFixed(anOther, false))
+          return true;
+      }
+    // 2. Another verifiers ...
+  }
+  return false;
+}
+
+
+Slvs_hConstraint SolveSpaceSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
+{
+  if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
+    // Constraint is already used, rewrite it
+    return updateConstraint(theConstraint);
+  }
+
+  Slvs_Constraint aConstraint = theConstraint;
+
+  // Find a constraint with same type uses same arguments to show user overconstraint situation
+  std::vector<Slvs_Constraint>::iterator aCIt = myConstraints.begin();
+  for (; aCIt != myConstraints.end(); aCIt++) {
+    if (aConstraint.type != aCIt->type)
+      continue;
+    if (aConstraint.ptA == aCIt->ptA && aConstraint.ptB == aCIt->ptB &&
+        aConstraint.entityA == aCIt->entityA && aConstraint.entityB == aCIt->entityB &&
+        aConstraint.entityC == aCIt->entityC && aConstraint.entityD == aCIt->entityD)
+      myDuplicatedConstraint = true;
+  }
+
+  if (aConstraint.h > myConstrMaxID)
+    myConstrMaxID = aConstraint.h;
+  else
+    aConstraint.h = ++myConstrMaxID;
+  myConstraints.push_back(aConstraint);
+  myNeedToResolve = true;
+  return aConstraint.h;
+}
+
+Slvs_hConstraint SolveSpaceSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint)
+{
+  if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
+    // Constraint already used, rewrite it
+    int aPos = Search(theConstraint.h, myConstraints);
+    if (aPos >= 0 && aPos < (int)myConstraints.size()) {
+      myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint);
+      myConstraints[aPos] = theConstraint;
+      return theConstraint.h;
+    }
+  }
+
+  // Constraint is not found, add new one
+  Slvs_Constraint aConstraint = theConstraint;
+  aConstraint.h = 0;
+  return addConstraint(aConstraint);
+}
+
+bool SolveSpaceSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID)
+{
+  bool aResult = true;
+  int aPos = Search(theConstraintID, myConstraints);
+  if (aPos >= 0 && aPos < (int)myConstraints.size()) {
+    Slvs_Constraint aConstraint = myConstraints[aPos];
+    myConstraints.erase(myConstraints.begin() + aPos);
+    myConstrMaxID = myConstraints.empty() ? SLVS_E_UNKNOWN : myConstraints.back().h;
+    myNeedToResolve = true;
+
+    // Remove all entities
+    Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB,
+        aConstraint.entityA, aConstraint.entityB,
+        aConstraint.entityC, aConstraint.entityD};
+    for (int i = 0; i < 6; i++)
+      if (anEntities[i] != SLVS_E_UNKNOWN)
+        aResult = removeEntity(anEntities[i]) && aResult;
+    // remove temporary fixed point, if available
+    if (myFixed == theConstraintID)
+      myFixed = SLVS_E_UNKNOWN;
+    if (myDuplicatedConstraint) {
+      // Check the duplicated constraints are still available
+      myDuplicatedConstraint = false;
+      std::vector<Slvs_Constraint>::const_iterator anIt1 = myConstraints.begin();
+      std::vector<Slvs_Constraint>::const_iterator anIt2 = myConstraints.begin();
+      for (; anIt1 != myConstraints.end() && !myDuplicatedConstraint; anIt1++)
+        for (anIt2 = anIt1+1; anIt2 != myConstraints.end() && !myDuplicatedConstraint; anIt2++) {
+          if (anIt1->type != anIt2->type)
+            continue;
+          if (anIt1->ptA == anIt2->ptA && anIt1->ptB == anIt2->ptB &&
+              anIt1->entityA == anIt2->entityA && anIt1->entityB == anIt2->entityB &&
+              anIt1->entityC == anIt2->entityC && anIt1->entityD == anIt2->entityD)
+            myDuplicatedConstraint = true;
+        }
+    }
+  }
+  return aResult;
+}
+
+const Slvs_Constraint& SolveSpaceSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const
+{
+  int aPos = Search(theConstraintID, myConstraints);
+  if (aPos >= 0 && aPos < (int)myConstraints.size())
+    return myConstraints[aPos];
+
+  // Constraint is not found, return empty object
+  static Slvs_Constraint aDummy;
+  aDummy.h = 0;
+  return aDummy;
+}
+
+std::list<Slvs_Constraint> SolveSpaceSolver_Storage::getConstraintsByType(int theConstraintType) const
+{
+  std::list<Slvs_Constraint> aResult;
+  std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
+  for (; aCIter != myConstraints.end(); aCIter++)
+    if (aCIter->type == theConstraintType)
+      aResult.push_back(*aCIter);
+  return aResult;
+}
+
+
+void SolveSpaceSolver_Storage::addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID)
+{
+  if (myFixed != SLVS_E_UNKNOWN)
+    return; // the point is already fixed
+  int aPos = Search(theConstraintID, myConstraints);
+  if (aPos >= 0 && aPos < (int)myConstraints.size())
+    myFixed = theConstraintID;
+}
+
+void SolveSpaceSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
+{
+  myTemporaryConstraints.insert(theConstraintID);
+}
+
+void SolveSpaceSolver_Storage::removeAllTemporary()
+{
+  myTemporaryConstraints.clear();
+}
+
+size_t SolveSpaceSolver_Storage::removeTemporary(size_t theNbConstraints)
+{
+  if (myTemporaryConstraints.empty())
+    return 0;
+  // Search the point-on-line or a non-rigid constraint
+  std::set<Slvs_hConstraint>::iterator aCIt = myTemporaryConstraints.begin();
+  for (; aCIt != myTemporaryConstraints.end(); aCIt++) {
+    int aPos = Search(*aCIt, myConstraints);
+    if (aPos >= (int)myConstraints.size() || myConstraints[aPos].type != SLVS_C_WHERE_DRAGGED)
+      break;
+    std::vector<Slvs_Constraint>::iterator anIt = myConstraints.begin();
+    for (; anIt != myConstraints.end(); anIt++)
+      if (anIt->type == SLVS_C_PT_ON_LINE && anIt->ptA == myConstraints[aPos].ptA)
+        break;
+    if (anIt != myConstraints.end())
+      break;
+  }
+  if (aCIt == myTemporaryConstraints.end())
+    aCIt = myTemporaryConstraints.begin();
+  bool aNewFixed = false;
+
+  size_t aNbRemain = theNbConstraints;
+  while (aNbRemain > 0 && aCIt != myTemporaryConstraints.end()) {
+    aNewFixed = aNewFixed || (*aCIt == myFixed);
+    --aNbRemain;
+
+    std::set<Slvs_hConstraint>::iterator aRemoveIt = aCIt++;
+    removeConstraint(*aRemoveIt);
+    myTemporaryConstraints.erase(aRemoveIt);
+    if (aCIt == myTemporaryConstraints.end())
+      aCIt = myTemporaryConstraints.begin();
+  }
+
+  if (aNewFixed) {
+    for (aCIt = myTemporaryConstraints.begin(); aCIt != myTemporaryConstraints.end(); aCIt++) {
+      int aPos = Search(*aCIt, myConstraints);
+      if (myConstraints[aPos].type == SLVS_C_WHERE_DRAGGED) {
+        myFixed = *aCIt;
+        break;
+      }
+    }
+  }
+  return myTemporaryConstraints.size();
+}
+
+bool SolveSpaceSolver_Storage::isTemporary(const Slvs_hConstraint& theConstraintID) const
+{
+  return myTemporaryConstraints.find(theConstraintID) != myTemporaryConstraints.end();
+}
+
+
+
+void SolveSpaceSolver_Storage::initializeSolver(SolverPtr theSolver)
+{
+  std::shared_ptr<SolveSpaceSolver_Solver> aSolver =
+      std::dynamic_pointer_cast<SolveSpaceSolver_Solver>(theSolver);
+  if (!aSolver)
+    return;
+
+  if (myConstraints.empty()) {
+    // Adjust all arc to place their points correctly
+    std::vector<Slvs_Entity>::const_iterator anEntIt = myEntities.begin();
+    for (; anEntIt != myEntities.end(); ++anEntIt)
+      if (anEntIt->type == SLVS_E_ARC_OF_CIRCLE)
+        adjustArc(*anEntIt);
+  }
+
+  aSolver->setParameters(myParameters.data(), (int)myParameters.size());
+  aSolver->setEntities(myEntities.data(), (int)myEntities.size());
+
+  // Copy constraints excluding the fixed one
+  std::vector<Slvs_Constraint> aConstraints = myConstraints;
+  if (myFixed != SLVS_E_UNKNOWN) {
+    Slvs_hEntity aFixedPoint = SLVS_E_UNKNOWN;
+    std::vector<Slvs_Constraint>::iterator anIt = aConstraints.begin();
+    for (; anIt != aConstraints.end(); anIt++)
+      if (anIt->h == myFixed) {
+        aFixedPoint = anIt->ptA;
+        aConstraints.erase(anIt);
+        break;
+      }
+    // set dragged parameters
+    int aPos = Search(aFixedPoint, myEntities);
+    aSolver->setDraggedParameters(myEntities[aPos].param);
+  }
+  aSolver->setConstraints(aConstraints.data(), (int)aConstraints.size());
+}
+
+
+bool SolveSpaceSolver_Storage::isEqual(
+    const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const
+{
+  // Precise checking of coincidence: verify that points have equal coordinates
+  int aEnt1Pos = Search(thePoint1, myEntities);
+  int aEnt2Pos = Search(thePoint2, myEntities);
+  if (aEnt1Pos >= 0 && aEnt1Pos < (int)myEntities.size() &&
+      aEnt2Pos >= 0 && aEnt2Pos < (int)myEntities.size()) {
+    double aDist[2];
+    int aParamPos;
+    for (int i = 0; i < 2; i++) {
+      aParamPos = Search(myEntities[aEnt1Pos].param[i], myParameters);
+      aDist[i] = myParameters[aParamPos].val;
+      aParamPos = Search(myEntities[aEnt2Pos].param[i], myParameters);
+      aDist[i] -= myParameters[aParamPos].val;
+    }
+    if (aDist[0] * aDist[0] + aDist[1] * aDist[1] < tolerance * tolerance)
+      return true;
+  }
+  return false;
+}
+
+
+std::vector<Slvs_hConstraint> SolveSpaceSolver_Storage::fixEntity(const Slvs_hEntity& theEntity)
+{
+  std::vector<Slvs_hConstraint> aNewConstraints;
+
+  int aPos = Search(theEntity, myEntities);
+  if (aPos >= 0 && aPos < (int)myEntities.size()) {
+    switch (myEntities[aPos].type) {
+    case SLVS_E_POINT_IN_2D:
+    case SLVS_E_POINT_IN_3D:
+      fixPoint(myEntities[aPos], aNewConstraints);
+      break;
+    case SLVS_E_LINE_SEGMENT:
+      fixLine(myEntities[aPos], aNewConstraints);
+      break;
+    case SLVS_E_CIRCLE:
+      fixCircle(myEntities[aPos], aNewConstraints);
+      break;
+    case SLVS_E_ARC_OF_CIRCLE:
+      fixArc(myEntities[aPos], aNewConstraints);
+      break;
+    default:
+      break;
+    }
+  }
+
+  return aNewConstraints;
+}
+
+void SolveSpaceSolver_Storage::fixPoint(const Slvs_Entity& thePoint,
+    std::vector<Slvs_hConstraint>& theCreated)
+{
+  Slvs_Constraint aConstraint;
+  Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN;
+  bool isFixed = isPointFixed(thePoint.h, aConstrID, true);
+  bool isForceUpdate = (isFixed && isTemporary(aConstrID));
+  if (!isForceUpdate) { // create new constraint
+    if (isFixed) return;
+    aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, thePoint.group, SLVS_C_WHERE_DRAGGED, thePoint.wrkpl,
+        0.0, thePoint.h, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+    aConstraint.h = addConstraint(aConstraint);
+    theCreated.push_back(aConstraint.h);
+  } else { // update already existent constraint
+    if (!isFixed || aConstrID == SLVS_E_UNKNOWN)
+      return;
+    int aPos = Search(aConstrID, myConstraints);
+    if (aPos >= 0 && aPos < (int)myConstraints.size())
+      myConstraints[aPos].ptA = thePoint.h;
+  }
+}
+
+void SolveSpaceSolver_Storage::fixLine(const Slvs_Entity& theLine,
+    std::vector<Slvs_hConstraint>& theCreated)
+{
+  Slvs_Entity aPoint[2] = {
+      getEntity(theLine.point[0]),
+      getEntity(theLine.point[1])
+  };
+
+  Slvs_Constraint anEqual;
+  if (isAxisParallel(theLine.h)) {
+    // Fix one point and a line length
+    Slvs_hConstraint aFixed;
+    if (!isPointFixed(theLine.point[0], aFixed, true) &&
+        !isPointFixed(theLine.point[1], aFixed, true))
+      fixPoint(aPoint[0], theCreated);
+    if (!isUsedInEqual(theLine.h, anEqual)) {
+      // Check the distance is not set yet
+      std::vector<Slvs_Constraint>::const_iterator aDistIt = myConstraints.begin();
+      for (; aDistIt != myConstraints.end(); ++aDistIt)
+        if ((aDistIt->type == SLVS_C_PT_PT_DISTANCE) &&
+           ((aDistIt->ptA == theLine.point[0] && aDistIt->ptB == theLine.point[1]) ||
+            (aDistIt->ptA == theLine.point[1] && aDistIt->ptB == theLine.point[0])))
+          return;
+      // Calculate distance between points on the line
+      double aCoords[4];
+      for (int i = 0; i < 2; i++)
+        for (int j = 0; j < 2; j++) {
+          Slvs_Param aParam = getParameter(aPoint[i].param[j]);
+          aCoords[2*i+j] = aParam.val;
+        }
+
+      double aLength = sqrt((aCoords[2] - aCoords[0]) * (aCoords[2] - aCoords[0]) + 
+                            (aCoords[3] - aCoords[1]) * (aCoords[3] - aCoords[1]));
+      // fix line length
+      Slvs_Constraint aDistance = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group,
+          SLVS_C_PT_PT_DISTANCE, theLine.wrkpl, aLength,
+          theLine.point[0], theLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+      aDistance.h = addConstraint(aDistance);
+      theCreated.push_back(aDistance.h);
+    }
+    return;
+  }
+  else if (isUsedInEqual(theLine.h, anEqual)) {
+    // Check another entity of Equal is already fixed
+    Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA;
+    if (isEntityFixed(anOtherEntID, true)) {
+      // Fix start point of the line (if end point is not fixed yet) ...
+      Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN;
+      bool isFixed = isPointFixed(theLine.point[1], anEndFixedID, true);
+      if (isFixed == SLVS_E_UNKNOWN)
+        fixPoint(aPoint[0], theCreated);
+      // ...  and create fixed point lying on this line
+      Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0];
+      // Firstly, search already fixed point on line
+      bool isPonLineFixed = false;
+      Slvs_hEntity aFixedPoint;
+      std::vector<Slvs_Constraint>::const_iterator aPLIter = myConstraints.begin();
+      for (; aPLIter != myConstraints.end() && !isPonLineFixed; ++aPLIter)
+        if (aPLIter->type == SLVS_C_PT_ON_LINE && aPLIter->entityA == theLine.h) {
+          isPonLineFixed = isPointFixed(aPLIter->ptA, anEndFixedID);
+          aFixedPoint = aPLIter->ptA;
+        }
+
+      if (isPonLineFixed) { // update existent constraint
+        copyEntity(aPointToCopy, aFixedPoint);
+      } else { // create new constraint
+        Slvs_hEntity aCopied = copyEntity(aPointToCopy);
+        Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group, SLVS_C_PT_ON_LINE,
+            theLine.wrkpl, 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN);
+        aPonLine.h = addConstraint(aPonLine);
+        theCreated.push_back(aPonLine.h);
+        fixPoint(getEntity(aCopied), theCreated);
+      }
+      return;
+    }
+  }
+
+  // Fix both points
+  for (int i = 0; i < 2; i++)
+    fixPoint(aPoint[i], theCreated);
+}
+
+void SolveSpaceSolver_Storage::fixCircle(const Slvs_Entity& theCircle,
+    std::vector<Slvs_hConstraint>& theCreated)
+{
+  bool isFixRadius = true;
+  // Verify the arc is under Equal constraint
+  Slvs_Constraint anEqual;
+  if (isUsedInEqual(theCircle.h, anEqual)) {
+    // Check another entity of Equal is already fixed
+    Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA;
+    if (isEntityFixed(anOtherEntID, true))
+      isFixRadius = false;
+  }
+
+  fixPoint(getEntity(theCircle.point[0]), theCreated);
+
+  if (isFixRadius) {
+    // Search the radius is already fixed
+    std::vector<Slvs_Constraint>::const_iterator aDiamIter = myConstraints.begin();
+    for (; aDiamIter != myConstraints.end(); ++aDiamIter)
+      if (aDiamIter->type == SLVS_C_DIAMETER && aDiamIter->entityA == theCircle.h)
+        return;
+
+    // Fix radius of a circle
+    const Slvs_Entity& aRadEnt = getEntity(theCircle.distance);
+    double aRadius = getParameter(aRadEnt.param[0]).val;
+    Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theCircle.group, SLVS_C_DIAMETER,
+        theCircle.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theCircle.h, SLVS_E_UNKNOWN);
+    aFixedR.h = addConstraint(aFixedR);
+    theCreated.push_back(aFixedR.h);
+  }
+}
+
+void SolveSpaceSolver_Storage::fixArc(const Slvs_Entity& theArc,
+    std::vector<Slvs_hConstraint>& theCreated)
+{
+  Slvs_Entity aPoint[3] = {
+      getEntity(theArc.point[0]),
+      getEntity(theArc.point[1]),
+      getEntity(theArc.point[2])
+  };
+
+  bool isFixRadius = true;
+  std::list<Slvs_Entity> aPointsToFix;
+  aPointsToFix.push_back(aPoint[1]);
+  aPointsToFix.push_back(aPoint[2]);
+
+  // Verify the arc is under Equal constraint
+  Slvs_Constraint anEqual;
+  if (isUsedInEqual(theArc.h, anEqual)) {
+    // Check another entity of Equal is already fixed
+    Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA;
+    if (isEntityFixed(anOtherEntID, true)) {
+      isFixRadius = false;
+      Slvs_Entity anOtherEntity = getEntity(anOtherEntID);
+      if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) {
+        aPointsToFix.pop_back();
+        aPointsToFix.push_back(aPoint[0]);
+      }
+    }
+  }
+
+  Slvs_hConstraint aConstrID;
+  int aNbPointsToFix = 2; // number of fixed points for the arc
+  if (isPointFixed(theArc.point[0], aConstrID, true))
+    aNbPointsToFix--;
+
+  double anArcPoints[3][2];
+  for (int i = 0; i < 3; i++) {
+    const Slvs_Entity& aPointOnArc = getEntity(theArc.point[i]);
+    for (int j = 0; j < 2; j++)
+      anArcPoints[i][j] = getParameter(aPointOnArc.param[j]).val;
+  }
+
+  // Radius of the arc
+  std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(anArcPoints[0][0], anArcPoints[0][1]));
+  std::shared_ptr<GeomAPI_Pnt2d> aStart(new GeomAPI_Pnt2d(anArcPoints[1][0], anArcPoints[1][1]));
+  double aRadius = aCenter->distance(aStart);
+
+  // Update end point of the arc to be on a curve
+  std::shared_ptr<GeomAPI_Pnt2d> anEnd(new GeomAPI_Pnt2d(anArcPoints[2][0], anArcPoints[2][1]));
+  double aDistance = anEnd->distance(aCenter);
+  std::shared_ptr<GeomAPI_XY> aDir = anEnd->xy()->decreased(aCenter->xy());
+  if (aDistance < tolerance)
+    aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0);
+  else
+    aDir = aDir->multiplied(aRadius / aDistance);
+  double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()};
+  const Slvs_Entity& aEndPoint = getEntity(theArc.point[2]);
+  for (int i = 0; i < 2; i++) {
+    Slvs_Param aParam = getParameter(aEndPoint.param[i]);
+    aParam.val = xy[i];
+    updateParameter(aParam);
+  }
+
+  std::list<Slvs_Entity>::iterator aPtIt = aPointsToFix.begin();
+  for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--)
+    fixPoint(*aPtIt, theCreated);
+
+  if (isFixRadius) {
+    // Fix radius of the arc
+    bool isExists = false;
+    std::vector<Slvs_Constraint>::iterator anIt = myConstraints.begin();
+    for (; anIt != myConstraints.end() && !isExists; ++anIt)
+      if (anIt->type == SLVS_C_DIAMETER && anIt->entityA == theArc.h)
+        isExists = true;
+    if (!isExists) {
+      Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theArc.group, SLVS_C_DIAMETER,
+          theArc.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theArc.h, SLVS_E_UNKNOWN);
+      aFixedR.h = addConstraint(aFixedR);
+      theCreated.push_back(aFixedR.h);
+    }
+  }
+}
+
+
+bool SolveSpaceSolver_Storage::isAxisParallel(const Slvs_hEntity& theEntity) const
+{
+  std::vector<Slvs_Constraint>::const_iterator anIter = myConstraints.begin();
+  for (; anIter != myConstraints.end(); anIter++)
+    if ((anIter->type == SLVS_C_HORIZONTAL || anIter->type == SLVS_C_VERTICAL) && 
+        anIter->entityA == theEntity)
+      return true;
+  return false;
+}
+
+bool SolveSpaceSolver_Storage::isUsedInEqual(
+    const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const
+{
+  // Check the entity is used in Equal constraint
+  std::vector<Slvs_Constraint>::const_iterator anEqIter = myConstraints.begin();
+  for (; anEqIter != myConstraints.end(); anEqIter++)
+    if ((anEqIter->type == SLVS_C_EQUAL_LENGTH_LINES ||
+         anEqIter->type == SLVS_C_EQUAL_LINE_ARC_LEN ||
+         anEqIter->type == SLVS_C_EQUAL_RADIUS) &&
+       (anEqIter->entityA == theEntity || anEqIter->entityB == theEntity)) {
+      theEqual = *anEqIter;
+      return true;
+    }
+  return false;
+}
+
+void SolveSpaceSolver_Storage::setTemporary(ConstraintPtr theConstraint)
+{
+  // TODO
+}
+
+bool SolveSpaceSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
+{
+  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::iterator
+      aFound = myConstraintMap.find(theConstraint);
+  if (aFound == myConstraintMap.end())
+    return true; // no constraint, already deleted
+
+  // Remove constraint
+  std::list<ConstraintWrapperPtr> aConstrList = aFound->second;
+  myConstraintMap.erase(aFound);
+  // Remove SolveSpace constraints
+  bool isFullyRemoved = true;
+  std::list<ConstraintWrapperPtr>::iterator anIt = aConstrList.begin();
+  while (anIt != aConstrList.end()) {
+    if (remove(*anIt)) {
+      std::list<ConstraintWrapperPtr>::iterator aRemoveIt = anIt++;
+      aConstrList.erase(aRemoveIt);
+    } else {
+      isFullyRemoved = false;
+      ++anIt;
+    }
+  }
+  if (!isFullyRemoved)
+    myConstraintMap[theConstraint] = aConstrList;
+  return isFullyRemoved;
+}
+
+template <class ENT_TYPE>
+static bool isUsed(ConstraintWrapperPtr theConstraint, ENT_TYPE theEntity)
+{
+  std::list<EntityWrapperPtr>::const_iterator anEntIt = theConstraint->entities().begin();
+  for (; anEntIt != theConstraint->entities().end(); ++anEntIt)
+    if (std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anEntIt)->isBase(theEntity))
+      return true;
+  return false;
+}
+
+static bool isUsed(EntityWrapperPtr theFeature, AttributePtr theSubEntity)
+{
+  std::list<EntityWrapperPtr>::const_iterator aSubIt = theFeature->subEntities().begin();
+  for (; aSubIt != theFeature->subEntities().end(); ++aSubIt)
+    if (std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*aSubIt)->isBase(theSubEntity))
+      return true;
+  return false;
+}
+
+bool SolveSpaceSolver_Storage::isUsed(FeaturePtr theFeature) const
+{
+  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+      aCIt = myConstraintMap.begin();
+  std::list<ConstraintWrapperPtr>::const_iterator aCWIt;
+  for (; aCIt != myConstraintMap.end(); ++aCIt)
+    for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt)
+      if (::isUsed(*aCWIt, theFeature))
+        return true;
+  // check attributes
+  std::list<AttributePtr> anAttrList = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
+  std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
+  for (; anIt != anAttrList.end(); ++anIt)
+    if (isUsed(*anIt))
+      return true;
+  return false;
+}
+
+bool SolveSpaceSolver_Storage::isUsed(AttributePtr theAttribute) const
+{
+  AttributePtr anAttribute = theAttribute;
+  AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
+  if (aRefAttr) {
+    if (aRefAttr->isObject())
+      return isUsed(ModelAPI_Feature::feature(aRefAttr->object()));
+    else
+      anAttribute = aRefAttr->attr();
+  }
+
+  std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+      aCIt = myConstraintMap.begin();
+  std::list<ConstraintWrapperPtr>::const_iterator aCWIt;
+  for (; aCIt != myConstraintMap.end(); ++aCIt)
+    for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt)
+      if (::isUsed(*aCWIt, anAttribute))
+        return true;
+  return false;
+}
+
+
+bool SolveSpaceSolver_Storage::removeEntity(FeaturePtr theFeature)
+{
+  std::map<FeaturePtr, EntityWrapperPtr>::iterator aFound = myFeatureMap.find(theFeature);
+  if (aFound == myFeatureMap.end())
+    return false; // feature not found, nothing to delete
+
+  // Check the feature is not used by constraints
+  if (isUsed(theFeature))
+    return false; // the feature is used, don't remove it
+
+  // Remove feature
+  EntityWrapperPtr anEntity = aFound->second;
+  myFeatureMap.erase(aFound);
+  if (remove(anEntity))
+    return true;
+  // feature is not removed, revert operation
+  myFeatureMap[theFeature] = anEntity;
+  return false;
+}
+
+bool SolveSpaceSolver_Storage::removeEntity(AttributePtr theAttribute)
+{
+  std::map<AttributePtr, EntityWrapperPtr>::iterator aFound = myAttributeMap.find(theAttribute);
+  if (aFound == myAttributeMap.end())
+    return false; // attribute not found, nothing to delete
+
+  // Check the attribute is not used by constraints
+  if (isUsed(theAttribute))
+    return false; // the attribute is used, don't remove it
+  // Check the attribute is not used by other features
+  std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
+  for (; aFIt != myFeatureMap.end(); ++aFIt)
+    if (::isUsed(aFIt->second, theAttribute)) // the attribute is used, don't remove it
+      return false;
+
+  // Remove attribute
+  EntityWrapperPtr anEntity = aFound->second;
+  myAttributeMap.erase(aFound);
+  if (remove(anEntity))
+    return true;
+  // attribute is not removed, revert operation
+  myAttributeMap[theAttribute] = anEntity;
+  return false;
+}
+
+
+bool SolveSpaceSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
+{
+  std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
+      std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
+
+  // verify whether the constraint has duplicated
+  SameConstraintMap::iterator anEqIt = myEqualConstraints.begin();
+  for (; anEqIt != myEqualConstraints.end(); ++anEqIt)
+    if (anEqIt->find(aConstraint) != anEqIt->end()) {
+      anEqIt->erase(aConstraint);
+      break;
+    }
+  if (anEqIt != myEqualConstraints.end())
+    return true;
+
+  bool isFullyRemoved = removeConstraint((Slvs_hConstraint)aConstraint->id());
+
+  std::list<EntityWrapperPtr>::const_iterator anIt = aConstraint->entities().begin();
+  for (; anIt != aConstraint->entities().end(); ++anIt) {
+    std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity = 
+        std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
+    FeaturePtr aBaseFeature = anEntity->baseFeature();
+    if (aBaseFeature)
+      isFullyRemoved = removeEntity(aBaseFeature) && isFullyRemoved;
+    else
+      isFullyRemoved = removeEntity(anEntity->baseAttribute()) && isFullyRemoved;
+  }
+
+  return isFullyRemoved;
+}
+
+bool SolveSpaceSolver_Storage::remove(EntityWrapperPtr theEntity)
+{
+  std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity = 
+        std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theEntity);
+  bool isFullyRemoved = removeEntity((Slvs_hEntity)anEntity->id());
+
+  std::list<EntityWrapperPtr>::const_iterator anEntIt = anEntity->subEntities().begin();
+  for (; anEntIt != anEntity->subEntities().end(); ++anEntIt) {
+    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSubEntity = 
+        std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anEntIt);
+    FeaturePtr aBaseFeature = aSubEntity->baseFeature();
+    if (aBaseFeature)
+      isFullyRemoved = removeEntity(aBaseFeature) && isFullyRemoved;
+    else
+      isFullyRemoved = removeEntity(aSubEntity->baseAttribute()) && isFullyRemoved;
+  }
+
+  std::list<ParameterWrapperPtr>::const_iterator aParIt = anEntity->parameters().begin();
+  for (; aParIt != anEntity->parameters().end(); ++aParIt)
+    isFullyRemoved = remove(*aParIt) && isFullyRemoved;
+  return isFullyRemoved;
+}
+
+bool SolveSpaceSolver_Storage::remove(ParameterWrapperPtr theParameter)
+{
+  return removeParameter((Slvs_hParam)theParameter->id());
+}
+
+
+void SolveSpaceSolver_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) {
+    // 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) {
+      std::shared_ptr<SolveSpaceSolver_ParameterWrapper> aWrapper = 
+          std::dynamic_pointer_cast<SolveSpaceSolver_ParameterWrapper>(*aParIt);
+      if (!theFixedOnly || aWrapper->group() == GID_OUTOFGROUP || aWrapper->isParametric()) {
+        aWrapper->changeParameter().val = getParameter((Slvs_hParam)aWrapper->id()).val;
+        aCoords[i] = aWrapper->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);
+            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;
+    }
+    std::shared_ptr<GeomDataAPI_Point> aPoint =
+        std::dynamic_pointer_cast<GeomDataAPI_Point>(anIt->first);
+    if (aPoint) {
+      if ((isUpd[0] && fabs(aPoint->x() - aCoords[0]) > tolerance) ||
+          (isUpd[1] && fabs(aPoint->y() - aCoords[1]) > tolerance) ||
+          (isUpd[2] && fabs(aPoint->z() - aCoords[2]) > tolerance))
+        if (!isUpd[0]) aCoords[0] = aPoint->x();
+        if (!isUpd[1]) aCoords[1] = aPoint->y();
+        if (!isUpd[2]) aCoords[2] = aPoint->z();
+        aPoint->setValue(aCoords[0], aCoords[1], aCoords[2]);
+      continue;
+    }
+  }
+
+  blockEvents(false);
+}
+
+void SolveSpaceSolver_Storage::verifyFixed()
+{
+  std::map<AttributePtr, EntityWrapperPtr>::iterator anAttrIt = myAttributeMap.begin();
+  for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
+    const std::list<ParameterWrapperPtr>& aParameters = anAttrIt->second->parameters();
+    std::list<ParameterWrapperPtr>::const_iterator aParIt = aParameters.begin();
+    for (; aParIt != aParameters.end(); ++aParIt)
+      if ((*aParIt)->group() == GID_OUTOFGROUP) {
+        Slvs_Param aParam = getParameter((Slvs_hParam)(*aParIt)->id());
+        if (aParam.group != (Slvs_hParam)GID_OUTOFGROUP) {
+          aParam.group = (Slvs_hParam)GID_OUTOFGROUP;
+          updateParameter(aParam);
+        }
+      }
+  }
+}
+
+
+void SolveSpaceSolver_Storage::adjustArc(const Slvs_Entity& theArc)
+{
+  double anArcPoints[3][2];
+  double aDist[3] = {0.0};
+  bool isFixed[3] = {false};
+  for (int i = 0; i < 3; ++i) {
+    Slvs_Entity aPoint = getEntity(theArc.point[i]);
+    isFixed[i] = (aPoint.group != (Slvs_hGroup)myGroupID);
+    anArcPoints[i][0] = getParameter(aPoint.param[0]).val;
+    anArcPoints[i][1] = getParameter(aPoint.param[1]).val;
+    if (i > 0) {
+      anArcPoints[i][0] -= anArcPoints[0][0];
+      anArcPoints[i][1] -= anArcPoints[0][1];
+      aDist[i] = sqrt(anArcPoints[i][0] * anArcPoints[i][0] + 
+                      anArcPoints[i][1] * anArcPoints[i][1]);
+    }
+  }
+
+  if (fabs(aDist[1] - aDist[2]) < tolerance)
+    return;
+
+  int anInd = 2;
+  while (anInd > 0 && isFixed[anInd])
+    --anInd;
+  if (anInd < 1)
+    return; // adjust only start or end point of the arc
+
+  anArcPoints[anInd][0] /= aDist[anInd];
+  anArcPoints[anInd][1] /= aDist[anInd];
+
+  Slvs_Entity aPoint = getEntity(theArc.point[anInd]);
+  for (int i = 0; i < 2; ++i) {
+    Slvs_Param aParam = getParameter(aPoint.param[i]);
+    aParam.val = anArcPoints[0][i] + aDist[3-anInd] * anArcPoints[anInd][i];
+    updateParameter(aParam);
+  }
+}
+
+
+
+
+
+
+
+// ========================================================
+// =========      Auxiliary functions       ===============
+// ========================================================
+
+template<typename T>
+int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
+{
+  int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
+  int aVecSize = theEntities.size();
+  if (theEntities.empty())
+    return 1;
+  while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
+    aResIndex--;
+  while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
+    aResIndex++;
+  if (aResIndex == -1 || (aResIndex < aVecSize && theEntities[aResIndex].h != theEntityID))
+    aResIndex = aVecSize;
+  return aResIndex;
+}
+
+bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2)
+{
+  return fabs(theParam1.val - theParam2.val) > tolerance;
+}
+
+bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2)
+{
+  int i = 0;
+  for (; theEntity1.param[i] != 0 && i < 4; i++)
+    if (theEntity1.param[i] != theEntity2.param[i])
+      return true;
+  i = 0;
+  for (; theEntity1.point[i] != 0 && i < 4; i++)
+    if (theEntity1.point[i] != theEntity2.point[i])
+      return true;
+  return false;
+}
+
+bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2)
+{
+  return theConstraint1.ptA != theConstraint2.ptA ||
+         theConstraint1.ptB != theConstraint2.ptB ||
+         theConstraint1.entityA != theConstraint2.entityA ||
+         theConstraint1.entityB != theConstraint2.entityB ||
+         theConstraint1.entityC != theConstraint2.entityC ||
+         theConstraint1.entityD != theConstraint2.entityD ||
+         fabs(theConstraint1.valA - theConstraint2.valA) > tolerance;
+}
diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.h
new file mode 100644 (file)
index 0000000..7136648
--- /dev/null
@@ -0,0 +1,280 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SolveSpaceSolver_Storage.h
+// Created: 18 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_Storage_H_
+#define SolveSpaceSolver_Storage_H_
+
+#include <SketchSolver_Storage.h>
+#include <SolveSpaceSolver_Solver.h>
+
+#include <list>
+#include <memory>
+#include <set>
+#include <vector>
+
+typedef std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> > CoincidentPointsMap;
+typedef std::list< std::set<ConstraintWrapperPtr> >             SameConstraintMap;
+
+/** \class   SolveSpaceSolver_Storage
+ *  \ingroup Plugins
+ *  \brief   Contains all necessary data in SolveSpace format to solve a single group of constraints
+ */
+class SolveSpaceSolver_Storage : public SketchSolver_Storage
+{
+public:
+  SolveSpaceSolver_Storage(const GroupID& theGroup);
+
+// =============   Inherited from SketchSolver_Storage   =============
+
+  /// \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 Removes constraint from the storage
+  /// \return \c true if the constraint and all its parameters are remove successfully
+  virtual bool removeConstraint(ConstraintPtr theConstraint);
+  /// \brief Removes feature from the storage
+  /// \return \c true if the feature and its attributes are removed successfully;
+  ///         \c false if the feature or any it attribute is used by remaining constraints.
+  virtual bool removeEntity(FeaturePtr theFeature);
+  /// \brief Removes attribute from the storage
+  /// \return \c true if the attribute is not used by remaining features and constraints
+  virtual bool removeEntity(AttributePtr theAttribute);
+
+  /// \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 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);
+
+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   =============
+public:
+  /// \brief Obtain and store identifier of sketch
+  void storeWorkplane(EntityWrapperPtr theSketch);
+
+  /** \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 Returns maximal ID of entities in this storage
+  const Slvs_hEntity& entityMaxID() const
+  { return myEntityMaxID; }
+
+  /// \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 Returns quantity of constraints in this storage
+  size_t nbConstraints() const
+  { return myConstraints.size(); }
+
+  /// \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 Mark specified constraint as temporary
+  virtual void setTemporary(ConstraintPtr theConstraint);
+  /// \brief Remove all transient constraints
+  void removeAllTemporary();
+  /// \brief Remove temporary constraint s. Preferable to remove the points under Point-on-Line constraint
+  /// \param theNbConstraints [in]  number of temporary constraints to be deleted
+  /// \return Number of remaining temporary constraints
+  virtual size_t removeTemporary(size_t theNbConstraints);
+  /// \brief Checks the constraint is temporary
+  bool isTemporary(const Slvs_hConstraint& theConstraintID) const;
+  /// \brief Number of temporary constraints
+  virtual size_t nbTemporary() const
+  { return myTemporaryConstraints.size(); }
+
+  /// \brief Shows the storage has the same constraint twice
+  virtual bool hasDuplicatedConstraint() const
+  { return myDuplicatedConstraint; }
+
+  /// \brief Initialize constraint solver by the entities collected by current storage
+  virtual void initializeSolver(SolverPtr theSolver);
+
+public:
+  /// \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);
+
+  /// \brief Update arc points to be on circle sharp.
+  void adjustArc(const Slvs_Entity& theArc);
+
+  /// \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;
+
+  /// \brief Replace sub-entity theSource in all features by theDest
+  void replaceInFeatures(EntityWrapperPtr theSource, EntityWrapperPtr theDest);
+  /// \brief Replace constrained entity theSource by theDest in all constraints;
+  void replaceInConstraints(EntityWrapperPtr theSource, EntityWrapperPtr theDest);
+
+  /// \brief Add pair of constraints which have same representation in SolveSpace notation.
+  ///
+  ///        These constraints may be different and become the same after the substitution
+  ///        of point coincidence.
+  void addSameConstraints(ConstraintWrapperPtr theConstraint1, ConstraintWrapperPtr theConstraint2);
+
+private:
+  Slvs_hEntity myWorkplaneID; ///< identifier of workplane
+
+  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)
+
+  CoincidentPointsMap myCoincidentPoints; ///< lists of coincident points (first is a master point, second is a set of slaves)
+  Slvs_hConstraint myFixed; ///< identifier of one of temporary constraints to fix separate point
+
+  bool myDuplicatedConstraint; ///< shows the storage has same constraint twice
+
+  std::set<Slvs_hConstraint> myTemporaryConstraints; ///< list of transient constraints
+  std::set<Slvs_hParam> myUpdatedParameters; ///< list of just updated parameters (cleared when isNeedToResolve() called)
+
+  SameConstraintMap myEqualConstraints; ///< list of groups of equal constraints
+};
+
+#endif