Salome HOME
updated copyright message
[modules/shaper.git] / src / SketchSolver / SolveSpaceSolver / SolveSpaceSolver_Builder.cpp
index 5e1b85015d27534de5c319239072282ecb0fbfba..c281c41fff7bca14e0fe4e4c6c7d5b48973fc05a 100644 (file)
@@ -1,8 +1,21 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SolveSpaceSolver_Builder.cpp
-// Created: 25 Mar 2015
-// Author:  Artem ZHIDKOV
+// Copyright (C) 2014-2023  CEA, EDF
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
 
 #include <SolveSpaceSolver_Builder.h>
 #include <SolveSpaceSolver_Solver.h>
@@ -14,6 +27,7 @@
 
 #include <SketchSolver_Manager.h>
 
+#include <GeomAPI_Angle2d.h>
 #include <GeomAPI_Dir2d.h>
 #include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_XY.h>
@@ -27,6 +41,8 @@
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
+#include <SketchPlugin_IntersectionPoint.h>
+#include <SketchPlugin_ConstraintAngle.h>
 
 #include <math.h>
 
@@ -51,10 +67,8 @@ static void adjustTangency(ConstraintWrapperPtr theConstraint);
 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,
@@ -100,6 +114,34 @@ std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
   if (theType == CONSTRAINT_SYMMETRIC)
     return createMirror(theConstraint, theGroupID, theSketchID,
                         thePoint1, thePoint2, theEntity1);
+  else if (theType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
+    // replace by distance from center of circle to the line
+    const std::list<EntityWrapperPtr>& aSubs = theEntity1->subEntities();
+    EntityWrapperPtr aCenter = aSubs.front();
+    AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+        aSubs.back()->baseAttribute());
+    return createConstraint(theConstraint, theGroupID, theSketchID,
+        CONSTRAINT_PT_LINE_DISTANCE, aRadius->value(), aCenter, EntityWrapperPtr(), theEntity2);
+  }
+  else if (theType == CONSTRAINT_COLLINEAR) {
+    // replace by two constraints point-on-line
+    std::list<ConstraintWrapperPtr> aConstraints;
+    const std::list<EntityWrapperPtr>& aSubs1 = theEntity1->subEntities();
+    const std::list<EntityWrapperPtr>& aSubs2 = theEntity2->subEntities();
+    std::list<EntityWrapperPtr>::const_iterator anIt1, anIt2;
+    for (anIt2 = aSubs2.begin(); anIt2 != aSubs2.end(); ++anIt2) {
+      for (anIt1 = aSubs1.begin(); anIt1 != aSubs1.end(); ++anIt1)
+        if ((*anIt1)->id() == (*anIt2)->id())
+          break;
+      if (anIt1 != aSubs1.end())
+        continue; // the lines have coincident point
+
+      std::list<ConstraintWrapperPtr> aC = createConstraint(theConstraint, theGroupID,
+          theSketchID, CONSTRAINT_PT_ON_LINE, theValue, *anIt2, EntityWrapperPtr(), theEntity1);
+      aConstraints.insert(aConstraints.end(), aC.begin(), aC.end());
+    }
+    return aConstraints;
+  }
 
   int aType = ConstraintType::toSolveSpace(theType);
   if (aType == SLVS_C_UNKNOWN)
@@ -112,8 +154,9 @@ std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
     if (!anOriginal[i])
       continue;
     aSlvsEntities[i] = (Slvs_hEntity)anOriginal[i]->id();
+    // entity is not added into a storage, constraint can not be created
     if (aSlvsEntities[i] == SLVS_E_UNKNOWN)
-      return std::list<ConstraintWrapperPtr>(); // entity is not added into a storage, constraint can not be created
+      return std::list<ConstraintWrapperPtr>();
     aConstrAttrList.push_back(anOriginal[i]);
   }
 
@@ -121,6 +164,7 @@ std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
       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->setGroup(theGroupID);
   aResult->setValue(theValue);
   aResult->setEntities(aConstrAttrList);
   adjustConstraint(aResult);
