]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Code optimization of multi-rotation and multi-translation in SketchSolver
authorazv <azv@opencascade.com>
Wed, 2 Sep 2015 09:22:33 +0000 (12:22 +0300)
committerazv <azv@opencascade.com>
Wed, 2 Sep 2015 11:28:28 +0000 (14:28 +0300)
src/SketchSolver/CMakeLists.txt
src/SketchSolver/SketchSolver_ConstraintMulti.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintMulti.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp
src/SketchSolver/SketchSolver_ConstraintMultiRotation.h
src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp
src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h

index eedad7a0f778ed13ff1c3aa0c9c7a7d5a2640f80..7c4c8c29e0cc3fdb0743b641024ed7e2159a91b2 100644 (file)
@@ -17,6 +17,7 @@ SET(PROJECT_HEADERS
     SketchSolver_ConstraintMirror.h
     SketchSolver_ConstraintRigid.h
     SketchSolver_ConstraintTangent.h
+    SketchSolver_ConstraintMulti.h
     SketchSolver_ConstraintMultiRotation.h
     SketchSolver_ConstraintMultiTranslation.h
     SketchSolver_ConstraintMovement.h
@@ -39,6 +40,7 @@ SET(PROJECT_SOURCES
     SketchSolver_ConstraintMirror.cpp
     SketchSolver_ConstraintRigid.cpp
     SketchSolver_ConstraintTangent.cpp
+    SketchSolver_ConstraintMulti.cpp
     SketchSolver_ConstraintMultiRotation.cpp
     SketchSolver_ConstraintMultiTranslation.cpp
     SketchSolver_ConstraintMovement.cpp
diff --git a/src/SketchSolver/SketchSolver_ConstraintMulti.cpp b/src/SketchSolver/SketchSolver_ConstraintMulti.cpp
new file mode 100644 (file)
index 0000000..92a79eb
--- /dev/null
@@ -0,0 +1,235 @@
+#include <SketchSolver_ConstraintMulti.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.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)
+{
+  // 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());
+    }
+
+    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);
+    }
+  }
+}
+
+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 aNbCopies = myBaseConstraint->integer(nameNbCopies());
+    if (anInitialRefList->size() != myNumberOfObjects || aNbCopies->value() != myNumberOfCopies) {
+      remove(myBaseConstraint);
+      process();
+      return;
+    }
+  }
+
+  updateLocal();
+  SketchSolver_Constraint::update();
+}
+
+bool SketchSolver_ConstraintMulti::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);
+  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;
+}
+
+void SketchSolver_ConstraintMulti::addFeature(FeaturePtr theFeature)
+{
+  SketchSolver_Constraint::addFeature(theFeature);
+
+  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.find(theFeature);
+  if (aFeatIt == myFeatureMap.end())
+    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]);
+}
+
+void SketchSolver_ConstraintMulti::adjustConstraint()
+{
+  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]);
+
+      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();
+}
diff --git a/src/SketchSolver/SketchSolver_ConstraintMulti.h b/src/SketchSolver/SketchSolver_ConstraintMulti.h
new file mode 100644 (file)
index 0000000..cf2f16d
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_ConstraintMulti.h
+// Created: 2 Sep 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintMulti_H_
+#define SketchSolver_ConstraintMulti_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+#include <vector>
+
+/** \class   SketchSolver_ConstraintMulti
+ *  \ingroup Plugins
+ *  \brief   Common base class for the Multi constraints
+ */
+class SketchSolver_ConstraintMulti : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintMulti(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint),
+      myNumberOfObjects(0),
+      myNumberOfCopies(0)
+  {}
+
+  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);
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process()
+  { /* do nothing here */ }
+
+  /// \brief Collect entities and their copies, like circles and arcs
+  void processEntities(const std::vector< std::vector<Slvs_hEntity> >& 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)
+  { /* do nothing here */ }
+
+  /// \brief This method is used in derived objects to check consistence of constraint.
+  virtual void adjustConstraint();
+
+  /// \brief Update parameters of derived classes
+  virtual void updateLocal() = 0;
+
+  /// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature
+  virtual const std::string& nameNbCopies() = 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
+};
+
+#endif
index ea4372fa648560509db0dfd30dde79a149fc4d96..da083caf78ce6f5f10ee05f58dab11c30d44fbef 100644 (file)
 
 #include <math.h>
 
