]> SALOME platform Git repositories - modules/shaper.git/blobdiff - src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp
Salome HOME
Fix problems in sketch unit tests
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_Builder.cpp
index 2267b067c939c6ba7bd1e986a14eded8525dec6e..a7c348db78a0c00b73b3ee9be87ea8a550d2c90d 100644 (file)
@@ -29,6 +29,7 @@
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
+#include <SketchPlugin_IntersectionPoint.h>
 #include <SketchPlugin_ConstraintAngle.h>
 
 #include <math.h>
@@ -128,17 +129,23 @@ static ConstraintWrapperPtr
                           const SketchSolver_ConstraintType& theType,
                           std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
                           std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
+static ConstraintWrapperPtr
+  createConstraintCollinear(ConstraintPtr theConstraint,
+                           const GroupID& theGroupID,
+                           std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+                           std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
+static ConstraintWrapperPtr
+  createConstraintMiddlePoint(ConstraintPtr theConstraint,
+                              const GroupID& theGroupID,
+                              std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
+                              std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity);
 
 
 
-/// \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 Update a sign of the point-line distance constraint
+static void adjustPtLineDistance(ConstraintWrapperPtr theConstraint);
 
 /// \brief Transform points to be symmetric regarding to the mirror line
 static void makeMirrorPoints(EntityWrapperPtr theOriginal,
@@ -200,6 +207,10 @@ std::list<ConstraintWrapperPtr> PlaneGCSSolver_Builder::createConstraint(
     aResult = createConstraintPointOnEntity(theConstraint, theGroupID, theType,
                   aPoint1, GCS_ENTITY_WRAPPER(theEntity1));
     break;
+  case CONSTRAINT_MIDDLE_POINT:
+    aResult = createConstraintMiddlePoint(theConstraint, theGroupID,
+                  aPoint1, GCS_ENTITY_WRAPPER(theEntity1));
+    break;
   case CONSTRAINT_PT_PT_DISTANCE:
     aResult = createConstraintDistancePointPoint(theConstraint, theGroupID,
                   GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)),
@@ -244,10 +255,15 @@ std::list<ConstraintWrapperPtr> PlaneGCSSolver_Builder::createConstraint(
                   GCS_PARAMETER_WRAPPER(anIntermediate));
     break;
   case CONSTRAINT_TANGENT_ARC_LINE:
+  case CONSTRAINT_TANGENT_CIRCLE_LINE:
   case CONSTRAINT_TANGENT_ARC_ARC:
     aResult = createConstraintTangent(theConstraint, theGroupID, theType,
                   GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
     break;
+  case CONSTRAINT_COLLINEAR:
+    aResult = createConstraintCollinear(theConstraint, theGroupID,
+                  GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
+    break;
   case CONSTRAINT_MULTI_TRANSLATION:
   case CONSTRAINT_MULTI_ROTATION:
     break;
@@ -324,10 +340,10 @@ std::list<ConstraintWrapperPtr> PlaneGCSSolver_Builder::createMirror(
         std::dynamic_pointer_cast<GCS::Line>(aMirrorLine->entity());
 
     std::list<GCSConstraintPtr> aConstrList;
-    aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintPerpendicular(
-        *(aPoint1->point()), *(aPoint2->point()), aLine->p1, aLine->p2)));
     aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintMidpointOnLine(
         *(aPoint1->point()), *(aPoint2->point()), aLine->p1, aLine->p2)));
+    aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintPerpendicular(
+        *(aPoint1->point()), *(aPoint2->point()), aLine->p1, aLine->p2)));
 
     ConstraintWrapperPtr aSubResult(new PlaneGCSSolver_ConstraintWrapper(
         theConstraint, aConstrList, CONSTRAINT_SYMMETRIC));