@@ -134,6 +178,7 @@ std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
     const EntityID& theSketchID,
     const SketchSolver_ConstraintType& theType,
     const double& theValue,
+    const bool theFullValue,
     const EntityWrapperPtr& thePoint1,
     const EntityWrapperPtr& thePoint2,
     const std::list<EntityWrapperPtr>& theTrsfEnt) const
@@ -155,7 +200,9 @@ std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
   aConstrAttrList.push_front(thePoint1);
 
   ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
+  aResult->setGroup(theGroupID);
   aResult->setValue(theValue);
+  aResult->setIsFullValue(theFullValue);
   aResult->setEntities(aConstrAttrList);
   return std::list<ConstraintWrapperPtr>(1, aResult);
 }
@@ -173,8 +220,7 @@ std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
   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);
+    makeMirrorPoints(theEntity1, theEntity2, theMirrorLine);
 
     aConstraint = Slvs_MakeConstraint(
         SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, SLVS_C_SYMMETRIC_LINE, (Slvs_hEntity)theSketchID,
@@ -187,6 +233,7 @@ std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
 
     ConstraintWrapperPtr aWrapper(new SolveSpaceSolver_ConstraintWrapper(
         theConstraint, aConstraint));
+    aWrapper->setGroup(theGroupID);
     aWrapper->setEntities(aConstrAttrList);
     aResult.push_back(aWrapper);
   }
@@ -223,15 +270,15 @@ std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
     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
+    // Do not allow mirrored arc recalculate its position until
+    // coordinated of all points recalculated
     FeaturePtr aMirrArc = theEntity2->baseFeature();
-    aMirrArc->data()->blockSendAttributeUpdated(true);
+    bool aWasBlocked = 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(*anIt1, *anIt2, theMirrorLine);
+    makeMirrorPoints(*anIt1, *anIt2, theMirrorLine);
 
     // Workaround to avoid problems in SolveSpace.
     // The symmetry of two arcs will be done using symmetry of three points on these arcs:
@@ -244,11 +291,12 @@ std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
     anIt1 = aBaseArcPoints.begin();
     anIt2 = aMirrorArcPoints.begin();
     for (; anIt1 != aBaseArcPoints.end(); ++anIt1, ++anIt2) {
-      aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
+      aMrrList =
+        createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
       aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
     }
     // Restore event sending
-    aMirrArc->data()->blockSendAttributeUpdated(false);
+    aMirrArc->data()->blockSendAttributeUpdated(aWasBlocked);
   }
   return aResult;
 }
@@ -263,10 +311,8 @@ void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstrai
     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);
+  else if (aType == CONSTRAINT_PT_LINE_DISTANCE)
+    adjustPtLineDistance(theConstraint);
 }
 
 EntityWrapperPtr SolveSpaceSolver_Builder::createFeature(
@@ -297,22 +343,27 @@ EntityWrapperPtr SolveSpaceSolver_Builder::createFeature(
     return createLine(theFeature, theAttributes, theGroupID, theSketchID);
   // Circle
   else if (aFeatureKind == SketchPlugin_Circle::ID())
-    return createCircle(theFeature, theAttributes,theGroupID, theSketchID);
+    return createCircle(theFeature, theAttributes, theGroupID, theSketchID);
   // Arc
   else if (aFeatureKind == SketchPlugin_Arc::ID())
-    return createArc(theFeature, theAttributes,theGroupID, theSketchID);
+    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()) {
+  else if (aFeatureKind == SketchPlugin_Point::ID() ||
+           aFeatureKind == SketchPlugin_IntersectionPoint::ID()) {
     AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID());
     if (!aPoint->isInitialized())
       return aDummy;
-    EntityWrapperPtr aSub = createAttribute(aPoint, theGroupID, theSketchID);
+    EntityWrapperPtr aSub = theAttributes.empty() ?
+                            createAttribute(aPoint, theGroupID, theSketchID) :
+                            theAttributes.front();
     if (!aSub)
       return aDummy;
 
     const Slvs_Entity& aSubEnt =
         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(aSub)->entity();
-    return EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, aPoint, aSubEnt));
+    EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theFeature, aPoint, aSubEnt));
+    aResult->setSubEntities(theAttributes);
+    return aResult;
   }
 
   // wrong entity