-static double squareDistance(
-    StoragePtr theStorage, const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2)
-{
-  Slvs_Entity aPoint1 = theStorage->getEntity(thePoint1);
-  Slvs_Entity aPoint2 = theStorage->getEntity(thePoint2);
-  double x1 = theStorage->getParameter(aPoint1.param[0]).val;
-  double y1 = theStorage->getParameter(aPoint1.param[1]).val;
-  double x2 = theStorage->getParameter(aPoint2.param[0]).val;
-  double y2 = theStorage->getParameter(aPoint2.param[1]).val;
-  return (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2);
-}
-
 void SketchSolver_ConstraintMultiRotation::getAttributes(
     Slvs_hEntity& theCenter, double& theAngle,
     std::vector< std::vector<Slvs_hEntity> >& thePoints,
@@ -138,131 +126,20 @@ void SketchSolver_ConstraintMultiRotation::process()
     mySlvsConstraints.push_back(aConstraint.h);
   }
 
-  // Keep all objects unchanged (only initial object may be changed by user)
-  myCircsAndCopies.clear();
-  std::vector<std::vector<Slvs_hEntity> >::const_iterator anEntIt = anEntitiesAndCopies.begin();
-  std::vector<Slvs_hEntity>::const_iterator aCpIt;
-  for (; anEntIt != anEntitiesAndCopies.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());
-    }
-
-    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);
-    }
-  }
-
+  processEntities(anEntitiesAndCopies);
   adjustConstraint();
 }
 
-void SketchSolver_ConstraintMultiRotation::update(ConstraintPtr theConstraint)
+void SketchSolver_ConstraintMultiRotation::updateLocal()
 {
-  cleanErrorMsg();
-  if (!theConstraint || theConstraint == myBaseConstraint) {
-    AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-        myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-    AttributeIntegerPtr aNbCopies = myBaseConstraint->integer(SketchPlugin_MultiRotation::NUMBER_OF_COPIES_ID());
-    if (anInitialRefList->size() != myNumberOfObjects || aNbCopies->value() != myNumberOfCopies) {
-      remove(myBaseConstraint);
-      process();
-      return;
-    }
-  }
-
   // update angle value
   myAngle = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
       myBaseConstraint->attribute(SketchPlugin_MultiRotation::ANGLE_ID()))->value();
-
-  SketchSolver_Constraint::update();
-}
-
-bool SketchSolver_ConstraintMultiRotation::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);
-  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;
-}
-
-void SketchSolver_ConstraintMultiRotation::addFeature(FeaturePtr theFeature)
-{
-  SketchSolver_Constraint::addFeature(theFeature);
-
-  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.find(theFeature);
-  if (aFeatIt == myFeatureMap.end())
-    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]);
 }
 
 void SketchSolver_ConstraintMultiRotation::adjustConstraint()
 {
-  if (abs(myAngle) < tolerance) {
+  if (fabs(myAngle) < tolerance) {
     myStorage->setNeedToResolve(false);
     return;
   }
@@ -290,102 +167,39 @@ void SketchSolver_ConstraintMultiRotation::adjustConstraint()
 
   // Obtain coordinates of rotation center
   Slvs_Entity aRotCenter = myStorage->getEntity(myRotationCenter);
-  double aCenterXY[2];
-  for (int i = 0; i < 2; i++)
-    aCenterXY[i] = myStorage->getParameter(aRotCenter.param[i]).val;
-
-  double cosA = cos(myAngle * PI / 180.0);
-  double sinA = sin(myAngle * PI / 180.0);
-
-  double aVec[2]; // coordinates of vector defining a direction from rotation center to a point
-
-  // 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++)
-      aVec[i] = myStorage->getParameter(anInitial.param[i]).val - aCenterXY[i];
-
-    // 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
+  myCenterCoord[0] = myStorage->getParameter(aRotCenter.param[0]).val;
+  myCenterCoord[1] = myStorage->getParameter(aRotCenter.param[1]).val;
 
-        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);
-          aVec[i] = anOtherParam.val - aCenterXY[i];
-        }
-      }
-    }
+  myRotationVal[0] = sin(myAngle * PI / 180.0);
+  myRotationVal[1] = cos(myAngle * PI / 180.0);
 