@@ -441,14 +457,10 @@ void PlaneGCSSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint
 {
   SketchSolver_ConstraintType aType = theConstraint->type();
   // Update flags and parameters in constraints
-  if (aType == CONSTRAINT_ANGLE)
-    adjustAngle(theConstraint);
-  //else if (aType == CONSTRAINT_SYMMETRIC)
-  //  adjustMirror(theConstraint);
-  else if (aType == CONSTRAINT_MULTI_ROTATION)
-    adjustMultiRotation(theConstraint);
-  else if (aType == CONSTRAINT_MULTI_TRANSLATION)
-    adjustMultiTranslation(theConstraint);
+  if (aType == CONSTRAINT_PT_LINE_DISTANCE)
+    adjustPtLineDistance(theConstraint);
+  else if (aType == CONSTRAINT_SYMMETRIC)
+    adjustMirror(theConstraint);
 }
 
 EntityWrapperPtr PlaneGCSSolver_Builder::createFeature(
@@ -484,7 +496,8 @@ EntityWrapperPtr PlaneGCSSolver_Builder::createFeature(
   else if (aFeatureKind == SketchPlugin_Arc::ID())
     return createArc(theFeature, theAttributes, theGroupID);
   // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
-  else if (aFeatureKind == SketchPlugin_Point::ID()) {
+  else if (aFeatureKind == SketchPlugin_Point::ID() ||
+           aFeatureKind == SketchPlugin_IntersectionPoint::ID()) {
     EntityWrapperPtr aSub;
     if (theAttributes.size() == 1)
       aSub = theAttributes.front();
@@ -812,6 +825,65 @@ ConstraintWrapperPtr createConstraintPointOnEntity(
   return aResult;
 }
 
+// calculate length of the line
+static inline double lineLength(const GCS::Line& theLine)
+{
+  double aDir[2] = {*(theLine.p2.x) - *(theLine.p1.x), *(theLine.p2.y) - *(theLine.p1.y)};
+  return sqrt(aDir[0] * aDir[0] + aDir[1] * aDir[1]);
+}
+
+// check the point is on the line
+static inline bool isPointOnLine(const GCS::Point& thePoint, const GCS::Line& theLine)
+{
+  double aDir[2] = {*(theLine.p2.x) - *(theLine.p1.x), *(theLine.p2.y) - *(theLine.p1.y)};
+  double aVec[2] = {*(thePoint.x) - *(theLine.p1.x), *(thePoint.y) - *(theLine.p1.y)};
+  double aCross = aVec[0] * aDir[1] - aVec[1] * aDir[0];
+  return fabs(aCross) < tolerance;
+}
+
+ConstraintWrapperPtr createConstraintMiddlePoint(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity)
+{
+  GCSPointPtr aPoint = thePoint->point();
+  std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity->entity());
+  if (!aLine)
+    return ConstraintWrapperPtr();
+
+  std::list<GCSConstraintPtr> aConstrList;
+  aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintPointOnLine(*aPoint, *aLine)));
+  double aDist = lineLength(*aLine);
+  std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aDistance =
+      std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(createParameter(theGroupID, aDist * 0.5));
+  aConstrList.push_back(GCSConstraintPtr(
+      new GCS::ConstraintP2PDistance(*aPoint, aLine->p1, aDistance->parameter())));
+  aConstrList.push_back(GCSConstraintPtr(
+      new GCS::ConstraintP2PDistance(*aPoint, aLine->p2, aDistance->parameter())));
+
+  // Workaround to avoid conflicting constraints when the point is already placed on line
+  if (thePoint->group() != GID_UNKNOWN && isPointOnLine(*aPoint, *aLine)) {
+    std::shared_ptr<GeomDataAPI_Point2D> aCoord =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(thePoint->baseAttribute());
+    if (aCoord) {
+      *(aPoint->x) = (*(aLine->p1.x) + *(aLine->p2.x)) * 0.5;
+      *(aPoint->y) = (*(aLine->p1.y) + *(aLine->p2.y)) * 0.5;
+      aCoord->setValue(*(aPoint->x), *(aPoint->y));
+    }
+  }
+
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(new PlaneGCSSolver_ConstraintWrapper(
+      theConstraint, aConstrList, CONSTRAINT_MIDDLE_POINT));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, thePoint);
+  aSubs.push_back(theEntity);
+  aResult->setEntities(aSubs);
+  aResult->setValueParameter(aDistance);
+  return aResult;
+}
+
+
 ConstraintWrapperPtr createConstraintDistancePointPoint(
     ConstraintPtr theConstraint,
     const GroupID& theGroupID,
@@ -879,9 +951,19 @@ ConstraintWrapperPtr createConstraintAngle(
     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
 {
   std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
+  bool isLine1Rev = theConstraint->boolean(
+      SketchPlugin_ConstraintAngle::ANGLE_REVERSED_FIRST_LINE_ID())->value();
+  GCS::Point aLine1Pt1 = isLine1Rev ? aLine1->p2 : aLine1->p1;
+  GCS::Point aLine1Pt2 = isLine1Rev ? aLine1->p1 : aLine1->p2;
+
   std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
+  bool isLine2Rev = theConstraint->boolean(
+      SketchPlugin_ConstraintAngle::ANGLE_REVERSED_SECOND_LINE_ID())->value();
+  GCS::Point aLine2Pt1 = isLine2Rev ? aLine2->p2 : aLine2->p1;
+  GCS::Point aLine2Pt2 = isLine2Rev ? aLine2->p1 : aLine2->p2;
+
   GCSConstraintPtr aNewConstr(new GCS::ConstraintL2LAngle(
-      *(aLine1), *(aLine2), theValue->parameter()));
+      aLine1Pt1, aLine1Pt2, aLine2Pt1, aLine2Pt2, theValue->parameter()));
 
   std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
       new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_ANGLE));