@@ -354,8 +405,10 @@ EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute(
     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()));
+      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);
@@ -364,7 +417,8 @@ EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute(
       AttributeDoublePtr aScalar =
           std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
       if (aScalar) {
-        aParameters.push_back(createParameter(theGroupID, aScalar->value(), !aScalar->text().empty()));
+        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);
@@ -432,7 +486,7 @@ EntityWrapperPtr SolveSpaceSolver_Builder::createNormal(
   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) || 
+      (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
       !aNorm->isInitialized())
     return EntityWrapperPtr();
   // calculate Y direction
@@ -487,7 +541,7 @@ EntityWrapperPtr createLine(FeaturePtr theFeature,
   EntityWrapperPtr aStartEnt, aEndEnt;
   std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
   for (; anIt != theAttributes.end(); ++anIt) {
-    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity = 
+    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
     if (aSlvsEntity->isBase(aStart))
       aStartEnt = aSlvsEntity;
@@ -523,7 +577,7 @@ EntityWrapperPtr createCircle(FeaturePtr theFeature,
   EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt;
   std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
   for (; anIt != theAttributes.end(); ++anIt) {
-    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity = 
+    std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
     if (aSlvsEntity->isBase(aCenter))
       aCenterEnt = aSlvsEntity;
@@ -563,7 +617,7 @@ EntityWrapperPtr createArc(FeaturePtr theFeature,
   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::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
     if (aSlvsEntity->isBase(aCenter))
       aCenterEnt = aSlvsEntity;
@@ -633,59 +687,38 @@ void adjustAngle(ConstraintWrapperPtr theConstraint)
   std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
     std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
 
+  bool isFixed[2][2];
   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)
+    for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt) {
+      isFixed[i][j] = ((*aLPIt)->group() != theConstraint->group());
       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]))
   };
-  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 isReversed[2] = {
+    aConstraint->baseConstraint()->boolean(
+        SketchPlugin_ConstraintAngle::ANGLE_REVERSED_FIRST_LINE_ID())->value(),
+    aConstraint->baseConstraint()->boolean(
+        SketchPlugin_ConstraintAngle::ANGLE_REVERSED_SECOND_LINE_ID())->value()
+  };
+  std::shared_ptr<GeomAPI_Angle2d>
+    anAngle(new GeomAPI_Angle2d(aLine[0], isReversed[0], aLine[1], isReversed[1]));
+  std::shared_ptr<GeomAPI_Pnt2d> aCenter = anAngle->center();
 
   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;
+  aSlvsConstraint.other = isReversed[0] != isReversed[1];
 }
 
 void adjustMirror(ConstraintWrapperPtr theConstraint)
@@ -726,124 +759,32 @@ void makeMirrorPoints(EntityWrapperPtr theOriginal,
     (*aMIt)->setValue(aCoord[i]);
 
   // update corresponding attribute
-  AttributePtr anAttr = std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMirrored)->baseAttribute();
+  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);
+    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)
+void adjustPtLineDistance(ConstraintWrapperPtr theConstraint)
 {
   BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
 
-  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();
-
-  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());
-
-  bool isFullValue = theConstraint->isFullValue();
-  int aNbObjects = aSubs.size()-3;
-  if (isFullValue && aNbObjects > 0) {
-    aDelta->setX(aDelta->x()/aNbObjects);
-    aDelta->setY(aDelta->y()/aNbObjects);
+  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::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
-  for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
-    translate(*aPrevIt, *aSIt, aDelta);
+  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));
 }