-    // update copied points
-    aCopyIter = aPointsIter->begin();
-    for (++aCopyIter; aCopyIter != aPointsIter->end(); ++aCopyIter) {
-      // rotate direction
-      double aTemp = aVec[0] * cosA - aVec[1] * sinA;
-      aVec[1] = aVec[0] * sinA + aVec[1] * cosA;
-      aVec[0] = aTemp;
+  SketchSolver_ConstraintMulti::adjustConstraint();
+}
 
-      const Slvs_Entity& aTarget = myStorage->getEntity(*aCopyIter);
-      for (int i = 0; i < 2; i++) {
-        Slvs_Param aParam = myStorage->getParameter(aTarget.param[i]);
-        aParam.val = aCenterXY[i] + aVec[i];
-        myStorage->updateParameter(aParam);
-      }
-    }
-  }
+void SketchSolver_ConstraintMultiRotation::getRelative(
+    double theAbsX, double theAbsY, double& theRelX, double& theRelY)
+{
+  theRelX = theAbsX - myCenterCoord[0];
+  theRelY = theAbsY - myCenterCoord[1];
+}
 
-  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]);
+void SketchSolver_ConstraintMultiRotation::getAbsolute(
+    double theRelX, double theRelY, double& theAbsX, double& theAbsY)
+{
+  theAbsX = theRelX + myCenterCoord[0];
+  theAbsY = theRelY + myCenterCoord[1];
+}
 
-      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;
-          }
-      }
-    }
-  }
+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;
+}
 
-  myPointsJustUpdated.clear();
+const std::string& SketchSolver_ConstraintMultiRotation::nameNbCopies()
+{
+  return SketchPlugin_MultiRotation::NUMBER_OF_COPIES_ID();
 }
index 3294112dd10378148f03831c0f23af911982be95..94355ba5bf2777876ad5cf7918de579091b19f8e 100644 (file)
@@ -8,46 +8,26 @@
 #define SketchSolver_ConstraintMultiRotation_H_
 
 #include "SketchSolver.h"
-#include <SketchSolver_Constraint.h>
-
-#include <vector>
+#include <SketchSolver_ConstraintMulti.h>
 
 /** \class   SketchSolver_ConstraintMultiRotation
  *  \ingroup Plugins
  *  \brief   Convert rotated features to the list of SolveSpace constraints
  */
-class SketchSolver_ConstraintMultiRotation : public SketchSolver_Constraint
+class SketchSolver_ConstraintMultiRotation : public SketchSolver_ConstraintMulti
 {
 public:
   SketchSolver_ConstraintMultiRotation(ConstraintPtr theConstraint) :
-      SketchSolver_Constraint(theConstraint),
-      myNumberOfObjects(0),
-      myNumberOfCopies(0)
+      SketchSolver_ConstraintMulti(theConstraint)
   {}
 
   virtual int getType() const
   { return SLVS_C_MULTI_ROTATION; }
 
-  /// \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);
-
 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)
-  { /* do nothing here */ }
-
   /// \brief Generate list of rotated entities
   /// \param[out] theCenter   ID of central point of rotation
   /// \param[out] theAngle    rotation angle
@@ -60,16 +40,27 @@ protected:
   /// \brief This method is used in derived objects to check consistence of constraint.
   virtual void adjustConstraint();
 
+  /// \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& nameNbCopies();
+
 private:
