Salome HOME
Test cases for constraint Angle, Multi-Rotation, Multi-Translation and Fillet features
authorazv <azv@opencascade.com>
Fri, 18 Sep 2015 16:08:27 +0000 (19:08 +0300)
committerazv <azv@opencascade.com>
Fri, 18 Sep 2015 16:30:39 +0000 (19:30 +0300)
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/Test/TestConstraintAngle.py [new file with mode: 0644]
src/SketchPlugin/Test/TestFillet.py [new file with mode: 0644]
src/SketchPlugin/Test/TestMultiRotation.py [new file with mode: 0644]
src/SketchPlugin/Test/TestMultiTranslation.py [new file with mode: 0644]

index 1780d356e10a46311bf4b0f64199d32bf7580051..508a7404906528307802a8a2607e85752352078c 100644 (file)
@@ -114,5 +114,9 @@ ADD_UNIT_TESTS(TestSketchPointLine.py
                TestConstraintEqual.py
                TestConstraintTangent.py
                TestConstraintMirror.py
+               TestConstraintAngle.py
+               TestMultiRotation.py
+               TestMultiTranslation.py
+               TestFillet.py
                TestHighload.py
                TestSnowflake.py)
diff --git a/src/SketchPlugin/Test/TestConstraintAngle.py b/src/SketchPlugin/Test/TestConstraintAngle.py
new file mode 100644 (file)
index 0000000..43b8ff0
--- /dev/null
@@ -0,0 +1,129 @@
+"""
+    TestConstraintAngle.py
+    Unit test of SketchPlugin_ConstraintAngle class
+        
+    SketchPlugin_ConstraintAngle
+        static const std::string MY_CONSTRAINT_ANGLE_ID("SketchConstraintAngle");
+        data()->addAttribute(SketchPlugin_Constraint::VALUE(),    ModelAPI_AttributeDouble::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
+        
+    
+"""
+from GeomDataAPI import *
+from ModelAPI import *
+import os
+import math
+
+#=========================================================================
+# Auxiliary functions
+#=========================================================================
+
+def angle(theLine1, theLine2):
+    # subroutine to angle between two lines
+    aStartPoint1 = geomDataAPI_Point2D(theLine1.attribute("StartPoint"))
+    aEndPoint1   = geomDataAPI_Point2D(theLine1.attribute("EndPoint"))
+    aStartPoint2 = geomDataAPI_Point2D(theLine2.attribute("StartPoint"))
+    aEndPoint2   = geomDataAPI_Point2D(theLine2.attribute("EndPoint"))
+    
+    aDirX1 = aEndPoint1.x() - aStartPoint1.x()
+    aDirY1 = aEndPoint1.y() - aStartPoint1.y()
+    aLen1 = math.hypot(aDirX1, aDirY1)
+    aDirX2 = aEndPoint2.x() - aStartPoint2.x()
+    aDirY2 = aEndPoint2.y() - aStartPoint2.y()
+    aLen2 = math.hypot(aDirX2, aDirY2)
+    
+    aDot = aDirX1 * aDirX2 + aDirY1 * aDirY2
+    
+    anAngle = math.acos(aDot / aLen1 / aLen2)
+    return round(anAngle * 180. / math.pi, 6)
+
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2015-09-18"
+
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchCommonFeature = aDocument.addFeature("Sketch")
+aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+#=========================================================================
+# Create two lines
+#=========================================================================
+aSession.startOperation()
+aSketchLineA = aSketchFeature.addFeature("SketchLine")
+aStartPoint = geomDataAPI_Point2D(aSketchLineA.attribute("StartPoint"))
+aEndPoint = geomDataAPI_Point2D(aSketchLineA.attribute("EndPoint"))
+aStartPoint.setValue(-10., 25.)
+aEndPoint.setValue(100., 25.)
+
+aSketchLineB = aSketchFeature.addFeature("SketchLine")
+aStartPoint = geomDataAPI_Point2D(aSketchLineB.attribute("StartPoint"))
+aEndPoint = geomDataAPI_Point2D(aSketchLineB.attribute("EndPoint"))
+aStartPoint.setValue(-20., 15.)
+aEndPoint.setValue(80., 50.)
+aSession.finishOperation()
+#=========================================================================
+# Make a constraint to keep the angle
+#=========================================================================
+ANGLE_DEGREE = 30.
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintAngle")
+anAngleVal = aConstraint.real("ConstraintValue")
+refattrA = aConstraint.refattr("ConstraintEntityA")
+refattrB = aConstraint.refattr("ConstraintEntityB")
+assert (not anAngleVal.isInitialized())
+assert (not refattrA.isInitialized())
+assert (not refattrB.isInitialized())
+anAngleVal.setValue(ANGLE_DEGREE)
+refattrA.setObject(aSketchLineA.firstResult())
+refattrB.setObject(aSketchLineB.firstResult())
+aConstraint.execute()
+aSession.finishOperation()
+assert (anAngleVal.isInitialized())
+assert (refattrA.isInitialized())
+assert (refattrB.isInitialized())
+assert (angle(aSketchLineA, aSketchLineB) == ANGLE_DEGREE)
+#=========================================================================
+# Move line, check that angle is constant
+#=========================================================================
+aSession.startOperation()
+aStartPoint = geomDataAPI_Point2D(aSketchLineA.attribute("StartPoint"))
+aStartPoint.setValue(0., 30.)
+aConstraint.execute()
+aSession.finishOperation()
+assert (angle(aSketchLineA, aSketchLineB) == ANGLE_DEGREE)
+#=========================================================================
+# Change angle value and check the lines are moved
+#=========================================================================
+NEW_ANGLE_DEGREE = 60.
+aSession.startOperation()
+anAngleVal.setValue(NEW_ANGLE_DEGREE)
+aConstraint.execute()
+aSession.finishOperation()
+assert (angle(aSketchLineA, aSketchLineB) == NEW_ANGLE_DEGREE)
+#=========================================================================
+# TODO: improve test
+# 1. remove constraint, move line's start point to
+#    check that constraint are not applied
+# 2. check constrained distance between:
+#    * point and line
+#    * two lines
+#=========================================================================
+#=========================================================================
+# End of test
+#=========================================================================
diff --git a/src/SketchPlugin/Test/TestFillet.py b/src/SketchPlugin/Test/TestFillet.py
new file mode 100644 (file)
index 0000000..5d719a1
--- /dev/null
@@ -0,0 +1,148 @@
+"""
+    TestFillet.py
+    Unit test of SketchPlugin_ConstraintFillet class
+        
+    SketchPlugin_ConstraintFillet
+        static const std::string MY_CONSTRAINT_FILLET_ID("SketchConstraintFillet");
+        data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeRefList::typeId());
+
+"""
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+
+#=========================================================================
+# Auxiliary functions
+#=========================================================================
+def createSketch(theSketch):
+    # Initialize sketch by two lines with coincident boundary
+    allFeatures = []
+    # Line1
+    aSketchLine1 = theSketch.addFeature("SketchLine")
+    aStartPoint1 = geomDataAPI_Point2D(aSketchLine1.attribute("StartPoint"))
+    aEndPoint1   = geomDataAPI_Point2D(aSketchLine1.attribute("EndPoint"))
+    aStartPoint1.setValue(10., 5.)
+    aEndPoint1.setValue(-10., 10.)
+    allFeatures.append(aSketchLine1)
+    # Line2
+    aSketchLine2 = theSketch.addFeature("SketchLine")
+    aStartPoint2 = geomDataAPI_Point2D(aSketchLine2.attribute("StartPoint"))
+    aEndPoint2   = geomDataAPI_Point2D(aSketchLine2.attribute("EndPoint"))
+    aStartPoint2.setValue(10., 5.)
+    aEndPoint2.setValue(15., 20.)
+    allFeatures.append(aSketchLine2)
+    # Coincidence
+    aCoincidence = theSketch.addFeature("SketchConstraintCoincidence")
+    aCoincidence.refattr("ConstraintEntityA").setAttr(aStartPoint1)
+    aCoincidence.refattr("ConstraintEntityB").setAttr(aStartPoint2)
+    
+    theSketch.execute()
+    return allFeatures
+    
+def checkFillet(theObjects, theRadius):
+    # Verify the arc and lines are connected smoothly
+    aLine = []
+    anArc = []
+    aSize = theObjects.size()
+    for i in range (0, aSize):
+        feat = ModelAPI_Feature.feature(theObjects.object(i))
+        assert(feat is not None)
+        if (feat.getKind() == "SketchLine"):
+            aLine.append(feat)
+        elif (feat.getKind() == "SketchArc"):
+            anArc.append(feat)
+    assert(anArc)
+    assert(anArc[0] is not None)
+    
+    anArcPoints = []
+    aPoint = geomDataAPI_Point2D(anArc[0].attribute("ArcStartPoint"))
+    anArcPoints.append((aPoint.x(), aPoint.y()))
+    aPoint = geomDataAPI_Point2D(anArc[0].attribute("ArcEndPoint"))
+    anArcPoints.append((aPoint.x(), aPoint.y()))
+    aPoint = geomDataAPI_Point2D(anArc[0].attribute("ArcCenter"))
+    aCenterX = aPoint.x()
+    aCenterY = aPoint.y()
+    
+    for line in aLine:
+        aStartPoint = geomDataAPI_Point2D(line.attribute("StartPoint"))
+        aEndPoint = geomDataAPI_Point2D(line.attribute("EndPoint"))
+        
+        aLinePoints = []
+        aLinePoints.append((aStartPoint.x(), aStartPoint.y()))
+        aLinePoints.append((aEndPoint.x(), aEndPoint.y()))
+        
+        aLineDirX = aEndPoint.x() - aStartPoint.x()
+        aLineDirY = aEndPoint.y() - aStartPoint.y()
+        
+        for arcPt in anArcPoints:
+            for linePt in aLinePoints:
+                if (math.hypot(linePt[0]-arcPt[0], linePt[1]-arcPt[1]) < 1.e-10):
+                    aDirX = linePt[0] - aCenterX
+                    aDirY = linePt[1] - aCenterY
+                    assert(math.fabs(math.hypot(aDirX, aDirY) - theRadius) < 1.e-7)
+                    aDot = aDirX * aLineDirX + aDirY * aLineDirY
+                    assert(math.fabs(aDot) < 1.e-7)
+                    break;
+
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2015-09-18"
+
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchCommonFeature = aDocument.addFeature("Sketch")
+aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+#=========================================================================
+# Initialize sketch
+#=========================================================================
+aSession.startOperation()
+aFeaturesList = createSketch(aSketchFeature)
+aSession.finishOperation()
+#=========================================================================
+# Global variables
+#=========================================================================
+FILLET_RADIUS1 = 3.
+FILLET_RADIUS2 = 5.
+#=========================================================================
+# Create the Fillet
+#=========================================================================
+aSession.startOperation()
+aFillet = aSketchFeature.addFeature("SketchConstraintFillet")
+aRefAttrA = aFillet.refattr("ConstraintEntityA");
+aRefAttrB = aFillet.refattr("ConstraintEntityB");
+aResConstr = modelAPI_ResultConstruction(aFeaturesList[0].lastResult())
+assert(aResConstr)
+aRefAttrA.setObject(aResConstr)
+aResConstr = modelAPI_ResultConstruction(aFeaturesList[1].lastResult())
+assert(aResConstr)
+aRefAttrB.setObject(aResConstr)
+aRadius = aFillet.real("ConstraintValue")
+aRadius.setValue(FILLET_RADIUS1)
+aFillet.execute()
+aResObjects = aFillet.reflist("ConstraintEntityC")
+#=========================================================================
+# Verify the objects of fillet are created
+#=========================================================================
+assert(aResObjects)
+checkFillet(aResObjects, FILLET_RADIUS1)
+aSession.finishOperation()
+#=========================================================================
+# End of test
+#=========================================================================
diff --git a/src/SketchPlugin/Test/TestMultiRotation.py b/src/SketchPlugin/Test/TestMultiRotation.py
new file mode 100644 (file)
index 0000000..bee56e4
--- /dev/null
@@ -0,0 +1,151 @@
+"""
+    TestMultiRotation.py
+    Unit test of SketchPlugin_MultiRotation class
+        
+    SketchPlugin_MultiRotation
+        static const std::string MY_CONSTRAINT_ROTATION_ID("SketchMultiRotation");
+        data()->addAttribute(START_POINT_ID(), GeomDataAPI_Point2D::typeId());
+        data()->addAttribute(END_POINT_ID(), GeomDataAPI_Point2D::typeId());
+        data()->addAttribute(NUMBER_OF_COPIES_ID(), ModelAPI_AttributeInteger::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefList::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::typeId());
+        data()->addAttribute(ROTATION_LIST_ID(), ModelAPI_AttributeRefList::typeId());
+
+"""
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+
+#=========================================================================
+# Auxiliary functions
+#=========================================================================
+def createSketch(theSketch):
+    # Initialize sketch by arc
+    allFeatures = []
+    # Create arc
+    aSketchArc = theSketch.addFeature("SketchArc")
+    aCenter     = geomDataAPI_Point2D(aSketchArc.attribute("ArcCenter"))
+    aStartPoint = geomDataAPI_Point2D(aSketchArc.attribute("ArcStartPoint"))
+    aEndPoint   = geomDataAPI_Point2D(aSketchArc.attribute("ArcEndPoint"))
+    aCenter.setValue(5., 5.)
+    aStartPoint.setValue(10., 5.)
+    aEndPoint.setValue(5., 10.)
+    allFeatures.append(aSketchArc)
+    theSketch.execute()
+    return allFeatures
+    
+def checkRotation(theObjects, theNbCopies, theCenterX, theCenterY, theAngle):
+    # Verify distances of the objects and the number of copies
+    aFeatures = []
+    aSize = theObjects.size()
+    for i in range (0, aSize):
+        feat = ModelAPI_Feature.feature(theObjects.object(i))
+        assert(feat is not None)
+        aFeatures.append(feat)
+        
+    cosA = math.cos(theAngle * math.pi / 180.)
+        
+    anInd = 0 
+    for feat, next in zip(aFeatures[:-1], aFeatures[1:]):
+        anInd = anInd + 1
+        if (anInd > theNbCopies):
+            anInd = 0
+            continue
+        assert(feat.getKind() == next.getKind())
+        
+        anAttributes = []
+        if (feat.getKind() == "SketchLine"):
+            anAttributes.append('StartPoint')
+            anAttributes.append('EndPoint')
+        elif (feat.getKind() == "SketchArc"):
+            anAttributes.append('ArcCenter')
+            anAttributes.append('ArcStartPoint')
+            anAttributes.append('ArcEndPoint')
+            
+        for attr in anAttributes:
+            aPoint1 = geomDataAPI_Point2D(feat.attribute(attr))
+            aPoint2 = geomDataAPI_Point2D(next.attribute(attr))
+            aDirX1 = aPoint1.x() - theCenterX
+            aDirY1 = aPoint1.y() - theCenterY
+            aLen1 = math.hypot(aDirX1, aDirY1)
+            aDirX2 = aPoint2.x() - theCenterX
+            aDirY2 = aPoint2.y() - theCenterY
+            aLen2 = math.hypot(aDirX2, aDirY2)
+            aLocCosA = (aDirX1 * aDirX2 + aDirY1 * aDirY2) / aLen1 / aLen2
+            assert(math.fabs(aLocCosA - cosA) < 1.e-10)
+    # Check the number of copies is as planed
+    assert(anInd == theNbCopies)
+
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2015-09-18"
+
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchCommonFeature = aDocument.addFeature("Sketch")
+aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+#=========================================================================
+# Initialize sketch
+#=========================================================================
+aSession.startOperation()
+aFeaturesList = createSketch(aSketchFeature)
+aSession.finishOperation()
+#=========================================================================
+# Global variables
+#=========================================================================
+CENTER_X = 0.
+CENTER_Y = 0.
+ANGLE = 30.
+#=========================================================================
+# Create the Rotation constraint
+#=========================================================================
+aSession.startOperation()
+aMultiRotation = aSketchFeature.addFeature("SketchMultiRotation")
+aRotList = aMultiRotation.reflist("MultiRotationList")
+for aFeature in aFeaturesList:
+    aResult = modelAPI_ResultConstruction(aFeature.lastResult())
+    assert(aResult is not None)
+    aRotList.append(aResult)
+aCenter = geomDataAPI_Point2D(aMultiRotation.attribute("MultiRotationCenter"))
+anAngle = aMultiRotation.real("MultiRotationAngle")
+aCenter.setValue(CENTER_X, CENTER_Y)
+anAngle.setValue(ANGLE)
+aNbCopies = aMultiRotation.integer("MultiRotationCopies")
+aNbCopies.setValue(1)
+aMultiRotation.execute()
+aSession.finishOperation()
+#=========================================================================
+# Verify the objects are moved for the specified distance
+#=========================================================================
+aRotated = aMultiRotation.reflist("ConstraintEntityB")
+checkRotation(aRotated, aNbCopies.value(), CENTER_X, CENTER_Y, ANGLE)
+#=========================================================================
+# Change number of copies and verify Rotation
+#=========================================================================
+aSession.startOperation()
+aNbCopies.setValue(3)
+aSession.finishOperation()
+aRotated = aMultiRotation.reflist("ConstraintEntityB")
+checkRotation(aRotated, aNbCopies.value(), CENTER_X, CENTER_Y, ANGLE)
+#=========================================================================
+# TODO: improve test
+# 1. Add more features into Rotation
+# 2. Move one of initial features and check the Rotated is moved too
+#=========================================================================
+#=========================================================================
+# End of test
+#=========================================================================
diff --git a/src/SketchPlugin/Test/TestMultiTranslation.py b/src/SketchPlugin/Test/TestMultiTranslation.py
new file mode 100644 (file)
index 0000000..b421c62
--- /dev/null
@@ -0,0 +1,146 @@
+"""
+    TestMultiTranslation.py
+    Unit test of SketchPlugin_MultiTranslation class
+        
+    SketchPlugin_MultiTranslation
+        static const std::string MY_CONSTRAINT_TRANSLATION_ID("SketchMultiTranslation");
+        data()->addAttribute(START_POINT_ID(), GeomDataAPI_Point2D::typeId());
+        data()->addAttribute(END_POINT_ID(), GeomDataAPI_Point2D::typeId());
+        data()->addAttribute(NUMBER_OF_COPIES_ID(), ModelAPI_AttributeInteger::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefList::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::typeId());
+        data()->addAttribute(TRANSLATION_LIST_ID(), ModelAPI_AttributeRefList::typeId());
+
+"""
+from GeomDataAPI import *
+from ModelAPI import *
+
+#=========================================================================
+# Auxiliary functions
+#=========================================================================
+def createSketch(theSketch):
+    # Initialize sketch by arc
+    allFeatures = []
+    # Create arc
+    aSketchArc = theSketch.addFeature("SketchArc")
+    aCenter     = geomDataAPI_Point2D(aSketchArc.attribute("ArcCenter"))
+    aStartPoint = geomDataAPI_Point2D(aSketchArc.attribute("ArcStartPoint"))
+    aEndPoint   = geomDataAPI_Point2D(aSketchArc.attribute("ArcEndPoint"))
+    aCenter.setValue(5., 5.)
+    aStartPoint.setValue(10., 5.)
+    aEndPoint.setValue(5., 10.)
+    allFeatures.append(aSketchArc)
+    theSketch.execute()
+    return allFeatures
+    
+def checkTranslation(theObjects, theNbCopies, theDeltaX, theDeltaY):
+    # Verify distances of the objects and the number of copies
+    aFeatures = []
+    aSize = theObjects.size()
+    for i in range (0, aSize):
+        feat = ModelAPI_Feature.feature(theObjects.object(i))
+        assert(feat is not None)
+        aFeatures.append(feat)
+        
+    anInd = 0 
+    for feat, next in zip(aFeatures[:-1], aFeatures[1:]):
+        anInd = anInd + 1
+        if (anInd > theNbCopies):
+            anInd = 0
+            continue
+        assert(feat.getKind() == next.getKind())
+        
+        anAttributes = []
+        if (feat.getKind() == "SketchLine"):
+            anAttributes.append('StartPoint')
+            anAttributes.append('EndPoint')
+        elif (feat.getKind() == "SketchArc"):
+            anAttributes.append('ArcCenter')
+            anAttributes.append('ArcStartPoint')
+            anAttributes.append('ArcEndPoint')
+            
+        for attr in anAttributes:
+            aPoint1 = geomDataAPI_Point2D(feat.attribute(attr))
+            aPoint2 = geomDataAPI_Point2D(next.attribute(attr))
+            aDiffX = aPoint2.x() - aPoint1.x() - theDeltaX
+            aDiffY = aPoint2.y() - aPoint1.y() - theDeltaY
+            assert(aDiffX**2 + aDiffY**2 < 1.e-15)
+    # Check the number of copies is as planed
+    assert(anInd == theNbCopies)
+
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2015-09-18"
+
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchCommonFeature = aDocument.addFeature("Sketch")
+aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+#=========================================================================
+# Initialize sketch
+#=========================================================================
+aSession.startOperation()
+aFeaturesList = createSketch(aSketchFeature)
+aSession.finishOperation()
+#=========================================================================
+# Global variables
+#=========================================================================
+START_X = 0.
+START_Y = 15.
+DIR_X = 20.
+DIR_Y = 10.
+DELTA_X = -5.
+DELTA_Y = 3.
+#=========================================================================
+# Create the Translation constraint
+#=========================================================================
+aSession.startOperation()
+aMultiTranslation = aSketchFeature.addFeature("SketchMultiTranslation")
+aTransList = aMultiTranslation.reflist("MultiTranslationList")
+for aFeature in aFeaturesList:
+    aResult = modelAPI_ResultConstruction(aFeature.lastResult())
+    assert(aResult is not None)
+    aTransList.append(aResult)
+aStartPoint = geomDataAPI_Point2D(aMultiTranslation.attribute("MultiTranslationStartPoint"))
+aEndPoint = geomDataAPI_Point2D(aMultiTranslation.attribute("MultiTranslationEndPoint"))
+aStartPoint.setValue(START_X, START_Y)
+aEndPoint.setValue(START_X + DIR_X, START_Y + DIR_Y)
+aNbCopies = aMultiTranslation.integer("MultiTranslationCopies")
+aNbCopies.setValue(1)
+aMultiTranslation.execute()
+aSession.finishOperation()
+#=========================================================================
+# Verify the objects are moved for the specified distance
+#=========================================================================
+aTranslated = aMultiTranslation.reflist("ConstraintEntityB")
+checkTranslation(aTranslated, aNbCopies.value(), DIR_X, DIR_Y)
+#=========================================================================
+# Change number of copies and verify translation
+#=========================================================================
+aSession.startOperation()
+aNbCopies.setValue(3)
+aSession.finishOperation()
+aTranslated = aMultiTranslation.reflist("ConstraintEntityB")
+checkTranslation(aTranslated, aNbCopies.value(), DIR_X, DIR_Y)
+#=========================================================================
+# TODO: improve test
+# 1. Add more features into translation
+# 2. Move one of initial features and check the translated is moved too
+#=========================================================================
+#=========================================================================
+# End of test
+#=========================================================================