diff --git a/Comparison/src/main/java/cz/fidentis/analyst/BatchProcessor.java b/Comparison/src/main/java/cz/fidentis/analyst/BatchProcessor.java
index 0058b65e2ae91cd12c4c0c7bde8bc69eaa6da412..6ace9bc23fee33da6720bd509fd833e1b886b19b 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/BatchProcessor.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/BatchProcessor.java
@@ -3,14 +3,27 @@ package cz.fidentis.analyst;
 import cz.fidentis.analyst.face.AvgFaceConstructor;
 import cz.fidentis.analyst.face.HumanFace;
 import cz.fidentis.analyst.face.HumanFaceFactory;
+import cz.fidentis.analyst.icp.IcpTransformation;
 import cz.fidentis.analyst.icp.IcpTransformer;
 import cz.fidentis.analyst.icp.UndersamplingStrategy;
 import cz.fidentis.analyst.kdtree.KdTree;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
+import cz.fidentis.analyst.mesh.io.MeshObjExporter;
+import cz.fidentis.analyst.symmetry.Plane;
+import cz.fidentis.analyst.symmetry.SignificantPoints;
+import static cz.fidentis.analyst.symmetry.SignificantPoints.CurvatureAlg.GAUSSIAN;
+import cz.fidentis.analyst.symmetry.SymmetryConfig;
+import cz.fidentis.analyst.symmetry.SymmetryEstimator;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.vecmath.AxisAngle4d;
+import javax.vecmath.Matrix4d;
+import javax.vecmath.Point3d;
+import javax.vecmath.Vector3d;
 
 /**
  * Helper class providing methods for batch N:N processing.
@@ -19,11 +32,6 @@ import java.util.List;
  */
 public class BatchProcessor {
     
-    /**
-     * IDs of registered (transformed) faces.
-     */
-    private final List<String> processedFaces = new ArrayList<>();
-    
     /**
      * Template face computed by averaging vertices processed faces.
      */
@@ -31,51 +39,112 @@ public class BatchProcessor {
     
     private double avgIcpIterations = 0.0;
     
+    private SymmetryConfig symmetryConfig;
+    private SignificantPoints.CurvatureAlg symmetryCurvArg = GAUSSIAN;
+    
     /**
-     * Returns template face that can be used for linear time N:N distance computation.
-     * 
-     * @return template face.
+     * Constructor.
+     * @param symmetryPoints Number of symmetry points used by the symmetry estimator
      */
-    public HumanFace getAvgTemplateFace() {
-        return templateFace;
+    public BatchProcessor(int symmetryPoints) {
+        symmetryConfig = new SymmetryConfig();
+        this.symmetryConfig.setSignificantPointCount(symmetryPoints); // default 200, best 500
+    }
+
+    /**
+     * Pre-reads faces from given directory into the HumanFactory.
+     * @param dir Directory.
+     * @return Face IDs
+     */
+    public List<String> readFaces(String dir) {
+        List<String> faces = new ArrayList<>();
+        for (File subdir : (new File(dir)).listFiles(File::isDirectory)) {
+            if (subdir.getName().matches("^\\d\\d$")) {
+                for (File file: subdir.listFiles(File::isFile)) {
+                    if (file.getName().endsWith(".obj")) {
+                        //System.out.print(file.getName() + " ");
+                        //if (file.getName().endsWith("00002_01_ECA.obj")) { // FOT DEBUGING
+                            String faceId = HumanFaceFactory.instance().loadFace(file);
+                            faces.add(faceId);
+                        //}
+                    }
+                }
+            }
+        }
+        return faces;
+    }
+    
+    /**
+     * Pre-computes symmetry planes for given faces.
+     * @param faceIDs Face IDs
+     */
+    public void computeSymmetryPlanes(List<String> faceIDs) {
+        for (String facePath: faceIDs) {
+            String faceId = HumanFaceFactory.instance().loadFace(new File(facePath));
+            HumanFace face = HumanFaceFactory.instance().getFace(faceId);
+            getSymmetryPlaneMesh(face);
+        }
     }
     
     /**
      * Registers faces with respect to the given primary face.
      * 
      * @param primaryFacePath Path to the primary face
-     * @param faces Paths to faces that are to be superimposed (registered)
+     * @param faceIDs Paths to faces that are to be superimposed (registered)
      * @param iters Maximal number of ICP iterations
      * @param error Maximal error of ICP computation
      * @param strategy Undersampling strategy
      */
-    public void registerToPrimaryFace(String primaryFacePath, List<String> faces, int iters, double error, UndersamplingStrategy strategy) {
-        if (faces == null) {
+    public void superimposeOnPrimaryFace(String primaryFaceId, List<String> faceIDs, 
+            int iters, double error, UndersamplingStrategy strategy, boolean symmetry) {
+        
+        if (faceIDs == null) {
             throw new IllegalArgumentException("faces");
         }
         
-        HumanFace primaryFace = pathToFace(primaryFacePath);
-        
-        int facesCounter = faces.size();
         HumanFaceFactory.instance().setStrategy(HumanFaceFactory.Strategy.MRU);
-        KdTree kdTree = primaryFace.computeKdTree(true);
-        IcpTransformer icpVisitor = new IcpTransformer(kdTree, iters, true, error, strategy);
+        
+        int facesCounter = faceIDs.size();
+        HumanFace primaryFace = HumanFaceFactory.instance().getFace(primaryFaceId);
+        IcpTransformer primPlaneTr = new IcpTransformer(getSymmetryPlaneMesh(primaryFace), iters, true, error, strategy);
+        KdTree primKdTree = primaryFace.computeKdTree(true);
+        
+        IcpTransformer icpTransformer = new IcpTransformer(primKdTree, iters, true, error, strategy);
             
-        for (String facePath: faces) {
-            String faceId = HumanFaceFactory.instance().loadFace(new File(facePath));
+        for (String faceId: faceIDs) {
+            //String faceId = HumanFaceFactory.instance().getFace(new File(facePath));
             if (primaryFace.getId().equals(faceId)) { // skip the same face
-                processedFaces.add(faceId);
                 facesCounter--;
                 continue;
             }
             
             HumanFace face = HumanFaceFactory.instance().getFace(faceId);
-            face.getMeshModel().compute(icpVisitor);
+            
+            if (symmetry) {
+                MeshFacet plane = getSymmetryPlaneMesh(face);
+                primPlaneTr.visitMeshFacet(plane);
+                IcpTransformation tr = primPlaneTr.getTransformations().get(plane).get(0);
+                for (MeshFacet f: face.getMeshModel().getFacets()) { // apply transformation onto the face
+                    primPlaneTr.applyTransformation(f, tr);
+                }
+
+                if (faceId.endsWith("00004_01_ECA.obj")) {
+                    MeshObjExporter exp = new MeshObjExporter(face.getMeshModel());
+                    try {
+                        System.out.println("../../analyst-data/multi-scan-models-anonymized-fixed/test04.obj");
+                        exp.exportModelToObj(new File("../../analyst-data/multi-scan-models-anonymized-fixed/test04.obj"));
+                    } catch (IOException ex) {
+                        Logger.getLogger(BatchProcessor.class.getName()).log(Level.SEVERE, null, ex);
+                    }
+                }
+            }
+            face.getMeshModel().compute(icpTransformer);
+            face.removeKdTree();
         }
         
         int itersCounter = 0;
-        for (MeshFacet f: icpVisitor.getTransformations().keySet()) {
-            itersCounter += icpVisitor.getTransformations().get(f).size();
+        for (MeshFacet f: icpTransformer.getTransformations().keySet()) {
+            itersCounter += icpTransformer.getTransformations().get(f).size();
         }
         this.avgIcpIterations = itersCounter / (double) facesCounter;
     }
@@ -85,54 +154,36 @@ public class BatchProcessor {
      * are already superimposed (registered) with the template face.
      * 
      * @param initTempPath Path to the face used as an initial template for the computation of the averaged face
-     * @param faces Paths to faces that are used to compute averaged face
+     * @param faceIDs Paths to faces that are used to compute averaged face
      */
-    public void computeTemplateFace(String initTempPath, List<String> faces) {
-        if (faces == null) {
+    public void computeTemplateFace(String initTempFaceId, List<String> faceIDs) {
+        if (faceIDs == null) {
             throw new IllegalArgumentException("faces");
         }
         
-        this.templateFace = pathToFace(initTempPath);
+        this.templateFace = HumanFaceFactory.instance().getFace(initTempFaceId);
         
         HumanFaceFactory.instance().setStrategy(HumanFaceFactory.Strategy.MRU);
         AvgFaceConstructor constructor = new AvgFaceConstructor(this.templateFace.getMeshModel());
-        for (String facePath: faces) {
-            String faceId = HumanFaceFactory.instance().loadFace(new File(facePath));
-            if (this.templateFace.getId().equals(faceId)) { // skip the same face
-                processedFaces.add(faceId);
-                continue; 
+        for (String faceId: faceIDs) {
+            System.out.println(faceId);
+            //String faceId = HumanFaceFactory.instance().loadFace(new File(facePath));
+            if (!this.templateFace.getId().equals(faceId)) { // skip the same face
+                HumanFace face = HumanFaceFactory.instance().getFace(faceId);
+                face.computeKdTree(false).accept(constructor);
             }
-        
-            HumanFace face = HumanFaceFactory.instance().getFace(faceId);
-            face.computeKdTree(false).accept(constructor);
         }
         
         this.templateFace.setMeshModel(constructor.getAveragedMeshModel());
     }
     
     /**
-     * Registers faces and simultaneously computes averaged face.
-     * It is faster (?) combination of {@link registerToGivenFace#registerToPrimaryFace} and
-     * {@link computeTemplateFaceOnly#computeTemplateFace}
+     * Returns template face that can be used for linear time N:N distance computation.
      * 
-     * @param initTempPath Path to the face used as an initial  template for the computation of the averaged face
-     * @param faces Paths to faces that are superimposed (registered) and simultaneously used to compute averaged face
-     * @param iters Maximal number of ICP iterations
-     * @param error Maximal error of ICP computation
-     * @param strategy Undersampling strategy
+     * @return template face.
      */
-    public void registerToTemplateFace(String initTempPath, List<String> faces, int iters, double error, UndersamplingStrategy strategy) {
-        if (faces == null) {
-            throw new IllegalArgumentException("faces");
-        }
-        
-        try {
-            this.templateFace = new HumanFace(new File(initTempPath));
-        } catch (IOException ex) {
-            throw new IllegalArgumentException("initTempPath", ex);
-        }
-        
-        // TO DO
+    public HumanFace getAvgTemplateFace() {
+        return templateFace;
     }
     
     /**
@@ -143,12 +194,18 @@ public class BatchProcessor {
         return this.avgIcpIterations;
     }
     
-    protected HumanFace pathToFace(String path) {
-        try {
-            return new HumanFace(new File(path));
-        } catch (IOException ex) {
-            throw new IllegalArgumentException(ex);
+    
+    
+    
+    protected MeshFacet getSymmetryPlaneMesh(HumanFace face) {
+        MeshFacet plane = face.getSymmetryPlaneFacet();
+        if (plane == null) {
+            SymmetryEstimator se = new SymmetryEstimator(this.symmetryConfig, this.symmetryCurvArg);
+            face.getMeshModel().compute(se);
+            plane = se.getSymmetryPlaneMesh();
+            face.setSymmetryPlane(se.getSymmetryPlane(), plane);
         }
+        return plane;
     }
     
 }
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/AvgFaceConstructor.java b/Comparison/src/main/java/cz/fidentis/analyst/face/AvgFaceConstructor.java
index e7fe7d0a25c2f9a5a8ad6d20c765375f34d9bf46..3a85a9136fc61f7cdfb8d8d7ec31a206b28d69bb 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/face/AvgFaceConstructor.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/face/AvgFaceConstructor.java
@@ -80,6 +80,7 @@ public class AvgFaceConstructor extends KdTreeVisitor {
         numInspectedFacets++;
 
         for (MeshFacet myFacet: transformations.keySet()) {
+            System.out.println("AAA "+ kdTree.getNumNodes() + " " + kdTree.getDepth());
             for (int i = 0; i < myFacet.getNumberOfVertices(); i++) {
                 Point3d myPoint = myFacet.getVertex(i).getPosition();
                 KdTreeClosestNode visitor = new KdTreeClosestNode(myPoint);
@@ -94,6 +95,7 @@ public class AvgFaceConstructor extends KdTreeVisitor {
                     transformations.get(myFacet).get(i).add(moveDir);
                 }
             }
+            System.out.println("BBB");
         }
     }
     
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java
index 1a510e2b73285db0fa6a8f8609266bbfdf95b614..b5a1fb090f5147ff7f273c51fc217ec8e1af3db5 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java
@@ -52,6 +52,8 @@ public class HumanFace implements MeshListener, Serializable {
     private KdTree kdTree;
 
     private Plane symmetryPlane;
+    
+    private MeshFacet symmetryPlaneMesh;
 
     private MeshFacet cuttingPlane;
     
@@ -132,9 +134,11 @@ public class HumanFace implements MeshListener, Serializable {
     /**
      *
      * @param plane The new symmetry plane
+     * @param paneFacet The symmetry plane mesh
      */
-    public void setSymmetryPlane(Plane plane) {
-        symmetryPlane = plane;
+    public void setSymmetryPlane(Plane plane, MeshFacet planeFacet) {
+        this.symmetryPlane = plane;
+        this.symmetryPlaneMesh = planeFacet;
     }
 
     /**
@@ -144,6 +148,10 @@ public class HumanFace implements MeshListener, Serializable {
     public Plane getSymmetryPlane() {
         return symmetryPlane;
     }
+    
+    public MeshFacet getSymmetryPlaneFacet() {
+        return this.symmetryPlaneMesh;
+    }
 
     /**
      *
@@ -191,6 +199,16 @@ public class HumanFace implements MeshListener, Serializable {
         }
         return kdTree;
     }
+    
+    /**
+     * Removes k-d tree from the Human face. 
+     * @return removed k-d tree or {@code null}
+     */
+    public KdTree removeKdTree() {
+        KdTree ret = this.kdTree;
+        this.kdTree = null;
+        return ret;
+    }
 
     /**
      * Creates serialized dump of the human face. Event buses are not stored.
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 62383fff1425e93f45f4c67f0f3aca8b3f12214f..1d9f181567bd4d9281dbac868e09cd5d64e3a20c 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java
@@ -363,7 +363,7 @@ public class IcpTransformer extends MeshVisitor   {
      * @param transformedFacet Facet to be transformed
      * @param transformation Computed transformation.
      */
-    private void applyTransformation(MeshFacet transformedFacet, IcpTransformation transformation) {
+    public void applyTransformation(MeshFacet transformedFacet, IcpTransformation transformation) {
         transformedFacet.getVertices().parallelStream().forEach(
                 p -> {
                     Point3d meshPointPosition = p.getPosition();
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/ApproxSymmetryPlane.java b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/ApproxSymmetryPlane.java
index 43fbfaad022f877192ae3eeedc7d97dcdadd7f0f..53304801656eb1ac98413f70db804bebf0b34100 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/ApproxSymmetryPlane.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/ApproxSymmetryPlane.java
@@ -24,7 +24,7 @@ public class ApproxSymmetryPlane extends Plane implements Comparable<ApproxSymme
      * @param maxDist Distance limit
      * @throws UnsupportedOperationException if the symmetry plane cannot be created
      */
-    public ApproxSymmetryPlane(SignificantPoints sigPoints, Config config, int i, int j, double maxDist) throws UnsupportedOperationException {
+    public ApproxSymmetryPlane(SignificantPoints sigPoints, SymmetryConfig config, int i, int j, double maxDist) throws UnsupportedOperationException {
         if (i == j) {
             throw new UnsupportedOperationException();
         }
@@ -41,7 +41,7 @@ public class ApproxSymmetryPlane extends Plane implements Comparable<ApproxSymme
         return votes;
     }
     
-    private void setNormAndDist(SignificantPoints sigPoints, Config config, int i, int j) {
+    private void setNormAndDist(SignificantPoints sigPoints, SymmetryConfig config, int i, int j) {
         MeshFacet facetI = sigPoints.getMeshFacet(i);
         MeshFacet facetJ = sigPoints.getMeshFacet(j);
         int sigPointI = sigPoints.getVertexIndex(i);
@@ -81,7 +81,7 @@ public class ApproxSymmetryPlane extends Plane implements Comparable<ApproxSymme
      * @param config Symmetry plane configuration
      * @param maxDist Distance limit
      */
-    private void computeVotes(SignificantPoints sigPoints, Config config, double maxDist) {
+    private void computeVotes(SignificantPoints sigPoints, SymmetryConfig config, double maxDist) {
         normalize();
         Vector3d normal = getNormal();
         double d = getDistance();
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Config.java b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryConfig.java
similarity index 89%
rename from Comparison/src/main/java/cz/fidentis/analyst/symmetry/Config.java
rename to Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryConfig.java
index 22af1f4e0b03bba086409d3f812b48a26987ba7a..c4ee1faa4832f9757285a182e0cee19a1763f86c 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Config.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryConfig.java
@@ -8,7 +8,8 @@ package cz.fidentis.analyst.symmetry;
  * 
  * @author Natalia Bebjakova
  */
-public class Config {
+public class SymmetryConfig {
+    
     private static final double DEFAULT_MIN_CURV_RATIO = 0.5;
     private static final double DEFAULT_MIN_ANGLE_COS = 0.985;
     private static final double DEFAULT_MIN_NORM_ANGLE_COS = 0.985;
@@ -23,6 +24,18 @@ public class Config {
     private int significantPointCount;
     private boolean averaging;
     
+    /**
+     * Creates configuration with default values 
+     */
+    public SymmetryConfig() {
+        minCurvRatio = DEFAULT_MIN_CURV_RATIO;
+        minAngleCos = DEFAULT_MIN_ANGLE_COS;
+        minNormAngleCos = DEFAULT_MIN_NORM_ANGLE_COS;
+        maxRelDistance = DEFAULT_MAX_REL_DISTANCE;
+        significantPointCount = DEFAULT_SIGNIFICANT_POINT_COUNT;
+        averaging = DEFAULT_AVERAGING;
+    }
+    
     /**
      * Parameter which denotes how similar the Gaussian curvatures in the two vertices
      * must be for this criteria to be satisfied.
@@ -135,24 +148,6 @@ public class Config {
         this.averaging = averaging;
     }
 
-    /**
-     * Creates new configuration with default values 
-     * 
-     * @return configuration with default values
-     */
-    public static Config getDefault() {
-        Config conf = new Config();
-
-        conf.minCurvRatio = DEFAULT_MIN_CURV_RATIO;
-        conf.minAngleCos = DEFAULT_MIN_ANGLE_COS;
-        conf.minNormAngleCos = DEFAULT_MIN_NORM_ANGLE_COS;
-        conf.maxRelDistance = DEFAULT_MAX_REL_DISTANCE;
-        conf.significantPointCount = DEFAULT_SIGNIFICANT_POINT_COUNT;
-        conf.averaging = DEFAULT_AVERAGING;
-
-        return conf;
-    }
-    
     /**
      * 
      * @return String representation of configuration
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java
index 9ade7e71c17683bfa463bd41f83df2da288ecc39..e3312f554cecd16463f468c300dd92faafb8fdec 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java
@@ -36,12 +36,10 @@ import javax.vecmath.Vector3d;
  */
 public class SymmetryEstimator extends MeshVisitor {
     
-    private final Config config;
+    private final SymmetryConfig config;
     private final SignificantPoints sigPointsVisitor;
     private final BoundingBox bbVisitor = new BoundingBox();
     
-    private CurvatureAlg curvatureAlg;
-    
     private Plane symmetryPlane;
     
     /**
@@ -52,7 +50,7 @@ public class SymmetryEstimator extends MeshVisitor {
      *        See {@link Curvature} for more details.
      * @throws IllegalArgumentException if some input parameter is missing
      */
-    public SymmetryEstimator(Config config, CurvatureAlg curvatureAlg) {
+    public SymmetryEstimator(SymmetryConfig config, CurvatureAlg curvatureAlg) {
         if (config == null) {
             throw new IllegalArgumentException("config");
         }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java b/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java
index 7b301610bbff7f4c465659001016fbca31c133ac..f9b5276a2ac50935f73e34b21b40a3b77da75334 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java
@@ -14,7 +14,7 @@ import com.jogamp.opengl.GLEventListener;
 import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_MODELVIEW_MATRIX;
 import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_PROJECTION_MATRIX;
 import com.jogamp.opengl.glu.GLU;
-import cz.fidentis.analyst.symmetry.Config;
+import cz.fidentis.analyst.symmetry.SymmetryConfig;
 import cz.fidentis.analyst.symmetry.SignificantPoints;
 import cz.fidentis.analyst.symmetry.SymmetryEstimator;
 import javax.vecmath.Point3d;
@@ -244,12 +244,12 @@ public class GeneralGLEventListener implements GLEventListener {
 
         //Generate SymmetryPlane first time we request to see it
         if (symmetryPlane && symmetryPlaneFacet == null) {
-            SymmetryEstimator estimator = new SymmetryEstimator(Config.getDefault(), SignificantPoints.CurvatureAlg.GAUSSIAN);
+            SymmetryEstimator estimator = new SymmetryEstimator(new SymmetryConfig(), SignificantPoints.CurvatureAlg.GAUSSIAN);
             model.getFacets().get(0).accept(estimator);
             symmetryPlaneFacet = estimator.getSymmetryPlaneMesh();
 
             //Set calculated planes for the loaded Face
-            glCanvas.loadedFace.setSymmetryPlane(estimator.getSymmetryPlane());
+            glCanvas.loadedFace.setSymmetryPlane(estimator.getSymmetryPlane(), symmetryPlaneFacet);
             glCanvas.loadedFace.setCuttingPlane(symmetryPlaneFacet);
         }
 
diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/SymmetryPanel.java b/GUI/src/main/java/cz/fidentis/analyst/gui/SymmetryPanel.java
index af8c975bae39086c5cdac07282e2bd6aa850a9c7..d5de605ee9e3991d0afc688037cffe8e1bb1a621 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/gui/SymmetryPanel.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/gui/SymmetryPanel.java
@@ -3,7 +3,7 @@ package cz.fidentis.analyst.gui;
 import static cz.fidentis.analyst.gui.UserInterface.frameMain;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
 import cz.fidentis.analyst.mesh.core.MeshModel;
-import cz.fidentis.analyst.symmetry.Config;
+import cz.fidentis.analyst.symmetry.SymmetryConfig;
 import cz.fidentis.analyst.symmetry.Plane;
 import cz.fidentis.analyst.symmetry.SignificantPoints;
 import cz.fidentis.analyst.symmetry.SymmetryEstimator;
@@ -25,7 +25,7 @@ public final class SymmetryPanel extends javax.swing.JPanel {
     /**
      * Configuration with optional parameters of the algorithm 
      */
-    private Config config;
+    private SymmetryConfig config;
     
     /**
      * GL Canvas on which model is displayed
@@ -58,7 +58,7 @@ public final class SymmetryPanel extends javax.swing.JPanel {
      * 
      * @return Configuration for computing symmetry
      */
-    public Config getConfig() {
+    public SymmetryConfig getConfig() {
         return config;
     }
 
@@ -66,7 +66,7 @@ public final class SymmetryPanel extends javax.swing.JPanel {
      * 
      * @param config Configuration for computing symmetry
      */
-    public void setConfig(Config config) {
+    public void setConfig(SymmetryConfig config) {
         this.config = config;
     }
     
@@ -139,7 +139,7 @@ public final class SymmetryPanel extends javax.swing.JPanel {
      */
     public SymmetryPanel() {
         initComponents();
-        config = Config.getDefault();
+        config = new SymmetryConfig();
         setSliders();
         
         showPlaneButtonsOnPanel(false);
@@ -607,7 +607,7 @@ public final class SymmetryPanel extends javax.swing.JPanel {
      * @param evt configuration is set to deafult values
      */
     private void defaultValuesMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_defaultValuesMouseClicked
-        config = Config.getDefault();
+        config = new SymmetryConfig();
         setTextFieldsDueToConfig();
         setSliders();
     }//GEN-LAST:event_defaultValuesMouseClicked
diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchTests.java b/GUI/src/main/java/cz/fidentis/analyst/tests/BatchTests.java
index fdd42d31c41f0f28d2a3b6510d3d90446a13ae75..663fc3e918f870066dd0d57b54b4fb09727d3fee 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchTests.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/tests/BatchTests.java
@@ -13,6 +13,7 @@ import cz.fidentis.analyst.mesh.io.MeshObjExporter;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -27,7 +28,7 @@ public class BatchTests {
     private static final String primaryFacePath = dataDir + "/average-boy-17-20/average_boy_17-20.obj";
     //private static final String primaryFacePath = dataDir + "/average-girl-17-20/average_girl_17-20.obj";
     //private static final String primaryFacePath = "../../analyst-data/basic-models/02.obj";
-    private static final String templateFacePath = dataDir + "/template.obj";
+    private static final String templateFacePath = dataDir + "template.obj";
     
     /**
      * Main method 
@@ -35,23 +36,32 @@ public class BatchTests {
      * @throws IOException on IO error
      */
     public static void main(String[] args) throws IOException, ClassNotFoundException, Exception {
-        BatchProcessor batch = new BatchProcessor();
+        BatchProcessor batch = new BatchProcessor(200); // the best is 500?
         long startTime, endTime;
         
         List<String> faceIDs;
-        String faceId = HumanFaceFactory.instance().loadFace(new File(primaryFacePath));
-        HumanFace primaryFace = HumanFaceFactory.instance().getFace(faceId);
-        KdTree kdTree = primaryFace.computeKdTree(false);
+        String primaryFaceId = HumanFaceFactory.instance().loadFace(new File(primaryFacePath));
+        HumanFace primaryFace = HumanFaceFactory.instance().getFace(primaryFaceId);
+        KdTree primaryFacekdTree = primaryFace.computeKdTree(false);
         
         //////////////////////////////////////////////
         System.out.println();
         System.out.println("Loading files:");
         startTime = System.currentTimeMillis();
-        faceIDs = readFiles(dataDir);
+        faceIDs = batch.readFaces(dataDir);
+        endTime = System.currentTimeMillis();
+        printTimes(startTime, endTime, faceIDs.size());
+        System.out.println(faceIDs.size() + "\t\t Number of files");
+        System.out.println(HumanFaceFactory.instance());
+        
+        //////////////////////////////////////////////
+        System.out.println();
+        System.out.println("Computation of symmetry planes:");
+        startTime = System.currentTimeMillis();
+        batch.computeSymmetryPlanes(faceIDs);
+        batch.computeSymmetryPlanes(Collections.singletonList(primaryFaceId));
         endTime = System.currentTimeMillis();
         printTimes(startTime, endTime, faceIDs.size());
-        System.out.println("Number of files: " + faceIDs.size());
-        System.out.println("File cache stats: " + HumanFaceFactory.instance());
         
         //////////////////////////////////////////////
         //UndersamplingStrategy strategy = new NoUndersampling();
@@ -59,7 +69,7 @@ public class BatchTests {
         System.out.println();
         System.out.println("ICP registration with " + strategy + ":");
         startTime = System.currentTimeMillis();
-        batch.registerToPrimaryFace(primaryFacePath, faceIDs, 10, 0.05, strategy);
+        batch.superimposeOnPrimaryFace(primaryFaceId, faceIDs, 10, 0.05, strategy, true);
         endTime = System.currentTimeMillis();
         printTimes(startTime, endTime, faceIDs.size());
         System.out.printf("%.2f \t\t Avg number of iterations", batch.getAvgNumIcpIterations());
@@ -69,33 +79,14 @@ public class BatchTests {
         System.out.println();
         System.out.println("Computation of averaged template face:");
         startTime = System.currentTimeMillis();
-        batch.computeTemplateFace(primaryFacePath, faceIDs);
+        batch.computeTemplateFace(primaryFaceId, faceIDs);
         endTime = System.currentTimeMillis();
         printTimes(startTime, endTime, faceIDs.size());
-        System.out.println("Writing average template to " + templateFacePath + "...");
+        System.out.println("Writing average template to " + templateFacePath);
         MeshObjExporter exp = new MeshObjExporter(batch.getAvgTemplateFace().getMeshModel());
         exp.exportModelToObj(new File(templateFacePath));
     }
     
-    private static List<String> readFiles(String dir) throws IOException {
-        List<String> faces = new ArrayList<>();
-        for (File subdir : (new File(dir)).listFiles(File::isDirectory)) {
-            if (subdir.getName().matches("^\\d\\d$")) {
-                for (File file: subdir.listFiles(File::isFile)) {
-                    if (file.getName().endsWith(".obj")) {
-                        //System.out.print(file.getName() + " ");
-                        //if (file.getName().endsWith("00002_01_ECA.obj")) { // FOT DEBUGING
-                            String faceId = HumanFaceFactory.instance().loadFace(file);
-                            faces.add(faceId);
-                        //}
-                    }
-                }
-            }
-        }
-        //System.out.println();
-        return faces;
-    }
-    
     private static void printTimes(long startTime, long endTime, int numFaces) {
         double timeDist = endTime - startTime;
         double avgTime = (timeDist/numFaces)/1000.0;
diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java b/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java
index 9b276361dc8edd7367e630c0517b3e97b86ea7fd..e1c4e1a5c48fed5ab54f91b31f9291cbd7423e5b 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java
@@ -3,7 +3,7 @@ package cz.fidentis.analyst.tests;
 import cz.fidentis.analyst.face.HumanFace;
 import cz.fidentis.analyst.kdtree.KdTree;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
-import cz.fidentis.analyst.symmetry.Config;
+import cz.fidentis.analyst.symmetry.SymmetryConfig;
 import cz.fidentis.analyst.symmetry.Plane;
 import cz.fidentis.analyst.symmetry.SignificantPoints;
 import cz.fidentis.analyst.symmetry.SymmetryEstimator;
@@ -105,7 +105,7 @@ public class EfficiencyTests {
     
     private static void printSymmetryPlane(HumanFace face, boolean concurrently, SignificantPoints.CurvatureAlg curvatureAlg) {
         long startTime = System.currentTimeMillis();
-        SymmetryEstimator est = new SymmetryEstimator(Config.getDefault(), curvatureAlg);
+        SymmetryEstimator est = new SymmetryEstimator(new SymmetryConfig(), curvatureAlg);
         face.getMeshModel().compute(est, false);
         Plane plane = est.getSymmetryPlane(concurrently);
         long endTime =  System.currentTimeMillis();
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTree.java b/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTree.java
index ee4e6ca05b606deb0731e229ce405fcb00e1c3b2..3de3a67302e7aeebe9e15db3d22d40259f64b20a 100644
--- a/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTree.java
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTree.java
@@ -133,6 +133,52 @@ public class KdTree implements Serializable {
         return ret;
     }
     
+    /**
+     * Return number of nodes in the k-d tree.
+     * @return number of nodes in the k-d tree
+     */
+    public int getNumNodes() {
+        int ret = 0;
+        Queue<KdNode> queue = new LinkedList<>();
+        queue.add(root);
+
+        while (!queue.isEmpty()) {
+            KdNode node = queue.poll();
+            if (node == null) {
+                continue;
+            }
+            queue.add(node.getLesser());
+            queue.add(node.getGreater());
+            ret++;
+        }
+        
+        return ret;
+    }
+    
+    /**
+     * Return the length of the longest path.
+     * @return Return the length of the longest path.
+     */
+    public int getDepth() {
+        int depth = 0;
+        Queue<KdNode> queue = new LinkedList<>();
+        queue.add(root);
+
+        while (!queue.isEmpty()) {
+            KdNode node = queue.poll();
+            if (node == null) {
+                continue;
+            }
+            queue.add(node.getLesser());
+            queue.add(node.getGreater());
+            if (node.getDepth() > depth) {
+                depth = node.getDepth();
+            }
+        }
+        
+        return depth;
+    }
+    
     /**
      * Visits this facet.
      *