-  size_t myNumberOfObjects; ///< number of previous initial objects
-  size_t myNumberOfCopies;  ///< number of previous copies of initial objects
   Slvs_hEntity myRotationCenter; ///< ID of center of rotation
-  double myAngle;           ///< angle of rotation
-  std::vector< std::vector<Slvs_hEntity> > myPointsAndCopies; ///< list of initial points and their rotated copies
-  std::vector< std::vector<Slvs_hEntity> > myCircsAndCopies;  ///< list of circles and their copies (to change their radii together)
+  double       myAngle;           ///< angle of rotation
 
-  std::set<Slvs_hEntity> myPointsJustUpdated; ///< list of points touched by user
-  std::set<Slvs_hEntity> myInitialPoints;     ///< list of points containig initial objects
+  double myCenterCoord[2]; ///< coordinates of rotation center
+  double myRotationVal[2]; ///< sinus and cosinus of rotation angle
 };
 
 #endif
index eb6b61e43c3f1c2478e2f8285bba120bcd837431..816aa8fccb6610cf125e4f7e895c903d79afe89c 100644 (file)
@@ -138,119 +138,10 @@ void SketchSolver_ConstraintMultiTranslation::process()
     }
   }
 
-  // Keep all objects unchanged (only initial object may be changed by user)
-  myCircsAndCopies.clear();
-  std::vector<std::vector<Slvs_hEntity> >::const_iterator anEntIt = anEntitiesAndCopies.begin();
-  std::vector<Slvs_hEntity>::const_iterator aCpIt;
-  for (; anEntIt != anEntitiesAndCopies.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());
-    }
-
-    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);
-    }
-  }
-
+  processEntities(anEntitiesAndCopies);
   adjustConstraint();
 }
 
-void SketchSolver_ConstraintMultiTranslation::update(ConstraintPtr theConstraint)
-{
-  cleanErrorMsg();
-  if (!theConstraint || theConstraint == myBaseConstraint) {
-    AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-        myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-    AttributeIntegerPtr aNbCopies = myBaseConstraint->integer(SketchPlugin_MultiTranslation::NUMBER_OF_COPIES_ID());
-    if (anInitialRefList->size() != myNumberOfObjects ||
-        (size_t)aNbCopies->value() != myNumberOfCopies) {
-      remove(myBaseConstraint);
-      process();
-      return;
-    }
-  }
-  SketchSolver_Constraint::update();
-}
-
-bool SketchSolver_ConstraintMultiTranslation::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);
-
-  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;
-  }
-
-  return true;
-}
-
-void SketchSolver_ConstraintMultiTranslation::addFeature(FeaturePtr theFeature)
-{
-  SketchSolver_Constraint::addFeature(theFeature);
-
-  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.find(theFeature);
-  if (aFeatIt == myFeatureMap.end())
-    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]);
-}
-
 void SketchSolver_ConstraintMultiTranslation::adjustConstraint()
 {
   Slvs_Entity aTranslationLine = myStorage->getEntity(myTranslationLine);
@@ -273,103 +164,38 @@ void SketchSolver_ConstraintMultiTranslation::adjustConstraint()
     aXY[2*i] = myStorage->getParameter(aPnt.param[0]).val;
     aXY[2*i+1] = myStorage->getParameter(aPnt.param[1]).val;
   }
-  double aDelta[2] = {aXY[2] - aXY[0], aXY[3] - aXY[1]};
-  if (fabs(aDelta[0]) + fabs(aDelta[1]) < tolerance) {
+  myDelta[0] = aXY[2] - aXY[0];
+  myDelta[1] = aXY[3] - aXY[1];
+  if (fabs(myDelta[0]) + fabs(myDelta[1]) < tolerance) {
     myStorage->setNeedToResolve(false);
     return;
   }
 
-  std::list<Slvs_Constraint> aCoincident = myStorage->getConstraintsByType(SLVS_C_POINTS_COINCIDENT);
-  std::list<Slvs_Constraint>::const_iterator aCoIt;
-
-  double aCoord[2];
-
-  // Update positions of all points to satisfy distances
-  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++)
-      aCoord[i] = myStorage->getParameter(anInitial.param[i]).val;
-
-    // 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);
-          aCoord[i] = anOtherParam.val;
-        }
-      }
-    }
-
-    // update copied points
-    aCopyIter = aPointsIter->begin();
-    for (++aCopyIter; aCopyIter != aPointsIter->end(); ++aCopyIter) {
-      // update position
-      aCoord[0] += aDelta[0];
-      aCoord[1] += aDelta[1];
+  SketchSolver_ConstraintMulti::adjustConstraint();
+}
 