@@ -914,6 +996,29 @@ ConstraintWrapperPtr createConstraintHorizVert(
   return aResult;
 }
 
+ConstraintWrapperPtr createConstraintCollinear(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
+{
+  std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
+  std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
+
+  // create two point-on-line constraints
+  std::list<GCSConstraintPtr> aConstrList;
+  aConstrList.push_back( GCSConstraintPtr(new GCS::ConstraintPointOnLine(aLine2->p1, *aLine1)) );
+  aConstrList.push_back( GCSConstraintPtr(new GCS::ConstraintPointOnLine(aLine2->p2, *aLine1)) );
+
+  ConstraintWrapperPtr aResult(new PlaneGCSSolver_ConstraintWrapper(
+      theConstraint, aConstrList, CONSTRAINT_COLLINEAR));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, theEntity1);
+  aSubs.push_back(theEntity2);
+  aResult->setEntities(aSubs);
+  return aResult;
+}
+
 ConstraintWrapperPtr createConstraintParallel(
     ConstraintPtr theConstraint,
     const GroupID& theGroupID,
@@ -972,6 +1077,11 @@ ConstraintWrapperPtr createConstraintEqual(
         new GCS::ConstraintP2PDistance(aLine1->p1, aLine1->p2, theIntermed->parameter())));
     aConstrList.push_back(GCSConstraintPtr(
         new GCS::ConstraintP2PDistance(aLine2->p1, aLine2->p2, theIntermed->parameter())));
+    // update value of intermediate parameter
+    double x = *aLine1->p1.x - *aLine1->p2.x;
+    double y = *aLine1->p1.y - *aLine1->p2.y;
+    double aLen = sqrt(x*x + y*y);
+    theIntermed->setValue(aLen);
   } else {
     std::shared_ptr<GCS::Circle> aCirc1 =
         std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
@@ -1000,7 +1110,7 @@ ConstraintWrapperPtr createConstraintTangent(
     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
 {
   GCSConstraintPtr aNewConstr;
-  if (theType == CONSTRAINT_TANGENT_ARC_LINE) {
+  if (theType == CONSTRAINT_TANGENT_ARC_LINE || theType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
     std::shared_ptr<GCS::Circle> aCirc = std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
     std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
 
@@ -1029,86 +1139,6 @@ ConstraintWrapperPtr createConstraintTangent(
 
 
 
-void adjustAngle(ConstraintWrapperPtr theConstraint)
-{
-  BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
-
-  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
-    std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
-
-  std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
-  const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
-  std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
-  for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
-    const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
-    std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
-    for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt)
-      aPoints[i][j] = aBuilder->point(*aLPIt);
-  }
-
-  std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
-    std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
-    std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
-  };
-  std::shared_ptr<GeomAPI_Pnt2d> anIntersection = aLine[0]->intersect(aLine[1]);
-  if (!anIntersection)
-    return;
-  double aDist[2][2];
-  for (int i = 0; i < 2; i++) {
-    for (int j = 0; j < 2; j++) {
-      aDist[i][j] = anIntersection->distance(aPoints[i][j]);
-      if (fabs(aDist[i][j]) <= tolerance)
-        aDist[i][j] = 0.0;
-    }
-    if (aDist[i][0] > tolerance && aDist[i][1] > tolerance &&
-        aDist[i][0] + aDist[i][1] < aPoints[i][0]->distance(aPoints[i][1]) + 2.0 * tolerance) {
-      // the intersection point is an inner point of the line,
-      // we change the sign of distance till start point to calculate correct coordinates
-      // after rotation
-      aDist[i][0] *= -1.0;
-    }
-  }
-  std::shared_ptr<GeomAPI_Dir2d> aDir[2];
-  for (int i = 0; i < 2; i++) {
-    if (aDist[i][1] > fabs(aDist[i][0]))
-      aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
-          aPoints[i][1]->xy()->decreased(anIntersection->xy())));
-    else {
-      aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
-          aPoints[i][0]->xy()->decreased(anIntersection->xy())));
-      // main direction is opposite => change signs
-      if (aDist[i][0] < 0.0) {
-        aDist[i][0] *= -1.0;
-        aDist[i][1] *= -1.0;
-      }
-    }
-  }
-
-  bool isChange = false;
-  for (int i = 0; i < 2; i++)
-    if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
-      isChange = !isChange;
-  if (isChange)
-    aConstraint->setValue(180.0 - aConstraint->value());
-}
-
-////void adjustMirror(ConstraintWrapperPtr theConstraint)
-////{
-////  std::vector<EntityWrapperPtr> aPoints;
-////  EntityWrapperPtr aMirrorLine;
-////
-////  const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
-////  std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
-////  for (; anIt != aSubs.end(); ++anIt) {
-////    if ((*anIt)->type() == ENTITY_POINT)
-////      aPoints.push_back(*anIt);
-////    else if ((*anIt)->type() == ENTITY_LINE)
-////      aMirrorLine = *anIt;
-////  }
-////
-////  makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
-////}
-
 void makeMirrorPoints(EntityWrapperPtr theOriginal,
                       EntityWrapperPtr theMirrored,
                       EntityWrapperPtr theMirrorLine)
