diff --git a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java
index 022861ed796af59bdf5d128b0b3d823f846c6178..da76e5a2cfba20e2c22a7dd38df46888db0cf865 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java
@@ -9,6 +9,7 @@ import cz.fidentis.analyst.mesh.core.MeshPoint;
 import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
 import cz.fidentis.analyst.visitors.mesh.sampling.NoSampling;
 import cz.fidentis.analyst.visitors.mesh.sampling.PointSampling;
+import cz.fidentis.analyst.visitors.mesh.sampling.RandomSampling;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -81,6 +82,29 @@ public class IcpTransformer extends MeshVisitor   {
     
     private final PointSampling samplingStrategy;
     
+    /**
+     * Constructor for random sampling, which is the best performing downsampling strategy.
+     * 
+     * @param mainFacet Primary mesh facet. Must not be {@code null}. 
+     * Inspected facets are transformed toward this primary mesh.
+     * @param maxIteration Maximal number of ICP iterations (it includes computing 
+     * new transformation and applying it). A number bigger than zero.
+     * Reasonable number seems to be 10.
+     * @param scale If {@code true}, then the scale factor is also computed.
+     * @param error Acceptable error - a number bigger than or equal to zero. 
+     * Mean distance of vertices is computed for each ICP iteration.
+     * If the difference between the previous and current mean distances is less than the error,
+     * then the ICP computation stops. Reasonable number seems to be 0.05.
+     * @param numSamples Number of samples for downsampling. Use 1000 for best performance. Zero = no downsampling
+     * @throws IllegalArgumentException if some parameter is wrong
+     */
+    public IcpTransformer(MeshFacet mainFacet, int maxIteration, boolean scale, double error, int numSamples) {
+        this(new HashSet<>(Collections.singleton(mainFacet)), maxIteration, scale, error, (numSamples == 0) ? new NoSampling() : new RandomSampling(numSamples));
+        if (mainFacet == null) {
+            throw new IllegalArgumentException("mainFacet");
+        }
+    }
+    
     /**
      * Constructor.
      * 
@@ -90,8 +114,10 @@ public class IcpTransformer extends MeshVisitor   {
      * new transformation and applying it). A number bigger than zero.
      * Reasonable number seems to be 10.
      * @param scale If {@code true}, then the scale factor is also computed.
-     * @param error Acceptable error. A number bigger than or equal to zero. 
-     * When reached, then the ICP stops. Reasonable number seems to be 0.05.
+     * @param error Acceptable error - a number bigger than or equal to zero. 
+     * Mean distance of vertices is computed for each ICP iteration.
+     * If the difference between the previous and current mean distances is less than the error,
+     * then the ICP computation stops. Reasonable number seems to be 0.05.
      * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used.
      * @throws IllegalArgumentException if some parameter is wrong
      */
@@ -111,8 +137,10 @@ public class IcpTransformer extends MeshVisitor   {
      * new transformation and applying it). A number bigger than zero.
      * Reasonable number seems to be 10.
      * @param scale If {@code true}, then the scale factor is also computed.
-     * @param error Acceptable error. A number bugger than or equal to zero. 
-     * When reached, then the ICP stops. Reasonable number seems to be 0.05.
+     * @param error Acceptable error - a number bigger than or equal to zero. 
+     * Mean distance of vertices is computed for each ICP iteration.
+     * If the difference between the previous and current mean distances is less than the error,
+     * then the ICP computation stops. Reasonable number seems to be 0.05.
      * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used.
      * @throws IllegalArgumentException if some parameter is wrong
      */
@@ -142,8 +170,10 @@ public class IcpTransformer extends MeshVisitor   {
      * new transformation and applying it). A number bigger than zero.
      * Reasonable number seems to be 10.
      * @param scale If {@code true}, then the scale factor is also computed.
-     * @param error Acceptable error. A number bugger than or equal to zero. 
-     * When reached, then the ICP stops. Reasonable number seems to be 0.05.
+     * @param error Acceptable error - a number bigger than or equal to zero. 
+     * Mean distance of vertices is computed for each ICP iteration.
+     * If the difference between the previous and current mean distances is less than the error,
+     * then the ICP computation stops. Reasonable number seems to be 0.05.
      * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used.
      * @throws IllegalArgumentException if some parameter is wrong
      */
@@ -163,7 +193,10 @@ public class IcpTransformer extends MeshVisitor   {
      * new transformation and applying it). A number bigger than zero.
      * Reasonable number seems to be 10.
      * @param scale If {@code true}, then the scale factor is also computed.
-     * @param error Acceptable error. A number bugger than or equal to zero. When reached, then the ICP stops.
+     * @param error Acceptable error - a number bigger than or equal to zero. 
+     * Mean distance of vertices is computed for each ICP iteration.
+     * If the difference between the previous and current mean distances is less than the error,
+     * then the ICP computation stops. Reasonable number seems to be 0.05.
      * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used.
      * @throws IllegalArgumentException if some parameter is wrong
      */
@@ -259,6 +292,8 @@ public class IcpTransformer extends MeshVisitor   {
                 false  // auto crop
         );
         
+        //int numSamples = samplingStrategy.getNumDownsampledPoints(transformedFacet.getNumberOfVertices());
+        //samplingStrategy.setRequiredSamples(200);
         MeshFacet reducedFacet = new UndersampledMeshFacet(transformedFacet, samplingStrategy);
 
         int currentIteration = 0;
@@ -289,7 +324,12 @@ public class IcpTransformer extends MeshVisitor   {
                 applyTransformation(reducedFacet, transformation);
             }
             
-            currentIteration ++;
+            currentIteration++;
+            
+            //if (currentIteration >= 3) {
+            //    samplingStrategy.setRequiredSamples(numSamples);
+            //    reducedFacet = new UndersampledMeshFacet(transformedFacet, samplingStrategy);
+            //}
         }
     }
     
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/sampling/PointSampling.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/sampling/PointSampling.java
index 12202b757e2b2eef05e13e772aa2eaa94a28a89d..5890d1fd81af6a3dcaa5320580a62c1648f38eea 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/sampling/PointSampling.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/sampling/PointSampling.java
@@ -134,7 +134,7 @@ public abstract class PointSampling extends MeshVisitor {
      * @param origPoints Original number of vertices
      * @return number of points to be returned after downsampling.
      */
-    protected int getNumDownsampledPoints(int origPoints) {
+    public int getNumDownsampledPoints(int origPoints) {
         switch (this.samplingType) {
             case PERCENTAGE:
                 return (int) (origPoints * this.samplingLimit);
diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/BatchPanel.java b/GUI/src/main/java/cz/fidentis/analyst/batch/BatchPanel.java
index be2eaeb35119355b61a7672e6378c8a53a642fd5..8b6ea4c9fe008329b5c0dbdc99c0a9f6ad88fc45 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/batch/BatchPanel.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/batch/BatchPanel.java
@@ -66,7 +66,7 @@ public class BatchPanel extends ControlPanel {
         
         jButton1.addActionListener(createListener(action, ACTION_COMMAND_COMPUTE_ICP));
         
-        spinSlider1.initInteger(2000, 0, 5000, 1);
+        spinSlider1.initInteger(1000, 0, 5000, 1); // downsampling strength
         
         jComboBox2.addItem(SIMILARITY_APPROX_HD);
         jComboBox2.addItem(SIMILARITY_COMPLETE_HD);
diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java b/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java
index 67d6cf51a44497be34a84d5e271cee51043c6fb9..886e86471b9989c3c03565a833233f4f825cce9d 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java
@@ -27,6 +27,9 @@ import javax.swing.SwingWorker;
  * @author Radek Oslejsek
  */
 public class IcpTask extends SwingWorker<MeshModel, HumanFace> {
+    
+    private static final double ICP_ERROR = 0.3; //0.05;
+    private static final int    ICP_ITERS = 100;
 
     private HumanFace avgFace;
     private final ProgressDialog progressDialog;
@@ -121,14 +124,14 @@ public class IcpTask extends SwingWorker<MeshModel, HumanFace> {
                     HumanFaceUtils.alignMeshes(
                             initFace,
                             face, // is transformed
-                            100,  // max iterations
+                            ICP_ITERS,  // max iterations
                             controlPanel.scaleIcp(),
-                            0.3,  // error
+                            ICP_ERROR,  // error
                             sampling,
                             false // drop k-d tree, if exists
                     );
                     icpComputationTime.stop();
-                    System.out.println(sampling);
+                    //System.out.println(sampling);
                 }
                 
                 if (computeAvgFace) { // AVG template face
diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/IcpDownsampling.java b/GUI/src/main/java/cz/fidentis/analyst/tests/IcpDownsampling.java
index 216a461cc2b1fd2914156fc8a882f2c631bcb1f8..2df712c7c4643955b4197f60c31b55d97d5d21bf 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/tests/IcpDownsampling.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/tests/IcpDownsampling.java
@@ -3,10 +3,9 @@ package cz.fidentis.analyst.tests;
 import cz.fidentis.analyst.batch.Stopwatch;
 import cz.fidentis.analyst.face.HumanFace;
 import cz.fidentis.analyst.face.HumanFaceUtils;
+import cz.fidentis.analyst.icp.UndersampledMeshFacet;
+import cz.fidentis.analyst.mesh.core.MeshFacet;
 import cz.fidentis.analyst.mesh.core.MeshModel;
-import cz.fidentis.analyst.symmetry.Plane;
-import cz.fidentis.analyst.symmetry.SymmetryEstimator;
-import cz.fidentis.analyst.symmetry.SymmetryEstimatorRobust;
 import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
 import cz.fidentis.analyst.visitors.mesh.sampling.CurvatureSampling;
 import cz.fidentis.analyst.visitors.mesh.sampling.NoSampling;
@@ -19,6 +18,7 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.SortedMap;
@@ -48,13 +48,13 @@ public class IcpDownsampling {
                 .limit(MAX_SAMPLES)
                 .collect(Collectors.toList());
         
-        SortedMap<Integer, Stopwatch> efficiency = new TreeMap<>();
-        SortedMap<Integer, List<Double>> precision = new TreeMap<>();
+        SortedMap<Integer, Stopwatch> efficiency = new TreeMap<>(Collections.reverseOrder());
+        SortedMap<Integer, List<Double>> precision = new TreeMap<>(Collections.reverseOrder());
         
-        //String alg = "random";
+        String alg = "random";
         //String alg = "gaussian";
         //String alg = "uniform space";
-        String alg = "uniform mesh";
+        //String alg = "uniform mesh";
         
         int counter = 1;
         for (int i = 0; i < faces.size(); i += 5) {
@@ -78,7 +78,7 @@ public class IcpDownsampling {
         });
         System.out.println();
         System.out.println("Avg. Precision - " + sampling + " sampling:");
-        System.out.println("# samples;average similarity;variance");
+        System.out.println("# samples;dissimilarity;variance");
         precision.entrySet().forEach(e -> {
             double avg = e.getValue().stream()
                     .mapToDouble(val -> val)
@@ -100,64 +100,86 @@ public class IcpDownsampling {
         //double[] percs = new double[]{0.5,1,2,4,6,8,10,15,20,30,40,50,60,70,80,85,90,92,94,96,98,100};
         //double[] percs = new double[]{100,90,80,70,60,50,40,30,20,15,10,8,6,4,2,1,0.5};
         //int[] samples = new int[]{0,200,500,1000,2000,3000,5000,10000,20000,30000,40000};
-        int[] samples = new int[]{0,200,500,1000,2000,3000,5000};
+        //int[] samples = new int[]{0,200,500,1000,2000,3000,5000};
+        //int[] samples = new int[]{50,100,150,300,400};
+        //int[] samples = new int[]{0,50,100,150,200,300,400,500,1000,2000,3000,5000,10000,20000,30000};
+        //int[] samples = new int[]{5,10,20,30,40,50};
+        int[] samples = new int[]{0,40,50,100,150,200,300,400,500,1000,2000,3000,5000,10000,20000,30000};
         
         HumanFace priFace = new HumanFace(priFacePath.toFile());
         priFace.computeKdTree(false);
-        SymmetryEstimator seVisitor = new SymmetryEstimatorRobust(new UniformSpaceSampling(), 100, 1000);
-        priFace.getMeshModel().compute(seVisitor);
-        priFace.setSymmetryPlane(seVisitor.getSymmetryPlane());
         
         HumanFace secFaceFromFile = new HumanFace(secFacePath.toFile());
-        seVisitor = new SymmetryEstimatorRobust(new UniformSpaceSampling(), 100, 1000);
-        secFaceFromFile.getMeshModel().compute(seVisitor);
-        secFaceFromFile.setSymmetryPlane(seVisitor.getSymmetryPlane());
-        
         
         System.out.println(secFaceFromFile.getShortName());
         for (int i: samples) {
             HumanFace secFace = new HumanFace(new MeshModel(secFaceFromFile.getMeshModel()), secFaceFromFile.getId());
-            secFace.setSymmetryPlane(new Plane(secFaceFromFile.getSymmetryPlane()));
             
-            PointSampling sampling;
+            PointSampling secSampling;
+            PointSampling priSampling;
             switch (samp) {
                 case "random":
-                    sampling = new RandomSampling();
+                    secSampling = new RandomSampling();
+                    priSampling = new RandomSampling();
                     break;
                 case "gaussian":
-                    sampling = new CurvatureSampling(CurvatureSampling.CurvatureAlg.GAUSSIAN);
+                    secSampling = new CurvatureSampling(CurvatureSampling.CurvatureAlg.GAUSSIAN);
+                    priSampling = new CurvatureSampling(CurvatureSampling.CurvatureAlg.GAUSSIAN);
                     break;
                 case "uniform space":
-                    sampling = new UniformSpaceSampling();
+                    secSampling = new UniformSpaceSampling();
+                    priSampling = new UniformSpaceSampling();
                     break;
                 case "uniform mesh":
-                    sampling = new UniformSurfaceSampling();
+                    secSampling = new UniformSurfaceSampling();
+                    priSampling = new UniformSurfaceSampling();
                     break;
                 default:
                     return;
             }
             
+            /*
+            if (samples[i] == 0) {
+                secSampling = new NoSampling();
+                priSampling = new NoSampling();
+            } else {
+                secSampling.setRequiredSamples(i);
+                priSampling.setRequiredSamples(i);
+            }
+            */
+            
             if (i == 0) {
-                sampling = new NoSampling();
+                priSampling = new NoSampling();
             } else {
-                //sampling.setRequiredSamples(i/100.0);
-                sampling.setRequiredSamples(i);
+                priSampling.setRequiredSamples(i);
             }
+            secSampling.setRequiredSamples(5000);
             
             efficiency.computeIfAbsent(i, k-> new Stopwatch("")).start();
-            HumanFaceUtils.alignSymmetryPlanes(priFace, secFace, false, true);
-            HumanFaceUtils.alignMeshes(
+            HumanFaceUtils.alignMeshes( 
+                            downsamplePriFace(priFace, priSampling),
+                            secFace, // is transformed
+                            100,  // max iterations
+                            false,// scale
+                            0.05,  // error
+                            secSampling, 
+                            false // drop k-d tree of the secFace, if exists
+            );
+            /*
+            HumanFaceUtils.alignMeshes(  /// ORIG SETTING
                             priFace,
                             secFace, // is transformed
                             100,  // max iterations
                             false,// scale
-                            0.3,  // error
-                            sampling, 
-                            false // drop k-d tree, if exists
+                            0.05,  // error
+                            secSampling, 
+                            false // drop k-d tree of the secFace, if exists
             );
+            */
             efficiency.get(i).stop();
             
-            System.out.println("" + sampling);
+            System.out.println("  Primary face: " + priSampling);
+            System.out.println("Secondary face: " + secSampling);
 
             HausdorffDistance hd = new HausdorffDistance(
                     priFace.getKdTree(),
@@ -171,4 +193,12 @@ public class IcpDownsampling {
         }
         System.out.println();
     }
+    
+    private static HumanFace downsamplePriFace(HumanFace priFace, PointSampling sampling) {
+        MeshFacet reducedFacet = new UndersampledMeshFacet(priFace.getMeshModel().getFacets().get(0), sampling);
+        MeshModel model = new MeshModel();
+        model.setFacets(List.of(reducedFacet));
+        HumanFace ret = new HumanFace(model, priFace.getId());
+        return ret;
+    }
 }