]> SALOME platform Git repositories - modules/shaper.git/blobdiff - src/SketchSolver/SketchSolver_ConstraintMirror.cpp
Salome HOME
Revert "First phase of SketchSolver refactoring"
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintMirror.cpp
index be15c46a0970b0f1a73e091a11db56fa72acf99c..9d1477545f9d969234e7c7115d2fe04b16ab2d5f 100644 (file)
@@ -1,33 +1,34 @@
 #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_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
 #include <ModelAPI_AttributeRefList.h>
-////#include <ModelAPI_ResultConstruction.h>
-////
-////#include <GeomAPI_Dir2d.h>
-////#include <GeomAPI_XY.h>
-////
-////#include <cmath>
+#include <ModelAPI_ResultConstruction.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_XY.h>
+
+#include <cmath>
 
 void SketchSolver_ConstraintMirror::getAttributes(
-    EntityWrapperPtr& theMirrorLine,
-    std::vector<EntityWrapperPtr>& theBaseEntities,
-    std::vector<EntityWrapperPtr>& theMirrorEntities)
+    Slvs_Entity& theMirrorLine,
+    std::vector<Slvs_Entity>& theBaseEntities,
+    std::vector<Slvs_Entity>& theMirrorEntities)
 {
-  AttributePtr aMirLineAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A());
-  AttributeRefAttrPtr aMirLineRefAttr =
-      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aMirLineAttr);
-  if (!aMirLineRefAttr || !aMirLineRefAttr->isInitialized() || !aMirLineRefAttr->isObject()) {
+  DataPtr aData = myBaseConstraint->data();
+  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;
   }
-
-  myType = TYPE(myBaseConstraint);
-  myStorage->update(aMirLineAttr, myGroupID);
-  theMirrorLine = myStorage->entity(aMirLineAttr);
+  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);
 
   // Create SolveSpace entity for all features
   AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
@@ -44,25 +45,26 @@ 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<EntityWrapperPtr>* aList = i == 0 ? &theBaseEntities : & theMirrorEntities;
+    std::vector<Slvs_Entity>* aList = i == 0 ? &theBaseEntities : & theMirrorEntities;
     for ( ; anIter != aEndIter; anIter++) {
-      aFeature = ModelAPI_Feature::feature(*anIter);
+      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anIter);
+      aFeature = aRC ? aRC->document()->feature(aRC) :
+        std::dynamic_pointer_cast<ModelAPI_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));
+      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));
     }
   }
 
@@ -73,16 +75,16 @@ void SketchSolver_ConstraintMirror::getAttributes(
 void SketchSolver_ConstraintMirror::process()
 {
   cleanErrorMsg();
-  if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) {
-    // Not enough parameters are assigned
+  if (!myBaseConstraint || !myStorage || myGroup == 0) {
+    /// TODO: Put error message here
     return;
   }
-////  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-////    update(myBaseConstraint);
+  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+    update(myBaseConstraint);
 
-  EntityWrapperPtr aMirrorLine;
-  std::vector<EntityWrapperPtr> aBaseList;
-  std::vector<EntityWrapperPtr> aMirrorList;
+  Slvs_Entity aMirrorLine;
+  std::vector<Slvs_Entity> aBaseList;
+  std::vector<Slvs_Entity> aMirrorList;
   getAttributes(aMirrorLine, aBaseList, aMirrorList);
   if (!myErrorMsg.empty())
     return;
@@ -92,328 +94,389 @@ void SketchSolver_ConstraintMirror::process()
     return;
   }
 
-  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());
+  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;
   }
 
-  myStorage->addConstraint(myBaseConstraint, aMirConstrList);
+  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);
+      }
+    }
+  }
 }
 
 
-void SketchSolver_ConstraintMirror::update()
+void SketchSolver_ConstraintMirror::update(ConstraintPtr theConstraint)
 {
   cleanErrorMsg();
-  AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-    myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C()));
-  if (aMirroredRefList->size() != myNumberOfObjects) {
-    remove();
-    process();
-    return;
+  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;
+    }
   }
   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);
-////  }
-////}
+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()
 {
-  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
-
-  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);
-
-////  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;
-////  }
-////
-////  // 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);
+  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;
+  }
+
+  // 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);
 }