@@ -1137,100 +1167,49 @@ void makeMirrorPoints(EntityWrapperPtr theOriginal,
   }
 }
 
-static void rotate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
-                   std::shared_ptr<GeomAPI_Pnt2d> theCenter,
-                   double theSin, double theCos)
-{
-  if (theSource->type() == ENTITY_POINT) {
-    // Rotate single point
-    std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theSource->baseAttribute());
-    std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theDest->baseAttribute());
-    if (aSrcAttr && aDstAttr) {
-      std::shared_ptr<GeomAPI_XY> aVec = aSrcAttr->pnt()->xy()->decreased(theCenter->xy());
-      double aNewX = aVec->x() * theCos - aVec->y() * theSin;
-      double aNewY = aVec->x() * theSin + aVec->y() * theCos;
-      aDstAttr->setValue(theCenter->x() + aNewX, theCenter->y() + aNewY);
-    }
-    return;
-  }
-
-  FeaturePtr aDestFeature = theDest->baseFeature();
-  if (aDestFeature)
-    aDestFeature->data()->blockSendAttributeUpdated(true);
-
-  // Rotate points of the feature
-  const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
-  const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
-  std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
-  for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
-       aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
-    rotate(*aSrcIt, *aDstIt, theCenter, theSin, theCos);
-
-  if (aDestFeature)
-    aDestFeature->data()->blockSendAttributeUpdated(false);
-}
-
-static void translate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
-                      std::shared_ptr<GeomAPI_XY> theDelta)
-{
-  if (theSource->type() == ENTITY_POINT) {
-    // Translate single point
-    std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theSource->baseAttribute());
-    std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theDest->baseAttribute());
-    if (aSrcAttr && aDstAttr)
-      aDstAttr->setValue(aSrcAttr->x() + theDelta->x(), aSrcAttr->y() + theDelta->y());
-    return;
-  }
-
-  FeaturePtr aDestFeature = theDest->baseFeature();
-  if (aDestFeature)
-    aDestFeature->data()->blockSendAttributeUpdated(true);
-
-  // Translate points of the feature
-  const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
-  const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
-  std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
-  for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
-       aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
-    translate(*aSrcIt, *aDstIt, theDelta);
-
-  if (aDestFeature)
-    aDestFeature->data()->blockSendAttributeUpdated(false);
-}
-
-void adjustMultiRotation(ConstraintWrapperPtr theConstraint)
+void adjustPtLineDistance(ConstraintWrapperPtr theConstraint)
 {
   BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
 
-  double anAngleRad = theConstraint->value() * PI / 180.0;
-  double aSin = sin(anAngleRad);
-  double aCos = cos(anAngleRad);
-
-  const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
+  std::shared_ptr<GeomAPI_Pnt2d> aPoint;
+  std::shared_ptr<GeomAPI_Lin2d> aLine;
+  std::list<EntityWrapperPtr> aSubs = theConstraint->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_Pnt2d> aCenter = aBuilder->point(*aSIt++);
-  std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
-  for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
-    rotate(*aPrevIt, *aSIt, aCenter, aSin, aCos);
+  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) * theConstraint->value() < 0.0)
+    theConstraint->setValue(theConstraint->value() * (-1.0));
 }
 
-void adjustMultiTranslation(ConstraintWrapperPtr theConstraint)
+void adjustMirror(ConstraintWrapperPtr theConstraint)
 {
-  BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
+  std::vector<EntityWrapperPtr> aPoints;
+  EntityWrapperPtr aMirrorLine;
 
   const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
-  std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+  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;
+  }
 
-  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());
+  if (aPoints.size() == 2)
+    makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
 
-  std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
-  for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
-    translate(*aPrevIt, *aSIt, aDelta);
+  // update scales of constraints
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aGCSConstraint = 
+      std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
+  std::list<GCSConstraintPtr>::const_iterator aCIt = aGCSConstraint->constraints().begin();
+  for (; aCIt != aGCSConstraint->constraints().end(); ++aCIt)
+    (*aCIt)->rescale();
 }
+