-      const Slvs_Entity& aTarget = myStorage->getEntity(*aCopyIter);
-      for (int i = 0; i < 2; i++) {
-        Slvs_Param aParam = myStorage->getParameter(aTarget.param[i]);
-        aParam.val = aCoord[i];
-        myStorage->updateParameter(aParam);
-      }
-    }
-  }
+void SketchSolver_ConstraintMultiTranslation::getRelative(
+    double theAbsX, double theAbsY, double& theRelX, double& theRelY)
+{
+  theRelX = theAbsX;
+  theRelY = theAbsY;
+}
 
-  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]);
+void SketchSolver_ConstraintMultiTranslation::getAbsolute(
+    double theRelX, double theRelY, double& theAbsX, double& theAbsY)
+{
+  theAbsX = theRelX;
+  theAbsY = theRelY;
+}
 
-      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;
-          }
-      }
-    }
-  }
+void SketchSolver_ConstraintMultiTranslation::transformRelative(double& theX, double& theY)
+{
+  // translate coordinates
+  theX += myDelta[0];
+  theY += myDelta[1];
+}
 
-  myPointsJustUpdated.clear();
+const std::string& SketchSolver_ConstraintMultiTranslation::nameNbCopies()
+{
+  return SketchPlugin_MultiTranslation::NUMBER_OF_COPIES_ID();
 }
index 10d44dbf1051eae40db2908622f0ee6b5acef943..68c4fbcb8c69eab3791fa5db113c4875b83fce74 100644 (file)
@@ -8,45 +8,27 @@
 #define SketchSolver_ConstraintMultiTranslation_H_
 
 #include "SketchSolver.h"
-#include <SketchSolver_Constraint.h>
+#include <SketchSolver_ConstraintMulti.h>
 
 /** \class   SketchSolver_ConstraintMultiTranslation
  *  \ingroup Plugins
  *  \brief   Convert translated features to the list of SolveSpace constraints
  */
-class SketchSolver_ConstraintMultiTranslation : public SketchSolver_Constraint
+class SketchSolver_ConstraintMultiTranslation : public SketchSolver_ConstraintMulti
 {
 public:
   SketchSolver_ConstraintMultiTranslation(ConstraintPtr theConstraint) :
-      SketchSolver_Constraint(theConstraint),
-      myNumberOfObjects(0),
-      myNumberOfCopies(0),
+      SketchSolver_ConstraintMulti(theConstraint),
       myTranslationLine(SLVS_E_UNKNOWN)
   {}
 
   virtual int getType() const
   { return SLVS_C_MULTI_TRANSLATION; }
 
-  /// \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);
-
 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)
-  { /* do nothing here */ }
-
   /// \brief Generate list of translated entities
   /// \param[out] theStartPoint ID of start point of translation
   /// \param[out] theEndPoint   ID of final point of translation
@@ -59,15 +41,26 @@ protected:
   /// \brief This method is used in derived objects to check consistence of constraint.
   virtual void adjustConstraint();
 
+  /// \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& nameNbCopies();
+
 private:
-  size_t myNumberOfObjects; ///< number of previous initial objects
-  size_t myNumberOfCopies;  ///< number of previous copies of initial objects
   Slvs_hEntity myTranslationLine; ///< ID of translation line
-  std::vector< std::vector<Slvs_hEntity> > myPointsAndCopies; ///< list of initial points and their translated 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 containig initial objects
+  double myDelta[2]; ///< increment of translation
 };
 
 #endif