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 15cafbc9995852a0bfa1091a36009ba5010d808f..8e089d9c2bcdb5f46a88ef66aea2b5f34a7d5f2e 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java
@@ -7,12 +7,7 @@ import cz.fidentis.analyst.face.events.HumanFaceEvent;
 import cz.fidentis.analyst.feature.FeaturePoint;
 import cz.fidentis.analyst.feature.services.FeaturePointImportService;
 import cz.fidentis.analyst.kdtree.KdTree;
-import cz.fidentis.analyst.face.events.KdTreeCreated;
-import cz.fidentis.analyst.face.events.KdTreeDestroyed;
-import cz.fidentis.analyst.face.events.MeshChangedEvent;
-import cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent;
 import cz.fidentis.analyst.mesh.core.MeshModel;
-import cz.fidentis.analyst.mesh.core.MeshRectangleFacet;
 import cz.fidentis.analyst.mesh.io.MeshObjLoader;
 import cz.fidentis.analyst.symmetry.Plane;
 import cz.fidentis.analyst.visitors.face.HumanFaceVisitor;
@@ -92,10 +87,7 @@ public class HumanFace implements Serializable {
         meshModel.simplifyModel();
         this.id = file.getCanonicalPath();
         
-        BoundingBox visitor = new BoundingBox();
-        meshModel.compute(visitor);
-        bbox = visitor.getBoundingBox();
-        
+        updateBoundingBox();
         eventBus = new EventBus();
         
         if (loadLandmarks) {
@@ -138,13 +130,8 @@ public class HumanFace implements Serializable {
             throw new IllegalArgumentException("id");
         }
         this.meshModel = model;
-        
-        BoundingBox visitor = new BoundingBox();
-        meshModel.compute(visitor);
-        bbox = visitor.getBoundingBox();
-        
+        updateBoundingBox();
         this.id = id;
-        
         eventBus = new EventBus();
     }
     
@@ -159,7 +146,6 @@ public class HumanFace implements Serializable {
     
     /**
      * Sets the mesh model. 
-     * Triggers {@link cz.fidentis.analyst.face.events.MeshChangedEvent}.
      * 
      * @param meshModel new mesh model, must not be {@code null}
      * @throws IllegalArgumentException if new model is missing
@@ -169,12 +155,8 @@ public class HumanFace implements Serializable {
             throw new IllegalArgumentException("meshModel");
         }
         this.meshModel = meshModel;
-        
-        BoundingBox visitor = new BoundingBox();
-        meshModel.compute(visitor);
-        bbox = visitor.getBoundingBox();
-        
-        announceEvent(new MeshChangedEvent(this, getShortName(), this));
+        updateBoundingBox();
+        //announceEvent(new MeshChangedEvent(this, getShortName(), this));
     }
 
     /**
@@ -210,16 +192,26 @@ public class HumanFace implements Serializable {
             eventBus.post(evt);
         }
     }
+    
+    /**
+     * Computes and return bounding box.
+     * 
+     * @return bounding box
+     */
+    public final BBox updateBoundingBox() {
+        BoundingBox visitor = new BoundingBox();
+        this.meshModel.compute(visitor);
+        this.bbox = visitor.getBoundingBox();
+        return bbox;
+    }
 
     /**
      * Sets the symmetry plane. If the input argument is {@code null}, then removes the plane.
-     * Triggers {@link cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent}.
      * 
      * @param plane The new symmetry plane; Must not be {@code null}
      */
     public void setSymmetryPlane(Plane plane) {
         this.symmetryPlane = plane;
-        this.announceEvent(new SymmetryPlaneChangedEvent(this, getShortName(), this));
     }
 
     /**
@@ -234,8 +226,17 @@ public class HumanFace implements Serializable {
      * Returns rectangular mesh facet of the symmetry plane, if exists.
      * @return a rectangular mesh facet of the symmetry plane or {@code null}
      */
-    public MeshRectangleFacet getSymmetryPlaneFacet() {
-        return (symmetryPlane == null) ? null : symmetryPlane.getMesh(bbox);
+    //@Deprecated
+    //public MeshRectangleFacet getSymmetryPlaneFacet() {
+    //    return (symmetryPlane == null) ? null : symmetryPlane.getMesh(bbox);
+    //}
+    
+    /**
+     * Returns {@code true} if the face has the symmetry plane computed.
+     * @return {@code true} if the face has the symmetry plane computed.
+     */
+    public boolean hasSymmetryPlane() {
+        return (symmetryPlane != null);
     }
     
     /**
@@ -250,6 +251,7 @@ public class HumanFace implements Serializable {
      * 
      * @param points List of feature points
      */
+    @Deprecated
     public void setFeaturePoints(List<FeaturePoint> points) {
         featurePoints = points;
     }
@@ -273,7 +275,8 @@ public class HumanFace implements Serializable {
         if (featurePoints == null) {
             return Collections.emptyList();
         }
-        return Collections.unmodifiableList(featurePoints);
+        //return Collections.unmodifiableList(featurePoints);
+        return featurePoints;
     }
     
     /**
@@ -337,9 +340,6 @@ public class HumanFace implements Serializable {
     public KdTree computeKdTree(boolean recompute) {
         if (kdTree == null || recompute) {
             kdTree = new KdTree(new ArrayList<>(meshModel.getFacets()));
-            if (eventBus != null) { // eventBus is null when the class is deserialized!
-                eventBus.post(new KdTreeCreated(this, this.getShortName(), this));
-            }
         }
         return kdTree;
     }
@@ -351,9 +351,6 @@ public class HumanFace implements Serializable {
     public KdTree removeKdTree() {
         KdTree ret = this.kdTree;
         this.kdTree = null;
-        if (eventBus != null) { // eventBus is null when the class is deserialized!
-            eventBus.post(new KdTreeDestroyed(this, this.getShortName(), this));
-        }
         return ret;
     }
     
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..27d4396722094d37c5a4fcfce3ca00863b7789ac
--- /dev/null
+++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java
@@ -0,0 +1,355 @@
+package cz.fidentis.analyst.face;
+
+import cz.fidentis.analyst.feature.FeaturePoint;
+import cz.fidentis.analyst.icp.EigenvalueDecomposition;
+import cz.fidentis.analyst.icp.IcpTransformer;
+import cz.fidentis.analyst.icp.NoUndersampling;
+import cz.fidentis.analyst.icp.Quaternion;
+import cz.fidentis.analyst.icp.RandomStrategy;
+import cz.fidentis.analyst.symmetry.Plane;
+import javax.vecmath.Matrix3d;
+import javax.vecmath.Matrix4d;
+import javax.vecmath.Point3d;
+import javax.vecmath.Vector3d;
+
+/**
+ * A utility class for operations (visitors) applied onto the whole human faces.
+ * Currently, transformation operations that affect multiple parts of the human
+ * face consistently (mesh, symmetry plane, feature points, etc.) are provided.
+ * 
+ * @author Radek Oslejsek
+ */
+public class HumanFaceUtils {
+    
+    /**
+     * Superimpose two faces using ICP applied on their triangular meshes.
+     * 
+     * @param staticFace A face that remains unchanged. 
+     * @param transformedFace A face to be transformed. 
+     * @param maxIterations Maximal number of ICP iterations, bigger than zero.
+     * Reasonable number seems to be 10.
+     * @param scale Whether to scale face as well
+     * @param error Acceptable error (a number bigger than or equal to zero).
+     * @param undersampling 100 = no undersampling, 10 = undersampling into 10% of vertices.
+     * @param recomputeKdTree If {@code true} and the k-d tree of the {@code transformedFace} exists, 
+     *        the it automatically re-computed. Otherwise, it is simply removed.
+     * @return ICP visitor that holds the transformations performed on the {@code transformedFace}.
+     */
+    public static IcpTransformer alignMeshes(
+            HumanFace staticFace, HumanFace transformedFace,
+            int maxIterations, boolean scale, double error, int undersampling,
+            boolean recomputeKdTree) {
+        
+        // transform mesh:
+        IcpTransformer icp = new IcpTransformer(
+                staticFace.getMeshModel(), 
+                maxIterations, 
+                scale, 
+                error, 
+                (undersampling == 100) ? new NoUndersampling() : new RandomStrategy(undersampling)
+        );
+        transformedFace.getMeshModel().compute(icp, true); // superimpose face towards the static face
+
+        // update k-d of transformed face:
+        if (transformedFace.hasKdTree()) { 
+            if (recomputeKdTree) {
+                transformedFace.computeKdTree(true);
+            } else {
+                transformedFace.removeKdTree();
+            }
+        }
+        
+        // update bounding box, which is always present:
+        transformedFace.updateBoundingBox();
+        
+        // transform feature points:
+        if (transformedFace.hasFeaturePoints()) {
+            icp.getTransformations().values().forEach(trList -> { // List<IcpTransformation> 
+                trList.forEach(tr -> { // IcpTransformation
+                    for (int i = 0; i < transformedFace.getFeaturePoints().size(); i++) {
+                        FeaturePoint fp = transformedFace.getFeaturePoints().get(i);
+                        Point3d trPoint = tr.transformPoint(fp.getPosition(), scale);
+                        transformedFace.getFeaturePoints().set(i, 
+                                new FeaturePoint(trPoint.x, trPoint.y, trPoint.z, fp.getFeaturePointType())
+                        );
+                    }
+                });
+            });
+        }
+        
+        // transform symmetry plane:
+        if (transformedFace.hasSymmetryPlane()) {
+            icp.getTransformations().values().forEach(trList -> { // List<IcpTransformation> 
+                trList.forEach(tr -> { // IcpTransformation
+                    transformedFace.setSymmetryPlane(transformPlane(
+                            transformedFace.getSymmetryPlane(), 
+                            tr.getRotation(), 
+                            tr.getTranslation(), 
+                            tr.getScaleFactor()));
+                });
+            });
+        }
+        
+        return icp;
+    }
+    
+    /**
+     * Transform the face.
+     * 
+     * @param face Face to be transformed.
+     * @param rotation Rotation vector denoting the rotation angle around axes X, Y, and Z.
+     * @param translation Translation vector denoting the translation in the X, Y, and Z direction.
+     * @param scale Scale factor (1 = no scale).
+     * @param recomputeKdTree If {@code true} and the k-d tree of the {@code transformedFace} exists, 
+     *        the it automatically re-computed. Otherwise, it is simply removed.
+     */
+    public static void transformFace(HumanFace face, Vector3d rotation, Vector3d translation, double scale, boolean recomputeKdTree) {
+        Quaternion rot = new Quaternion(rotation.x, rotation.y, rotation.z, 1.0);
+        
+        face.getMeshModel().getFacets().stream()
+                .map(facet -> facet.getVertices())
+                .flatMap(meshPoint -> meshPoint.parallelStream())
+                .forEach(meshPoint -> {
+                    transformPoint(meshPoint.getPosition(), rot, translation, scale);
+                });
+                    
+        
+        // update k-d of transformed face:
+        if (face.hasKdTree()) { 
+            if (recomputeKdTree) {
+                face.computeKdTree(true);
+            } else {
+                face.removeKdTree();
+            }
+        }
+        
+        // update bounding box, which is always present:
+        face.updateBoundingBox();
+
+        // transform feature points:
+        if (face.hasFeaturePoints()) {
+            face.getFeaturePoints().parallelStream().forEach(fp -> {
+                transformPoint(fp.getPosition(), rot, translation, scale);
+            });
+        }
+
+        // transform symmetry plane:
+        if (face.hasSymmetryPlane()) {
+            face.setSymmetryPlane(transformPlane(face.getSymmetryPlane(), rot, translation, scale));
+        }
+    }
+    
+    /**
+     * Transforms one face so that its symmetry plane fits the symmetry plane of the other face.
+     * 
+     * @param staticFace a human face that remains unchanged
+     * @param transformedFace a human face that will be transformed
+     * @param recomputeKdTree  If {@code true} and the k-d tree of the {@code transformedFace} exists, 
+     *        the it automatically re-computed. Otherwise, it is simply removed.
+     */
+    public static void alignSymmetryPlanes(HumanFace staticFace, HumanFace transformedFace, boolean recomputeKdTree) {
+        Plane statPlane = staticFace.getSymmetryPlane();
+        Plane tranPlane = transformedFace.getSymmetryPlane();
+        
+        // Get "centroids" of the planes
+        Point3d statCentroid = statPlane.projectToPlane(staticFace.getBoundingBox().getMidPoint());
+        Point3d tranCentroid = tranPlane.projectToPlane(transformedFace.getBoundingBox().getMidPoint());
+        
+        // Compute a 3D transformation of planes. 
+        // However, this transforation rotates the face around the plane axis arbitrarily
+        Vector3d translation = new Vector3d(
+                statCentroid.x - tranCentroid.x,
+                statCentroid.y - tranCentroid.y, 
+                statCentroid.z - tranCentroid.z
+        );        
+        Quaternion rotation = computeRotation(tranPlane.getNormal(), statPlane.getNormal());
+        
+        // Compute rotation around plane's normal so that the face is oriented as before
+        
+        // Get a vector perpendicular to the transformed plane nornal (and then laying at the plane)
+        Point3d pp = getPerpendicularPoint(tranPlane); // point at the original plane
+        Vector3d pv = new Vector3d(pp);
+        pv.sub(tranCentroid);
+        pv.normalize();
+        
+        // transform the point so that it lays at the target plane
+        transformPoint(pp, rotation, translation, 1.0); // point at the transformed plane
+        transformPoint(tranCentroid, rotation, translation, 1.0); // point at the transformed plane
+        Vector3d trPV = new Vector3d(pp);
+        trPV.sub(tranCentroid);
+        trPV.normalize();
+
+        // compute angle of rotation around the plane normal so that the face is oriented as before
+        double cosRot = pv.dot(trPV);
+        pv.cross(pv, trPV);
+        double sinRot = pv.length(); 
+        Vector3d axis = (statPlane.getNormal().dot(tranPlane.getNormal()) < 0)
+                ? statPlane.getNormal()
+                : new Vector3d(-statPlane.getNormal().x, -statPlane.getNormal().y, -statPlane.getNormal().z);
+        
+        // get rotation matrix around the plane's normal
+        Matrix3d rotMat = rotMatAroundAxis(axis, sinRot, cosRot);
+        
+        // Transform mesh vertices:
+        transformedFace.getMeshModel().getFacets().forEach(f -> {
+            f.getVertices().stream().forEach(p -> {
+                transformPoint(p.getPosition(), rotation, translation, 1.0);
+                rotMat.transform(p.getPosition()); // rotate around the plane's normal
+            });
+        });
+        
+        // update k-d of transformed face:
+        if (transformedFace.hasKdTree()) { 
+            if (recomputeKdTree) {
+                transformedFace.computeKdTree(true);
+            } else {
+                transformedFace.removeKdTree();
+            }
+        }
+        
+        // update bounding box, which is always present:
+        transformedFace.updateBoundingBox();
+        
+        // Transform feature points:
+        if (transformedFace.hasFeaturePoints()) {
+            transformedFace.getFeaturePoints().parallelStream().forEach(fp -> {
+                transformPoint(fp.getPosition(), rotation, translation, 1.0);
+                rotMat.transform(fp.getPosition()); // rotate around the plane's normal
+            });
+        }        
+        
+        // Transform the symmetry plane:
+        if (transformedFace.hasSymmetryPlane()) {
+            transformedFace.setSymmetryPlane(transformPlane(
+                    transformedFace.getSymmetryPlane(), rotation, translation, 1.0)
+            );
+        }
+    }
+    
+    /**
+     * Create rotation matrix from rotation axis and the angle
+     * 
+     * @param axis rotation axis
+     * @param sinAngle cosine of the angle
+     * @param cosAngle sin of the angle
+     * @return rotation matrix
+     */
+    protected static Matrix3d rotMatAroundAxis(Vector3d axis, double sinAngle, double cosAngle) {
+        Matrix3d matC = new Matrix3d(
+                0, -axis.z, axis.y,
+                axis.z, 0, -axis.x,
+                -axis.y, axis.x, 0
+        );
+        
+        Matrix3d matCC = new Matrix3d(matC);
+        matCC.mul(matCC);
+        matCC.mul(1.0 - cosAngle);
+        
+        matC.mul(sinAngle);
+        
+        Matrix3d rotMat = new Matrix3d();
+        rotMat.setIdentity();
+        rotMat.add(matC);
+        rotMat.add(matCC);
+        
+        return rotMat;
+    }
+    
+    /**
+     * Computes a "random" point at the plan, i.e. a point, which is
+     * perpendicular to the plane's normal and lays at the plane.
+     * 
+     * @param plane the plane
+     * @return point at the plane
+     */
+    protected static Point3d getPerpendicularPoint(Plane plane) {
+        Point3d p;
+        if (plane.getNormal().x >= Math.max(plane.getNormal().y, plane.getNormal().z)) {
+            p = new Point3d(0, 1000, 0);
+        } else if (plane.getNormal().y >= Math.max(plane.getNormal().x, plane.getNormal().y)) {
+            p = new Point3d(1000, 0, 0);
+        } else {
+            p = new Point3d(0, 1000, 0);
+        }
+        return plane.projectToPlane(p);
+    }
+    
+    /**
+     * Computed 3D rotation matrix that transforms one vector onto another.
+     * @param trDir vector to be transformed
+     * @param targetDir target vector
+     * @return rotation
+     */
+    protected static Quaternion computeRotation(Vector3d trDir, Vector3d targetDir) {
+        Matrix4d multipleMatrix = new Matrix4d();
+        Matrix4d sumMatrixComp = new Matrix4d(
+                      0, -trDir.x, -trDir.y, -trDir.z,
+                trDir.x,        0,  trDir.z, -trDir.y,
+                trDir.y, -trDir.z,        0,  trDir.x,
+                trDir.z,  trDir.y, -trDir.x,        0
+        );
+        Matrix4d sumMatrixMain = new Matrix4d(
+                          0, -targetDir.x, -targetDir.y, -targetDir.z,
+                targetDir.x,            0, -targetDir.z,  targetDir.y,
+                targetDir.y,  targetDir.z,            0, -targetDir.x,
+                targetDir.z, -targetDir.y,  targetDir.x,            0
+        );
+        
+        multipleMatrix.mulTransposeLeft(sumMatrixComp, sumMatrixMain);
+        Quaternion rotation = new Quaternion(new EigenvalueDecomposition(multipleMatrix));
+        rotation.normalize();
+        return rotation;
+    }
+    
+    
+    /**
+     * Transform a single 3d point.
+     * 
+     * @param point point to be transformed
+     * @param rotation rotation, can be {@code null}
+     * @param translation translation
+     * @param scale scale
+     */
+    protected static void transformPoint(Point3d point, Quaternion rotation, Vector3d translation, double scale) {
+        Quaternion rotQuat = new Quaternion(point.x, point.y, point.z, 1);
+
+        if (rotation != null) {
+            Quaternion rotationCopy = Quaternion.multiply(rotQuat, rotation.getConjugate());
+            rotQuat = Quaternion.multiply(rotation, rotationCopy);
+        }
+
+        point.set(
+                (rotQuat.x + translation.x) * scale,
+                (rotQuat.y + translation.y) * scale,
+                (rotQuat.z + translation.z) * scale
+        );
+    }
+
+    /**
+     * Transforms the whole plane, i.e., its normal and position.
+     * 
+     * @param plane plane to be transformed
+     * @param rot rotation
+     * @param translation translation
+     * @param scale scale
+     * @return transformed plane
+     */
+    protected static Plane transformPlane(Plane plane, Quaternion rot, Vector3d translation, double scale) {
+        Point3d point = new Point3d(plane.getNormal());
+        transformPoint(point, rot, new Vector3d(0, 0, 0), 1.0); // rotate only
+        Plane retPlane = new Plane(point, plane.getDistance());
+
+        // ... then translate and scale a point projected on the rotate plane:
+        point.scale(retPlane.getDistance()); // point laying on the rotated plane
+        transformPoint(point, null, translation, scale); // translate and scale only
+        Vector3d normal = retPlane.getNormal();
+        double dist = ((normal.x * point.x) + (normal.y * point.y) + (normal.z * point.z))
+                / Math.sqrt(normal.dot(normal)); // distance of tranformed surface point in the plane's mormal direction
+        
+        return new Plane(retPlane.getNormal(), dist);
+    }
+    
+
+    
+    
+}
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/events/HumanFaceTransformedEvent.java b/Comparison/src/main/java/cz/fidentis/analyst/face/events/HumanFaceTransformedEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..960862ef40ddd6d697f3759ff2dad16f35a214bb
--- /dev/null
+++ b/Comparison/src/main/java/cz/fidentis/analyst/face/events/HumanFaceTransformedEvent.java
@@ -0,0 +1,46 @@
+package cz.fidentis.analyst.face.events;
+
+import cz.fidentis.analyst.face.HumanFace;
+
+/**
+ * A human face all its components (mesh, symmetry plane, feature points, etc.)
+ * have been transformed in scape.
+ * 
+ * @author Radek Oslejsek
+ */
+public class HumanFaceTransformedEvent extends HumanFaceEvent {
+    
+    private final boolean isFinished;
+    
+    /**
+     * Constructor of finished transformation.
+     * 
+     * @param face Human face related to the event
+     * @param name Event name provided by issuer
+     * @param issuer The issuer
+     */
+    public HumanFaceTransformedEvent(HumanFace face, String name, Object issuer) {
+        this(face, name, issuer, true);
+    }
+    
+    /**
+     * Constructor.
+     * @param face Human face related to the event
+     * @param name Event name provided by issuer
+     * @param issuer The issuer
+     * @param isFinished if {@code true}, then it is supposed that the transformation will continue
+     *        (is in the progress).
+     */
+    public HumanFaceTransformedEvent(HumanFace face, String name, Object issuer, boolean isFinished) {
+        super(face, name, issuer);
+        this.isFinished = isFinished;
+    }
+    
+    /**
+     * Returns {@code true} it the transformation is finished (is not under progress)
+     * @return {@code true} it the transformation is finished 
+     */
+    public boolean isFinished() {
+        return this.isFinished;
+    }
+}
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/events/KdTreeCreated.java b/Comparison/src/main/java/cz/fidentis/analyst/face/events/KdTreeCreated.java
deleted file mode 100644
index 52d62d033e3197dab56c82f90449285a11f8f743..0000000000000000000000000000000000000000
--- a/Comparison/src/main/java/cz/fidentis/analyst/face/events/KdTreeCreated.java
+++ /dev/null
@@ -1,29 +0,0 @@
-
-package cz.fidentis.analyst.face.events;
-
-import cz.fidentis.analyst.face.HumanFace;
-
-/**
- * An event fired when a new KdTree is calculated
-
- * @author Matej Kovar
- */
-public class KdTreeCreated extends KdTreeEvent {
-    
-    /**
-     * Constructor.
-     * @param face Human face related to the event
-     * @param name Event name provided by issuer
-     * @param issuer The issuer
-     */
-    public KdTreeCreated(HumanFace face, String name, Object issuer) {
-        super(face, name, issuer);
-    }
-
-    @Override
-    public boolean isCalculated() {
-        return true;
-    }
-
-    
-}
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/events/KdTreeDestroyed.java b/Comparison/src/main/java/cz/fidentis/analyst/face/events/KdTreeDestroyed.java
deleted file mode 100644
index 30d3ffd832a4a1a46ebcee62428f2bdb58743683..0000000000000000000000000000000000000000
--- a/Comparison/src/main/java/cz/fidentis/analyst/face/events/KdTreeDestroyed.java
+++ /dev/null
@@ -1,24 +0,0 @@
-
-package cz.fidentis.analyst.face.events;
-
-import cz.fidentis.analyst.face.HumanFace;
-
-/**
- * An event fired when a KD-tree is destroyed
-
- * @author Matej Kovar
- */
-
-public class KdTreeDestroyed extends KdTreeEvent {
-    
-    /**
-     * Constructor.
-     * @param face Human face related to the event
-     * @param name Event name provided by issuer
-     * @param issuer The issuer
-     */
-    public KdTreeDestroyed(HumanFace face, String name, Object issuer) {
-        super(face, name, issuer);
-    }
-
-}
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/events/MeshChangedEvent.java b/Comparison/src/main/java/cz/fidentis/analyst/face/events/MeshChangedEvent.java
deleted file mode 100644
index daa6bc3d7c22a59dec1ca1febf2e8cce274f23ea..0000000000000000000000000000000000000000
--- a/Comparison/src/main/java/cz/fidentis/analyst/face/events/MeshChangedEvent.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package cz.fidentis.analyst.face.events;
-
-import cz.fidentis.analyst.face.HumanFace;
-
-/**
- * An event fired when the topology or position has changed.
-
- * @author Radek Oslejsek
- */
-public class MeshChangedEvent extends MeshEvent {
-    
-    /**
-     * Constructor.
-     * @param face Human face related to the event
-     * @param name Event name provided by issuer
-     * @param issuer The issuer
-     */
-    public MeshChangedEvent(HumanFace face, String name, Object issuer) {
-        super(face, name, issuer);
-    }
-    
-}
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/events/MeshEvent.java b/Comparison/src/main/java/cz/fidentis/analyst/face/events/MeshEvent.java
deleted file mode 100644
index b4f0df4f470d64f2f2dc0941927f044b93512ada..0000000000000000000000000000000000000000
--- a/Comparison/src/main/java/cz/fidentis/analyst/face/events/MeshEvent.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package cz.fidentis.analyst.face.events;
-
-import cz.fidentis.analyst.face.HumanFace;
-
-/**
- * The root type for events related to changes in the triangular mesh.
- * 
- * @author Radek Oslejsek
- */
-public class MeshEvent extends HumanFaceEvent {
-    
-    /**
-     * Constructor.
-     * @param face Human face related to the event
-     * @param name Event name provided by issuer
-     * @param issuer The issuer
-     */
-    public MeshEvent(HumanFace face, String name, Object issuer) {
-        super(face, name, issuer);
-    }
-    
-}
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/events/SymmetryPlaneChangedEvent.java b/Comparison/src/main/java/cz/fidentis/analyst/face/events/SymmetryPlaneChangedEvent.java
index f171633aceccb3b150c38fca80be6f7a43362e47..04f52440f578647b86a11d361989afbba74263df 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/face/events/SymmetryPlaneChangedEvent.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/face/events/SymmetryPlaneChangedEvent.java
@@ -3,7 +3,11 @@ package cz.fidentis.analyst.face.events;
 import cz.fidentis.analyst.face.HumanFace;
 
 /**
- * New symmetry plane has been added or changed (transformed).
+ * A new symmetry plane has been added or the previous one has been recomputed.
+ * If the plane is transformed separately (without the transformation of mesh or
+ * other parts of the human face), use this event as well. 
+ * On the contrary, if symmetry plane is transformed together with 
+ * the mesh transformation, use the {@link HausdorffDistanceComputed} event instead.
  * 
  * @author Radek Oslejsek
  */
@@ -11,6 +15,7 @@ public class SymmetryPlaneChangedEvent extends HumanFaceEvent {
     
     /**
      * Constructor.
+     * 
      * @param face Human face related to the event
      * @param name Event name provided by issuer
      * @param issuer The issuer
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformation.java b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformation.java
index fcf0fda9110e5afdc8e8d007220d3d088bfb09c2..363ee1e8b7666b1fffcd1cf8def6965f391d20f7 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformation.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformation.java
@@ -22,7 +22,7 @@ public class IcpTransformation {
      * @param rotation Rotation is represented by Quaternion
      *                 (x, y, z coordinate and scalar component).
      * @param scaleFactor ScaleFactor represents scale between two objects.
-     *                    In case there is no scale the value is 0.
+     *                    In case there is no scale the value is 1.
      * @param meanD MeanD represents mean distance between objects.
      */
     public IcpTransformation(Vector3d translation, Quaternion rotation, double scaleFactor, double meanD) {
@@ -82,9 +82,9 @@ public class IcpTransformation {
         
         if(scale && !Double.isNaN(getScaleFactor())) {
             return new Point3d(
-                    rotQuat.x * getScaleFactor() + getTranslation().x,
-                    rotQuat.y * getScaleFactor() + getTranslation().y,
-                    rotQuat.z * getScaleFactor() + getTranslation().z
+                    (rotQuat.x + getTranslation().x) * getScaleFactor(),
+                    (rotQuat.y + getTranslation().y) * getScaleFactor(),
+                    (rotQuat.z + getTranslation().z) * getScaleFactor()
             );
         } else {
             return new Point3d(
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 5f9d1a51ad9f754ff36c77949ebf5abcfd478309..5c47b7e9700ba9317bcb13a7e5bc8dbd81a1dbbc 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java
@@ -76,7 +76,7 @@ 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. 
+     * @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 strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used.
      * @throws IllegalArgumentException if some parameter is wrong
@@ -295,7 +295,7 @@ public class IcpTransformer extends MeshVisitor   {
         List<Point3d>centers = computeCenterBothFacets(nearestPoints, comparedPoints);
         Point3d mainCenter = centers.get(0);
         Point3d comparedCenter = centers.get(1);
-
+        
         Matrix4d sumMatrix = new Matrix4d();
         Matrix4d multipleMatrix = new Matrix4d();
 
@@ -330,7 +330,7 @@ public class IcpTransformer extends MeshVisitor   {
         // END computing rotation parameter
 
         //computing SCALE parameter
-        double scaleFactor = 0;
+        double scaleFactor = 1.0;
         if (scale) {
             double sxUp = 0;
             double sxDown = 0;
@@ -341,7 +341,7 @@ public class IcpTransformer extends MeshVisitor   {
                 }
 
                 Matrix4d matrixPoint = pointToMatrix(relativeCoordinate(nearestPoints.get(i), mainCenter));
-                Matrix4d matrixPointCompare = pointToMatrix(relativeCoordinate(comparedPoints.get(i).getPosition(),comparedCenter));
+                Matrix4d matrixPointCompare = pointToMatrix(relativeCoordinate(comparedPoints.get(i).getPosition(), comparedCenter));
 
                 matrixPointCompare.mul(rotationMatrix);
                 
@@ -383,38 +383,28 @@ public class IcpTransformer extends MeshVisitor   {
      * and the second one represents center of compared facet.
      */
     private List<Point3d> computeCenterBothFacets(List<Point3d> nearestPoints, List<MeshPoint> comparedPoints) {
-        double xN = 0;
-        double yN = 0;
-        double zN = 0;
-
-        double xC = 0;
-        double yC = 0;
-        double zC = 0;
-
+        //assert(nearestPoints.size() == comparedPoints.size());
+        Point3d n = new Point3d(0, 0, 0);
+        Point3d c = new Point3d(0, 0, 0);
         int countOfNotNullPoints = 0;
         List<Point3d> result = new ArrayList<>(2);
 
         for (int i = 0; i < nearestPoints.size(); i++) {
-
-            if(nearestPoints.get(i) == null){
+            if (nearestPoints.get(i) == null) {
                 continue;
             }
-
-            xN += nearestPoints.get(i).x;
-            yN += nearestPoints.get(i).y;
-            zN += nearestPoints.get(i).z;
-
-            xC += comparedPoints.get(i).getPosition().x;
-            yC += comparedPoints.get(i).getPosition().y;
-            zC += comparedPoints.get(i).getPosition().z;
-
+            n.add(nearestPoints.get(i));
+            c.add(comparedPoints.get(i).getPosition());
             countOfNotNullPoints ++;
         }
-        result.add(new Point3d(xN/countOfNotNullPoints, yN/countOfNotNullPoints, zN/countOfNotNullPoints));
-        result.add(new Point3d(xC/countOfNotNullPoints, yC/countOfNotNullPoints, zC/countOfNotNullPoints));
+        
+        n.scale(1.0/countOfNotNullPoints);
+        c.scale(1.0/countOfNotNullPoints);
+        result.add(n);
+        result.add(c);
         return result;
     }
-
+    
     /**
      * Compute relative coordinate of given point according to given center.
      * Relative coordinates represents distance from the center of the mesh to vertex.
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java
index 80737435ff3459dbd291c509b212babfd5f0fa8f..2b9489bf6f2f0eebf8424608e5084294c29d2b45 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java
@@ -5,10 +5,11 @@ import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox;
 import java.io.Serializable;
 import java.util.List;
 import javax.vecmath.Point3d;
+import javax.vecmath.Tuple3d;
 import javax.vecmath.Vector3d;
 
 /**
- * Symmetry plane.
+ * Immutable symmetry plane.
  * 
  * @author Natalia Bebjakova
  * @author Dominik Racek
@@ -26,8 +27,8 @@ public class Plane implements Serializable {
      * @param dist distance
      * @throws IllegalArgumentException if the @code{plane} argument is null
      */
-    public Plane(Vector3d normal, double dist) {
-        setNormal(new Vector3d(normal));
+    public Plane(Tuple3d normal, double dist) {
+        setNormal(normal);
         setDistance(dist);
     }
     
@@ -54,7 +55,7 @@ public class Plane implements Serializable {
         Vector3d n = new Vector3d();
         double d = 0;
         Vector3d refDir = planes.get(0).getNormal();
-        for (int i = 0; i < planes.size(); i++) {
+        for (int i = 1; i < planes.size(); i++) {
             Vector3d normDir = planes.get(i).getNormal();
             if (normDir.dot(refDir) < 0) {
                 n.sub(normDir);
@@ -66,7 +67,7 @@ public class Plane implements Serializable {
         }
         
         setNormal(n);
-        setDistance(d);
+        setDistance(-d);
         normalize();
     }
     
@@ -90,11 +91,7 @@ public class Plane implements Serializable {
      */
     @Override
     public String toString(){
-        return "APPROXIMATE PLANE:" + System.lineSeparator() + 
-                normal.x + System.lineSeparator() + 
-                normal.y + System.lineSeparator() + 
-                normal.z + System.lineSeparator() + 
-                distance + System.lineSeparator();
+        return normal + " dist " + distance;
     }
     
     public Vector3d getNormal() {
@@ -104,14 +101,47 @@ public class Plane implements Serializable {
     public double getDistance() {
         return distance;
     }
+    
+    /**
+     * Returns a point laying at the plane
+     * @return a point laying at the plane
+     */
+    public Point3d getPlanePoint() {
+        Point3d ret = new Point3d(normal);
+        ret.scale(distance);
+        return ret;
+    }
 
     /**
      * Translate the plane along its normal
      *
      * @param value
      */
-    public void translate(double value) {
-        this.distance += value;
+    //public void shift(double value) {
+    //    this.distance += value;
+    //}
+    
+    /**
+     * Translate the plane along its normal
+     *
+     * @param value a value to be added to the current plane's distance value
+     * @return shifted plane
+     */
+    public Plane shift(double value) {
+        Plane ret = new Plane(this);
+        ret.distance += value;
+        return ret;
+    }
+    
+    /**
+     * Returns a plane with flipped direction
+     * @return a plane with flipped direction
+     */
+    public Plane flip() {
+        Plane ret = new Plane(this);
+        ret.normal.scale(-1.0);
+        ret.distance *= -1.0;
+        return ret;
     }
     
     /**
@@ -122,39 +152,50 @@ public class Plane implements Serializable {
      * @throws NullPointerException if the {@code point} is {@code null}
      */
     public Point3d projectToPlane(Point3d point) {
+        Point3d ret = new Point3d(normal);
+        ret.scale(-getPointDistance(point));
+        ret.add(point);
+        return ret;
+        
+        /*
         double shiftDist = 
                 ((normal.x * point.x) + 
                   (normal.y * point.y) + 
-                  (normal.z * point.z) +
-                  distance) / normSquare;
+                  (normal.z * point.z)) / normSquare;
+        shiftDist -= distance;
         
         Point3d ret = new Point3d(normal);
         ret.scale(-shiftDist);
         ret.add(point);
         return ret;
+        */
     }
     
     /**
      * Returns a point laying on the opposite side of the plane ("mirrors" the point).
-     * This method implements equation (1) of 
-     * <a href="https://link.springer.com/content/pdf/10.1007/s00371-020-02034-w.pdf">Hruda et al: Robust, fast and flexible symmetry plane detection based
-on differentiable symmetry measure</a>
      * 
      * @param point A 3D point to be reflected
      * @return a point on the opposite side of the plane.
      * @throws NullPointerException if the {@code point} is {@code null}
      */
     public Point3d reflectOverPlane(Point3d point) {
+        Point3d ret = new Point3d(normal);
+        ret.scale(-2.0 * getPointDistance(point));
+        ret.add(point);
+        return ret;
+        
+        /*
         double shiftDist = 
                 ((normal.x * point.x) + 
                   (normal.y * point.y) + 
                   (normal.z * point.z) +
                   distance) / normSquare;
-        
+        //System.out.println("HHH "+ shiftDist);
         Point3d ret = new Point3d(normal);
         ret.scale(-2.0 * shiftDist);
         ret.add(point);
         return ret;
+        */
     }
     
     /**
@@ -181,7 +222,7 @@ on differentiable symmetry measure</a>
      * @throws IllegalArgumentException if {@code size} is &lt;= 0
      */
     public MeshRectangleFacet getMesh(Point3d point, double size) {
-        return Plane.this.getMesh(point, size, size);
+        return getMesh(point, size, size);
     }
 
     /**
@@ -193,14 +234,27 @@ on differentiable symmetry measure</a>
      * @throws NullPointerException if the {@code midPoint} or {@code bbox} are {@code null}
      */
     public MeshRectangleFacet getMesh(BBox bbox) {
-        return Plane.this.getMesh(bbox.getMidPoint(), bbox.getDiagonalLength(), bbox.getDiagonalLength());
+        return getMesh(bbox.getMidPoint(), bbox.getDiagonalLength(), bbox.getDiagonalLength());
     }
 
-    protected final void setNormal(Vector3d normal) {
-        this.normal = normal;
-        this.normSquare = normal.dot(normal);
+    /**
+     * Changes the normal vector.
+     * @param normal new normalized normal vector
+     * @throw IllegalArgumentExcpetion if the normal is {@code null} 
+     *        or if length is not one.
+     */
+    protected final void setNormal(Tuple3d normal) {
+        if (normal == null) {
+            throw new IllegalArgumentException("noraml");
+        }
+        this.normal = new Vector3d(normal);
+        this.normSquare = this.normal.dot(this.normal);
     }
     
+    /**
+     * Changes the distance.
+     * @param dist new distance
+     */
     protected final void setDistance(double dist) {
         this.distance = dist;
     }
@@ -212,8 +266,10 @@ on differentiable symmetry measure</a>
      * the respect to the plane's normal, the negative distance is returned
      */
     public double getPointDistance(Point3d point) {
-        return ((normal.x * point.x) + (normal.y * point.y) + (normal.z * point.z) + distance)
-                / Math.sqrt(normSquare);
+        Point3d v = new Point3d(point);
+        v.sub(this.getPlanePoint());
+        return (normal.x * v.x) + (normal.y * v.y) + (normal.z * v.z);
+        //return ((normal.x * point.x) + (normal.y * point.y) + (normal.z * point.z) + distance) / Math.sqrt(normSquare);
     }
 
     /**
@@ -226,12 +282,14 @@ on differentiable symmetry measure</a>
     public Point3d getIntersectionWithLine(Point3d p1, Point3d p2) {
         double distance1 = getPointDistance(p1);
         double distance2 = getPointDistance(p2);
-        double t = distance1 / (distance1 - distance2);
-
-        if (distance1 * distance2 > 0) {
+        
+        if (distance1 * distance2 > 0) { // both are positive or negative
             return null;
         }
 
+        double t = distance1 / (distance1 - distance2);
+
+        //Logger.print("EEE "+p1+ " "+getPointDistance(p1));
         Point3d output = new Point3d(p2);
         output.sub(p1);
         output.scale(t);
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/HausdorffDistance.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/HausdorffDistance.java
index 7e1f96886f692fd60b3f299f753ce50ee78309bb..ca0484675ec400f1d788067597e1a247cd243f5f 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/HausdorffDistance.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/HausdorffDistance.java
@@ -356,7 +356,7 @@ import javax.vecmath.Point3d;
                 updateResults(visitor, vertices.get(i), comparedFacet);
             }
         }
-            
+        
         if (inParallel()) { // process asynchronous computation of distance
             executor.shutdown();
             while (!executor.isTerminated()){}
diff --git a/Comparison/src/test/java/cz/fidentis/analyst/symmetry/PlaneTest.java b/Comparison/src/test/java/cz/fidentis/analyst/symmetry/PlaneTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1e053ae74c4002d23b66100de000a94c4c1a4256
--- /dev/null
+++ b/Comparison/src/test/java/cz/fidentis/analyst/symmetry/PlaneTest.java
@@ -0,0 +1,129 @@
+package cz.fidentis.analyst.symmetry;
+
+import javax.vecmath.Point3d;
+import javax.vecmath.Vector3d;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+
+/**
+ *
+ * @author Radek Oslejsek
+ */
+public class PlaneTest {
+    
+    @Test
+    public void construction() {
+        Vector3d norm = new Vector3d(-1, -1, -1);
+        norm.normalize();
+        
+        Plane p = new Plane(norm, -3);
+        Assertions.assertEquals(norm, p.getNormal());
+        Assertions.assertEquals(-3, p.getDistance());
+        
+        p = new Plane(p);
+        Assertions.assertEquals(norm, p.getNormal());
+        Assertions.assertEquals(-3, p.getDistance());
+    }
+    
+    @Test
+    public void modification() {
+        Vector3d norm = new Vector3d(-1, -1, -1);
+        norm.normalize();
+        Plane p = new Plane(norm, -3);
+        
+        Assertions.assertTrue(p.getPlanePoint()
+                .epsilonEquals(new Vector3d(1.7320508075688776, 1.7320508075688776, 1.7320508075688776), 0.001));
+        Assertions.assertTrue(p.shift(1)
+                .getPlanePoint().epsilonEquals(new Vector3d(1.1547005383792517, 1.1547005383792517, 1.1547005383792517), 0.001));
+        Assertions.assertTrue(p.shift(-1)
+                .getPlanePoint().epsilonEquals(new Vector3d(2.3094010767585034, 2.3094010767585034, 2.3094010767585034), 0.001));
+        
+        Vector3d n2 = new Vector3d(norm);
+        n2.scale(-1);
+        Assertions.assertEquals(n2, p.flip().getNormal());
+        Assertions.assertEquals(3, p.flip().getDistance());
+    }
+    
+    @Test
+    public void projectToPlane() {
+        Plane p = new Plane(new Vector3d(-1, 0, 0), -3);
+        Assertions.assertTrue(p.projectToPlane(new Point3d(9,9,9))
+                .epsilonEquals(new Vector3d(3, 9, 9), 0.001));
+        Assertions.assertTrue(p.projectToPlane(new Point3d(-9,-9,-9))
+                .epsilonEquals(new Vector3d(3, -9, -9), 0.001));
+        Assertions.assertTrue(p.projectToPlane(new Point3d(0,0,0))
+                .epsilonEquals(new Vector3d(3, 0, 0), 0.001));
+        
+        p = new Plane(new Vector3d(-1, 0, 0), 3);
+        Assertions.assertTrue(p.projectToPlane(new Point3d(9,9,9))
+                .epsilonEquals(new Vector3d(-3, 9, 9), 0.001));
+        Assertions.assertTrue(p.projectToPlane(new Point3d(-9,-9,-9))
+                .epsilonEquals(new Vector3d(-3, -9, -9), 0.001));
+        Assertions.assertTrue(p.projectToPlane(new Point3d(0,0,0))
+                .epsilonEquals(new Vector3d(-3, 0, 0), 0.001));        
+        
+        Vector3d norm = new Vector3d(-1, -1, -1);
+        norm.normalize();
+        p = new Plane(norm, -3);
+        Assertions.assertTrue(p.projectToPlane(new Point3d(9,9,9))
+                .epsilonEquals(new Vector3d(1.7320508075688776, 1.7320508075688776, 1.7320508075688776), 0.001));
+        Assertions.assertTrue(p.projectToPlane(new Point3d(-9,-9,-9))
+                .epsilonEquals(new Vector3d(1.7320508075688776, 1.7320508075688776, 1.7320508075688776), 0.001));
+        Assertions.assertTrue(p.projectToPlane(new Point3d(0,0,0))
+                .epsilonEquals(new Vector3d(1.7320508075688776, 1.7320508075688776, 1.7320508075688776), 0.001));
+    }
+    
+    @Test
+    public void reflectOverPlane() {
+        Plane p = new Plane(new Vector3d(-1, 0, 0), -3);
+        Assertions.assertTrue(p.reflectOverPlane(new Point3d(9,9,9))
+                .epsilonEquals(new Vector3d(-3, 9, 9), 0.001));
+        Assertions.assertTrue(p.reflectOverPlane(new Point3d(-9,-9,-9))
+                .epsilonEquals(new Vector3d(15, -9, -9), 0.001));
+        Assertions.assertTrue(p.reflectOverPlane(new Point3d(0,0,0))
+                .epsilonEquals(new Vector3d(6, 0, 0), 0.001));
+        
+        p = new Plane(new Vector3d(-1, 0, 0), 3);
+        Assertions.assertTrue(p.reflectOverPlane(new Point3d(9,9,9))
+                .epsilonEquals(new Vector3d(-15, 9, 9), 0.001));
+        Assertions.assertTrue(p.reflectOverPlane(new Point3d(-9,-9,-9))
+                .epsilonEquals(new Vector3d(3, -9, -9), 0.001));
+        Assertions.assertTrue(p.reflectOverPlane(new Point3d(0,0,0))
+                .epsilonEquals(new Vector3d(-6, 0, 0), 0.001));
+        
+        Vector3d norm = new Vector3d(-1, -1, -1);
+        norm.normalize();
+        p = new Plane(norm, -3);
+        
+        Assertions.assertTrue(p.reflectOverPlane(new Point3d(9,9,9))
+                .epsilonEquals(new Vector3d(-5.535898384862248, -5.535898384862248, -5.535898384862248), 0.001));
+        Assertions.assertTrue(p.reflectOverPlane(new Point3d(-9,-9,-9))
+                .epsilonEquals(new Vector3d(12.464101615137768, 12.464101615137768, 12.464101615137768), 0.001));
+        Assertions.assertTrue(p.reflectOverPlane(new Point3d(0,0,0))
+                .epsilonEquals(new Vector3d(3.464101615137756, 3.464101615137756, 3.464101615137756), 0.001));
+    }
+    
+    @Test
+    public void getPointDistance() {
+        Plane p = new Plane(new Vector3d(-1, 0, 0), -3);
+        Assertions.assertEquals(-6, p.getPointDistance(new Point3d(9, 9, 9)));
+        Assertions.assertEquals(12, p.getPointDistance(new Point3d(-9, -9, -9)));
+        Assertions.assertEquals(3, p.getPointDistance(new Point3d(0, 0, 0)));
+        
+        p = new Plane(new Vector3d(-1, 0, 0), 3);
+        Assertions.assertEquals(-12, p.getPointDistance(new Point3d(9, 9, 9)));
+        Assertions.assertEquals(6, p.getPointDistance(new Point3d(-9, -9, -9)));
+        Assertions.assertEquals(-3, p.getPointDistance(new Point3d(0, 0, 0)));
+        
+        p = new Plane(new Vector3d(1, 0, 0), 3);
+        Assertions.assertEquals(6, p.getPointDistance(new Point3d(9, 9, 9)));
+        Assertions.assertEquals(-12, p.getPointDistance(new Point3d(-9, -9, -9)));
+        Assertions.assertEquals(-3, p.getPointDistance(new Point3d(0, 0, 0)));
+        
+        p = new Plane(new Vector3d(1, 0, 0), -3);
+        Assertions.assertEquals(12, p.getPointDistance(new Point3d(9, 9, 9)));
+        Assertions.assertEquals(-6, p.getPointDistance(new Point3d(-9, -9, -9)));
+        Assertions.assertEquals(3, p.getPointDistance(new Point3d(0, 0, 0)));
+    }
+}
diff --git a/Comparison/src/test/java/cz/fidentis/analyst/visitors/mesh/CrossSectionTest.java b/Comparison/src/test/java/cz/fidentis/analyst/visitors/mesh/CrossSectionTest.java
index 217995700ed30ef5f8d6a3ea17a8459d8da82073..29d32ff33feaf376aa7bec416c95fdc14e2a2915 100644
--- a/Comparison/src/test/java/cz/fidentis/analyst/visitors/mesh/CrossSectionTest.java
+++ b/Comparison/src/test/java/cz/fidentis/analyst/visitors/mesh/CrossSectionTest.java
@@ -55,7 +55,7 @@ public class CrossSectionTest {
      */
     @Test
     public void CrossSectionZigZag() {
-        Plane cuttingPlane = new Plane(new Vector3d(1, 0, 0), -0.5);
+        Plane cuttingPlane = new Plane(new Vector3d(-1, 0, 0), -0.5);
         MeshModel model = createModel();
 
         CrossSectionZigZag cs = new CrossSectionZigZag(cuttingPlane);
@@ -63,7 +63,7 @@ public class CrossSectionTest {
         CrossSectionCurve curve = cs.getCrossSectionCurve();
 
         //They can be ordered two ways, check both
-        Assertions.assertEquals(curve.getSegmentSize(0), 6);
+        Assertions.assertEquals(6, curve.getSegmentSize(0));
         if (curve.getSegment(0).get(0).equals(new Point3d(0.5, 0, 0))) {
             Assertions.assertEquals(curve.getSegment(0).get(0), new Point3d(0.5, 0, 0));
             Assertions.assertEquals(curve.getSegment(0).get(1), new Point3d(0.5, 0.5, 0));
@@ -88,7 +88,7 @@ public class CrossSectionTest {
      */
     @Test
     public void CrossSection() {
-        Plane cuttingPlane = new Plane(new Vector3d(1, 0, 0), -0.5);
+        Plane cuttingPlane = new Plane(new Vector3d(-1, 0, 0), -0.5);
         MeshModel model = createModel();
 
         CrossSection cs = new CrossSection(cuttingPlane);
@@ -98,7 +98,7 @@ public class CrossSectionTest {
         //They can be ordered two ways, check both
         //Flaw of the non-zigzag design: it can't detect first and last intersection,
         //since it only controls edges between two triangles.
-        Assertions.assertEquals(points.size(), 4);
+        Assertions.assertEquals(4, points.size());
         if (points.get(0).equals(new Point3d(0.5, 0.5, 0))) {
             Assertions.assertEquals(points.get(0), new Point3d(0.5, 0.5, 0));
             Assertions.assertEquals(points.get(1), new Point3d(0.5, 1, 0));
diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java
index 0a18717db2f118eaa3d099f45b2b53d6b38f0654..f7666fbfa8e3a8a3ffa4635e28284f2596a6be8d 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java
@@ -94,21 +94,16 @@ public class ApproxHausdorffDistTask extends SimilarityTask {
                 HausdorffDistance hd = new HausdorffDistance(
                         face.getKdTree(),
                         HausdorffDistance.Strategy.POINT_TO_POINT,
-                        true, // relative
+                        true, // relative distance
                         true, // parallel
                         true  // crop
                 );
-                templateFace.getMeshModel().compute(hd, true);
-                
-                // Store relative distances of individual vertices to the cache                
-                distCache.add(hd.getDistances()
-                        .values()
-                        .stream()
-                        .flatMap(List::stream)
-                        .collect(Collectors.toList()));
-                face.removeKdTree(); // k-d tree construction is fast, and the memory is more valuable
-                
+                templateFace.getMeshModel().compute(hd);
+                distCache.add(hd.getDistances().values().stream() // Store relative distances of vertices to the cache
+                        .flatMap(List::stream).collect(Collectors.toList())); 
                 hdComputationTime.stop();
+
+                face.removeKdTree(); // k-d tree construction is fast, and the memory is more valuable
             } else {
                 distCache.add(DoubleStream.generate(() -> 0.0d)
                         .limit(templateFace.getMeshModel().getNumVertices())
diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java
index b95faa4a1b271da3f4214e40fb2bad86bb115d3b..f6879d116407f6ecf699406d6450119f394f4b72 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java
@@ -150,11 +150,11 @@ public class ApproxHausdorffDistTaskGPU extends SimilarityTask {
                 HausdorffDistance hd = new HausdorffDistance(
                         face.getKdTree(),
                         HausdorffDistance.Strategy.POINT_TO_POINT,
-                        true, // relative
+                        true, // relative distance
                         true, // parallel
                         true  // crop
                 );
-                templateFace.getMeshModel().compute(hd, true);
+                templateFace.getMeshModel().compute(hd);
                 
                 // Copy commputed distances into the GPU memory:
                 float[] auxDist = new float[numVertices];
@@ -168,9 +168,9 @@ public class ApproxHausdorffDistTaskGPU extends SimilarityTask {
                         CL.CL_MEM_READ_ONLY | CL.CL_MEM_COPY_HOST_PTR,
                         Sizeof.cl_float * numVertices, arrayP, null);
 
-                face.removeKdTree(); // TO BE TESTED
-                
                 hdComputationTime.stop();
+
+                face.removeKdTree();
             } else { // distance to template face itself is zero
                 float[] auxDist = new float[numVertices]; // filled by zeros by default
                 Pointer arrayP = Pointer.to(auxDist);
diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/CompleteHausdorffDistTask.java b/GUI/src/main/java/cz/fidentis/analyst/batch/CompleteHausdorffDistTask.java
index ea7eec93a4bd0b919116521f70f219f0b9515af7..c01d5330a272ef6107fceb029aeda47f6f1205c0 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/batch/CompleteHausdorffDistTask.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/batch/CompleteHausdorffDistTask.java
@@ -60,28 +60,26 @@ public class CompleteHausdorffDistTask extends SimilarityTask {
                 
                 //Logger.print(priFace.getShortName() + " - " + secFace.getShortName());
                 
-                // compute Huasdorff distance in both ways
+                // compute Huasdorff distance in both directions
                 hdComputationTime.start();
-                //priFace.computeKdTree(true);
                 HausdorffDistance hd = new HausdorffDistance(
-                        priFace.getMeshModel(), 
-                        HausdorffDistance.Strategy.POINT_TO_POINT, 
-                        false, // relative
+                        priFace.getKdTree(), 
+                        HausdorffDistance.Strategy.POINT_TO_POINT,
+                        false, // relative distance
                         true,  // parallel
-                        true  // crop
+                        true   // crop
                 );
-                secFace.getMeshModel().compute(hd, true);
+                secFace.getMeshModel().compute(hd);
                 setDistSimilarity(j, i, hd.getStats().getAverage());
                 
-                //secFace.computeKdTree(true);
                 hd = new HausdorffDistance(
-                        secFace.getMeshModel(), 
-                        HausdorffDistance.Strategy.POINT_TO_POINT, 
-                        false, // relative
+                        secFace.getKdTree(), 
+                        HausdorffDistance.Strategy.POINT_TO_POINT,
+                        false, // relative distance
                         true,  // parallel
-                        false  // crop
-                ); 
-                priFace.getMeshModel().compute(hd, true);
+                        true   // crop
+                );
+                priFace.getMeshModel().compute(hd);
                 setDistSimilarity(i, j, hd.getStats().getAverage());
                 hdComputationTime.stop();
                 
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 a6b375c9bcb43e21c0734ef76cc2c714a1b5f24f..d82266ed172fbc583cc3917a52872c4ea0b79cad 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java
@@ -5,9 +5,7 @@ import cz.fidentis.analyst.canvas.Canvas;
 import cz.fidentis.analyst.core.ProgressDialog;
 import cz.fidentis.analyst.face.HumanFace;
 import cz.fidentis.analyst.face.HumanFaceFactory;
-import cz.fidentis.analyst.icp.IcpTransformer;
-import cz.fidentis.analyst.icp.NoUndersampling;
-import cz.fidentis.analyst.icp.RandomStrategy;
+import cz.fidentis.analyst.face.HumanFaceUtils;
 import cz.fidentis.analyst.mesh.core.MeshModel;
 import cz.fidentis.analyst.mesh.io.MeshObjExporter;
 import cz.fidentis.analyst.scene.DrawableFace;
@@ -103,13 +101,15 @@ public class IcpTask extends SwingWorker<MeshModel, HumanFace> {
 
                 if (computeICP) { // ICP registration - face is transformed!
                     icpComputationTime.start();
-                    IcpTransformer icp = new IcpTransformer(
-                            initFace.getMeshModel(), 
-                            100, 
-                            controlPanel.scaleIcp(), 
-                            0.3, 
-                            (undersampling == 100) ? new NoUndersampling() : new RandomStrategy(undersampling));
-                    face.getMeshModel().compute(icp, true); // superimpose face towards the initFace
+                    HumanFaceUtils.alignMeshes(
+                            initFace,
+                            face, // is transformed
+                            100,  // max iterations
+                            controlPanel.scaleIcp(),
+                            0.3,  // error
+                            undersampling,
+                            false // drop k-d tree, if exists
+                    );
                     icpComputationTime.stop();
                 }
                 
diff --git a/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java b/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java
index 29feb0575f1688aab17e92ed1de04179501da65f..053f750f4a12ea28922e26108cad818f32054828 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java
@@ -8,7 +8,12 @@ import cz.fidentis.analyst.scene.Camera;
 import cz.fidentis.analyst.scene.Scene;
 import cz.fidentis.analyst.scene.SceneRenderer;
 import cz.fidentis.analyst.canvas.toolbar.RenderingModeToolbox;
+import cz.fidentis.analyst.face.events.HumanFaceEvent;
+import cz.fidentis.analyst.face.events.HumanFaceListener;
+import cz.fidentis.analyst.face.events.HumanFaceTransformedEvent;
+import cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent;
 import cz.fidentis.analyst.scene.Drawable;
+import cz.fidentis.analyst.scene.DrawableFace;
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.event.ActionEvent;
@@ -39,7 +44,7 @@ import org.openide.util.NbBundle;
  * @author Natalia Bebjakova 
  * @author Radek Oslejsek
  */
-public class Canvas extends JPanel {
+public class Canvas extends JPanel implements HumanFaceListener {
     
     private static final String RENDERING_MODE_TOOLBOX_ICON = "wireframe28x28.png";
     private static final String BACKGROUND_BUTTON_ICON = "background28x28.png";
@@ -87,6 +92,7 @@ public class Canvas extends JPanel {
             int index = scene.getFreeSlot();
             scene.setHumanFace(index, face);
             scene.setFaceAsPrimary(index);
+            face.registerListener(this);
             return index;
         }
         return -1;
@@ -104,6 +110,7 @@ public class Canvas extends JPanel {
             int index = scene.getFreeSlot();
             scene.setHumanFace(index, face);
             scene.setFaceAsSecondary(index);
+            face.registerListener(this);
             return index;
         }
         return -1;
@@ -226,6 +233,24 @@ public class Canvas extends JPanel {
         }
     }
     
+    @Override
+    public void acceptEvent(HumanFaceEvent event) {
+        // The symmtery plane is replaced with new nstance during the transformation 
+        // of a human face. Therefore, the drawable plane has to be updated.
+        // It is not necesary for meshes and feature points because their vertices 
+        // are directly modified and then do not affect their drawable wrappers
+        if (event instanceof HumanFaceTransformedEvent || event instanceof SymmetryPlaneChangedEvent) { 
+            final HumanFace face = event.getFace();
+            final List<DrawableFace> drFaces = getScene().getDrawableFaces();
+            for (int i = 0; i < drFaces.size(); i++) {
+                if (drFaces.get(i).getHumanFace().equals(face)) { // recomputes and replaces i-th symmetry plane
+                    getScene().setDrawableSymmetryPlane(i, face);
+                    break;
+                }
+            }
+        }
+    }
+    
 
 
     private ControlButtons getButtonsPanel(Canvas canvas) {
diff --git a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java
index 984f9ac28cd4eb8e7f7b01a52de31aba6f6ffd75..3ec0db480d37e02d252f769f725452c1a1f95f8f 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java
@@ -1,8 +1,12 @@
 package cz.fidentis.analyst.canvas.toolbar;
 
 import cz.fidentis.analyst.canvas.Canvas;
+import cz.fidentis.analyst.face.HumanFace;
+import cz.fidentis.analyst.face.events.HumanFaceEvent;
+import cz.fidentis.analyst.face.events.HumanFaceListener;
+import cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent;
 import cz.fidentis.analyst.scene.DrawableFace;
-import cz.fidentis.analyst.scene.DrawableFeaturePoints;
+import cz.fidentis.analyst.scene.DrawablePlane;
 import java.awt.Color;
 import java.awt.FlowLayout;
 import java.awt.event.ActionEvent;
@@ -23,8 +27,9 @@ import org.openide.util.NbBundle;
  * @author Richard Pajersky
  * @author Radek Oslejsek
  */
-public class SceneToolboxFaceToFace extends JPanel {
+public class SceneToolboxFaceToFace extends JPanel implements HumanFaceListener {
     
+    private static final String SYMMETRY_BUTTON_ICON = "symmetry28x28.png";
     private static final String PRIMARY_FACE_ICON = "primaryFace28x28.png";
     private static final String SECONDARY_FACE_ICON = "secondaryFace28x28.png";
     private static final String FEATURE_POINTS_ICON = "fps28x28.png";
@@ -32,10 +37,12 @@ public class SceneToolboxFaceToFace extends JPanel {
     
     private static final int TRANSPARENCY_RANGE = 50;
     
-    private JToggleButton primLandButton;
+    private JToggleButton priLandButton;
     private JToggleButton secLandButton;
-    private JToggleButton primFaceButton;
+    private JToggleButton priFaceButton;
     private JToggleButton secFaceButton;
+    private JToggleButton priSymmetryButton;
+    private JToggleButton secSymmetryButton;
     private JSlider       slider;
     private JToggleButton secDistButton;
     
@@ -47,50 +54,106 @@ public class SceneToolboxFaceToFace extends JPanel {
      */
     public SceneToolboxFaceToFace(Canvas canvas) {
         this.canvas = canvas;
-        initComponents();
+        initComponents();  // buttons are turned on by default
+        
+        // be informed if something changes in the faces -- see acceptEvent()
+        canvas.getPrimaryFace().registerListener(this);
+        canvas.getSecondaryFace().registerListener(this);
         
         // Change inital state:
-        primLandButton.setSelected(false);
-        DrawableFeaturePoints fp0 = canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceSlot());
-        if (fp0 != null) {
-            fp0.show(false);
-        }
+
+        // show the symmetry planes automatically, but only after they are computed
+        priSymmetryButton.setSelected(true); 
+        priSymmetryButton.setEnabled(false); 
+        secSymmetryButton.setSelected(true); 
+        secSymmetryButton.setEnabled(false); 
         
+        // currently, FPs (landmarks) are either presented or not
+        priLandButton.setSelected(false);
+        if (canvas.getPrimaryFace().hasFeaturePoints()) {
+            canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceSlot()).show(false);
+        } else {
+            priLandButton.setEnabled(false);
+        }
         secLandButton.setSelected(false);
-        DrawableFeaturePoints fp1 = canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getSecondaryFaceSlot());
-        if (fp1 != null) {
-            fp1.show(false);
+        if (canvas.getSecondaryFace().hasFeaturePoints()) {
+            canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getSecondaryFaceSlot()).show(false);
+        } else {
+            secLandButton.setEnabled(false);
         }
         
-        secDistButton.setSelected(true);
-        canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setRenderHeatmap(true);
+        secDistButton.setSelected(false);
+        canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setRenderHeatmap(false);
         
         slider.setValue(30);
         canvas.getScene().getDrawableFace(canvas.getScene().getPrimaryFaceSlot()).setTransparency(30/(float)TRANSPARENCY_RANGE);
         canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setTransparency(1);
     }
+    
+    
+    @Override
+    public void acceptEvent(HumanFaceEvent event) {
+        if (event instanceof SymmetryPlaneChangedEvent) { 
+            DrawablePlane dp = null;
+            JToggleButton button = null;
+            HumanFace face = event.getFace();
+
+            if (face.equals(canvas.getPrimaryFace())) {
+                dp = canvas.getScene().getDrawableSymmetryPlane(canvas.getScene().getPrimaryFaceSlot());
+                button = priSymmetryButton;
+            } else if (face.equals(canvas.getSecondaryFace())) {
+                dp = canvas.getScene().getDrawableSymmetryPlane(canvas.getScene().getSecondaryFaceSlot());
+                button = secSymmetryButton;
+            }
+
+            if (dp != null) { // the symmetry plane is included in the scene
+                button.setEnabled(true);
+                dp.show(button.isSelected());
+            } else {
+                button.setEnabled(false);
+            }
+        }
+    }
+    
+    private JToggleButton initButton(Color color, String icon, String tooltip) {
+        JToggleButton button = new JToggleButton();
+        button.setBorder(Canvas.BUTTONS_BORDER);
+        if (color != null) {
+            button.setBackground(null); // default color
+            button.setUI(new MetalToggleButtonUI() {
+                @Override
+                protected Color getSelectColor() {
+                    return color;
+                }
+            });
+        }
+        button.setIcon(new ImageIcon(getClass().getResource("/" + icon)));
+        button.setFocusable(false);
+        button.setSelected(true);
+        button.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, tooltip));
+        
+        return button;
+    }
 
     private void initComponents() {
         JPanel panel = new JPanel();
         panel.setLayout(new FlowLayout());
         add(panel);
         
-        primLandButton = new JToggleButton();
-        primLandButton.setBorder(Canvas.BUTTONS_BORDER);
-        primLandButton.setBackground(DrawableFace.SKIN_COLOR_PRIMARY);
-        primLandButton.setUI(new MetalToggleButtonUI() {
+        priSymmetryButton = initButton(null, SYMMETRY_BUTTON_ICON, "SceneToolboxFaceToFace.symmetryButton.tooltip");
+        panel.add(priSymmetryButton);
+        priSymmetryButton.addActionListener(new AbstractAction() {
             @Override
-            protected Color getSelectColor() {
-                return DrawableFace.SKIN_COLOR_PRIMARY.darker();
+            public void actionPerformed(ActionEvent e) {
+                boolean onOff = ((JToggleButton) e.getSource()).isSelected();
+                canvas.getScene().getDrawableSymmetryPlane(canvas.getScene().getPrimaryFaceSlot()).show(onOff);
+                canvas.renderScene();
             }
         });
-        primLandButton.setIcon(new ImageIcon(getClass().getResource("/" + FEATURE_POINTS_ICON)));
-        primLandButton.setFocusable(false);
-        primLandButton.setSelected(true);
-        primLandButton.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, "SceneToolboxFaceToFace.landButton.tooltip"));
-        panel.add(primLandButton);
-        
-        primLandButton.addActionListener(new AbstractAction() {
+
+        priLandButton = initButton(null, FEATURE_POINTS_ICON, "SceneToolboxFaceToFace.landButton.tooltip");
+        panel.add(priLandButton);
+        priLandButton.addActionListener(new AbstractAction() {
             @Override
             public void actionPerformed(ActionEvent e) {
                 boolean onOff = ((JToggleButton) e.getSource()).isSelected();
@@ -99,23 +162,9 @@ public class SceneToolboxFaceToFace extends JPanel {
             }
         });
 
-        /////////////////////////
-        primFaceButton = new JToggleButton();
-        primFaceButton.setBorder(Canvas.BUTTONS_BORDER);
-        primFaceButton.setBackground(DrawableFace.SKIN_COLOR_PRIMARY);
-        primFaceButton.setUI(new MetalToggleButtonUI() {
-            @Override
-            protected Color getSelectColor() {
-                return DrawableFace.SKIN_COLOR_PRIMARY.darker();
-            }
-        });
-        primFaceButton.setIcon(new ImageIcon(getClass().getResource("/" + PRIMARY_FACE_ICON)));
-        primFaceButton.setFocusable(false);
-        primFaceButton.setSelected(true);
-        primFaceButton.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, "SceneToolboxFaceToFace.faceButton.tooltip"));
-        panel.add(primFaceButton);
-        
-        primFaceButton.addActionListener(new AbstractAction() {
+        priFaceButton = initButton(DrawableFace.SKIN_COLOR_PRIMARY, PRIMARY_FACE_ICON, "SceneToolboxFaceToFace.faceButton.tooltip");
+        panel.add(priFaceButton);
+        priFaceButton.addActionListener(new AbstractAction() {
             @Override
             public void actionPerformed(ActionEvent e) {
                 boolean onOff = ((JToggleButton) e.getSource()).isSelected();
@@ -150,21 +199,8 @@ public class SceneToolboxFaceToFace extends JPanel {
         });
         
         /////////////////////////
-        secFaceButton = new JToggleButton();
-        secFaceButton.setBorder(Canvas.BUTTONS_BORDER);
-        secFaceButton.setBackground(DrawableFace.SKIN_COLOR_SECONDARY);
-        secFaceButton.setUI(new MetalToggleButtonUI() {
-            @Override
-            protected Color getSelectColor() {
-                return DrawableFace.SKIN_COLOR_SECONDARY.darker();
-            }
-        });
-        secFaceButton.setIcon(new ImageIcon(getClass().getResource("/" + SECONDARY_FACE_ICON)));
-        secFaceButton.setFocusable(false);
-        secFaceButton.setSelected(true);
-        secFaceButton.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, "SceneToolboxFaceToFace.faceButton.tooltip"));
+        secFaceButton = initButton(DrawableFace.SKIN_COLOR_SECONDARY, SECONDARY_FACE_ICON, "SceneToolboxFaceToFace.faceButton.tooltip");
         panel.add(secFaceButton);
-        
         secFaceButton.addActionListener(new AbstractAction() {
             @Override
             public void actionPerformed(ActionEvent e) {
@@ -174,23 +210,8 @@ public class SceneToolboxFaceToFace extends JPanel {
             }
         });
         
-
-        /////////////////////////
-        secLandButton = new JToggleButton();
-        secLandButton.setBorder(Canvas.BUTTONS_BORDER);
-        secLandButton.setBackground(DrawableFace.SKIN_COLOR_SECONDARY);
-        secLandButton.setUI(new MetalToggleButtonUI() {
-            @Override
-            protected Color getSelectColor() {
-                return DrawableFace.SKIN_COLOR_SECONDARY.darker();
-            }
-        });
-        secLandButton.setIcon(new ImageIcon(getClass().getResource("/" + FEATURE_POINTS_ICON)));
-        secLandButton.setFocusable(false);
-        secLandButton.setSelected(true);
-        secLandButton.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, "SceneToolboxFaceToFace.landButton.tooltip"));
+        secLandButton = initButton(null, FEATURE_POINTS_ICON, "SceneToolboxFaceToFace.landButton.tooltip");
         panel.add(secLandButton);
-        
         secLandButton.addActionListener(new AbstractAction() {
             @Override
             public void actionPerformed(ActionEvent e) {
@@ -199,38 +220,27 @@ public class SceneToolboxFaceToFace extends JPanel {
                 canvas.renderScene();
             }
         });
-
-        /////////////////////
-        secDistButton = new JToggleButton();
-        secDistButton.setBorder(Canvas.BUTTONS_BORDER);
-        secDistButton.setBackground(DrawableFace.SKIN_COLOR_SECONDARY);
-        secDistButton.setUI(new MetalToggleButtonUI() {
+        
+        secSymmetryButton = initButton(null, SYMMETRY_BUTTON_ICON, "SceneToolboxFaceToFace.symmetryButton.tooltip");
+        panel.add(secSymmetryButton);
+        secSymmetryButton.addActionListener(new AbstractAction() {
             @Override
-            protected Color getSelectColor() {
-                return DrawableFace.SKIN_COLOR_SECONDARY.darker();
+            public void actionPerformed(ActionEvent e) {
+                boolean onOff = ((JToggleButton) e.getSource()).isSelected();
+                canvas.getScene().getDrawableSymmetryPlane(canvas.getScene().getSecondaryFaceSlot()).show(onOff);
+                canvas.renderScene();
             }
         });
-        secDistButton.setIcon(new ImageIcon(getClass().getResource("/" + DISTANCE_BUTTON_ICON)));
-        secDistButton.setFocusable(false);
-        secDistButton.setSelected(true);
-        secDistButton.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, "SceneToolboxFaceToFace.distButton.tooltip"));
+
+        secDistButton = initButton(null, DISTANCE_BUTTON_ICON, "SceneToolboxFaceToFace.distButton.tooltip");
         panel.add(secDistButton);
-        
         secDistButton.addActionListener(new AbstractAction() { 
             @Override
             public void actionPerformed(ActionEvent e) {
-                if (((JToggleButton) e.getSource()).isSelected()) {
-                    canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setRenderHeatmap(true);
-                } else {
-                    canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setRenderHeatmap(false);
-                }
-                // Switch:
-                //canvas.getScene().getDrawableFace(secIndex).setRenderHeatmap(
-                //        !canvas.getScene().getDrawableFace(secIndex).isHeatmapRendered()
-                //);
+                boolean onOff = ((JToggleButton) e.getSource()).isSelected();
+                canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setRenderHeatmap(onOff);
                 canvas.renderScene();
             }
         });
     }
-    
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java
index b5078bcb9453b228bb8c85f201d0248231e64fa0..c27fee4866ba12a91574ebd158b79c6b45dd13e6 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java
@@ -1,7 +1,11 @@
 package cz.fidentis.analyst.canvas.toolbar;
 
 import cz.fidentis.analyst.canvas.Canvas;
+import cz.fidentis.analyst.face.events.HumanFaceEvent;
+import cz.fidentis.analyst.face.events.HumanFaceListener;
+import cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent;
 import cz.fidentis.analyst.scene.DrawableFace;
+import cz.fidentis.analyst.scene.DrawablePlane;
 import java.awt.Color;
 import java.awt.FlowLayout;
 import java.awt.event.ActionEvent;
@@ -22,15 +26,17 @@ import org.openide.util.NbBundle;
  * @author Richard Pajersky
  * @author Radek Oslejsek
  */
-public class SceneToolboxSingleFace extends JPanel {
+public class SceneToolboxSingleFace extends JPanel implements HumanFaceListener {
     
+    private static final String SYMMETRY_BUTTON_ICON = "symmetry28x28.png";
     private static final String FACE_ICON = "head28x28.png";
     private static final String FEATURE_POINTS_ICON = "fps28x28.png";
     
     private static final int TRANSPARENCY_RANGE = 100;
     
-    private JToggleButton primLandButton;
-    private JToggleButton primFaceButton;
+    private JToggleButton priLandButton;
+    private JToggleButton priFaceButton;
+    private JToggleButton priSymmetryButton;
     private JSlider       slider;
     
     private final Canvas canvas;
@@ -42,6 +48,56 @@ public class SceneToolboxSingleFace extends JPanel {
     public SceneToolboxSingleFace(Canvas canvas) {
         this.canvas = canvas;
         initComponents();
+        
+        // show the symmetry planes automatically, but only after they are computed
+        priSymmetryButton.setSelected(true); 
+        priSymmetryButton.setEnabled(false); 
+        
+        // currently, FPs (landmarks) are either presented or not
+        priLandButton.setSelected(false);
+        if (canvas.getPrimaryFace() != null) {
+            if (canvas.getPrimaryFace().hasFeaturePoints()) {
+                canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceSlot()).show(false);
+            } else {
+                priLandButton.setEnabled(false);
+            }
+        
+            // be informed if something changes in the faces -- see acceptEvent()
+            canvas.getPrimaryFace().registerListener(this);
+        }
+    }
+    
+    @Override
+    public void acceptEvent(HumanFaceEvent event) {
+        if (event instanceof SymmetryPlaneChangedEvent) { 
+            DrawablePlane dp = canvas.getScene().getDrawableSymmetryPlane(canvas.getScene().getPrimaryFaceSlot());
+            if (dp != null) { // the symmetry plane is included in the scene
+                priSymmetryButton.setEnabled(true);
+                dp.show(priSymmetryButton.isSelected());
+            } else {
+                priSymmetryButton.setEnabled(false);
+            }
+        }
+    }
+    
+    private JToggleButton initButton(Color color, String icon, String tooltip) {
+        JToggleButton button = new JToggleButton();
+        button.setBorder(Canvas.BUTTONS_BORDER);
+        if (color != null) {
+            button.setBackground(null); // default color
+            button.setUI(new MetalToggleButtonUI() {
+                @Override
+                protected Color getSelectColor() {
+                    return color;
+                }
+            });
+        }
+        button.setIcon(new ImageIcon(getClass().getResource("/" + icon)));
+        button.setFocusable(false);
+        button.setSelected(true);
+        button.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, tooltip));
+        
+        return button;
     }
 
     private void initComponents() {
@@ -49,22 +105,20 @@ public class SceneToolboxSingleFace extends JPanel {
         panel.setLayout(new FlowLayout());
         add(panel);
         
-        primLandButton = new JToggleButton();
-        primLandButton.setBorder(Canvas.BUTTONS_BORDER);
-        primLandButton.setBackground(DrawableFace.SKIN_COLOR_PRIMARY);
-        primLandButton.setUI(new MetalToggleButtonUI() {
+        priSymmetryButton = initButton(null, SYMMETRY_BUTTON_ICON, "SceneToolboxFaceToFace.symmetryButton.tooltip");
+        panel.add(priSymmetryButton);
+        priSymmetryButton.addActionListener(new AbstractAction() {
             @Override
-            protected Color getSelectColor() {
-                return DrawableFace.SKIN_COLOR_PRIMARY.darker();
+            public void actionPerformed(ActionEvent e) {
+                boolean onOff = ((JToggleButton) e.getSource()).isSelected();
+                canvas.getScene().getDrawableSymmetryPlane(canvas.getScene().getPrimaryFaceSlot()).show(onOff);
+                canvas.renderScene();
             }
         });
-        primLandButton.setIcon(new ImageIcon(getClass().getResource("/" + FEATURE_POINTS_ICON)));
-        primLandButton.setFocusable(false);
-        primLandButton.setSelected(true);
-        primLandButton.setToolTipText(NbBundle.getMessage(SceneToolboxSingleFace.class, "SceneToolboxSingleFace.landButton.tooltip"));
-        panel.add(primLandButton);
         
-        primLandButton.addActionListener(new AbstractAction() {
+        priLandButton = initButton(null, FEATURE_POINTS_ICON, "SceneToolboxFaceToFace.landButton.tooltip");
+        panel.add(priLandButton);
+        priLandButton.addActionListener(new AbstractAction() {
             @Override
             public void actionPerformed(ActionEvent e) {
                 boolean onOff = ((JToggleButton) e.getSource()).isSelected();
@@ -72,24 +126,10 @@ public class SceneToolboxSingleFace extends JPanel {
                 canvas.renderScene();
             }
         });
-
-        /////////////////////////
-        primFaceButton = new JToggleButton();
-        primFaceButton.setBorder(Canvas.BUTTONS_BORDER);
-        primFaceButton.setBackground(DrawableFace.SKIN_COLOR_PRIMARY);
-        primFaceButton.setUI(new MetalToggleButtonUI() {
-            @Override
-            protected Color getSelectColor() {
-                return DrawableFace.SKIN_COLOR_PRIMARY.darker();
-            }
-        });
-        primFaceButton.setIcon(new ImageIcon(getClass().getResource("/" + FACE_ICON)));
-        primFaceButton.setFocusable(false);
-        primFaceButton.setSelected(true);
-        primFaceButton.setToolTipText(NbBundle.getMessage(SceneToolboxSingleFace.class, "SceneToolboxSingleFace.faceButton.tooltip"));
-        panel.add(primFaceButton);
         
-        primFaceButton.addActionListener(new AbstractAction() {
+        priFaceButton = initButton(DrawableFace.SKIN_COLOR_PRIMARY, FACE_ICON, "SceneToolboxFaceToFace.faceButton.tooltip");
+        panel.add(priFaceButton);
+        priFaceButton.addActionListener(new AbstractAction() {
             @Override
             public void actionPerformed(ActionEvent e) {
                 boolean onOff = ((JToggleButton) e.getSource()).isSelected();
@@ -98,6 +138,7 @@ public class SceneToolboxSingleFace extends JPanel {
             }
         });
         
+
         /////////////////////////
         slider = new JSlider();
         //slider.setMajorTickSpacing(TRANSPARENCY_RANGE/2);
diff --git a/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java b/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java
index 455ab3f81433672de8fa0485cfd459496e73390e..28798ab389df4daee6ae1fef6d76c0c000980706 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java
@@ -8,7 +8,7 @@ import cz.fidentis.analyst.core.ControlPanelAction;
 import cz.fidentis.analyst.face.events.HausdorffDistanceComputed;
 import cz.fidentis.analyst.face.events.HumanFaceEvent;
 import cz.fidentis.analyst.face.events.HumanFaceListener;
-import cz.fidentis.analyst.face.events.MeshChangedEvent;
+import cz.fidentis.analyst.face.events.HumanFaceTransformedEvent;
 import cz.fidentis.analyst.feature.FeaturePoint;
 import cz.fidentis.analyst.feature.FeaturePointType;
 import cz.fidentis.analyst.scene.DrawableFpWeights;
@@ -203,15 +203,18 @@ public class DistanceAction extends ControlPanelAction implements HumanFaceListe
     
     @Override
     public void acceptEvent(HumanFaceEvent event) {
-        if (event instanceof MeshChangedEvent && event.getIssuer() != this) { // recompte (W)HD
-            hdVisitor = null;
-            whdVisitor = null;
-            computeAndUpdateHausdorffDistance(true);
-            // Relocate weight speheres:
-            final List<FeaturePoint> secondaryFPs = getSecondaryFeaturePoints().getFeaturePoints();
-            final List<FeaturePoint> weightedFPs = fpSpheres.getFeaturePoints();
-            for (int i = 0; i < secondaryFPs.size(); i++) {
-                weightedFPs.get(i).getPosition().set(secondaryFPs.get(i).getPosition());
+        if (event instanceof HumanFaceTransformedEvent && event.getIssuer() != this) { // recompte (W)HD
+            HumanFaceTransformedEvent ftEvent = (HumanFaceTransformedEvent) event;
+            if (ftEvent.isFinished()) {
+                hdVisitor = null;
+                whdVisitor = null;
+                computeAndUpdateHausdorffDistance(true);
+                // Relocate weight speheres:
+                final List<FeaturePoint> secondaryFPs = getSecondaryFeaturePoints().getFeaturePoints();
+                final List<FeaturePoint> weightedFPs = fpSpheres.getFeaturePoints();
+                for (int i = 0; i < secondaryFPs.size(); i++) {
+                    weightedFPs.get(i).getPosition().set(secondaryFPs.get(i).getPosition());
+                }
             }
         } else if (event instanceof HausdorffDistanceComputed) { // update stats
             HausdorffDistanceComputed hdEvent = (HausdorffDistanceComputed) event;
@@ -281,14 +284,16 @@ public class DistanceAction extends ControlPanelAction implements HumanFaceListe
                     getPrimaryDrawableFace().getHumanFace().getKdTree(), 
                     useStrategy, 
                     relativeDist, 
-                    true,
+                    true, // parallel
                     crop
             );
         }
         whdVisitor = new HausdorffDistancePrioritized(hdVisitor, featurePoints);
         
         Logger out = Logger.measureTime();
+        
         getSecondaryDrawableFace().getHumanFace().accept(whdVisitor);
+        
         out.printDuration("Weighted Hausdorff distance for models with " 
                 + getPrimaryDrawableFace().getHumanFace().getMeshModel().getNumVertices()
                 + "/"
@@ -304,7 +309,7 @@ public class DistanceAction extends ControlPanelAction implements HumanFaceListe
                 getSecondaryDrawableFace().getHumanFace().getShortName(),
                 this
         ));
-    }
+   }
     
     /**
      * Updates the GUI elements of {@link DistancePanel} that display
diff --git a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java
index 63982c2364a89d3033dfd943fcae1114492b0523..a18d4d5e6dad070bcb24673b9da4b8658193ddae 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java
@@ -4,29 +4,19 @@ import cz.fidentis.analyst.Logger;
 import cz.fidentis.analyst.canvas.Canvas;
 import cz.fidentis.analyst.core.ControlPanelAction;
 import cz.fidentis.analyst.face.HumanFace;
+import cz.fidentis.analyst.face.HumanFaceUtils;
 import cz.fidentis.analyst.face.events.HausdorffDistanceComputed;
 import cz.fidentis.analyst.face.events.HumanFaceEvent;
 import cz.fidentis.analyst.face.events.HumanFaceListener;
-import cz.fidentis.analyst.face.events.MeshChangedEvent;
-import cz.fidentis.analyst.feature.FeaturePoint;
-import cz.fidentis.analyst.icp.IcpTransformation;
-import cz.fidentis.analyst.icp.IcpTransformer;
-import cz.fidentis.analyst.icp.NoUndersampling;
-import cz.fidentis.analyst.icp.RandomStrategy;
-import cz.fidentis.analyst.icp.UndersamplingStrategy;
-import cz.fidentis.analyst.mesh.core.MeshFacet;
-import cz.fidentis.analyst.mesh.core.MeshPoint;
+import cz.fidentis.analyst.face.events.HumanFaceTransformedEvent;
 import cz.fidentis.analyst.procrustes.ProcrustesAnalysis;
-import cz.fidentis.analyst.scene.DrawableFace;
 import java.awt.Color;
 import java.awt.event.ActionEvent;
-import java.util.List;
 import java.util.zip.DataFormatException;
 import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
 import javax.swing.JFormattedTextField;
+import javax.swing.JOptionPane;
 import javax.swing.JTabbedPane;
-import javax.vecmath.Point3d;
 import javax.vecmath.Vector3d;
 
 /**
@@ -61,13 +51,11 @@ public class RegistrationAction extends ControlPanelAction implements HumanFaceL
     private boolean scale = true;
     private int maxIterations = 10;
     private double error = 0.3;
-    private UndersamplingStrategy undersampling = new RandomStrategy(200);
     private String strategy = RegistrationPanel.STRATEGY_POINT_TO_POINT;
     private boolean relativeDist = false;
     private boolean heatmapRender = false;
     private boolean procrustesScalingEnabled = false;
 
-
     /*
      * Coloring threshold and statistical values of feature point distances:
      */
@@ -115,100 +103,29 @@ public class RegistrationAction extends ControlPanelAction implements HumanFaceL
             case RegistrationPanel.ACTION_COMMAND_APPLY_ICP:
                 applyICP();
                 highlightCloseFeaturePoints();
-                announceMeshChange(getSecondaryDrawableFace());
-                break;
-            case RegistrationPanel.ACTION_COMMAND_SHIFT_X:
-                value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue();
-                getSecondaryDrawableFace().getTranslation().x = value;
-                if (getSecondaryFeaturePoints() != null) {
-                    getSecondaryFeaturePoints().getTranslation().x = value;
-                }
-                highlightCloseFeaturePoints();
-                break;
-            case RegistrationPanel.ACTION_COMMAND_SHIFT_Y:
-                value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue();
-                getSecondaryDrawableFace().getTranslation().y = value;
-                if (getSecondaryFeaturePoints() != null) {
-                    getSecondaryFeaturePoints().getTranslation().y = value;
-                }
-                highlightCloseFeaturePoints();
-                break;
-            case RegistrationPanel.ACTION_COMMAND_SHIFT_Z:
-                value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue();
-                getSecondaryDrawableFace().getTranslation().z = value;
-                if (getSecondaryFeaturePoints() != null) {
-                    getSecondaryFeaturePoints().getTranslation().z = value;
-                }
-                highlightCloseFeaturePoints();
+                //announceMeshChange(getSecondaryDrawableFace());
+                getCanvas().getSecondaryFace().announceEvent(new HumanFaceTransformedEvent(
+                        getCanvas().getSecondaryFace(), "", this)
+                );
                 break;
-            case RegistrationPanel.ACTION_COMMAND_ROTATE_X:
-                value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue();
-                getSecondaryDrawableFace().getRotation().x = value;
-                if (getSecondaryFeaturePoints() != null) {
-                    getSecondaryFeaturePoints().getRotation().x = value;
-                }
+            case RegistrationPanel.ACTION_COMMAND_MANUAL_TRANSFORMATION_IN_PROGRESS:
+                HumanFaceUtils.transformFace(
+                        getSecondaryDrawableFace().getHumanFace(),
+                        controlPanel.getAndClearManualRotation(),
+                        controlPanel.getAndClearManualTranslation(),
+                        controlPanel.getAndClearManualScale(),
+                        false
+                );
                 highlightCloseFeaturePoints();
+                getCanvas().getSecondaryFace().announceEvent(new HumanFaceTransformedEvent(
+                        getCanvas().getSecondaryFace(), "", this, false) // transformation under progress
+                );
                 break;
-            case RegistrationPanel.ACTION_COMMAND_ROTATE_Y:
-                value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue();
-                getSecondaryDrawableFace().getRotation().y = value;
-                if (getSecondaryFeaturePoints() != null) {
-                    getSecondaryFeaturePoints().getRotation().y = value;
-                }
-                highlightCloseFeaturePoints();
-                break;
-            case RegistrationPanel.ACTION_COMMAND_ROTATE_Z:
-                value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue();
-                getSecondaryDrawableFace().getRotation().z = value;
-                if (getSecondaryFeaturePoints() != null) {
-                    getSecondaryFeaturePoints().getRotation().z = value;
-                }
-                highlightCloseFeaturePoints();
-                break;
-            case RegistrationPanel.ACTION_COMMAND_SCALE:
-                value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue();
-                getSecondaryDrawableFace().getScale().x = value;
-                getSecondaryDrawableFace().getScale().y = value;
-                getSecondaryDrawableFace().getScale().z = value;
-                if (getSecondaryFeaturePoints() != null) {
-                    getSecondaryFeaturePoints().getScale().x = value;
-                    getSecondaryFeaturePoints().getScale().y = value;
-                    getSecondaryFeaturePoints().getScale().z = value;
-                }
-                highlightCloseFeaturePoints();
-                break;
-            case RegistrationPanel.ACTION_COMMAND_RESET_TRANSLATION:
-                getSecondaryDrawableFace().setTranslation(new Vector3d(0, 0, 0));
-                if (getSecondaryFeaturePoints() != null) {
-                    getSecondaryFeaturePoints().setTranslation(new Vector3d(0, 0, 0));
-                }
-                highlightCloseFeaturePoints();
-                break;
-            case RegistrationPanel.ACTION_COMMAND_RESET_ROTATION:
-                getSecondaryDrawableFace().setRotation(new Vector3d(0, 0, 0));
-                if (getSecondaryFeaturePoints() != null) {
-                    getSecondaryFeaturePoints().setRotation(new Vector3d(0, 0, 0));
-                }
-                highlightCloseFeaturePoints();
-                break;
-            case RegistrationPanel.ACTION_COMMAND_RESET_SCALE:
-                getSecondaryDrawableFace().setScale(new Vector3d(0, 0, 0));
-                if (getSecondaryFeaturePoints() != null) {
-                    getSecondaryFeaturePoints().setScale(new Vector3d(0, 0, 0));
-                }
-                highlightCloseFeaturePoints();
-                break;
-            case RegistrationPanel.ACTION_COMMAND_APPLY_TRANSFORMATIONS:
-                transformFace();
-                getSecondaryDrawableFace().setTranslation(new Vector3d(0, 0, 0));
-                getSecondaryDrawableFace().setRotation(new Vector3d(0, 0, 0));
-                getSecondaryDrawableFace().setScale(new Vector3d(0, 0, 0));
-                if (getSecondaryFeaturePoints() != null) {
-                    getSecondaryFeaturePoints().setTranslation(new Vector3d(0, 0, 0));
-                    getSecondaryFeaturePoints().setRotation(new Vector3d(0, 0, 0));
-                    getSecondaryFeaturePoints().setScale(new Vector3d(0, 0, 0));
-                }
-                announceMeshChange(getSecondaryDrawableFace());
+            case RegistrationPanel.ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED:
+                getCanvas().getSecondaryFace().announceEvent(new HumanFaceTransformedEvent(
+                        getCanvas().getSecondaryFace(), "", this, true) // finished transformation
+                );
+                //announceMeshChange(getSecondaryDrawableFace());
                 break;
             case RegistrationPanel.ACTION_COMMAND_FP_CLOSENESS_THRESHOLD:
                 fpThreshold = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue();
@@ -223,27 +140,28 @@ public class RegistrationAction extends ControlPanelAction implements HumanFaceL
             case RegistrationPanel.ACTION_COMMAND_ICP_ERROR:
                 error = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue();
                 break;
-            case RegistrationPanel.ACTION_COMMAND_ICP_UNDERSAMPLING:
-                String item = (String) ((JComboBox) ae.getSource()).getSelectedItem();
-                switch (item) {
-                    case "None":
-                        this.undersampling = new NoUndersampling();
-                        break;
-                    case "Random 200":
-                        this.undersampling = new RandomStrategy(200);
-                        break;
-                    default:
-                        throw new UnsupportedOperationException(item);
-                }
-                break;
             case RegistrationPanel.ACTION_COMMAND_PROCRUSTES_SCALE:
                 this.procrustesScalingEnabled = ((JCheckBox) ae.getSource()).isSelected();
                 break;
             case RegistrationPanel.ACTION_COMMAND_PROCRUSTES_APPLY:
                 applyProcrustes();
                 highlightCloseFeaturePoints();
-                announceMeshChange(getPrimaryDrawableFace());
-                announceMeshChange(getSecondaryDrawableFace());
+                getCanvas().getPrimaryFace().announceEvent(new HumanFaceTransformedEvent(
+                        getCanvas().getPrimaryFace(), "", this)
+                );
+                getCanvas().getSecondaryFace().announceEvent(new HumanFaceTransformedEvent(
+                        getCanvas().getSecondaryFace(), "", this)
+                );
+                //announceMeshChange(getPrimaryDrawableFace());
+                //announceMeshChange(getSecondaryDrawableFace());
+                break;
+            case RegistrationPanel.ACTION_COMMAND_ALIGN_SYMMETRY_PLANES:
+                alignSymmetryPlanes();
+                highlightCloseFeaturePoints();
+                getCanvas().getSecondaryFace().announceEvent(new HumanFaceTransformedEvent(
+                        getCanvas().getSecondaryFace(), "", this)
+                );
+                //announceMeshChange(getSecondaryDrawableFace());
                 break;
             default:
                 // do nothing
@@ -305,20 +223,17 @@ public class RegistrationAction extends ControlPanelAction implements HumanFaceL
     
     protected void applyICP() {
         Logger out = Logger.measureTime();
-
-        IcpTransformer visitor = new IcpTransformer(getPrimaryDrawableFace().getModel(), maxIterations, scale, error, undersampling);
-        getSecondaryDrawableFace().getModel().compute(visitor); // NOTE: the secondary face is physically transformed
-        getSecondaryDrawableFace().getHumanFace().removeKdTree(); // invalidate k-d tree, if exists
-        for (List<IcpTransformation> trList : visitor.getTransformations().values()) { // transform feature points
-            for (IcpTransformation tr : trList) {
-                for (int i = 0; i < getSecondaryFeaturePoints().getFeaturePoints().size(); i++) {
-                    FeaturePoint fp = getSecondaryFeaturePoints().getFeaturePoints().get(i);
-                    Point3d trPoint = tr.transformPoint(fp.getPosition(), scale);
-                    getSecondaryFeaturePoints().getFeaturePoints().set(i, new FeaturePoint(trPoint.x, trPoint.y, trPoint.z, fp.getFeaturePointType()));
-                }
-            }
-        }
-
+        
+        HumanFaceUtils.alignMeshes(
+                getPrimaryDrawableFace().getHumanFace(),
+                getSecondaryDrawableFace().getHumanFace(), // is transformed
+                maxIterations,
+                scale,
+                error,
+                controlPanel.getIcpUndersampling(),
+                false // drop k-d tree, if exists
+        );
+        
         out.printDuration("ICP for models with "
                 + getPrimaryDrawableFace().getHumanFace().getMeshModel().getNumVertices()
                 + "/"
@@ -346,14 +261,9 @@ public class RegistrationAction extends ControlPanelAction implements HumanFaceL
         double fpMinDist = Double.POSITIVE_INFINITY;
         double distSum = 0.0;
         for (int i = 0; i < getPrimaryFeaturePoints().getFeaturePoints().size(); i++) {
-            FeaturePoint primary = getPrimaryFeaturePoints().getFeaturePoints().get(i);
-            FeaturePoint secondary = getSecondaryFeaturePoints().getFeaturePoints().get(i);
-            Point3d transformed = new Point3d(secondary.getX(), secondary.getY(), secondary.getZ());
-            transformPoint(transformed);
-            double distance = Math.sqrt(
-                Math.pow(transformed.x - primary.getX(), 2) + 
-                Math.pow(transformed.y - primary.getY(), 2) + 
-                Math.pow(transformed.z - primary.getZ(), 2));
+            Vector3d v = new Vector3d(getPrimaryFeaturePoints().getFeaturePoints().get(i).getPosition());
+            v.sub(getSecondaryFeaturePoints().getFeaturePoints().get(i).getPosition());
+            double distance = v.length();
             if (distance > fpThreshold) {
                 getPrimaryFeaturePoints().resetColorToDefault(i);
                 getSecondaryFeaturePoints().resetColorToDefault(i);
@@ -369,88 +279,27 @@ public class RegistrationAction extends ControlPanelAction implements HumanFaceL
         // to do: show ACF dist
     }
 
-    /**
-     * Applies carried out transformations first on
-     * {@link #getSecondaryDrawableFace} and then on
-     * {@link #getSecondaryDrawableFace} feature points
-     */
-    private void transformFace() {
-        for (MeshFacet transformedFacet : getSecondaryDrawableFace().getFacets()) {
-            for (MeshPoint comparedPoint : transformedFacet.getVertices()) {
-                transformPoint(comparedPoint.getPosition());
-            }
-        }
-        for (int i = 0; i < getSecondaryFeaturePoints().getFeaturePoints().size(); i++) {
-            FeaturePoint point = getSecondaryFeaturePoints().getFeaturePoints().get(i);
-            Point3d transformed = new Point3d(point.getX(), point.getY(), point.getZ());
-            transformPoint(transformed);
-            point = new FeaturePoint(transformed.x, transformed.y, transformed.z, point.getFeaturePointType());
-            getSecondaryFeaturePoints().getFeaturePoints().set(i, point);
-        }
-        getSecondaryDrawableFace().getHumanFace().removeKdTree(); // invalidate k-d tree, if exists
-    }
-
-    /**
-     * Transforms point based on transformation info from
-     * {@link #getSecondaryDrawableFace}
-     *
-     * @param point Point to transform
-     */
-    private void transformPoint(Point3d point) {
-        if (point == null) {
-            throw new IllegalArgumentException("point is null");
-        }
-
-        Point3d newPoint = new Point3d(0, 0, 0);
-        double quotient;
-
-        // rotate around X
-        quotient = Math.toRadians(getSecondaryDrawableFace().getRotation().x);
-        if (!Double.isNaN(quotient)) {
-            double cos = Math.cos(quotient);
-            double sin = Math.sin(quotient);
-            newPoint.y = point.y * cos - point.z * sin;
-            newPoint.z = point.z * cos + point.y * sin;
-            point.y = newPoint.y;
-            point.z = newPoint.z;
-        }
-
-        // rotate around Y
-        quotient = Math.toRadians(getSecondaryDrawableFace().getRotation().y);
-        if (!Double.isNaN(quotient)) {
-            double cos = Math.cos(quotient);
-            double sin = Math.sin(quotient);
-            newPoint.x = point.x * cos + point.z * sin;
-            newPoint.z = point.z * cos - point.x * sin;
-            point.x = newPoint.x;
-            point.z = newPoint.z;
-        }
-
-        // rotate around Z
-        quotient = Math.toRadians(getSecondaryDrawableFace().getRotation().z);
-        if (!Double.isNaN(quotient)) {
-            double cos = Math.cos(quotient);
-            double sin = Math.sin(quotient);
-            newPoint.x = point.x * cos - point.y * sin;
-            newPoint.y = point.y * cos + point.x * sin;
-            point.x = newPoint.x;
-            point.y = newPoint.y;
-        }
+    //protected void announceMeshChange(DrawableFace face) {
+    //    if (face != null) {
+    //        face.getHumanFace().announceEvent(new MeshChangedEvent(face.getHumanFace(), face.getHumanFace().getShortName(), this));
+    //    }
+    //}
 
-        // translate
-        point.x += getSecondaryDrawableFace().getTranslation().x;
-        point.y += getSecondaryDrawableFace().getTranslation().y;
-        point.z += getSecondaryDrawableFace().getTranslation().z;
-
-        // scale
-        point.x *= 1 + getSecondaryDrawableFace().getScale().x;
-        point.y *= 1 + getSecondaryDrawableFace().getScale().y;
-        point.z *= 1 + getSecondaryDrawableFace().getScale().z;
-    }
-    
-    protected void announceMeshChange(DrawableFace face) {
-        if (face != null) {
-            face.getHumanFace().announceEvent(new MeshChangedEvent(face.getHumanFace(), face.getHumanFace().getShortName(), this));
+    private void alignSymmetryPlanes() {
+        if (!getPrimaryDrawableFace().getHumanFace().hasSymmetryPlane() 
+                || !getSecondaryDrawableFace().getHumanFace().hasSymmetryPlane()) {
+            
+            JOptionPane.showMessageDialog(controlPanel,
+                    "Compute symmetry planes first",
+                    "No symmerty planes",
+                    JOptionPane.INFORMATION_MESSAGE);
+            return;
         }
+        
+        HumanFaceUtils.alignSymmetryPlanes(
+                getPrimaryDrawableFace().getHumanFace(),
+                getSecondaryDrawableFace().getHumanFace(), // is transformed
+                false // drops k-d tree, if exists
+        );
     }
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.form b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.form
index 146a2f5abf312602f0057d3c65ad94b603a82d75..754e92b26aadcb71ca82f2aaea191c0dc879981c 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.form
+++ b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.form
@@ -44,15 +44,18 @@
           <Group type="102" alignment="0" attributes="0">
               <EmptySpace max="-2" attributes="0"/>
               <Group type="103" groupAlignment="1" max="-2" attributes="0">
-                  <Component id="jPanel2" alignment="0" max="32767" attributes="0"/>
+                  <Component id="jPanel1" alignment="0" max="32767" attributes="0"/>
                   <Component id="jPanel4" alignment="0" max="32767" attributes="0"/>
-                  <Component id="jPanel7" alignment="0" max="32767" attributes="0"/>
                   <Component id="transformationPanel" alignment="0" min="-2" pref="585" max="-2" attributes="0"/>
-                  <Component id="jPanel1" alignment="0" max="32767" attributes="0"/>
+                  <Component id="jPanel7" max="32767" attributes="0"/>
               </Group>
-              <EmptySpace min="-2" pref="153" max="-2" attributes="0"/>
+              <EmptySpace max="32767" attributes="0"/>
               <Component id="jSeparator7" min="-2" pref="50" max="-2" attributes="0"/>
-              <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
+          </Group>
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jPanel2" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="32767" attributes="0"/>
           </Group>
       </Group>
     </DimensionLayout>
@@ -72,12 +75,12 @@
               <EmptySpace max="-2" attributes="0"/>
               <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
               <EmptySpace max="-2" attributes="0"/>
-              <Component id="transformationPanel" min="-2" pref="209" max="-2" attributes="0"/>
+              <Component id="transformationPanel" min="-2" pref="176" max="-2" attributes="0"/>
               <EmptySpace max="-2" attributes="0"/>
               <Component id="jPanel4" min="-2" max="-2" attributes="0"/>
               <EmptySpace max="-2" attributes="0"/>
               <Component id="jPanel2" min="-2" max="-2" attributes="0"/>
-              <EmptySpace min="-2" pref="232" max="-2" attributes="0"/>
+              <EmptySpace min="-2" pref="328" max="-2" attributes="0"/>
               <Component id="jSeparator11" min="-2" pref="10" max="-2" attributes="0"/>
               <EmptySpace min="-2" pref="221" max="-2" attributes="0"/>
               <Component id="jSeparator2" min="-2" pref="10" max="-2" attributes="0"/>
@@ -93,7 +96,7 @@
       <Properties>
         <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
           <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
-            <TitledBorder title="Fine-tuning the mutual position:">
+            <TitledBorder title="Manual alignment:">
               <ResourceString PropertyName="titleX" bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.transformationPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
               <Font PropertyName="font" name="Dialog" size="14" style="1"/>
             </TitledBorder>
@@ -117,36 +120,16 @@
                           <EmptySpace min="-2" pref="580" max="-2" attributes="0"/>
                           <Component id="shiftPanel" min="-2" max="-2" attributes="0"/>
                       </Group>
-                      <Group type="102" attributes="0">
-                          <EmptySpace min="-2" pref="349" max="-2" attributes="0"/>
-                          <Component id="jSeparator10" min="-2" pref="15" max="-2" attributes="0"/>
+                      <Group type="102" alignment="0" attributes="0">
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="jButton3" min="-2" max="-2" attributes="0"/>
                       </Group>
                       <Group type="102" alignment="0" attributes="0">
-                          <Group type="103" groupAlignment="0" attributes="0">
-                              <Group type="102" attributes="0">
-                                  <EmptySpace min="-2" pref="24" max="-2" attributes="0"/>
-                                  <Component id="shiftLabel" min="-2" max="-2" attributes="0"/>
-                                  <EmptySpace max="-2" attributes="0"/>
-                                  <Component id="lowShiftRB" min="-2" max="-2" attributes="0"/>
-                                  <EmptySpace max="-2" attributes="0"/>
-                                  <Component id="highShiftRB" min="-2" max="-2" attributes="0"/>
-                              </Group>
-                              <Component id="translationPanel" alignment="0" min="-2" pref="227" max="-2" attributes="0"/>
-                          </Group>
-                          <Group type="103" groupAlignment="0" attributes="0">
-                              <Group type="102" alignment="0" attributes="0">
-                                  <EmptySpace min="-2" pref="24" max="-2" attributes="0"/>
-                                  <Component id="resetAllButton" min="-2" pref="128" max="-2" attributes="0"/>
-                                  <EmptySpace type="unrelated" max="-2" attributes="0"/>
-                                  <Component id="applyButton" min="-2" pref="128" max="-2" attributes="0"/>
-                              </Group>
-                              <Group type="102" alignment="0" attributes="0">
-                                  <EmptySpace max="-2" attributes="0"/>
-                                  <Component id="rotationPanel" min="-2" pref="224" max="-2" attributes="0"/>
-                                  <EmptySpace max="-2" attributes="0"/>
-                                  <Component id="scalePanel" min="-2" pref="102" max="-2" attributes="0"/>
-                              </Group>
-                          </Group>
+                          <Component id="translationPanel" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="rotationPanel" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="scalePanel" min="-2" max="-2" attributes="0"/>
                       </Group>
                   </Group>
                   <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
@@ -157,24 +140,14 @@
           <Group type="103" groupAlignment="0" attributes="0">
               <Group type="102" attributes="0">
                   <EmptySpace max="-2" attributes="0"/>
-                  <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="103" groupAlignment="0" max="-2" attributes="0">
                       <Component id="scalePanel" max="32767" attributes="0"/>
-                      <Component id="rotationPanel" max="32767" attributes="0"/>
-                      <Component id="translationPanel" max="32767" attributes="0"/>
+                      <Component id="rotationPanel" alignment="0" max="32767" attributes="0"/>
+                      <Component id="translationPanel" alignment="0" max="32767" attributes="0"/>
                   </Group>
-                  <EmptySpace max="-2" attributes="0"/>
-                  <Group type="103" groupAlignment="0" attributes="0">
-                      <Component id="applyButton" alignment="0" min="-2" pref="26" max="-2" attributes="0"/>
-                      <Group type="103" groupAlignment="3" attributes="0">
-                          <Component id="shiftLabel" alignment="3" min="-2" max="-2" attributes="0"/>
-                          <Component id="lowShiftRB" alignment="3" min="-2" max="-2" attributes="0"/>
-                          <Component id="highShiftRB" alignment="3" min="-2" max="-2" attributes="0"/>
-                          <Component id="resetAllButton" alignment="3" min="-2" max="-2" attributes="0"/>
-                      </Group>
-                  </Group>
-                  <EmptySpace min="-2" pref="39" max="-2" attributes="0"/>
-                  <Component id="jSeparator10" min="-2" pref="62" max="-2" attributes="0"/>
-                  <EmptySpace min="-2" pref="25" max="-2" attributes="0"/>
+                  <EmptySpace max="32767" attributes="0"/>
+                  <Component id="jButton3" min="-2" max="-2" attributes="0"/>
+                  <EmptySpace min="-2" pref="59" max="-2" attributes="0"/>
                   <Component id="shiftPanel" min="-2" max="-2" attributes="0"/>
                   <EmptySpace max="32767" attributes="0"/>
                   <Component id="jSeparator5" min="-2" pref="10" max="-2" attributes="0"/>
@@ -198,36 +171,21 @@
             <DimensionLayout dim="0">
               <Group type="103" groupAlignment="0" attributes="0">
                   <Group type="102" alignment="0" attributes="0">
-                      <Group type="103" groupAlignment="1" max="-2" attributes="0">
-                          <Group type="102" alignment="1" attributes="0">
-                              <EmptySpace min="-2" pref="31" max="-2" attributes="0"/>
-                              <Component id="translXLabel" min="-2" max="-2" attributes="0"/>
-                          </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="1" attributes="0">
+                          <Component id="translXLabel" alignment="1" min="-2" max="-2" attributes="0"/>
                           <Group type="102" alignment="1" attributes="0">
-                              <EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
-                              <Component id="translationButton" min="-2" max="-2" attributes="0"/>
-                              <EmptySpace max="32767" attributes="0"/>
-                              <Group type="103" groupAlignment="0" attributes="0">
-                                  <Component id="translationXFTF" alignment="0" min="-2" pref="54" max="-2" attributes="0"/>
-                                  <Group type="102" alignment="0" attributes="0">
-                                      <Component id="leftTranslationXButton" min="-2" max="-2" attributes="0"/>
-                                      <EmptySpace max="-2" attributes="0"/>
-                                      <Component id="rightTranslationXButton" min="-2" max="-2" attributes="0"/>
-                                  </Group>
-                              </Group>
+                              <Component id="leftTranslationXButton" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="rightTranslationXButton" min="-2" max="-2" attributes="0"/>
                           </Group>
                       </Group>
                       <Group type="103" groupAlignment="0" attributes="0">
-                          <Group type="102" attributes="0">
+                          <Group type="102" alignment="0" attributes="0">
                               <EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
-                              <Group type="103" groupAlignment="0" attributes="0">
-                                  <Group type="102" alignment="0" attributes="0">
-                                      <Component id="leftTranslationYButton" min="-2" max="-2" attributes="0"/>
-                                      <EmptySpace max="-2" attributes="0"/>
-                                      <Component id="rightTranslationYButton" min="-2" max="-2" attributes="0"/>
-                                  </Group>
-                                  <Component id="translationYFTF" min="-2" pref="54" max="-2" attributes="0"/>
-                              </Group>
+                              <Component id="leftTranslationYButton" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="rightTranslationYButton" min="-2" max="-2" attributes="0"/>
                           </Group>
                           <Group type="102" alignment="0" attributes="0">
                               <EmptySpace min="-2" pref="15" max="-2" attributes="0"/>
@@ -238,14 +196,9 @@
                       <Group type="103" groupAlignment="0" attributes="0">
                           <Group type="102" alignment="0" attributes="0">
                               <EmptySpace min="-2" pref="1" max="-2" attributes="0"/>
-                              <Group type="103" groupAlignment="0" attributes="0">
-                                  <Group type="102" alignment="0" attributes="0">
-                                      <Component id="leftTranslationZButton" min="-2" max="-2" attributes="0"/>
-                                      <EmptySpace max="-2" attributes="0"/>
-                                      <Component id="rightTranslationZButton" min="-2" max="-2" attributes="0"/>
-                                  </Group>
-                                  <Component id="translationZFTF" min="-2" pref="54" max="-2" attributes="0"/>
-                              </Group>
+                              <Component id="leftTranslationZButton" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="rightTranslationZButton" min="-2" max="-2" attributes="0"/>
                               <EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
                           </Group>
                           <Component id="translZLabel" alignment="1" min="-2" max="-2" attributes="0"/>
@@ -265,75 +218,21 @@
                       </Group>
                       <EmptySpace min="-2" pref="9" max="-2" attributes="0"/>
                       <Group type="103" groupAlignment="0" attributes="0">
-                          <Group type="102" alignment="0" attributes="0">
-                              <Group type="103" groupAlignment="1" attributes="0">
-                                  <Component id="rightTranslationXButton" alignment="0" min="-2" max="-2" attributes="0"/>
-                                  <Component id="leftTranslationXButton" alignment="0" min="-2" max="-2" attributes="0"/>
-                              </Group>
-                              <EmptySpace max="-2" attributes="0"/>
-                              <Group type="103" groupAlignment="0" attributes="0">
-                                  <Component id="translationXFTF" max="-2" attributes="0"/>
-                                  <Group type="102" alignment="1" attributes="0">
-                                      <Component id="translationButton" min="-2" max="-2" attributes="0"/>
-                                      <EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
-                                  </Group>
-                              </Group>
-                          </Group>
-                          <Group type="102" alignment="0" attributes="0">
-                              <Group type="103" groupAlignment="1" attributes="0">
-                                  <Component id="rightTranslationYButton" alignment="0" min="-2" max="-2" attributes="0"/>
-                                  <Component id="leftTranslationYButton" alignment="0" min="-2" max="-2" attributes="0"/>
-                              </Group>
-                              <EmptySpace max="-2" attributes="0"/>
-                              <Component id="translationYFTF" min="-2" max="-2" attributes="0"/>
-                          </Group>
-                          <Group type="102" alignment="0" attributes="0">
-                              <Group type="103" groupAlignment="1" attributes="0">
-                                  <Group type="102" alignment="1" attributes="0">
-                                      <Component id="rightTranslationZButton" min="-2" max="-2" attributes="0"/>
-                                      <EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
-                                  </Group>
-                                  <Group type="102" alignment="0" attributes="0">
-                                      <Component id="leftTranslationZButton" min="-2" max="-2" attributes="0"/>
-                                      <EmptySpace max="-2" attributes="0"/>
-                                  </Group>
-                              </Group>
-                              <Component id="translationZFTF" min="-2" max="-2" attributes="0"/>
+                          <Group type="103" alignment="0" groupAlignment="1" attributes="0">
+                              <Component id="rightTranslationZButton" alignment="1" min="-2" max="-2" attributes="0"/>
+                              <Component id="leftTranslationZButton" alignment="0" min="-2" max="-2" attributes="0"/>
                           </Group>
+                          <Component id="rightTranslationXButton" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="leftTranslationXButton" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="rightTranslationYButton" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="leftTranslationYButton" alignment="0" min="-2" max="-2" attributes="0"/>
                       </Group>
-                      <EmptySpace min="10" pref="10" max="-2" attributes="0"/>
+                      <EmptySpace max="32767" attributes="0"/>
                   </Group>
               </Group>
             </DimensionLayout>
           </Layout>
           <SubComponents>
-            <Component class="javax.swing.JButton" name="translationButton">
-              <Properties>
-                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
-                  <Image iconType="3" name="/restart-line.png"/>
-                </Property>
-                <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-                  <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.translationButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-                </Property>
-                <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-                  <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.translationButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-                </Property>
-                <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
-                  <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
-                    <TitledBorder/>
-                  </Border>
-                </Property>
-                <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
-                  <Color id="Default Cursor"/>
-                </Property>
-                <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
-                  <Insets value="[2, 2, 2, 2]"/>
-                </Property>
-              </Properties>
-              <Events>
-                <EventHandler event="mousePressed" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="translationButtonMousePressed"/>
-              </Events>
-            </Component>
             <Component class="javax.swing.JButton" name="rightTranslationXButton">
               <Properties>
                 <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
@@ -368,19 +267,6 @@
                 <EventHandler event="mouseReleased" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="rightTranslationXButtonMouseReleased"/>
               </Events>
             </Component>
-            <Component class="javax.swing.JFormattedTextField" name="translationXFTF">
-              <Properties>
-                <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor">
-                  <Format subtype="0" type="0"/>
-                </Property>
-                <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-                  <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.translationXFTF.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-                </Property>
-                <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
-                  <Color id="Text Cursor"/>
-                </Property>
-              </Properties>
-            </Component>
             <Component class="javax.swing.JButton" name="leftTranslationYButton">
               <Properties>
                 <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
@@ -409,13 +295,6 @@
                 <EventHandler event="mouseReleased" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="leftTranslationYButtonMouseReleased"/>
               </Events>
             </Component>
-            <Component class="javax.swing.JFormattedTextField" name="translationYFTF">
-              <Properties>
-                <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor">
-                  <Format subtype="0" type="0"/>
-                </Property>
-              </Properties>
-            </Component>
             <Component class="javax.swing.JButton" name="rightTranslationYButton">
               <Properties>
                 <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
@@ -454,13 +333,6 @@
                 </Property>
               </Properties>
             </Component>
-            <Component class="javax.swing.JFormattedTextField" name="translationZFTF">
-              <Properties>
-                <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor">
-                  <Format subtype="0" type="0"/>
-                </Property>
-              </Properties>
-            </Component>
             <Component class="javax.swing.JLabel" name="translZLabel">
               <Properties>
                 <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
@@ -588,36 +460,24 @@
             <DimensionLayout dim="0">
               <Group type="103" groupAlignment="0" attributes="0">
                   <Group type="102" alignment="0" attributes="0">
-                      <EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
                       <Group type="103" groupAlignment="0" attributes="0">
                           <Group type="102" alignment="0" attributes="0">
-                              <Component id="rotationButton" min="-2" max="-2" attributes="0"/>
+                              <Component id="leftRotationXButton" min="-2" max="-2" attributes="0"/>
                               <EmptySpace max="-2" attributes="0"/>
-                              <Group type="103" groupAlignment="0" attributes="0">
-                                  <Component id="rotationXFTF" min="-2" pref="54" max="-2" attributes="0"/>
-                                  <Group type="102" alignment="0" attributes="0">
-                                      <Component id="leftRotationXButton" min="-2" max="-2" attributes="0"/>
-                                      <EmptySpace max="-2" attributes="0"/>
-                                      <Component id="rightRotationXButton" min="-2" max="-2" attributes="0"/>
-                                  </Group>
-                              </Group>
+                              <Component id="rightRotationXButton" min="-2" max="-2" attributes="0"/>
                           </Group>
                           <Group type="102" alignment="0" attributes="0">
-                              <EmptySpace min="-2" pref="55" max="-2" attributes="0"/>
+                              <EmptySpace min="-2" pref="23" max="-2" attributes="0"/>
                               <Component id="rotatXLabel" min="-2" pref="20" max="-2" attributes="0"/>
                           </Group>
                       </Group>
                       <Group type="103" groupAlignment="0" attributes="0">
-                          <Group type="102" attributes="0">
+                          <Group type="102" alignment="0" attributes="0">
                               <EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
-                              <Group type="103" groupAlignment="0" attributes="0">
-                                  <Group type="102" attributes="0">
-                                      <Component id="leftRotationYButton" min="-2" max="-2" attributes="0"/>
-                                      <EmptySpace max="-2" attributes="0"/>
-                                      <Component id="rightRotationYButton" min="-2" max="-2" attributes="0"/>
-                                  </Group>
-                                  <Component id="rotationYFTF" min="-2" pref="54" max="-2" attributes="0"/>
-                              </Group>
+                              <Component id="leftRotationYButton" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="rightRotationYButton" min="-2" max="-2" attributes="0"/>
                           </Group>
                           <Group type="102" alignment="0" attributes="0">
                               <EmptySpace min="-2" pref="29" max="-2" attributes="0"/>
@@ -631,14 +491,9 @@
                           </Group>
                           <Group type="102" alignment="0" attributes="0">
                               <EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
-                              <Group type="103" groupAlignment="0" max="-2" attributes="0">
-                                  <Component id="rotationZFTF" min="-2" pref="54" max="-2" attributes="0"/>
-                                  <Group type="102" attributes="0">
-                                      <Component id="leftRotationZButton" min="-2" max="-2" attributes="0"/>
-                                      <EmptySpace max="-2" attributes="0"/>
-                                      <Component id="rightRotationZButton" max="32767" attributes="0"/>
-                                  </Group>
-                              </Group>
+                              <Component id="leftRotationZButton" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="rightRotationZButton" min="-2" max="-2" attributes="0"/>
                           </Group>
                       </Group>
                       <EmptySpace max="32767" attributes="0"/>
@@ -661,31 +516,12 @@
                       </Group>
                       <EmptySpace max="-2" attributes="0"/>
                       <Group type="103" groupAlignment="0" attributes="0">
-                          <Group type="102" attributes="0">
-                              <Group type="103" groupAlignment="0" attributes="0">
-                                  <Component id="leftRotationXButton" min="-2" max="-2" attributes="0"/>
-                                  <Component id="rightRotationXButton" min="-2" max="-2" attributes="0"/>
-                                  <Component id="leftRotationYButton" min="-2" max="-2" attributes="0"/>
-                                  <Component id="rightRotationYButton" min="-2" max="-2" attributes="0"/>
-                                  <Component id="leftRotationZButton" min="-2" max="-2" attributes="0"/>
-                              </Group>
-                              <EmptySpace max="-2" attributes="0"/>
-                              <Group type="103" groupAlignment="0" attributes="0">
-                                  <Group type="103" groupAlignment="3" attributes="0">
-                                      <Component id="rotationXFTF" alignment="3" min="-2" max="-2" attributes="0"/>
-                                      <Component id="rotationYFTF" alignment="3" min="-2" max="-2" attributes="0"/>
-                                      <Component id="rotationZFTF" alignment="3" min="-2" max="-2" attributes="0"/>
-                                  </Group>
-                                  <Group type="102" alignment="1" attributes="0">
-                                      <Component id="rotationButton" max="-2" attributes="0"/>
-                                      <EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
-                                  </Group>
-                              </Group>
-                          </Group>
-                          <Group type="102" attributes="0">
-                              <Component id="rightRotationZButton" min="-2" pref="24" max="-2" attributes="0"/>
-                              <EmptySpace min="-2" pref="41" max="-2" attributes="0"/>
-                          </Group>
+                          <Component id="rightRotationZButton" min="-2" pref="24" max="-2" attributes="0"/>
+                          <Component id="leftRotationXButton" min="-2" max="-2" attributes="0"/>
+                          <Component id="rightRotationXButton" min="-2" max="-2" attributes="0"/>
+                          <Component id="leftRotationYButton" min="-2" max="-2" attributes="0"/>
+                          <Component id="rightRotationYButton" min="-2" max="-2" attributes="0"/>
+                          <Component id="leftRotationZButton" min="-2" max="-2" attributes="0"/>
                       </Group>
                       <EmptySpace max="32767" attributes="0"/>
                   </Group>
@@ -785,47 +621,6 @@
                 </Property>
               </Properties>
             </Component>
-            <Component class="javax.swing.JButton" name="rotationButton">
-              <Properties>
-                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
-                  <Image iconType="3" name="/restart-line.png"/>
-                </Property>
-                <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-                  <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.rotationButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-                </Property>
-                <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-                  <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.rotationButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-                </Property>
-                <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
-                  <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
-                    <TitledBorder/>
-                  </Border>
-                </Property>
-                <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
-                  <Color id="Default Cursor"/>
-                </Property>
-                <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
-                  <Insets value="[2, 2, 2, 2]"/>
-                </Property>
-              </Properties>
-              <Events>
-                <EventHandler event="mousePressed" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="rotationButtonMousePressed"/>
-              </Events>
-            </Component>
-            <Component class="javax.swing.JFormattedTextField" name="rotationZFTF">
-              <Properties>
-                <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor">
-                  <Format subtype="0" type="0"/>
-                </Property>
-              </Properties>
-            </Component>
-            <Component class="javax.swing.JFormattedTextField" name="rotationYFTF">
-              <Properties>
-                <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor">
-                  <Format subtype="0" type="0"/>
-                </Property>
-              </Properties>
-            </Component>
             <Component class="javax.swing.JButton" name="rightRotationZButton">
               <Properties>
                 <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
@@ -962,16 +757,6 @@
                 <EventHandler event="mouseReleased" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="rightRotationXButtonMouseReleased"/>
               </Events>
             </Component>
-            <Component class="javax.swing.JFormattedTextField" name="rotationXFTF">
-              <Properties>
-                <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor">
-                  <Format subtype="0" type="0"/>
-                </Property>
-                <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-                  <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.rotationXFTF.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-                </Property>
-              </Properties>
-            </Component>
           </SubComponents>
         </Container>
         <Container class="javax.swing.JPanel" name="scalePanel">
@@ -989,38 +774,23 @@
             <DimensionLayout dim="0">
               <Group type="103" groupAlignment="0" attributes="0">
                   <Group type="102" alignment="0" attributes="0">
-                      <EmptySpace min="-2" pref="32" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
                       <Component id="scalePlusButton" min="-2" max="-2" attributes="0"/>
                       <EmptySpace max="-2" attributes="0"/>
                       <Component id="scaleMinusButton" min="-2" max="-2" attributes="0"/>
-                      <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
-                  </Group>
-                  <Group type="102" alignment="1" attributes="0">
-                      <EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
-                      <Component id="scaleButton" min="-2" max="-2" attributes="0"/>
-                      <EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
-                      <Component id="scaleFTF" min="-2" pref="54" max="-2" attributes="0"/>
-                      <EmptySpace max="32767" attributes="0"/>
+                      <EmptySpace pref="15" max="32767" attributes="0"/>
                   </Group>
               </Group>
             </DimensionLayout>
             <DimensionLayout dim="1">
               <Group type="103" groupAlignment="0" attributes="0">
-                  <Group type="102" alignment="1" attributes="0">
-                      <EmptySpace max="32767" attributes="0"/>
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
                       <Group type="103" groupAlignment="0" attributes="0">
                           <Component id="scalePlusButton" min="-2" max="-2" attributes="0"/>
                           <Component id="scaleMinusButton" min="-2" max="-2" attributes="0"/>
                       </Group>
-                      <EmptySpace max="-2" attributes="0"/>
-                      <Group type="103" groupAlignment="0" attributes="0">
-                          <Component id="scaleFTF" min="-2" max="-2" attributes="0"/>
-                          <Group type="102" alignment="1" attributes="0">
-                              <Component id="scaleButton" max="-2" attributes="0"/>
-                              <EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
-                          </Group>
-                      </Group>
-                      <EmptySpace max="-2" attributes="0"/>
+                      <EmptySpace max="32767" attributes="0"/>
                   </Group>
               </Group>
             </DimensionLayout>
@@ -1060,46 +830,6 @@
                 <EventHandler event="mouseReleased" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="scalePlusButtonMouseReleased"/>
               </Events>
             </Component>
-            <Component class="javax.swing.JFormattedTextField" name="scaleFTF">
-              <Properties>
-                <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor">
-                  <Format subtype="0" type="0"/>
-                </Property>
-                <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-                  <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.scaleFTF.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-                </Property>
-              </Properties>
-              <Events>
-                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="scaleFTFActionPerformed"/>
-              </Events>
-            </Component>
-            <Component class="javax.swing.JButton" name="scaleButton">
-              <Properties>
-                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
-                  <Image iconType="3" name="/restart-line.png"/>
-                </Property>
-                <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-                  <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.scaleButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-                </Property>
-                <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-                  <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.scaleButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-                </Property>
-                <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
-                  <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
-                    <TitledBorder/>
-                  </Border>
-                </Property>
-                <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
-                  <Color id="Default Cursor"/>
-                </Property>
-                <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
-                  <Insets value="[2, 2, 2, 2]"/>
-                </Property>
-              </Properties>
-              <Events>
-                <EventHandler event="mousePressed" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="scaleButtonMousePressed"/>
-              </Events>
-            </Component>
             <Component class="javax.swing.JButton" name="scaleMinusButton">
               <Properties>
                 <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
@@ -1136,28 +866,6 @@
             </Component>
           </SubComponents>
         </Container>
-        <Component class="javax.swing.JButton" name="resetAllButton">
-          <Properties>
-            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
-              <Image iconType="3" name="/refresh-line.png"/>
-            </Property>
-            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-              <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.resetAllButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-            </Property>
-            <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-              <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.resetAllButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-            </Property>
-            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
-              <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
-                <TitledBorder/>
-              </Border>
-            </Property>
-            <Property name="focusPainted" type="boolean" value="false"/>
-          </Properties>
-          <Events>
-            <EventHandler event="mousePressed" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="resetAllButtonMousePressed"/>
-          </Events>
-        </Component>
         <Container class="javax.swing.JPanel" name="shiftPanel">
 
           <Layout>
@@ -1173,79 +881,14 @@
             </DimensionLayout>
           </Layout>
         </Container>
-        <Component class="javax.swing.JSeparator" name="jSeparator10">
-          <Properties>
-            <Property name="orientation" type="int" value="1"/>
-          </Properties>
-        </Component>
-        <Component class="javax.swing.JButton" name="applyButton">
-          <Properties>
-            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-              <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.applyButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-            </Property>
-            <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-              <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.applyButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-            </Property>
-            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
-              <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
-                <TitledBorder/>
-              </Border>
-            </Property>
-            <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
-              <Color id="Hand Cursor"/>
-            </Property>
-            <Property name="focusPainted" type="boolean" value="false"/>
-          </Properties>
-          <Events>
-            <EventHandler event="mousePressed" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="applyButtonMousePressed"/>
-          </Events>
-        </Component>
         <Component class="javax.swing.JSeparator" name="jSeparator5">
         </Component>
-        <Component class="javax.swing.JLabel" name="shiftLabel">
-          <Properties>
-            <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
-              <Font name="Ubuntu" size="15" style="1"/>
-            </Property>
-            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-              <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.shiftLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-            </Property>
-            <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-              <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.shiftLabel.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-            </Property>
-          </Properties>
-        </Component>
-        <Component class="javax.swing.JRadioButton" name="lowShiftRB">
-          <Properties>
-            <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
-              <ComponentRef name="precisionGroup"/>
-            </Property>
-            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-              <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.lowShiftRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-            </Property>
-            <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-              <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.lowShiftRB.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-            </Property>
-          </Properties>
-          <Events>
-            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="lowShiftRBActionPerformed"/>
-          </Events>
-        </Component>
-        <Component class="javax.swing.JRadioButton" name="highShiftRB">
+        <Component class="javax.swing.JButton" name="jButton3">
           <Properties>
-            <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
-              <ComponentRef name="precisionGroup"/>
-            </Property>
             <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-              <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.highShiftRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-            </Property>
-            <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-              <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.highShiftRB.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+              <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.jButton3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
             </Property>
           </Properties>
-          <Events>
-            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="highShiftRBActionPerformed"/>
-          </Events>
         </Component>
       </SubComponents>
     </Container>
@@ -1271,27 +914,31 @@
           <Group type="103" groupAlignment="0" attributes="0">
               <Group type="102" attributes="0">
                   <EmptySpace max="-2" attributes="0"/>
-                  <Group type="103" groupAlignment="0" max="-2" attributes="0">
-                      <Group type="102" attributes="0">
-                          <Component id="jLabel8" min="-2" max="-2" attributes="0"/>
-                          <EmptySpace max="-2" attributes="0"/>
-                          <Component id="jComboBox1" min="-2" pref="166" max="-2" attributes="0"/>
-                          <EmptySpace max="32767" attributes="0"/>
-                          <Component id="jButton1" min="-2" max="-2" attributes="0"/>
-                      </Group>
+                  <Group type="103" groupAlignment="0" attributes="0">
                       <Group type="102" attributes="0">
-                          <Component id="jLabel7" min="-2" max="-2" attributes="0"/>
-                          <EmptySpace max="-2" attributes="0"/>
-                          <Component id="jCheckBox1" min="-2" max="-2" attributes="0"/>
-                          <EmptySpace type="separate" max="-2" attributes="0"/>
-                          <Component id="jLabel5" min="-2" max="-2" attributes="0"/>
-                          <EmptySpace max="-2" attributes="0"/>
-                          <Component id="jFormattedTextField1" min="-2" pref="49" max="-2" attributes="0"/>
-                          <EmptySpace type="separate" max="-2" attributes="0"/>
-                          <Component id="jLabel6" min="-2" max="-2" attributes="0"/>
-                          <EmptySpace max="-2" attributes="0"/>
-                          <Component id="jFormattedTextField2" min="-2" pref="53" max="-2" attributes="0"/>
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Group type="102" alignment="0" attributes="0">
+                                  <Component id="jLabel7" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Component id="jCheckBox1" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace type="separate" max="-2" attributes="0"/>
+                                  <Component id="jLabel5" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Component id="jFormattedTextField1" min="-2" pref="49" max="-2" attributes="0"/>
+                              </Group>
+                              <Component id="comboSliderInteger1" alignment="0" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                          <EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Group type="102" attributes="0">
+                                  <Component id="jLabel6" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Component id="jFormattedTextField2" min="-2" pref="53" max="-2" attributes="0"/>
+                              </Group>
+                              <Component id="jLabel8" min="-2" max="-2" attributes="0"/>
+                          </Group>
                       </Group>
+                      <Component id="jButton1" alignment="0" min="-2" max="-2" attributes="0"/>
                   </Group>
                   <EmptySpace max="32767" attributes="0"/>
               </Group>
@@ -1311,14 +958,18 @@
                           <Component id="jFormattedTextField2" alignment="3" min="-2" pref="20" max="-2" attributes="0"/>
                       </Group>
                   </Group>
-                  <EmptySpace type="separate" max="-2" attributes="0"/>
                   <Group type="103" groupAlignment="0" attributes="0">
-                      <Group type="103" groupAlignment="3" attributes="0">
-                          <Component id="jLabel8" alignment="3" min="-2" max="-2" attributes="0"/>
-                          <Component id="jComboBox1" alignment="3" min="-2" pref="27" max="-2" attributes="0"/>
+                      <Group type="102" attributes="0">
+                          <EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
+                          <Component id="comboSliderInteger1" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <Group type="102" alignment="0" attributes="0">
+                          <EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
+                          <Component id="jLabel8" min="-2" max="-2" attributes="0"/>
                       </Group>
-                      <Component id="jButton1" alignment="0" min="-2" max="-2" attributes="0"/>
                   </Group>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jButton1" min="-2" max="-2" attributes="0"/>
                   <EmptySpace max="32767" attributes="0"/>
               </Group>
           </Group>
@@ -1384,19 +1035,6 @@
             </Property>
           </Properties>
         </Component>
-        <Component class="javax.swing.JComboBox" name="jComboBox1">
-          <Properties>
-            <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
-              <StringArray count="2">
-                <StringItem index="0" value="None"/>
-                <StringItem index="1" value="Random 200"/>
-              </StringArray>
-            </Property>
-          </Properties>
-          <AuxValues>
-            <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
-          </AuxValues>
-        </Component>
         <Component class="javax.swing.JButton" name="jButton1">
           <Properties>
             <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
@@ -1413,6 +1051,8 @@
             <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton1ActionPerformed"/>
           </Events>
         </Component>
+        <Component class="cz.fidentis.analyst.core.ComboSliderInteger" name="comboSliderInteger1">
+        </Component>
       </SubComponents>
     </Container>
     <Container class="javax.swing.JPanel" name="jPanel4">
@@ -1563,12 +1203,12 @@
           <Group type="103" groupAlignment="0" attributes="0">
               <Group type="102" alignment="0" attributes="0">
                   <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jButton2" min="-2" max="-2" attributes="0"/>
+                  <EmptySpace type="separate" max="-2" attributes="0"/>
                   <Component id="jLabel4" min="-2" max="-2" attributes="0"/>
                   <EmptySpace max="-2" attributes="0"/>
                   <Component id="jCheckBox2" min="-2" max="-2" attributes="0"/>
                   <EmptySpace max="32767" attributes="0"/>
-                  <Component id="jButton2" min="-2" max="-2" attributes="0"/>
-                  <EmptySpace min="-2" pref="190" max="-2" attributes="0"/>
               </Group>
           </Group>
         </DimensionLayout>
@@ -1577,9 +1217,11 @@
               <Group type="102" alignment="0" attributes="0">
                   <EmptySpace max="-2" attributes="0"/>
                   <Group type="103" groupAlignment="0" max="-2" attributes="0">
-                      <Component id="jButton2" min="-2" max="-2" attributes="0"/>
                       <Component id="jCheckBox2" alignment="1" max="32767" attributes="0"/>
-                      <Component id="jLabel4" alignment="1" max="32767" attributes="0"/>
+                      <Group type="103" alignment="1" groupAlignment="3" attributes="0">
+                          <Component id="jLabel4" alignment="3" max="32767" attributes="0"/>
+                          <Component id="jButton2" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
                   </Group>
                   <EmptySpace max="32767" attributes="0"/>
               </Group>
@@ -1650,7 +1292,7 @@
                   <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
                   <EmptySpace max="-2" attributes="0"/>
                   <Component id="jTextField2" min="-2" pref="60" max="-2" attributes="0"/>
-                  <EmptySpace max="32767" attributes="0"/>
+                  <EmptySpace pref="30" max="32767" attributes="0"/>
               </Group>
           </Group>
         </DimensionLayout>
diff --git a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.java b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.java
index d2d56b969909d736f3f9d99f7e226d75710dbce8..d3eaa22f72b69ddaeb602a843566a5527c75a4a4 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.java
@@ -2,10 +2,11 @@ package cz.fidentis.analyst.registration;
 
 import cz.fidentis.analyst.canvas.Direction;
 import cz.fidentis.analyst.core.ControlPanel;
+import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.DoubleSummaryStatistics;
 import javax.swing.ImageIcon;
-import javax.swing.JFormattedTextField;
+import javax.vecmath.Vector3d;
 
 /**
  * Panel used to interactively visualize two face and adjust their registration.
@@ -26,53 +27,44 @@ public class RegistrationPanel extends ControlPanel {
      */
     public static final String ACTION_COMMAND_APPLY_ICP = "apply ICP";
     
-    public static final String ACTION_COMMAND_SHIFT_X = "shift x";
-    public static final String ACTION_COMMAND_SHIFT_Y = "shift y";
-    public static final String ACTION_COMMAND_SHIFT_Z = "shift z";
-    public static final String ACTION_COMMAND_ROTATE_X = "rotate x";
-    public static final String ACTION_COMMAND_ROTATE_Y = "rotate y";
-    public static final String ACTION_COMMAND_ROTATE_Z = "rotate z";
-    public static final String ACTION_COMMAND_SCALE = "scale";
-    public static final String ACTION_COMMAND_RESET_ROTATION = "reset translation";
-    public static final String ACTION_COMMAND_RESET_TRANSLATION = "reset rotation";
-    public static final String ACTION_COMMAND_RESET_SCALE = "reset scale";
-    public static final String ACTION_COMMAND_APPLY_TRANSFORMATIONS = "apply transformations";
+    public static final String ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED = "manual transformation";
+    public static final String ACTION_COMMAND_MANUAL_TRANSFORMATION_IN_PROGRESS = "manual transformation in progress";
     
     public static final String ACTION_COMMAND_FP_CLOSENESS_THRESHOLD = "fp closeness treshold";
     
     public static final String ACTION_COMMAND_ICP_SCALE = "ICP scale";
     public static final String ACTION_COMMAND_ICP_MAX_ITERATIONS = "ICP iterations";
     public static final String ACTION_COMMAND_ICP_ERROR = "ICP error";
-    public static final String ACTION_COMMAND_ICP_UNDERSAMPLING = "ICP undersampling";
     
     public static final String ACTION_COMMAND_PROCRUSTES_APPLY = "Procrustes apply";
     public static final String ACTION_COMMAND_PROCRUSTES_SCALE = "Procrustes scale";
     
+    public static final String ACTION_COMMAND_ALIGN_SYMMETRY_PLANES = "align symmetry planes";
+    
     /*
      * Configuration of panel-specific GUI elements
      */
     public static final String STRATEGY_POINT_TO_POINT = "Point to point";
     public static final String STRATEGY_POINT_TO_TRIANGLE = "Point to triangle";
     
-    public static final double TRANSFORMATION_FINESS = 1.0;
-    
     /**
-     * Transformation shift is higher 
+     * Animator which animates transformations
      */
-    public static final double HIGH_SHIFT_QUOTIENT = 1.0;
+    private final ModelRotationAnimator animator = new ModelRotationAnimator();
     
-    /**
-     * Transformation shift is lower 
-     */
-    public static final double LOW_SHIFT_QUOTIENT = 0.1;
+    private static final double MOVE_MODIFIER = 0.2; 
     
     /**
-     * Animator which animates transformations
+     * ICP undersampling. 100 = none
      */
-    private final ModelRotationAnimator animator = new ModelRotationAnimator();
+    private int undersampling = 100;
     
-    private double moveModifier = LOW_SHIFT_QUOTIENT;
+    private Vector3d manualRotation = new Vector3d();
+    private Vector3d manualTranslation = new Vector3d();
+    private double   manualScale = 1.0;
     
+    private final ActionListener action;
+
     /**
      * Constructor.
      * @param action Action listener
@@ -80,36 +72,67 @@ public class RegistrationPanel extends ControlPanel {
     public RegistrationPanel(ActionListener action) {
         this.setName(NAME);
         initComponents();
-        setDefaults();
+        this.action = action;
         
         // connect GUI element with RegistrationAction listener:
         jButton1.addActionListener(createListener(action, ACTION_COMMAND_APPLY_ICP));
-        translationXFTF.addActionListener(createListener(action, ACTION_COMMAND_SHIFT_X));
-        translationYFTF.addActionListener(createListener(action, ACTION_COMMAND_SHIFT_Y));
-        translationZFTF.addActionListener(createListener(action, ACTION_COMMAND_SHIFT_Z));
-        rotationXFTF.addActionListener(createListener(action, ACTION_COMMAND_ROTATE_X));
-        rotationYFTF.addActionListener(createListener(action, ACTION_COMMAND_ROTATE_Y));
-        rotationZFTF.addActionListener(createListener(action, ACTION_COMMAND_ROTATE_Z));
-        scaleFTF.addActionListener(createListener(action, ACTION_COMMAND_SCALE));
-        translationButton.addActionListener(createListener(action, ACTION_COMMAND_RESET_TRANSLATION));
-        rotationButton.addActionListener(createListener(action, ACTION_COMMAND_RESET_ROTATION));
-        scaleButton.addActionListener(createListener(action, ACTION_COMMAND_RESET_SCALE));
-        
         jButton2.addActionListener(createListener(action, ACTION_COMMAND_PROCRUSTES_APPLY));
-        scaleFTF.addActionListener(createListener(action, ACTION_COMMAND_PROCRUSTES_SCALE));
-        
-        resetAllButton.addActionListener(createListener(action, ACTION_COMMAND_RESET_TRANSLATION));
-        resetAllButton.addActionListener(createListener(action, ACTION_COMMAND_RESET_SCALE));
-        resetAllButton.addActionListener(createListener(action, ACTION_COMMAND_RESET_ROTATION));
+        jButton3.addActionListener(createListener(action, ACTION_COMMAND_ALIGN_SYMMETRY_PLANES));
         
-        applyButton.addActionListener(createListener(action, ACTION_COMMAND_APPLY_TRANSFORMATIONS));
+        thersholdFTF.setValue(5.0);
         thersholdFTF.addActionListener(createListener(action, ACTION_COMMAND_FP_CLOSENESS_THRESHOLD));
+
         jCheckBox1.addActionListener(createListener(action, ACTION_COMMAND_ICP_SCALE));
         jFormattedTextField1.addActionListener(createListener(action, ACTION_COMMAND_ICP_ERROR));
         jFormattedTextField2.addActionListener(createListener(action, ACTION_COMMAND_ICP_MAX_ITERATIONS));
-        jComboBox1.addActionListener(createListener(action, ACTION_COMMAND_ICP_UNDERSAMPLING));
+        
+        //comboSliderInteger1.setSliderEast();
+        comboSliderInteger1.setRange(10, 100);
+        comboSliderInteger1.setValue(this.undersampling);
+        comboSliderInteger1.addInputFieldListener((ActionEvent ae) -> { // update slider when the input field changed
+            this.undersampling = comboSliderInteger1.getValue();
+        });
+    }
+    
+    /**
+     * Returns the manual rotation info and resents it
+     * @return rotation info
+     */
+    public Vector3d getAndClearManualRotation() {
+        Vector3d ret = this.manualRotation;
+        this.manualRotation = new Vector3d(0, 0, 0);
+        return ret;
+    }
+    
+    /**
+     * Returns the manual translation info and resents it
+     * @return translation info
+     */
+    public Vector3d getAndClearManualTranslation() {
+        Vector3d ret = this.manualTranslation;
+        this.manualTranslation = new Vector3d(0, 0, 0);
+        return ret;
     }
     
+    /**
+     * Returns the manual scale info and resents it
+     * @return scale info
+     */
+    public double getAndClearManualScale() {
+        double ret = this.manualScale;
+        this.manualScale = 1.0;
+        return ret;
+    }
+    
+    /**
+     * Returns ICP undersampling parameter
+     * @return ICP undersampling parameter
+     */
+    public int getIcpUndersampling() {
+        return undersampling;
+    }
+
+    
     /**
      * Updates GUI elements that display statistical data about the calculated Hausdorff distance.
      * 
@@ -131,50 +154,56 @@ public class RegistrationPanel extends ControlPanel {
     public void transform(Direction dir) {
         switch (dir) {
             case TRANSLATE_LEFT:
-                decreaseInputField(translationXFTF);
+                this.manualTranslation.x -= this.MOVE_MODIFIER;
                 break;
             case TRANSLATE_RIGHT:
-                increaseInputField(translationXFTF);
+                this.manualTranslation.x += this.MOVE_MODIFIER;
                 break;
             case TRANSLATE_UP:
-                decreaseInputField(translationYFTF);
+                this.manualTranslation.y -= this.MOVE_MODIFIER;
                 break;
             case TRANSLATE_DOWN:
-                increaseInputField(translationYFTF);
+                this.manualTranslation.y += this.MOVE_MODIFIER;
                 break;
             case TRANSLATE_IN:
-                decreaseInputField(translationZFTF);
+                this.manualTranslation.z -= this.MOVE_MODIFIER;
                 break;
             case TRANSLATE_OUT:
-                increaseInputField(translationZFTF);
+                this.manualTranslation.z += this.MOVE_MODIFIER;
                 break;
             case ROTATE_LEFT:
-                decreaseInputField(rotationXFTF);
+                this.manualRotation.x -= this.MOVE_MODIFIER / 180.0;
                 break;
             case ROTATE_RIGHT:
-                increaseInputField(rotationXFTF);
+                this.manualRotation.x += this.MOVE_MODIFIER / 180.0;
                 break;
             case ROTATE_UP:
-                increaseInputField(rotationYFTF);
+                this.manualRotation.y -= this.MOVE_MODIFIER / 180.0;
                 break;
             case ROTATE_DOWN:
-                decreaseInputField(rotationYFTF);
+                this.manualRotation.y += this.MOVE_MODIFIER / 180.0;
                 break;
             case ROTATE_IN:
-                increaseInputField(rotationZFTF);
+                this.manualRotation.z += this.MOVE_MODIFIER / 180.0;
                 break;
             case ROTATE_OUT:
-                decreaseInputField(rotationZFTF);
+                this.manualRotation.z -= this.MOVE_MODIFIER / 180.0;
                 break;
             case ZOOM_OUT:
-                decreaseInputField(scaleFTF);
+                this.manualScale /= 1.005;
                 break;
             case ZOOM_IN:
-                increaseInputField(scaleFTF);
+                this.manualScale *= 1.005;
                 break;
             default:
                 throw new UnsupportedOperationException();
         }
+        
+        action.actionPerformed(new ActionEvent(
+                this, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_IN_PROGRESS)
+        );
     }
     
     @Override
@@ -191,37 +220,6 @@ public class RegistrationPanel extends ControlPanel {
         return new ImageIcon(RegistrationPanel.class.getClassLoader().getResource("/" + ICON));
     }
 
-    /**
-     * Additional initialization of panel
-     */
-    private void setDefaults() {
-        lowShiftRB.setSelected(true);
-        thersholdFTF.setValue(5.0);
-        //resetAllButtonActionPerformed(null);
-        
-        rotationXFTF.setValue(0.0);
-        rotationYFTF.setValue(0.0);
-        rotationZFTF.setValue(0.0);
-        translationXFTF.setValue(0.0);
-        translationYFTF.setValue(0.0);
-        translationZFTF.setValue(0.0);
-        scaleFTF.setValue(0.0);
-    }
-    
-    private void increaseInputField(JFormattedTextField textField) {
-        double newValue = ((Number)textField.getValue()).doubleValue() + moveModifier;
-        newValue *= TRANSFORMATION_FINESS;
-        textField.setValue(newValue);
-        textField.postActionEvent();
-    }
-    
-    private void decreaseInputField(JFormattedTextField textField) {
-        double newValue = ((Number)textField.getValue()).doubleValue() - moveModifier;
-        newValue *= TRANSFORMATION_FINESS;
-        textField.setValue(newValue);
-        textField.postActionEvent();
-    }
-    
     /**
      * This method is called from within the constructor to initialize the form.
      * WARNING: Do NOT modify this code. The content of this method is always
@@ -237,14 +235,10 @@ public class RegistrationPanel extends ControlPanel {
         jSeparator11 = new javax.swing.JSeparator();
         transformationPanel = new javax.swing.JPanel();
         translationPanel = new javax.swing.JPanel();
-        translationButton = new javax.swing.JButton();
         rightTranslationXButton = new javax.swing.JButton();
-        translationXFTF = new javax.swing.JFormattedTextField();
         leftTranslationYButton = new javax.swing.JButton();
-        translationYFTF = new javax.swing.JFormattedTextField();
         rightTranslationYButton = new javax.swing.JButton();
         translXLabel = new javax.swing.JLabel();
-        translationZFTF = new javax.swing.JFormattedTextField();
         translZLabel = new javax.swing.JLabel();
         translYLabel = new javax.swing.JLabel();
         rightTranslationZButton = new javax.swing.JButton();
@@ -256,27 +250,16 @@ public class RegistrationPanel extends ControlPanel {
         rotatZLabel = new javax.swing.JLabel();
         rotatYLabel = new javax.swing.JLabel();
         rotatXLabel = new javax.swing.JLabel();
-        rotationButton = new javax.swing.JButton();
-        rotationZFTF = new javax.swing.JFormattedTextField();
-        rotationYFTF = new javax.swing.JFormattedTextField();
         rightRotationZButton = new javax.swing.JButton();
         rightRotationYButton = new javax.swing.JButton();
         leftRotationZButton = new javax.swing.JButton();
         rightRotationXButton = new javax.swing.JButton();
-        rotationXFTF = new javax.swing.JFormattedTextField();
         scalePanel = new javax.swing.JPanel();
         scalePlusButton = new javax.swing.JButton();
-        scaleFTF = new javax.swing.JFormattedTextField();
-        scaleButton = new javax.swing.JButton();
         scaleMinusButton = new javax.swing.JButton();
-        resetAllButton = new javax.swing.JButton();
         shiftPanel = new javax.swing.JPanel();
-        jSeparator10 = new javax.swing.JSeparator();
-        applyButton = new javax.swing.JButton();
         jSeparator5 = new javax.swing.JSeparator();
-        shiftLabel = new javax.swing.JLabel();
-        lowShiftRB = new javax.swing.JRadioButton();
-        highShiftRB = new javax.swing.JRadioButton();
+        jButton3 = new javax.swing.JButton();
         jSeparator2 = new javax.swing.JSeparator();
         jPanel1 = new javax.swing.JPanel();
         jLabel7 = new javax.swing.JLabel();
@@ -286,8 +269,8 @@ public class RegistrationPanel extends ControlPanel {
         jLabel6 = new javax.swing.JLabel();
         jFormattedTextField2 = new javax.swing.JFormattedTextField();
         jLabel8 = new javax.swing.JLabel();
-        jComboBox1 = new javax.swing.JComboBox<>();
         jButton1 = new javax.swing.JButton();
+        comboSliderInteger1 = new cz.fidentis.analyst.core.ComboSliderInteger();
         jPanel4 = new javax.swing.JPanel();
         featurePointsLabel = new javax.swing.JLabel();
         thersholdFTF = new javax.swing.JFormattedTextField();
@@ -312,18 +295,6 @@ public class RegistrationPanel extends ControlPanel {
 
         translationPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.translationPanel.border.title"))); // NOI18N
 
-        translationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/restart-line.png"))); // NOI18N
-        org.openide.awt.Mnemonics.setLocalizedText(translationButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.translationButton.text")); // NOI18N
-        translationButton.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.translationButton.toolTipText")); // NOI18N
-        translationButton.setBorder(javax.swing.BorderFactory.createTitledBorder(""));
-        translationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
-        translationButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
-        translationButton.addMouseListener(new java.awt.event.MouseAdapter() {
-            public void mousePressed(java.awt.event.MouseEvent evt) {
-                translationButtonMousePressed(evt);
-            }
-        });
-
         rightTranslationXButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/arrow-right-s-line.png"))); // NOI18N
         org.openide.awt.Mnemonics.setLocalizedText(rightTranslationXButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rightTranslationXButton.text")); // NOI18N
         rightTranslationXButton.setBorder(javax.swing.BorderFactory.createTitledBorder(""));
@@ -341,10 +312,6 @@ public class RegistrationPanel extends ControlPanel {
             }
         });
 
-        translationXFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter()));
-        translationXFTF.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.translationXFTF.toolTipText")); // NOI18N
-        translationXFTF.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR));
-
         leftTranslationYButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/arrow-left-s-line.png"))); // NOI18N
         org.openide.awt.Mnemonics.setLocalizedText(leftTranslationYButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.leftTranslationYButton.text")); // NOI18N
         leftTranslationYButton.setBorder(javax.swing.BorderFactory.createTitledBorder(""));
@@ -360,8 +327,6 @@ public class RegistrationPanel extends ControlPanel {
             }
         });
 
-        translationYFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter()));
-
         rightTranslationYButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/arrow-right-s-line.png"))); // NOI18N
         org.openide.awt.Mnemonics.setLocalizedText(rightTranslationYButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rightTranslationYButton.text")); // NOI18N
         rightTranslationYButton.setBorder(javax.swing.BorderFactory.createTitledBorder(""));
@@ -380,8 +345,6 @@ public class RegistrationPanel extends ControlPanel {
         translXLabel.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
         org.openide.awt.Mnemonics.setLocalizedText(translXLabel, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.translXLabel.text")); // NOI18N
 
-        translationZFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter()));
-
         translZLabel.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
         org.openide.awt.Mnemonics.setLocalizedText(translZLabel, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.translZLabel.text")); // NOI18N
 
@@ -440,29 +403,19 @@ public class RegistrationPanel extends ControlPanel {
         translationPanelLayout.setHorizontalGroup(
             translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(translationPanelLayout.createSequentialGroup()
-                .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
-                    .addGroup(translationPanelLayout.createSequentialGroup()
-                        .addGap(31, 31, 31)
-                        .addComponent(translXLabel))
+                .addContainerGap()
+                .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                    .addComponent(translXLabel)
                     .addGroup(translationPanelLayout.createSequentialGroup()
-                        .addGap(2, 2, 2)
-                        .addComponent(translationButton)
-                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                        .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                            .addComponent(translationXFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE)
-                            .addGroup(translationPanelLayout.createSequentialGroup()
-                                .addComponent(leftTranslationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                                .addComponent(rightTranslationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))))
+                        .addComponent(leftTranslationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(rightTranslationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                 .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                     .addGroup(translationPanelLayout.createSequentialGroup()
                         .addGap(7, 7, 7)
-                        .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                            .addGroup(translationPanelLayout.createSequentialGroup()
-                                .addComponent(leftTranslationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                                .addComponent(rightTranslationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
-                            .addComponent(translationYFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                        .addComponent(leftTranslationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(rightTranslationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                     .addGroup(translationPanelLayout.createSequentialGroup()
                         .addGap(15, 15, 15)
                         .addComponent(translYLabel)))
@@ -470,12 +423,9 @@ public class RegistrationPanel extends ControlPanel {
                 .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                     .addGroup(translationPanelLayout.createSequentialGroup()
                         .addGap(1, 1, 1)
-                        .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                            .addGroup(translationPanelLayout.createSequentialGroup()
-                                .addComponent(leftTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                                .addComponent(rightTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
-                            .addComponent(translationZFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE))
+                        .addComponent(leftTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(rightTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                         .addGap(2, 2, 2))
                     .addComponent(translZLabel, javax.swing.GroupLayout.Alignment.TRAILING))
                 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
@@ -490,32 +440,14 @@ public class RegistrationPanel extends ControlPanel {
                     .addComponent(translZLabel))
                 .addGap(9, 9, 9)
                 .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                    .addGroup(translationPanelLayout.createSequentialGroup()
-                        .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
-                            .addComponent(rightTranslationXButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                            .addComponent(leftTranslationXButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
-                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                        .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                            .addComponent(translationXFTF, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, translationPanelLayout.createSequentialGroup()
-                                .addComponent(translationButton)
-                                .addGap(6, 6, 6))))
-                    .addGroup(translationPanelLayout.createSequentialGroup()
-                        .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
-                            .addComponent(rightTranslationYButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                            .addComponent(leftTranslationYButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
-                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                        .addComponent(translationYFTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
-                    .addGroup(translationPanelLayout.createSequentialGroup()
-                        .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
-                            .addGroup(translationPanelLayout.createSequentialGroup()
-                                .addComponent(rightTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                                .addGap(6, 6, 6))
-                            .addGroup(javax.swing.GroupLayout.Alignment.LEADING, translationPanelLayout.createSequentialGroup()
-                                .addComponent(leftTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)))
-                        .addComponent(translationZFTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
-                .addGap(10, 10, 10))
+                    .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                        .addComponent(rightTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addComponent(leftTranslationZButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addComponent(rightTranslationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(leftTranslationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(rightTranslationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(leftTranslationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
         );
 
         rotationPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rotationPanel.border.title"))); // NOI18N
@@ -561,22 +493,6 @@ public class RegistrationPanel extends ControlPanel {
         rotatXLabel.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
         org.openide.awt.Mnemonics.setLocalizedText(rotatXLabel, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rotatXLabel.text")); // NOI18N
 
-        rotationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/restart-line.png"))); // NOI18N
-        org.openide.awt.Mnemonics.setLocalizedText(rotationButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rotationButton.text")); // NOI18N
-        rotationButton.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rotationButton.toolTipText")); // NOI18N
-        rotationButton.setBorder(javax.swing.BorderFactory.createTitledBorder(""));
-        rotationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
-        rotationButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
-        rotationButton.addMouseListener(new java.awt.event.MouseAdapter() {
-            public void mousePressed(java.awt.event.MouseEvent evt) {
-                rotationButtonMousePressed(evt);
-            }
-        });
-
-        rotationZFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter()));
-
-        rotationYFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter()));
-
         rightRotationZButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/arrow-right-s-line.png"))); // NOI18N
         org.openide.awt.Mnemonics.setLocalizedText(rightRotationZButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rightRotationZButton.text")); // NOI18N
         rightRotationZButton.setBorder(javax.swing.BorderFactory.createTitledBorder(""));
@@ -645,37 +561,26 @@ public class RegistrationPanel extends ControlPanel {
             }
         });
 
-        rotationXFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter()));
-        rotationXFTF.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rotationXFTF.toolTipText")); // NOI18N
-
         javax.swing.GroupLayout rotationPanelLayout = new javax.swing.GroupLayout(rotationPanel);
         rotationPanel.setLayout(rotationPanelLayout);
         rotationPanelLayout.setHorizontalGroup(
             rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(rotationPanelLayout.createSequentialGroup()
-                .addGap(2, 2, 2)
+                .addContainerGap()
                 .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                     .addGroup(rotationPanelLayout.createSequentialGroup()
-                        .addComponent(rotationButton)
+                        .addComponent(leftRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                        .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                            .addComponent(rotationXFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE)
-                            .addGroup(rotationPanelLayout.createSequentialGroup()
-                                .addComponent(leftRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                                .addComponent(rightRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
+                        .addComponent(rightRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                     .addGroup(rotationPanelLayout.createSequentialGroup()
-                        .addGap(55, 55, 55)
+                        .addGap(23, 23, 23)
                         .addComponent(rotatXLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)))
                 .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                     .addGroup(rotationPanelLayout.createSequentialGroup()
                         .addGap(6, 6, 6)
-                        .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                            .addGroup(rotationPanelLayout.createSequentialGroup()
-                                .addComponent(leftRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                                .addComponent(rightRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
-                            .addComponent(rotationYFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                        .addComponent(leftRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(rightRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                     .addGroup(rotationPanelLayout.createSequentialGroup()
                         .addGap(29, 29, 29)
                         .addComponent(rotatYLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE)))
@@ -685,12 +590,9 @@ public class RegistrationPanel extends ControlPanel {
                         .addComponent(rotatZLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE))
                     .addGroup(rotationPanelLayout.createSequentialGroup()
                         .addGap(6, 6, 6)
-                        .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
-                            .addComponent(rotationZFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE)
-                            .addGroup(rotationPanelLayout.createSequentialGroup()
-                                .addComponent(leftRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                                .addComponent(rightRotationZButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
+                        .addComponent(leftRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(rightRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
         );
         rotationPanelLayout.setVerticalGroup(
@@ -706,25 +608,12 @@ public class RegistrationPanel extends ControlPanel {
                     .addComponent(rotatYLabel))
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                    .addGroup(rotationPanelLayout.createSequentialGroup()
-                        .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                            .addComponent(leftRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                            .addComponent(rightRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                            .addComponent(leftRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                            .addComponent(rightRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                            .addComponent(leftRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
-                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                        .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                            .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
-                                .addComponent(rotationXFTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                                .addComponent(rotationYFTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                                .addComponent(rotationZFTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
-                            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, rotationPanelLayout.createSequentialGroup()
-                                .addComponent(rotationButton)
-                                .addGap(5, 5, 5))))
-                    .addGroup(rotationPanelLayout.createSequentialGroup()
-                        .addComponent(rightRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)
-                        .addGap(41, 41, 41)))
+                    .addComponent(rightRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(leftRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(rightRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(leftRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(rightRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(leftRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
         );
 
@@ -747,26 +636,6 @@ public class RegistrationPanel extends ControlPanel {
             }
         });
 
-        scaleFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter()));
-        scaleFTF.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.scaleFTF.toolTipText")); // NOI18N
-        scaleFTF.addActionListener(new java.awt.event.ActionListener() {
-            public void actionPerformed(java.awt.event.ActionEvent evt) {
-                scaleFTFActionPerformed(evt);
-            }
-        });
-
-        scaleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/restart-line.png"))); // NOI18N
-        org.openide.awt.Mnemonics.setLocalizedText(scaleButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.scaleButton.text")); // NOI18N
-        scaleButton.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.scaleButton.toolTipText")); // NOI18N
-        scaleButton.setBorder(javax.swing.BorderFactory.createTitledBorder(""));
-        scaleButton.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
-        scaleButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
-        scaleButton.addMouseListener(new java.awt.event.MouseAdapter() {
-            public void mousePressed(java.awt.event.MouseEvent evt) {
-                scaleButtonMousePressed(evt);
-            }
-        });
-
         scaleMinusButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/subtract-line.png"))); // NOI18N
         org.openide.awt.Mnemonics.setLocalizedText(scaleMinusButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.scaleMinusButton.text")); // NOI18N
         scaleMinusButton.setBorder(javax.swing.BorderFactory.createTitledBorder(""));
@@ -789,45 +658,22 @@ public class RegistrationPanel extends ControlPanel {
         scalePanelLayout.setHorizontalGroup(
             scalePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(scalePanelLayout.createSequentialGroup()
-                .addGap(32, 32, 32)
+                .addContainerGap()
                 .addComponent(scalePlusButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addComponent(scaleMinusButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                .addGap(0, 0, Short.MAX_VALUE))
-            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, scalePanelLayout.createSequentialGroup()
-                .addGap(2, 2, 2)
-                .addComponent(scaleButton)
-                .addGap(7, 7, 7)
-                .addComponent(scaleFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE)
-                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                .addContainerGap(15, Short.MAX_VALUE))
         );
         scalePanelLayout.setVerticalGroup(
             scalePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, scalePanelLayout.createSequentialGroup()
-                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+            .addGroup(scalePanelLayout.createSequentialGroup()
+                .addGap(26, 26, 26)
                 .addGroup(scalePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                     .addComponent(scalePlusButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                     .addComponent(scaleMinusButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
-                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                .addGroup(scalePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                    .addComponent(scaleFTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, scalePanelLayout.createSequentialGroup()
-                        .addComponent(scaleButton)
-                        .addGap(5, 5, 5)))
-                .addContainerGap())
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
         );
 
-        resetAllButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/refresh-line.png"))); // NOI18N
-        org.openide.awt.Mnemonics.setLocalizedText(resetAllButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.resetAllButton.text")); // NOI18N
-        resetAllButton.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.resetAllButton.toolTipText")); // NOI18N
-        resetAllButton.setBorder(javax.swing.BorderFactory.createTitledBorder(""));
-        resetAllButton.setFocusPainted(false);
-        resetAllButton.addMouseListener(new java.awt.event.MouseAdapter() {
-            public void mousePressed(java.awt.event.MouseEvent evt) {
-                resetAllButtonMousePressed(evt);
-            }
-        });
-
         javax.swing.GroupLayout shiftPanelLayout = new javax.swing.GroupLayout(shiftPanel);
         shiftPanel.setLayout(shiftPanelLayout);
         shiftPanelLayout.setHorizontalGroup(
@@ -839,40 +685,7 @@ public class RegistrationPanel extends ControlPanel {
             .addGap(0, 84, Short.MAX_VALUE)
         );
 
-        jSeparator10.setOrientation(javax.swing.SwingConstants.VERTICAL);
-
-        org.openide.awt.Mnemonics.setLocalizedText(applyButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.applyButton.text")); // NOI18N
-        applyButton.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.applyButton.toolTipText")); // NOI18N
-        applyButton.setBorder(javax.swing.BorderFactory.createTitledBorder(""));
-        applyButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
-        applyButton.setFocusPainted(false);
-        applyButton.addMouseListener(new java.awt.event.MouseAdapter() {
-            public void mousePressed(java.awt.event.MouseEvent evt) {
-                applyButtonMousePressed(evt);
-            }
-        });
-
-        shiftLabel.setFont(new java.awt.Font("Ubuntu", 1, 15)); // NOI18N
-        org.openide.awt.Mnemonics.setLocalizedText(shiftLabel, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.shiftLabel.text")); // NOI18N
-        shiftLabel.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.shiftLabel.toolTipText")); // NOI18N
-
-        precisionGroup.add(lowShiftRB);
-        org.openide.awt.Mnemonics.setLocalizedText(lowShiftRB, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.lowShiftRB.text")); // NOI18N
-        lowShiftRB.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.lowShiftRB.toolTipText")); // NOI18N
-        lowShiftRB.addActionListener(new java.awt.event.ActionListener() {
-            public void actionPerformed(java.awt.event.ActionEvent evt) {
-                lowShiftRBActionPerformed(evt);
-            }
-        });
-
-        precisionGroup.add(highShiftRB);
-        org.openide.awt.Mnemonics.setLocalizedText(highShiftRB, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.highShiftRB.text")); // NOI18N
-        highShiftRB.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.highShiftRB.toolTipText")); // NOI18N
-        highShiftRB.addActionListener(new java.awt.event.ActionListener() {
-            public void actionPerformed(java.awt.event.ActionEvent evt) {
-                highShiftRBActionPerformed(evt);
-            }
-        });
+        org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.jButton3.text")); // NOI18N
 
         javax.swing.GroupLayout transformationPanelLayout = new javax.swing.GroupLayout(transformationPanel);
         transformationPanel.setLayout(transformationPanelLayout);
@@ -887,50 +700,27 @@ public class RegistrationPanel extends ControlPanel {
                         .addGap(580, 580, 580)
                         .addComponent(shiftPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                     .addGroup(transformationPanelLayout.createSequentialGroup()
-                        .addGap(349, 349, 349)
-                        .addComponent(jSeparator10, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE))
+                        .addContainerGap()
+                        .addComponent(jButton3))
                     .addGroup(transformationPanelLayout.createSequentialGroup()
-                        .addGroup(transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                            .addGroup(transformationPanelLayout.createSequentialGroup()
-                                .addGap(24, 24, 24)
-                                .addComponent(shiftLabel)
-                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                                .addComponent(lowShiftRB)
-                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                                .addComponent(highShiftRB))
-                            .addComponent(translationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 227, javax.swing.GroupLayout.PREFERRED_SIZE))
-                        .addGroup(transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                            .addGroup(transformationPanelLayout.createSequentialGroup()
-                                .addGap(24, 24, 24)
-                                .addComponent(resetAllButton, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE)
-                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
-                                .addComponent(applyButton, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE))
-                            .addGroup(transformationPanelLayout.createSequentialGroup()
-                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                                .addComponent(rotationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 224, javax.swing.GroupLayout.PREFERRED_SIZE)
-                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                                .addComponent(scalePanel, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE)))))
+                        .addComponent(translationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(rotationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(scalePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                 .addGap(0, 0, Short.MAX_VALUE))
         );
         transformationPanelLayout.setVerticalGroup(
             transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(transformationPanelLayout.createSequentialGroup()
                 .addContainerGap()
-                .addGroup(transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                .addGroup(transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                     .addComponent(scalePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                     .addComponent(rotationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                     .addComponent(translationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
-                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                .addGroup(transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                    .addComponent(applyButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
-                    .addGroup(transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
-                        .addComponent(shiftLabel)
-                        .addComponent(lowShiftRB)
-                        .addComponent(highShiftRB)
-                        .addComponent(resetAllButton)))
-                .addGap(39, 39, 39)
-                .addComponent(jSeparator10, javax.swing.GroupLayout.PREFERRED_SIZE, 62, javax.swing.GroupLayout.PREFERRED_SIZE)
-                .addGap(25, 25, 25)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addComponent(jButton3)
+                .addGap(59, 59, 59)
                 .addComponent(shiftPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                 .addComponent(jSeparator5, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE))
@@ -961,8 +751,6 @@ public class RegistrationPanel extends ControlPanel {
 
         org.openide.awt.Mnemonics.setLocalizedText(jLabel8, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.jLabel8.text")); // NOI18N
 
-        jComboBox1.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "None", "Random 200" }));
-
         jButton1.setFont(new java.awt.Font("Ubuntu", 1, 15)); // NOI18N
         org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.jButton1.text")); // NOI18N
         jButton1.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.jButton1.toolTipText")); // NOI18N
@@ -978,25 +766,26 @@ public class RegistrationPanel extends ControlPanel {
             jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(jPanel1Layout.createSequentialGroup()
                 .addContainerGap()
-                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
-                    .addGroup(jPanel1Layout.createSequentialGroup()
-                        .addComponent(jLabel8)
-                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                        .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, 166, javax.swing.GroupLayout.PREFERRED_SIZE)
-                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                        .addComponent(jButton1))
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                     .addGroup(jPanel1Layout.createSequentialGroup()
-                        .addComponent(jLabel7)
-                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                        .addComponent(jCheckBox1)
-                        .addGap(18, 18, 18)
-                        .addComponent(jLabel5)
-                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                        .addComponent(jFormattedTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE)
-                        .addGap(18, 18, 18)
-                        .addComponent(jLabel6)
-                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                        .addComponent(jFormattedTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addGroup(jPanel1Layout.createSequentialGroup()
+                                .addComponent(jLabel7)
+                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                                .addComponent(jCheckBox1)
+                                .addGap(18, 18, 18)
+                                .addComponent(jLabel5)
+                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                                .addComponent(jFormattedTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE))
+                            .addComponent(comboSliderInteger1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                        .addGap(12, 12, 12)
+                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addGroup(jPanel1Layout.createSequentialGroup()
+                                .addComponent(jLabel6)
+                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                                .addComponent(jFormattedTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE))
+                            .addComponent(jLabel8)))
+                    .addComponent(jButton1))
                 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
         );
         jPanel1Layout.setVerticalGroup(
@@ -1011,12 +800,15 @@ public class RegistrationPanel extends ControlPanel {
                         .addComponent(jFormattedTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE)
                         .addComponent(jLabel6)
                         .addComponent(jFormattedTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)))
-                .addGap(18, 18, 18)
                 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
-                        .addComponent(jLabel8)
-                        .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE))
-                    .addComponent(jButton1))
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addGap(5, 5, 5)
+                        .addComponent(comboSliderInteger1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addGap(26, 26, 26)
+                        .addComponent(jLabel8)))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jButton1)
                 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
         );
 
@@ -1111,21 +903,22 @@ public class RegistrationPanel extends ControlPanel {
             jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(jPanel7Layout.createSequentialGroup()
                 .addContainerGap()
+                .addComponent(jButton2)
+                .addGap(18, 18, 18)
                 .addComponent(jLabel4)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addComponent(jCheckBox2)
-                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                .addComponent(jButton2)
-                .addGap(190, 190, 190))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
         );
         jPanel7Layout.setVerticalGroup(
             jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(jPanel7Layout.createSequentialGroup()
                 .addContainerGap()
                 .addGroup(jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
-                    .addComponent(jButton2)
                     .addComponent(jCheckBox2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                    .addComponent(jLabel4, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                        .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addComponent(jButton2)))
                 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
         );
 
@@ -1154,7 +947,7 @@ public class RegistrationPanel extends ControlPanel {
                 .addComponent(jLabel2)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
-                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                .addContainerGap(30, Short.MAX_VALUE))
         );
         jPanel2Layout.setVerticalGroup(
             jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@@ -1183,14 +976,16 @@ public class RegistrationPanel extends ControlPanel {
             .addGroup(layout.createSequentialGroup()
                 .addContainerGap()
                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
-                    .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                     .addComponent(jPanel4, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                    .addComponent(jPanel7, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                     .addComponent(transformationPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 585, javax.swing.GroupLayout.PREFERRED_SIZE)
-                    .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
-                .addGap(153, 153, 153)
-                .addComponent(jSeparator7, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
-                .addGap(0, 0, Short.MAX_VALUE))
+                    .addComponent(jPanel7, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addComponent(jSeparator7, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
         );
         layout.setVerticalGroup(
             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@@ -1205,12 +1000,12 @@ public class RegistrationPanel extends ControlPanel {
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                .addComponent(transformationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 209, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addComponent(transformationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                .addGap(232, 232, 232)
+                .addGap(328, 328, 328)
                 .addComponent(jSeparator11, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                 .addGap(221, 221, 221)
                 .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
@@ -1220,7 +1015,6 @@ public class RegistrationPanel extends ControlPanel {
 
        
     private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
-        resetAllButtonMousePressed(null);
     }//GEN-LAST:event_jButton1ActionPerformed
 
     private void jCheckBox1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBox1ActionPerformed
@@ -1239,38 +1033,26 @@ public class RegistrationPanel extends ControlPanel {
         thersholdFTF.postActionEvent();
     }//GEN-LAST:event_thersholdUpButtonActionPerformed
 
-    private void highShiftRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_highShiftRBActionPerformed
-        this.moveModifier = HIGH_SHIFT_QUOTIENT;
-    }//GEN-LAST:event_highShiftRBActionPerformed
-
-    private void lowShiftRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_lowShiftRBActionPerformed
-        this.moveModifier = LOW_SHIFT_QUOTIENT;
-    }//GEN-LAST:event_lowShiftRBActionPerformed
-
-    private void applyButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_applyButtonMousePressed
-        resetAllButtonMousePressed(evt);
-    }//GEN-LAST:event_applyButtonMousePressed
-
-    private void resetAllButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_resetAllButtonMousePressed
-        translationButtonMousePressed(evt);
-        rotationButtonMousePressed(evt);
-        scaleButtonMousePressed(evt);
-    }//GEN-LAST:event_resetAllButtonMousePressed
-
     private void scaleMinusButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_scaleMinusButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_scaleMinusButtonMouseReleased
 
     private void scaleMinusButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_scaleMinusButtonMousePressed
         animator.startModelAnimation(Direction.ZOOM_OUT, this);
     }//GEN-LAST:event_scaleMinusButtonMousePressed
 
-    private void scaleButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_scaleButtonMousePressed
-        scaleFTF.setValue(0.0);
-    }//GEN-LAST:event_scaleButtonMousePressed
-
     private void scalePlusButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_scalePlusButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_scalePlusButtonMouseReleased
 
     private void scalePlusButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_scalePlusButtonMousePressed
@@ -1279,6 +1061,11 @@ public class RegistrationPanel extends ControlPanel {
 
     private void rightRotationXButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightRotationXButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_rightRotationXButtonMouseReleased
 
     private void rightRotationXButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightRotationXButtonMousePressed
@@ -1287,6 +1074,11 @@ public class RegistrationPanel extends ControlPanel {
 
     private void leftRotationZButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftRotationZButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_leftRotationZButtonMouseReleased
 
     private void leftRotationZButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftRotationZButtonMousePressed
@@ -1295,6 +1087,11 @@ public class RegistrationPanel extends ControlPanel {
 
     private void rightRotationYButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightRotationYButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_rightRotationYButtonMouseReleased
 
     private void rightRotationYButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightRotationYButtonMousePressed
@@ -1303,20 +1100,24 @@ public class RegistrationPanel extends ControlPanel {
 
     private void rightRotationZButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightRotationZButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_rightRotationZButtonMouseReleased
 
     private void rightRotationZButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightRotationZButtonMousePressed
         animator.startModelAnimation(Direction.ROTATE_OUT, this);
     }//GEN-LAST:event_rightRotationZButtonMousePressed
 
-    private void rotationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rotationButtonMousePressed
-        rotationXFTF.setValue(0.0);
-        rotationYFTF.setValue(0.0);
-        rotationZFTF.setValue(0.0);
-    }//GEN-LAST:event_rotationButtonMousePressed
-
     private void leftRotationXButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftRotationXButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_leftRotationXButtonMouseReleased
 
     private void leftRotationXButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftRotationXButtonMousePressed
@@ -1325,6 +1126,11 @@ public class RegistrationPanel extends ControlPanel {
 
     private void leftRotationYButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftRotationYButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_leftRotationYButtonMouseReleased
 
     private void leftRotationYButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftRotationYButtonMousePressed
@@ -1333,6 +1139,11 @@ public class RegistrationPanel extends ControlPanel {
 
     private void leftTranslationZButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftTranslationZButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_leftTranslationZButtonMouseReleased
 
     private void leftTranslationZButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftTranslationZButtonMousePressed
@@ -1341,6 +1152,11 @@ public class RegistrationPanel extends ControlPanel {
 
     private void leftTranslationXButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftTranslationXButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_leftTranslationXButtonMouseReleased
 
     private void leftTranslationXButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftTranslationXButtonMousePressed
@@ -1349,6 +1165,11 @@ public class RegistrationPanel extends ControlPanel {
 
     private void rightTranslationZButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightTranslationZButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_rightTranslationZButtonMouseReleased
 
     private void rightTranslationZButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightTranslationZButtonMousePressed
@@ -1357,6 +1178,11 @@ public class RegistrationPanel extends ControlPanel {
 
     private void rightTranslationYButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightTranslationYButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_rightTranslationYButtonMouseReleased
 
     private void rightTranslationYButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightTranslationYButtonMousePressed
@@ -1365,6 +1191,11 @@ public class RegistrationPanel extends ControlPanel {
 
     private void leftTranslationYButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftTranslationYButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_leftTranslationYButtonMouseReleased
 
     private void leftTranslationYButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftTranslationYButtonMousePressed
@@ -1373,22 +1204,17 @@ public class RegistrationPanel extends ControlPanel {
 
     private void rightTranslationXButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightTranslationXButtonMouseReleased
         animator.stopModelAnimation(this);
+        action.actionPerformed(new ActionEvent(
+                evt, 
+                ActionEvent.ACTION_PERFORMED, 
+                ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED)
+        );
     }//GEN-LAST:event_rightTranslationXButtonMouseReleased
 
     private void rightTranslationXButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightTranslationXButtonMousePressed
         animator.startModelAnimation(Direction.TRANSLATE_RIGHT, this);
     }//GEN-LAST:event_rightTranslationXButtonMousePressed
 
-    private void translationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_translationButtonMousePressed
-        translationXFTF.setValue(0.0);
-        translationYFTF.setValue(0.0);
-        translationZFTF.setValue(0.0);
-    }//GEN-LAST:event_translationButtonMousePressed
-
-    private void scaleFTFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleFTFActionPerformed
-        // TODO add your handling code here:
-    }//GEN-LAST:event_scaleFTFActionPerformed
-
     private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
         // TODO add your handling code here:
     }//GEN-LAST:event_jButton2ActionPerformed
@@ -1399,14 +1225,13 @@ public class RegistrationPanel extends ControlPanel {
 
 
     // Variables declaration - do not modify//GEN-BEGIN:variables
-    private javax.swing.JButton applyButton;
+    private cz.fidentis.analyst.core.ComboSliderInteger comboSliderInteger1;
     private javax.swing.JLabel featurePointsLabel;
-    private javax.swing.JRadioButton highShiftRB;
     private javax.swing.JButton jButton1;
     private javax.swing.JButton jButton2;
+    private javax.swing.JButton jButton3;
     private javax.swing.JCheckBox jCheckBox1;
     private javax.swing.JCheckBox jCheckBox2;
-    private javax.swing.JComboBox<String> jComboBox1;
     private javax.swing.JFormattedTextField jFormattedTextField1;
     private javax.swing.JFormattedTextField jFormattedTextField2;
     private javax.swing.JLabel jLabel1;
@@ -1420,7 +1245,6 @@ public class RegistrationPanel extends ControlPanel {
     private javax.swing.JPanel jPanel2;
     private javax.swing.JPanel jPanel4;
     private javax.swing.JPanel jPanel7;
-    private javax.swing.JSeparator jSeparator10;
     private javax.swing.JSeparator jSeparator11;
     private javax.swing.JSeparator jSeparator2;
     private javax.swing.JSeparator jSeparator5;
@@ -1433,10 +1257,8 @@ public class RegistrationPanel extends ControlPanel {
     private javax.swing.JButton leftTranslationXButton;
     private javax.swing.JButton leftTranslationYButton;
     private javax.swing.JButton leftTranslationZButton;
-    private javax.swing.JRadioButton lowShiftRB;
     private javax.swing.ButtonGroup precisionGroup;
     private javax.swing.ButtonGroup primaryRenderModeGroup;
-    private javax.swing.JButton resetAllButton;
     private javax.swing.JButton rightRotationXButton;
     private javax.swing.JButton rightRotationYButton;
     private javax.swing.JButton rightRotationZButton;
@@ -1446,18 +1268,11 @@ public class RegistrationPanel extends ControlPanel {
     private javax.swing.JLabel rotatXLabel;
     private javax.swing.JLabel rotatYLabel;
     private javax.swing.JLabel rotatZLabel;
-    private javax.swing.JButton rotationButton;
     private javax.swing.JPanel rotationPanel;
-    private javax.swing.JFormattedTextField rotationXFTF;
-    private javax.swing.JFormattedTextField rotationYFTF;
-    private javax.swing.JFormattedTextField rotationZFTF;
-    private javax.swing.JButton scaleButton;
-    private javax.swing.JFormattedTextField scaleFTF;
     private javax.swing.JButton scaleMinusButton;
     private javax.swing.JPanel scalePanel;
     private javax.swing.JButton scalePlusButton;
     private javax.swing.ButtonGroup secondaryRenerModeGroup;
-    private javax.swing.JLabel shiftLabel;
     private javax.swing.JPanel shiftPanel;
     private javax.swing.JFormattedTextField thersholdFTF;
     private javax.swing.JButton thersholdUpButton;
@@ -1466,10 +1281,6 @@ public class RegistrationPanel extends ControlPanel {
     private javax.swing.JLabel translXLabel;
     private javax.swing.JLabel translYLabel;
     private javax.swing.JLabel translZLabel;
-    private javax.swing.JButton translationButton;
     private javax.swing.JPanel translationPanel;
-    private javax.swing.JFormattedTextField translationXFTF;
-    private javax.swing.JFormattedTextField translationYFTF;
-    private javax.swing.JFormattedTextField translationZFTF;
     // End of variables declaration//GEN-END:variables
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/Drawable.java b/GUI/src/main/java/cz/fidentis/analyst/scene/Drawable.java
index 90193a7ffd5f204fc8d4bdf1cd45c2d1f64897fc..3b60dee7000f46b2a9f5ffadbe1070d89c01979c 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/scene/Drawable.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/Drawable.java
@@ -4,7 +4,6 @@ import com.jogamp.opengl.GL;
 import com.jogamp.opengl.GL2;
 import java.awt.Color;
 import java.util.Comparator;
-import javax.vecmath.Vector3d;
 
 /**
  * A drawable object, i.e., an object with drawing state and capable to 
@@ -22,12 +21,6 @@ public abstract class Drawable {
     private float transparency = 1; // 0 = off, 1 = max
     private Color highlights = new Color(0, 0, 0, 1);
     
-    /* transformation */
-    private Vector3d translation = new Vector3d(0, 0, 0);
-    private Vector3d rotation = new Vector3d(0, 0, 0);
-    private Vector3d scale = new Vector3d(0, 0, 0);
-    
-    /* rendering mode */
     /**
      * Render mode to use, one from {@code GL_FILL}, {@code GL_LINE}, {@code GL_POINT}
      */
@@ -49,9 +42,6 @@ public abstract class Drawable {
         this.color = drawable.color;
         this.highlights = drawable.highlights;
         this.transparency = drawable.transparency;
-        this.translation = new Vector3d(drawable.translation);
-        this.rotation = new Vector3d(drawable.rotation);
-        this.scale = new Vector3d(drawable.scale);
     }
 
     /**
@@ -78,22 +68,7 @@ public abstract class Drawable {
      */
     public void render(GL2 gl) {
         initRendering(gl);
-        
-        gl.glPushMatrix(); 
-        
-        // rotate
-        gl.glRotated(getRotation().x, 1, 0, 0);
-        gl.glRotated(getRotation().y, 0, 1, 0);
-        gl.glRotated(getRotation().z, 0, 0, 1);
-        // move
-        gl.glTranslated(getTranslation().x, getTranslation().y, getTranslation().z);
-        // scale
-        gl.glScaled(1 + getScale().x, 1 + getScale().y, 1 + getScale().z);
-        
         renderObject(gl);
-
-        gl.glPopMatrix();
-        
         finishRendering(gl);
     }
     
@@ -175,51 +150,6 @@ public abstract class Drawable {
         this.highlights = highlights;
     }
     
-    /**
-     * @return Current translation
-     */
-    public Vector3d getTranslation() {
-        return translation;
-    }
-
-    /**
-     * Sets tranlation
-     * @param translation Translation
-     */
-    public void setTranslation(Vector3d translation) {
-        this.translation = translation;
-    }
-
-    /**
-     * @return Current rotation
-     */
-    public Vector3d getRotation() {
-        return rotation;
-    }
-
-    /**
-     * Sets rotation
-     * @param rotation 
-     */
-    public void setRotation(Vector3d rotation) {
-        this.rotation = rotation;
-    }
-
-    /**
-     * @return Current scale
-     */
-    public Vector3d getScale() {
-        return scale;
-    }
-
-    /**
-     * Sets scale
-     * @param scale Scale
-     */
-    public void setScale(Vector3d scale) {
-        this.scale = scale;
-    }
-    
     /**
      * @return Value of {@link #renderMode}
      */
diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableCuttingPlane.java b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableCuttingPlane.java
index c4f334e1ace5c5dab60871f3719bf5019ee983b5..2a8dab3ba0bfa2ded1290a884213ada662dcce99 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableCuttingPlane.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableCuttingPlane.java
@@ -1,10 +1,8 @@
 package cz.fidentis.analyst.scene;
 
-import cz.fidentis.analyst.mesh.core.MeshFacet;
-import cz.fidentis.analyst.mesh.core.MeshFacetImpl;
+import com.jogamp.opengl.GL2;
 import cz.fidentis.analyst.symmetry.Plane;
-import javax.vecmath.Point3d;
-import javax.vecmath.Vector3d;
+import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox;
 
 /**
  * Drawable plane with the possibility to shift it along the normal and,
@@ -16,6 +14,17 @@ import javax.vecmath.Vector3d;
 public class DrawableCuttingPlane extends DrawablePlane {
     
     private double shift = 0.0;
+    private boolean showMirror = false;
+    
+    /**
+     * Constructor.
+     * 
+     * @param plane plane
+     * @param bbox bounding box used to estimate cutting pale shape (rectangle)
+     */
+    public DrawableCuttingPlane(Plane plane, BBox bbox) {
+        super(plane, bbox);
+    }
     
     /**
      * Copy constructor.
@@ -28,58 +37,26 @@ public class DrawableCuttingPlane extends DrawablePlane {
     }
     
     /**
-     * Constructor.
-     * @param facet Mesh facet of the plane
-     * @param plane The plane
-     */
-    public DrawableCuttingPlane(MeshFacet facet, Plane plane) {
-        super(facet, plane);
-    }
-    
-    /**
-     * Constructor.
-     * 
-     * @param plane The plane
-     * @param midPoint A 3D point, which is projected to the plane and used as a center of the rectangular facet
-     * @param width Width
-     * @param height Height
-     * @throws NullPointerException if the {@code plane} or {@code midPoint} are {@code null}
-     * @throws IllegalArgumentException if {@code width} or {@code height} are &lt;= 0
-     */
-    public DrawableCuttingPlane(Plane plane, Point3d midPoint, double width, double height) {
-        super(plane, midPoint, width, height);
-    }
-
-    /**
-     * Moves the plane in the plane's normal direction.
+     * Moves the plane in the plane's normal direction relatively to the original position.
      * 
      * @param dist Distance. If positive, then the movements is in the direction of the normal vector.
      * Otherwise, the movement is against the normal direction.
      */
     public void shift(double dist) {
-        shift += dist;
-        
-        Vector3d move = getPlane().getNormal();
-        move.scale(dist);
-        for (int i = 0; i < getFacets().get(0).getNumberOfVertices(); ++i) {
-            getFacets().get(0).getVertex(i).getPosition().sub(move);
-        }
-        
-        if (isMirrorPlaneShown()) {
-            move.scale(-1.0);
-            for (int i = 0; i < getFacets().get(1).getNumberOfVertices(); ++i) {
-                getFacets().get(1).getVertex(i).getPosition().sub(move);
-            }
-        }
+        this.shift = dist;
     }
     
-    /**
-     * Returns shifted cutting plane.
-     * @return shifted cutting plane.
-     */
     @Override
     public Plane getPlane() {
-        return new Plane(super.getPlane().getNormal(), super.getPlane().getDistance() + shift);
+        return super.getPlane().shift(this.shift);
+    }
+    
+    /**
+     * Returns original non-shifted plane
+     * @return original non-shifted plane
+     */
+    public Plane getNonShiftedPlane() {
+        return super.getPlane();
     }
     
     /**
@@ -87,7 +64,7 @@ public class DrawableCuttingPlane extends DrawablePlane {
      * @return the cutting plane shifted to opposite direction
      */
     public Plane getMirrorPlane() {
-        return new Plane(super.getPlane().getNormal(), super.getPlane().getDistance() - shift);
+        return super.getPlane().shift(-this.shift);
     }
     
     /**
@@ -95,20 +72,7 @@ public class DrawableCuttingPlane extends DrawablePlane {
      * @param show Shows if {@code true}, hides otherwise
      */
     public void showMirrorPlane(boolean show) {
-        if (show) {
-            if (isMirrorPlaneShown()) { // already shown
-                return;
-            }
-            MeshFacetImpl mirror = new MeshFacetImpl(getModel().getFacets().get(0));
-            Vector3d move = new Vector3d(super.getPlane().getNormal());
-            move.scale(-2.0 * shift);
-            for (int i = 0; i < mirror.getNumberOfVertices(); ++i) {
-                mirror.getVertex(i).getPosition().sub(move);
-            }
-            getModel().addFacet(mirror);
-        } else if (isMirrorPlaneShown()) {
-            getModel().removeFacet(1);
-        }
+        this.showMirror = show;
     }
     
     /**
@@ -116,6 +80,15 @@ public class DrawableCuttingPlane extends DrawablePlane {
      * @return {@code true} if the mirror planes are set to be shown.
      */
     public boolean isMirrorPlaneShown() {
-        return getModel().getFacets().size() > 1;
+        return this.showMirror;
+        //return getModel().getFacets().size() > 1;
+    }
+    
+    @Override
+    protected void renderObject(GL2 gl) {
+        renderObject(gl, getPlane().getMesh(getBBox()));
+        if (showMirror) {
+            renderObject(gl, getMirrorPlane().getMesh(getBBox()));
+        }
     }
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFeaturePoints.java b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFeaturePoints.java
index 3018786eef6d85c0396ff3282523be0aaa92b11c..d0d7723cc64657637d48656e1569667339b71204 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFeaturePoints.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFeaturePoints.java
@@ -5,7 +5,6 @@ import com.jogamp.opengl.glu.GLU;
 import com.jogamp.opengl.glu.GLUquadric;
 import cz.fidentis.analyst.feature.FeaturePoint;
 import java.awt.Color;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -60,7 +59,8 @@ public class DrawableFeaturePoints extends Drawable {
      * @param defaultPerimeter Default perimeter
      */
     public DrawableFeaturePoints(List<FeaturePoint> featurePoints, Color defaultColor, double defaultPerimeter) {
-        this.featurePoints = new ArrayList<>(featurePoints);
+        //this.featurePoints = new ArrayList<>(featurePoints);
+        this.featurePoints = featurePoints;
         this.defaultPerimeter = defaultPerimeter;
         setColor(defaultColor);
     }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java
index 7999836ca817a0e3bd6b3ffab87a770066c3e1e3..0796f9d7a9c207a60f13d0912333fda836bfb9b9 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java
@@ -1,20 +1,35 @@
 package cz.fidentis.analyst.scene;
 
-import cz.fidentis.analyst.mesh.core.MeshFacet;
-import cz.fidentis.analyst.mesh.core.MeshModel;
+import com.jogamp.opengl.GL2;
+import cz.fidentis.analyst.mesh.core.MeshRectangleFacet;
 import cz.fidentis.analyst.symmetry.Plane;
+import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox;
 import javax.vecmath.Point3d;
 
 /**
  * A plane to be shown as a rectangular mesh facet.
+ * The rectangular shape is generated at run-time from the associated plane.
  * 
  * @author Radek Oslejsek
  * @author Dominik Racek
  */
-public class DrawablePlane extends DrawableMesh {
+public class DrawablePlane extends Drawable {
     
-    private final Plane plane;
+    private Plane plane;
+    private final BBox bbox;
     
+    
+    /**
+     * Constructor.
+     * 
+     * @param plane plane
+     * @param bbox bounding box used to estimate cutting pale shape (rectangle)
+     */
+    public DrawablePlane(Plane plane, BBox bbox) {
+        this.plane = plane;
+        this.bbox = bbox;
+    }
+
     /**
      * Copy constructor.
      * @param drPlane Original plane
@@ -23,51 +38,35 @@ public class DrawablePlane extends DrawableMesh {
     public DrawablePlane(DrawablePlane drPlane) {
         super(drPlane);
         this.plane = new Plane(drPlane.getPlane());
+        this.bbox = drPlane.bbox;
     }
     
-    /**
-     * Constructor.
-     * @param model Mesh model of the plane
-     * @param plane The plane
-     */
-    public DrawablePlane(MeshModel model, Plane plane) {
-        super(model);
-        if (plane == null) {
-            throw new IllegalArgumentException("plane");
-        }
+    public Plane getPlane() {
+        return plane;
+    }
+    
+    protected void setPlane(Plane plane) {
         this.plane = plane;
     }
+
+    @Override
+    protected void renderObject(GL2 gl) {
+        renderObject(gl, getPlane().getMesh(bbox));
+    }
     
-    /**
-     * Constructor.
-     * @param facet Mesh facet of the plane
-     * @param plane The plane
-     */
-    public DrawablePlane(MeshFacet facet, Plane plane) {
-        super(facet);
-        if (plane == null) {
-            throw new IllegalArgumentException("plane");
+    protected void renderObject(GL2 gl, MeshRectangleFacet facet) {
+        gl.glBegin(GL2.GL_TRIANGLES); //vertices are rendered as triangles
+        // get the normal and tex coords indicies for face i  
+        for (int v = 0; v < facet.getCornerTable().getSize(); v++) {
+            Point3d vert = facet.getVertices().get(facet.getCornerTable().getRow(v).getVertexIndex()).getPosition();
+            if (v == 0) {
+            }
+            gl.glVertex3d(vert.x, vert.y, vert.z);
         }
-        this.plane = new Plane(plane);
+        gl.glEnd();
     }
     
-    /**
-     * Constructor.
-     * 
-     * @param plane The plane
-     * @param midPoint A 3D point, which is projected to the plane and used as a center of the rectangular facet
-     * @param width Width
-     * @param height Height
-     * @throws NullPointerException if the {@code plane} or {@code midPoint} are {@code null}
-     * @throws IllegalArgumentException if {@code width} or {@code height} are &lt;= 0
-     */
-    public DrawablePlane(Plane plane, Point3d midPoint, double width, double height) {
-        super(plane.getMesh(midPoint, width, height));
-        this.plane = new Plane(plane);
+    protected BBox getBBox() {
+        return this.bbox;
     }
-
-    public Plane getPlane() {
-        return plane;
-    }
-
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java b/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java
index 28613b1aee5c307c07aa179276282bb920897676..22fbdc2fd9c2825cda4dcfc3b4da9ca03e6a4225 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java
@@ -3,12 +3,13 @@ package cz.fidentis.analyst.scene;
 import cz.fidentis.analyst.face.HumanFace;
 import java.awt.Color;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
  * A simple 3D scene. The structure is as follows:
  * Drawable components of a single human face (mesh, symmetry plane, feature points. etc.)
- * are always stored at the same index. One face can be labeled as "primary", one as "secondary".
+ * are always stored at the same index (slot). One face can be labeled as "primary", one as "secondary".
  * Other faces have no label.
  * Then, there is a special list of so-called other drawables. The size of this list can differ.
  * 
@@ -170,7 +171,6 @@ public class Scene {
         }        
         
         drawableFaces.set(slot, new DrawableFace(face));
-        
         return true;
     }
     
@@ -184,7 +184,7 @@ public class Scene {
     public boolean setDrawableFeaturePoints(int slot, HumanFace face) {
         if (slot < 0 || slot >= Scene.MAX_FACES_IN_SCENE) {
             return false;
-        } else if (face == null) { // remove
+        } else if (face == null || face.getFeaturePoints() == null) { // remove
             if (slot >= getArraySize()){
                 return false;
             } else {
@@ -195,13 +195,7 @@ public class Scene {
             return false;
         }        
         
-        drawableFeaturePoints.set(
-                slot,
-                (face.getFeaturePoints() != null) 
-                        ? new DrawableFeaturePoints(face.getFeaturePoints())
-                        : null
-        );
-        
+        drawableFeaturePoints.set(slot, new DrawableFeaturePoints(face.getFeaturePoints()));
         return true;
     }
     
@@ -215,7 +209,7 @@ public class Scene {
     public boolean setDrawableSymmetryPlane(int slot, HumanFace face) {
         if (slot < 0 || slot >= Scene.MAX_FACES_IN_SCENE) {
             return false;
-        } else if (face == null) { // remove
+        } else if (face == null || face.getSymmetryPlane() == null) { // remove
             if (slot >= getArraySize()){
                 return false;
             } else {
@@ -224,14 +218,13 @@ public class Scene {
             }
         } else if (!prepareArrays(slot, face)) {
             return false;
-        }        
+        }
         
-        drawableSymmetryPlanes.set(
-                slot,
-                (face.getSymmetryPlane() != null && face.getSymmetryPlaneFacet() != null) 
-                        ? new DrawablePlane(face.getSymmetryPlaneFacet(), face.getSymmetryPlane())
-                        : null
-        );
+        if (drawableSymmetryPlanes.get(slot) == null) { // add new 
+            drawableSymmetryPlanes.set(slot, new DrawablePlane(face.getSymmetryPlane(), face.getBoundingBox()));
+        } else { // replace existing
+            drawableSymmetryPlanes.get(slot).setPlane(face.getSymmetryPlane());
+        }
         
         return true;
     }
@@ -376,6 +369,10 @@ public class Scene {
         return ret;
     }
     
+    public List<DrawableFace> getDrawableFaces() {
+        return Collections.unmodifiableList(this.drawableFaces);
+    }
+    
     protected Color getColorOfFeaturePoints(Color origColor) {
         return new Color(
                 Math.min(255, origColor.getRed() + 40),
diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/SceneRenderer.java b/GUI/src/main/java/cz/fidentis/analyst/scene/SceneRenderer.java
index cbd6d37ccad08421b66fc91cb4c024447878ecee..2e45de1efe8ca5b7ec9b1df231b8a7f00465d305 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/scene/SceneRenderer.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/SceneRenderer.java
@@ -127,6 +127,19 @@ public class SceneRenderer {
             }
         }
         
+        // draw coordinates:
+        /*
+        gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, new float[]{255,255,255,255}, 0);
+        gl.glBegin(GL2.GL_LINES); //vertices are rendered as triangles
+        gl.glVertex3d(-30, 0, 0);
+        gl.glVertex3d(30, 0, 0);
+        gl.glVertex3d(0, -30, 0);
+        gl.glVertex3d(0, 30, 0);
+        gl.glVertex3d(0, 0, -30);
+        gl.glVertex3d(0, 0, 30);
+        gl.glEnd();
+        */
+        
         gl.glFlush();
         
         //out.printDuration("Scene rendering");
diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java
index 6eab131fb490978fb610ada620284774d10f90d5..50c730c0d054d15f4021583b5dffab7ebf1a8d68 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java
@@ -6,9 +6,7 @@ import cz.fidentis.analyst.core.ControlPanelAction;
 import cz.fidentis.analyst.face.HumanFace;
 import cz.fidentis.analyst.face.events.HumanFaceEvent;
 import cz.fidentis.analyst.face.events.HumanFaceListener;
-import cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent;
-import cz.fidentis.analyst.mesh.core.MeshFacet;
-import cz.fidentis.analyst.mesh.core.MeshFacetImpl;
+import cz.fidentis.analyst.face.events.HumanFaceTransformedEvent;
 import cz.fidentis.analyst.scene.DrawableCuttingPlane;
 import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox;
 import cz.fidentis.analyst.visitors.mesh.CrossSectionZigZag;
@@ -24,7 +22,6 @@ import java.io.PrintWriter;
 import java.util.List;
 import java.util.stream.Collectors;
 import javax.swing.JComboBox;
-import javax.swing.JFrame;
 import javax.swing.JOptionPane;
 import javax.vecmath.Vector3d;
 
@@ -52,11 +49,10 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
     private CrossSectionCurve primaryMirrorCurve;
     private CrossSectionCurve secondaryMirrorCurve;
 
-    private double lastSliderValue = 0.5;
     private boolean cuttingPlaneFromSymmetry;
     
-    private int priCuttingPlaneIndex = -1;
-    private int secCuttingPlaneIndex = -1;    
+    private int priCuttingPlaneSlot = -1;
+    private int secCuttingPlaneSlot = -1;    
     
     /**
      * Constructor.
@@ -68,9 +64,9 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
         super(canvas, topControlPanel);
         this.topControlPanel = topControlPanel;
         
-        computeOrthogonalCuttingPlanes(false);
+        computeVerticalCuttingPlanes(); // compute default cutting planes
 
-        //recomputePrimaryProfile();
+        //recomputePrimaryProfile(); 
 
         if (getSecondaryDrawableFace() != null) {
             //recomputeSecondaryProfile();
@@ -121,18 +117,17 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
                     }
                 }
                 break;
-            case ProfilesPanel.ACTION_OFFSET_CUTTING_PLANE:
-                double auxVal = ((ComboSliderDouble) ae.getSource()).getValue();
-                double value =  auxVal - lastSliderValue;
-                double multiplier = -150;
-                
-                setCuttingPlaneOffset(priCuttingPlaneIndex, multiplier * value);
-
+            case ProfilesPanel.ACTION_SHIFT_CUTTING_PLANE:
+                double sliderVal = ((ComboSliderDouble) ae.getSource()).getValue();
+                double xExtent = maxExtentX();
+                double shift = (sliderVal >= 0.5) 
+                        ? ( (sliderVal - 0.5) / 0.5) * xExtent  // move right
+                        : -((0.5 - sliderVal) / 0.5) * xExtent; // move left
+                getDrawableCuttingPlane(priCuttingPlaneSlot).shift(shift);
                 if (getSecondaryDrawableFace() != null) {
-                    setCuttingPlaneOffset(secCuttingPlaneIndex, multiplier * value);
+                    getDrawableCuttingPlane(secCuttingPlaneSlot).shift(shift);
                 }
                 recomputeProfiles();
-                lastSliderValue = auxVal;
                 break;
             case ProfilesPanel.ACTION_CHANGE_CUTTING_PLANE:
                 String option = (String)((JComboBox) ae.getSource()).getSelectedItem();
@@ -140,9 +135,9 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
                 if (option.equals(ProfilesPanel.OPTION_SYMMETRY_PLANE)) {
                     if (getScene().getDrawableSymmetryPlane(0) == null) {
                        JOptionPane.showMessageDialog(
-                               new JFrame(), 
+                               controlPanel, 
                                "Compute a symmetry plane at the Symmetry tab first.", 
-                               "Dialog", 
+                               "No symmetry plane", 
                                JOptionPane.INFORMATION_MESSAGE
                        );
                        controlPanel.setDefaultPlaneSelection();
@@ -152,7 +147,7 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
                     computeCuttingPlanesFromSymmetry();
                 } else if (option.equals(ProfilesPanel.OPTION_VERTICAL_PLANE)) {
                     controlPanel.resetSliderSilently();
-                    computeOrthogonalCuttingPlanes(false);
+                    computeVerticalCuttingPlanes();
                 }
                 
                 showCuttingPlanes(true, controlPanel.isMirrorCutsChecked());
@@ -170,10 +165,19 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
     
     @Override
     public void acceptEvent(HumanFaceEvent event) {
-        if (event instanceof SymmetryPlaneChangedEvent && cuttingPlaneFromSymmetry) {
+        // If some human face is transformed, then cutting planes have to updated.
+        if (event instanceof HumanFaceTransformedEvent) {
             controlPanel.resetSliderSilently();
-            computeCuttingPlanesFromSymmetry(); // recompute cutting planes
-            //getCanvas().getScene().showCuttingPlanes(false, controlPanel.isMirrorCutsChecked());
+            if (cuttingPlaneFromSymmetry) {
+                computeCuttingPlanesFromSymmetry(); // recompute cutting planes
+                //getCanvas().getScene().showCuttingPlanes(false, controlPanel.isMirrorCutsChecked());
+            } else {
+                computeVerticalCuttingPlanes();
+            }
+            getDrawableCuttingPlane(priCuttingPlaneSlot).show(false); // will be shown on the panel focus
+            if (getDrawableCuttingPlane(secCuttingPlaneSlot) != null) {
+                getDrawableCuttingPlane(secCuttingPlaneSlot).show(false);
+            }
         }
     }
 
@@ -214,27 +218,27 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
             System.out.println("ERROR writing to a file: " + ex);
         }
     }
-
+    
     private void recomputePrimaryProfile() {
         //Main profile
-        CrossSectionZigZag cs = new CrossSectionZigZag(getDrawableCuttingPlane(priCuttingPlaneIndex).getPlane());
+        CrossSectionZigZag cs = new CrossSectionZigZag(getDrawableCuttingPlane(priCuttingPlaneSlot).getPlane());
         getPrimaryDrawableFace().getModel().compute(cs);
         this.primaryCurve = cs.getCrossSectionCurve();
 
         //Mirror profile
-        CrossSectionZigZag mcs = new CrossSectionZigZag(getDrawableCuttingPlane(priCuttingPlaneIndex).getMirrorPlane());
+        CrossSectionZigZag mcs = new CrossSectionZigZag(getDrawableCuttingPlane(priCuttingPlaneSlot).getMirrorPlane());
         getPrimaryDrawableFace().getModel().compute(mcs);
         this.primaryMirrorCurve = mcs.getCrossSectionCurve();
     }
 
     private void recomputeSecondaryProfile() {
         //Main profile
-        CrossSectionZigZag cs = new CrossSectionZigZag(getDrawableCuttingPlane(secCuttingPlaneIndex).getPlane());
+        CrossSectionZigZag cs = new CrossSectionZigZag(getDrawableCuttingPlane(secCuttingPlaneSlot).getPlane());
         getSecondaryDrawableFace().getModel().compute(cs);
         this.secondaryCurve = cs.getCrossSectionCurve();
 
         //Mirror profile
-        CrossSectionZigZag mcs = new CrossSectionZigZag(getDrawableCuttingPlane(secCuttingPlaneIndex).getMirrorPlane());
+        CrossSectionZigZag mcs = new CrossSectionZigZag(getDrawableCuttingPlane(secCuttingPlaneSlot).getMirrorPlane());
         getSecondaryDrawableFace().getModel().compute(mcs);
         this.secondaryMirrorCurve = mcs.getCrossSectionCurve();
     }
@@ -244,11 +248,11 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
         projectCloseFeaturePoints(
                 primaryCurve, 
                 getCanvas().getPrimaryFace(), 
-                getDrawableCuttingPlane(priCuttingPlaneIndex).getPlane());
+                getDrawableCuttingPlane(priCuttingPlaneSlot).getPlane());
         projectCloseFeaturePoints(
                 primaryMirrorCurve, 
                 getCanvas().getPrimaryFace(), 
-                getDrawableCuttingPlane(priCuttingPlaneIndex).getPlane());
+                getDrawableCuttingPlane(priCuttingPlaneSlot).getPlane());
         controlPanel.getProfileRenderingPanel().setPrimarySegments(this.primaryCurve);
         controlPanel.getProfileRenderingPanel().setPrimaryMirrorSegments(this.primaryMirrorCurve);
 
@@ -257,94 +261,73 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
             projectCloseFeaturePoints(
                     secondaryCurve, 
                     getCanvas().getSecondaryFace(), 
-                    getDrawableCuttingPlane(secCuttingPlaneIndex).getPlane());
+                    getDrawableCuttingPlane(secCuttingPlaneSlot).getPlane());
             projectCloseFeaturePoints(
                     secondaryMirrorCurve, 
                     getCanvas().getSecondaryFace(), 
-                    getDrawableCuttingPlane(secCuttingPlaneIndex).getPlane());
+                    getDrawableCuttingPlane(secCuttingPlaneSlot).getPlane());
             controlPanel.getProfileRenderingPanel().setSecondarySegments(this.secondaryCurve);
             controlPanel.getProfileRenderingPanel().setSecondaryMirrorSegments(this.secondaryMirrorCurve);
         }
     }
 
-    private void setCuttingPlaneOffset(int index, double value) {
-        //Move cutting planes left and mirror planes right
-        //If normal is negative, need to negate value
-        if (getDrawableCuttingPlane(index).getPlane().getNormal().x < 0) {
-            getDrawableCuttingPlane(index).shift(-value);
-        } else {
-            getDrawableCuttingPlane(index).shift(value);
-        }
-    }
-    
-    /**
-     * Creates vertical or horizontal cutting and mirror planes from bounding box.
-     * 
-     * @param horizontal 
-     */
-    protected void computeOrthogonalCuttingPlanes(boolean horizontal) {
-        DrawableCuttingPlane drPlane = getDrawableOrthogonalPlane(horizontal);
-        if (priCuttingPlaneIndex == -1) {
-            priCuttingPlaneIndex = getCanvas().getScene().getFreeSlotForOtherDrawables();
+    protected void computeVerticalCuttingPlanes() {
+        BBox bbox = getCanvas().getPrimaryFace().getBoundingBox(); 
+        Plane plane = new Plane(new Vector3d(1,0,0), bbox.getMidPoint().x);
+        DrawableCuttingPlane cuttingPlane = new DrawableCuttingPlane(plane, bbox);
+        cuttingPlane.setTransparency(0.5f);
+        if (priCuttingPlaneSlot == -1) {
+            priCuttingPlaneSlot = getCanvas().getScene().getFreeSlotForOtherDrawables();
         }
-        getCanvas().getScene().setOtherDrawable(priCuttingPlaneIndex, drPlane);
+        getCanvas().getScene().setOtherDrawable(priCuttingPlaneSlot, cuttingPlane);
         
         if (getSecondaryDrawableFace() != null) {
-            if (secCuttingPlaneIndex == -1) {
-                secCuttingPlaneIndex = getCanvas().getScene().getFreeSlotForOtherDrawables();
+            bbox = getCanvas().getSecondaryFace().getBoundingBox(); 
+            plane = new Plane(new Vector3d(1,0,0), bbox.getMidPoint().x);
+            cuttingPlane = new DrawableCuttingPlane(plane, bbox);
+            cuttingPlane.setTransparency(0.5f);
+            if (secCuttingPlaneSlot == -1) {
+                secCuttingPlaneSlot = getCanvas().getScene().getFreeSlotForOtherDrawables();
             }
-            getCanvas().getScene().setOtherDrawable(secCuttingPlaneIndex, new DrawableCuttingPlane(drPlane));
+            getCanvas().getScene().setOtherDrawable(secCuttingPlaneSlot, new DrawableCuttingPlane(cuttingPlane));
         }
+        
         cuttingPlaneFromSymmetry = false;
     }
     
-    protected DrawableCuttingPlane getDrawableOrthogonalPlane(boolean horizontal) {
-        BBox bbox = getCanvas().getPrimaryFace().getBoundingBox(); // use BBox of the first face for size and position estimation
-        Plane plane = new Plane(
-                (horizontal) ? new Vector3d(0,1,0) : new Vector3d(-1,0,0), 
-                (horizontal) ? bbox.getMidPoint().y : bbox.getMidPoint().x
-        );
-        DrawableCuttingPlane cuttingPlane = new DrawableCuttingPlane(
-                plane, 
-                bbox.getMidPoint(), 
-                bbox.getDiagonalLength(), 
-                bbox.getDiagonalLength()
-        );
-        cuttingPlane.setTransparency(0.5f);
-        return cuttingPlane;
-    }
-    
-    /**
-     * Copy rectangle from the symmetry plane.
-     * 
-     * @param faceIndex
-     * @return 
-     */
-    protected DrawableCuttingPlane getCuttingPlaneFromSymmetry(int faceIndex) {
-        MeshFacet symmetryFacet = getCanvas().getHumanFace(faceIndex).getSymmetryPlaneFacet();
-        Plane symmetryPlane = getCanvas().getHumanFace(faceIndex).getSymmetryPlane();
-        return new DrawableCuttingPlane(new MeshFacetImpl(symmetryFacet), new Plane(symmetryPlane));
-    }
-    
     /**
      * Creates cutting and mirror planes by copying the rectangle from the symmetry plane.
      */
     protected void computeCuttingPlanesFromSymmetry() {
-        DrawableCuttingPlane cuttingPlane = getCuttingPlaneFromSymmetry(getCanvas().getPrimaryFaceIndex());
+        Plane symmetryPlane = getCanvas().getPrimaryFace().getSymmetryPlane();
+        if (symmetryPlane.getNormal().x < 0) { // orient to the right-hand direction
+            symmetryPlane = symmetryPlane.flip();
+        }
+        DrawableCuttingPlane cuttingPlane = new DrawableCuttingPlane(
+                new Plane(symmetryPlane), 
+                getCanvas().getPrimaryFace().getBoundingBox()
+        );
         cuttingPlane.setTransparency(0.5f);
-        if (priCuttingPlaneIndex == -1) {
-            priCuttingPlaneIndex = getCanvas().getScene().getFreeSlotForOtherDrawables();
+        if (priCuttingPlaneSlot == -1) {
+            priCuttingPlaneSlot = getCanvas().getScene().getFreeSlotForOtherDrawables();
         }
-        getCanvas().getScene().setOtherDrawable(priCuttingPlaneIndex, cuttingPlane);
+        getCanvas().getScene().setOtherDrawable(priCuttingPlaneSlot, cuttingPlane);
         recomputePrimaryProfile();
         
-        if (getSecondaryDrawableFace() != null) {
-            cuttingPlane = getCuttingPlaneFromSymmetry(getCanvas().getSecondaryFaceIndex());
+        if (getCanvas().getSecondaryFace() != null) {
+            symmetryPlane = getCanvas().getSecondaryFace().getSymmetryPlane();
+            if (symmetryPlane.getNormal().x < 0) { // orient to the right-hand direction
+               symmetryPlane = symmetryPlane.flip();
+            }
+            cuttingPlane = new DrawableCuttingPlane(
+                    new Plane(symmetryPlane), 
+                    getCanvas().getSecondaryFace().getBoundingBox()
+            );
             cuttingPlane.setTransparency(0.5f);
-            if (secCuttingPlaneIndex == -1) {
-                secCuttingPlaneIndex = getCanvas().getScene().getFreeSlotForOtherDrawables();
+            if (secCuttingPlaneSlot == -1) {
+                secCuttingPlaneSlot = getCanvas().getScene().getFreeSlotForOtherDrawables();
             }
-            getCanvas().getScene().setOtherDrawable(secCuttingPlaneIndex, cuttingPlane);
+            getCanvas().getScene().setOtherDrawable(secCuttingPlaneSlot, cuttingPlane);
             recomputeSecondaryProfile();
         }
         cuttingPlaneFromSymmetry = true;
@@ -367,13 +350,34 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
     }
     
     protected void showCuttingPlanes(boolean show, boolean showMirrors) {
-        if (getDrawableCuttingPlane(priCuttingPlaneIndex) != null) {
-            getDrawableCuttingPlane(priCuttingPlaneIndex).show(show);
-            getDrawableCuttingPlane(priCuttingPlaneIndex).showMirrorPlane(showMirrors);
+        if (getDrawableCuttingPlane(priCuttingPlaneSlot) != null) {
+            getDrawableCuttingPlane(priCuttingPlaneSlot).show(show);
+            getDrawableCuttingPlane(priCuttingPlaneSlot).showMirrorPlane(showMirrors);
         }
-        if (getDrawableCuttingPlane(secCuttingPlaneIndex) != null) {
-            getDrawableCuttingPlane(secCuttingPlaneIndex).show(show);
-            getDrawableCuttingPlane(secCuttingPlaneIndex).showMirrorPlane(showMirrors);
+        if (getDrawableCuttingPlane(secCuttingPlaneSlot) != null) {
+            getDrawableCuttingPlane(secCuttingPlaneSlot).show(show);
+            getDrawableCuttingPlane(secCuttingPlaneSlot).showMirrorPlane(showMirrors);
         }
     }
+    
+    protected double maxExtentX() {
+        double max = Double.NEGATIVE_INFINITY;
+        
+        double planeX = getDrawableCuttingPlane(priCuttingPlaneSlot).getNonShiftedPlane().getPlanePoint().x;
+        double bboxX = getCanvas().getPrimaryFace().getBoundingBox().getMaxPoint().x;
+        max = Math.max(max, Math.abs(bboxX - planeX));
+        bboxX = getCanvas().getPrimaryFace().getBoundingBox().getMinPoint().x;
+        max = Math.max(max, Math.abs(bboxX - planeX));
+        
+        if (getCanvas().getSecondaryFace() != null) {
+            planeX = getDrawableCuttingPlane(secCuttingPlaneSlot).getNonShiftedPlane().getPlanePoint().x;
+            bboxX = getCanvas().getSecondaryFace().getBoundingBox().getMaxPoint().x;
+            max = Math.max(max, Math.abs(bboxX - planeX));
+            bboxX = getCanvas().getSecondaryFace().getBoundingBox().getMinPoint().x;
+            max = Math.max(max, Math.abs(bboxX - planeX));
+        }
+        
+        return max;
+    }
+            
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.form b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.form
index affc6fe65a3789e7d85801ca7c22cd486426aff0..652258b3a0b315ab88eb05e8c1852e0c7dbcb788 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.form
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.form
@@ -20,7 +20,7 @@
               <EmptySpace max="-2" attributes="0"/>
               <Group type="103" groupAlignment="1" max="-2" attributes="0">
                   <Component id="jPanel1" max="32767" attributes="0"/>
-                  <Component id="polylinePanel1" max="32767" attributes="0"/>
+                  <Component id="polylinePanel1" pref="500" max="32767" attributes="0"/>
               </Group>
               <EmptySpace max="32767" attributes="0"/>
           </Group>
@@ -132,7 +132,7 @@
         </DimensionLayout>
         <DimensionLayout dim="1">
           <Group type="103" groupAlignment="0" attributes="0">
-              <EmptySpace min="0" pref="498" max="32767" attributes="0"/>
+              <EmptySpace min="0" pref="398" max="32767" attributes="0"/>
           </Group>
         </DimensionLayout>
       </Layout>
diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java
index e9ac0b558c5e1574433758cc35be0720d0325f52..347c46eaba2516164c99e4919de0baa7b976029d 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java
@@ -21,7 +21,7 @@ public class ProfilesPanel extends ControlPanel {
      * Handled actions
      */
     public static final String ACTION_COMMAND_EXPORT = "export";
-    public static final String ACTION_OFFSET_CUTTING_PLANE = "offset plane";
+    public static final String ACTION_SHIFT_CUTTING_PLANE = "shift plane";
     public static final String ACTION_MIRROR_CUTS = "mirror-cuts";
     public static final String ACTION_CHANGE_CUTTING_PLANE = "change cutting plane";
     
@@ -60,7 +60,7 @@ public class ProfilesPanel extends ControlPanel {
         
         comboSliderDouble1.setRange(0, 1, 2);
         comboSliderDouble1.setValue(0.5);
-        comboSliderDouble1.addListener(createListener(action, ACTION_OFFSET_CUTTING_PLANE));
+        comboSliderDouble1.addListener(createListener(action, ACTION_SHIFT_CUTTING_PLANE));
         jCheckBox1.addActionListener(createListener(action, ACTION_MIRROR_CUTS));
         jButton1.addActionListener(createListener(action, ACTION_COMMAND_EXPORT));
         
diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryAction.java b/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryAction.java
index a044a14be0706fc051a44783b15ce129e8f336fe..c6a46ba130367314824d83d8196a13326796ea20 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryAction.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryAction.java
@@ -6,7 +6,6 @@ import cz.fidentis.analyst.core.ControlPanelAction;
 import cz.fidentis.analyst.face.HumanFace;
 import cz.fidentis.analyst.face.events.HumanFaceEvent;
 import cz.fidentis.analyst.face.events.HumanFaceListener;
-import cz.fidentis.analyst.face.events.MeshChangedEvent;
 import cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent;
 import cz.fidentis.analyst.feature.FeaturePoint;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
@@ -54,6 +53,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
 
         // Place control panel to the topControlPanel
         this.topControlPanel.addTab(controlPanel.getName(), controlPanel.getIcon(), controlPanel);
+        /*
         this.topControlPanel.addChangeListener(e -> {
             // If the symmetry panel is focused...
             if (((JTabbedPane) e.getSource()).getSelectedComponent() instanceof SymmetryPanel) {
@@ -65,6 +65,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
                 getCanvas().getScene().showSymmetryPlane(getCanvas().getScene().getSecondaryFaceSlot(), false);
             }
         });
+        */
 
         // Be informed about changes in faces perfomed by other GUI elements
         getPrimaryDrawableFace().getHumanFace().registerListener(this);
@@ -96,6 +97,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
     
     @Override
     public void acceptEvent(HumanFaceEvent event) {
+        /* symmetry plane is transformed together with the mesh
         if (event instanceof MeshChangedEvent) { // recompute symmetry plane, if necessary
             switch (sPlane) {
                 case 0: // none
@@ -113,6 +115,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
                 default:
             }
         }
+        */
         if (event instanceof SymmetryPlaneChangedEvent) {
             updatePrecision(event.getFace());
         }
@@ -127,6 +130,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
             face.setSymmetryPlane(estimator.getSymmetryPlane());
             log.printDuration("Symmetry plane estimation from mesh for " + face.getShortName());
             setDrawablePlane(face, index);
+            face.announceEvent(new SymmetryPlaneChangedEvent(face, "", this));
         }
     }
     
@@ -169,6 +173,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
         
         face.setSymmetryPlane(new Plane(planes)); // creates an average plane
         setDrawablePlane(face, index);
+        face.announceEvent(new SymmetryPlaneChangedEvent(face, "", this));
     }
     
     protected void setDrawablePlane(HumanFace face, int index) {
@@ -186,7 +191,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
         
         MeshModel clone = new MeshModel(face.getMeshModel());
         
-        for (MeshFacet facet: clone.getFacets()) {
+        for (MeshFacet facet: clone.getFacets()) { // invert mesh
             facet.getVertices().parallelStream().forEach(v -> {
                 v.getPosition().set(face.getSymmetryPlane().reflectOverPlane(v.getPosition()));
             });
@@ -196,9 +201,9 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
         HausdorffDistance visitor = new HausdorffDistance(
                 face.getKdTree(), 
                 Strategy.POINT_TO_POINT_DISTANCE_ONLY, 
-                false, 
-                true,
-                false
+                false, // relative
+                true, // parallel
+                false // crop
         );
         clone.compute(visitor);
         controlPanel.updateHausdorffDistanceStats(visitor.getStats(), getCanvas().getHumanFace(0) == face);
diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityApproxHausdorff.java b/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityApproxHausdorff.java
deleted file mode 100644
index 7cc8988b4220d79f87e5aed318cecbd92856f6d2..0000000000000000000000000000000000000000
--- a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityApproxHausdorff.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package cz.fidentis.analyst.tests;
-
-import cz.fidentis.analyst.face.HumanFace;
-import cz.fidentis.analyst.icp.IcpTransformer;
-import cz.fidentis.analyst.icp.NoUndersampling;
-import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.DoubleSummaryStatistics;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * A class for testing the efficiency of batch processing algorithms.
- * The goal of this tool is to measure time and precision of 
- * approximated Hausdorff distance (HD). 
- * 
- * - First, HD of the first face (primary face) with other faces is computed
- *   - Each secondary face is superimposed using ICP
- *   - Then it is stored in k-d tree 
- *   - Relative (!) HD from the primary to secondary face is computed and stored.
- *     The order cannot be reverted because we need HD matrices of the same size.
- *   - TODO: First face should be replaced with average face
- * - Then, the mutual distances are approximated:
- *   - For each pair of faces A and B, the distance is computed as the difference 
- *     between distances A-P and B-P, where P is the primary face.
- * 
- * @author Radek Oslejsek
- */
-public class BatchSimilarityApproxHausdorff {
-    private static final String DATA_DIR = "../../analyst-data-antropologie/_ECA";
-    private static final String OUTPUT_FILE = "../../SIMILARITY_APPROX_HAUSDORFF.csv";
-    
-    /**
-     * Main method 
-     * @param args Input arguments 
-     * @throws IOException on IO error
-     */
-    public static void main(String[] args) throws IOException, ClassNotFoundException, Exception {
-        List<Path> faces = Files.list(new File(DATA_DIR).toPath())
-                .filter(f -> f.toString().endsWith(".obj"))
-                .sorted()
-                .limit(100)
-                .collect(Collectors.toList());
-        
-        
-        Map<Integer, List<Double>> distances = new HashMap<>();
-        
-        for (int i = 1; i < faces.size(); i++) {
-            HumanFace priFace = new HumanFace(faces.get(0).toFile());
-            HumanFace secFace = new HumanFace(faces.get(i).toFile());
-            
-            secFace.computeKdTree(false);
-            
-            System.out.println(i + "/" + (faces.size()-1) + " (" + priFace.getShortName() + "/" + secFace.getShortName() + ")");
-            
-            IcpTransformer icp = new IcpTransformer(priFace.getMeshModel(), 50, true, 0.3, new NoUndersampling());
-            secFace.getMeshModel().compute(icp, true);
-            
-            HausdorffDistance hd = new HausdorffDistance(secFace.getKdTree(), HausdorffDistance.Strategy.POINT_TO_POINT, true, true, true);
-            priFace.getMeshModel().compute(hd, true);
-            
-            //System.out.println(hd.getDistances().get(priFace.getMeshModel().getFacets().get(0)).size());
-            distances.put(i, hd.getDistances().get(priFace.getMeshModel().getFacets().get(0)));
-        }
-        
-        BufferedWriter bfw = new BufferedWriter(new FileWriter(OUTPUT_FILE));
-        bfw.write("PRI FACE;SEC FACE;MIN;MAX;AVG");
-        bfw.newLine();
-        
-        for (int i = 0; i < faces.size(); i++) {
-            for (int j = 0; j < faces.size(); j++) {
-                if (i == j) {
-                    continue;
-                }
-                
-                DoubleSummaryStatistics stats;
-                if (i == 0 || j == 0) {
-                    stats = getStats(distances.get((i == 0) ? j : i));
-                } else {
-                    stats = getStats(distances.get(i), distances.get(j));
-                }
-                
-                bfw.write(getShortName(faces.get(i).toFile())+";");
-                bfw.write(getShortName(faces.get(j).toFile())+";");
-                if (stats != null) {
-                    bfw.write(String.format("%.20f", stats.getMin())+";");
-                    bfw.write(String.format("%.20f", stats.getMax())+";");
-                    bfw.write(String.format("%.20f", stats.getAverage())+"");
-                    bfw.newLine();
-                } else {
-                    bfw.write(String.format("%.20f", Double.NaN)+";");
-                    bfw.write(String.format("%.20f", Double.NaN)+";");
-                    bfw.write(String.format("%.20f", Double.NaN)+"");
-                    bfw.newLine();
-                }
-                bfw.flush();
-            }
-        }
-        
-        bfw.close(); 
-        
-    }    
-
-    private static DoubleSummaryStatistics getStats(List<Double> d1, List<Double> d2) {
-        if (d1.size() != d2.size()) {
-            return null;
-        }
-        
-        List<Double> ret = new ArrayList<>(d1.size());
-        for (int i = 0; i < d1.size(); i++) {
-            ret.add(Math.abs(d2.get(i) - d1.get(i)));
-        }
-        
-        return ret.stream()
-                .mapToDouble(Double::doubleValue)
-                .summaryStatistics();
-    }
-    
-    private static DoubleSummaryStatistics getStats(List<Double> d1) {
-        List<Double> ret = new ArrayList<>(d1.size());
-        for (int i = 0; i < d1.size(); i++) {
-            ret.add(Math.abs(d1.get(i)));
-        }
-        
-        return d1.stream()
-                .mapToDouble(v -> Math.abs(v))
-                .summaryStatistics();
-    }
-    
-    private static String getShortName(File file) throws IOException {
-        String id = file.getCanonicalPath();
-        String name = id.substring(0, id.lastIndexOf('.')); // remove extention
-        name = name.substring(id.lastIndexOf('/')+1, name.length());
-        name = name.substring(name.lastIndexOf(File.separatorChar) + 1, name.length());
-        return name;
-    }
-}
diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruth.java b/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruth.java
index d6c43c62d5431ca7486f4d681f20e64a746154c9..f8dd484f18afa4150e29d19b38f4e45efe3f5376 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruth.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruth.java
@@ -1,10 +1,8 @@
 package cz.fidentis.analyst.tests;
 
 import cz.fidentis.analyst.face.HumanFace;
-import cz.fidentis.analyst.icp.IcpTransformer;
-import cz.fidentis.analyst.icp.NoUndersampling;
+import cz.fidentis.analyst.face.HumanFaceUtils;
 import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
-import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy;
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileWriter;
@@ -77,22 +75,41 @@ public class BatchSimilarityGroundTruth {
                 // transform secondary face
                 if (i != j) { // register only different faces
                     long icpTime = System.currentTimeMillis();
-                    IcpTransformer icp = new IcpTransformer(priFace.getMeshModel(), 100, false, 0.3, new NoUndersampling());
-                    secFace.getMeshModel().compute(icp, true);
+                    HumanFaceUtils.alignMeshes(
+                            priFace,
+                            secFace, // is transformed
+                            100,  // max iterations
+                            false,// scale
+                            0.3,  // error
+                            100,  // no undersampling
+                            false // drop k-d tree, if exists
+                    );
                     icpComputationTime += System.currentTimeMillis() - icpTime;
                 }
                 
                 long hdTime = System.currentTimeMillis();
                 // compute HD from secondary to primary:
-                priFace.computeKdTree(true);
-                HausdorffDistance hd = new HausdorffDistance(priFace.getKdTree(), Strategy.POINT_TO_POINT, false, true, CROP_HD);
-                secFace.getMeshModel().compute(hd, true);
+                HausdorffDistance hd = new HausdorffDistance(
+                        priFace.getKdTree(), 
+                        HausdorffDistance.Strategy.POINT_TO_POINT,
+                        false,  // relative distance
+                        true,   // parallel
+                        CROP_HD // crop
+                );
+                secFace.getMeshModel().compute(hd);
                 distances[j][i] = hd.getStats().getAverage();
+
                 // compute HD from primary to secondary:
-                secFace.computeKdTree(true);
-                hd = new HausdorffDistance(secFace.getKdTree(), Strategy.POINT_TO_POINT, false, true, CROP_HD);
-                priFace.getMeshModel().compute(hd, true);
+                hd = new HausdorffDistance(
+                        secFace.getKdTree(), 
+                        HausdorffDistance.Strategy.POINT_TO_POINT,
+                        false,  // relative distance
+                        true,   // parallel
+                        CROP_HD // crop
+                );
+                priFace.getMeshModel().compute(hd);
                 distances[i][j] = hd.getStats().getAverage();
+
                 hdComputationTime += System.currentTimeMillis() - hdTime;
             }
         }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruthOpt.java b/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruthOpt.java
deleted file mode 100644
index c28f38325a3815be14911607a1c19af86a2e3c10..0000000000000000000000000000000000000000
--- a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruthOpt.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package cz.fidentis.analyst.tests;
-
-import cz.fidentis.analyst.visitors.kdtree.AvgFaceConstructor;
-import cz.fidentis.analyst.face.HumanFace;
-import cz.fidentis.analyst.face.HumanFaceFactory;
-import cz.fidentis.analyst.icp.IcpTransformer;
-import cz.fidentis.analyst.icp.NoUndersampling;
-import cz.fidentis.analyst.mesh.io.MeshObjExporter;
-import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
-import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.time.Duration;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * A class for testing the efficiency of batch processing algorithms.
- * It works in the same way as {@link BatchSimilarityGroundTruth} with the following changes:
- * <ul>
- * <li>All faces are transformed (ICP) to the very first face of the collection. They are not transformed mutually.
- *   It enables us to compute ICP only once for every face, but with possible loss of precision.
- *   Moreover, {@code HumanFaceFactory} is used to quickly load/swap faces when used multiple times.</li>
- * </ul>
- * Stats for 100 faces WITH CROP:
- * <pre>
- * Time of AVG face computation time: 00:00:19,529
- * ICP computation time: 00:05:19,096
- * HD computation time: 03:17:29,446
- * Total computation time: 03:32:30,671
- * </pre>
- * Stats for 100 faces WITHOUT CROP:
- * <pre>
- * Time of AVG face computation time: 00:00:19,386
- * ICP computation time: 00:05:39,318
- * HD computation time: 03:11:49,226
- * Total computation time: 03:25:50,957
- * </pre>
- * 
- * @author Radek Oslejsek
- */
-public class BatchSimilarityGroundTruthOpt {
-    
-    private static final String DATA_DIR = "../../analyst-data-antropologie/_ECA";
-    private static final String OUTPUT_FILE = "../../SIMILARITY_GROUND_TRUTH_OPT.csv";
-    private static final String TEMPLATE_FACE_PATH = "../../analyst-data-antropologie/template_face.obj";
-    private static final int MAX_SAMPLES = 100;
-    private static final boolean CROP_HD = false;
-    
-    /**
-     * Main method 
-     * @param args Input arguments 
-     * @throws IOException on IO error
-     */
-    public static void main(String[] args) throws IOException, ClassNotFoundException, Exception {
-        List<Path> faces = Files.list(new File(DATA_DIR).toPath())
-                .filter(f -> f.toString().endsWith(".obj"))
-                .sorted()
-                .limit(MAX_SAMPLES)
-                .collect(Collectors.toList());
-        
-        double[][] distances = new double[faces.size()][faces.size()];
-        String[] names = new String[faces.size()];
-        
-        long totalTime = System.currentTimeMillis();
-        long avgFaceComputationTime = 0;
-        long icpComputationTime = 0;
-        long hdComputationTime = 0;
-        
-        AvgFaceConstructor avgFaceConstructor = new AvgFaceConstructor(new HumanFace(faces.get(0).toFile()).getMeshModel());
-        
-        HumanFaceFactory factory = new HumanFaceFactory();
-        factory.setReuseDumpFile(true);
-        factory.setStrategy(HumanFaceFactory.Strategy.MRU);
-        
-        int counter = 0;
-        for (int i = 0; i < faces.size(); i++) {
-            String priFaceId = factory.loadFace(faces.get(i).toFile());
-            HumanFace priFace = factory.getFace(priFaceId);
-            names[i] = priFace.getShortName().replaceAll("_01_ECA", "");
-            
-            for (int j = i; j < faces.size(); j++) { // starts with "i"!
-                priFace = factory.getFace(priFaceId); // re-read if dumped, at leat update the access time
-                
-                String secFaceId = factory.loadFace(faces.get(j).toFile());
-                HumanFace secFace = factory.getFace(secFaceId);
-                
-                System.out.print(++counter + ": " + priFace.getShortName() + " - " + secFace.getShortName());
-                
-                // transform secondary face, but only once. Transformed faces are stored in the HumanFaceFactory! Don't transform the same face
-                if (i == 0 && i != j) { 
-                    System.out.print(", ICP");
-                    long icpTime = System.currentTimeMillis();
-                    IcpTransformer icp = new IcpTransformer(priFace.getMeshModel(), 100, true, 0.3, new NoUndersampling());
-                    secFace.getMeshModel().compute(icp, true);
-                    icpComputationTime += System.currentTimeMillis() - icpTime;
-                }
-                
-                long hdTime = System.currentTimeMillis();
-                // compute HD from secondary to primary:
-                priFace.computeKdTree(true);
-                HausdorffDistance hd = new HausdorffDistance(priFace.getKdTree(), Strategy.POINT_TO_POINT, false, true, CROP_HD);
-                secFace.getMeshModel().compute(hd, true);
-                distances[j][i] = hd.getStats().getAverage();
-                // compute HD from primary to secondary:
-                secFace.computeKdTree(true);
-                hd = new HausdorffDistance(secFace.getKdTree(), Strategy.POINT_TO_POINT, false, true, CROP_HD);
-                priFace.getMeshModel().compute(hd, true);
-                distances[i][j] = hd.getStats().getAverage();
-                hdComputationTime += System.currentTimeMillis() - hdTime;
-                
-                // Compute AVG face. Use each tranfromed face only once. Skip the very first face
-                if (i == 0 && j != 0) { 
-                    System.out.print(", AVG");
-                    long avgFaceTime = System.currentTimeMillis();
-                    priFace.getKdTree().accept(avgFaceConstructor);
-                    avgFaceComputationTime += System.currentTimeMillis() - avgFaceTime;
-                }
-                
-                System.out.println(", " + factory.toString());
-            }
-            
-            factory.removeFace(priFaceId); // the face is no longer needed
-        }
-        
-        MeshObjExporter exp = new MeshObjExporter(avgFaceConstructor.getAveragedMeshModel());
-        exp.exportModelToObj(new File(TEMPLATE_FACE_PATH));
-        
-        BufferedWriter w = new BufferedWriter(new FileWriter(OUTPUT_FILE));
-        w.write("PRI FACE;SEC FACE;AVG HD from PRI to SEC;AVG HD from SEC to PRI");
-        w.newLine();
-        for (int i = 0; i < faces.size(); i++) {
-            for (int j = i; j < faces.size(); j++) {
-                w.write(names[i] + ";");
-                w.write(names[j] + ";");
-                w.write(String.format("%.8f", distances[i][j]) + ";");
-                w.write(String.format("%.8f", distances[j][i]) + ";");
-                if (distances[i][j] > distances[j][i]) {
-                    w.write(String.format("%.8f", distances[i][j]) + ";");
-                    w.write(String.format("%.8f", distances[j][i]) + "");
-                } else {
-                    w.write(String.format("%.8f", distances[j][i]) + ";");
-                    w.write(String.format("%.8f", distances[i][j]) + "");
-                }
-                w.newLine();
-            }
-        }
-        w.close();
-        
-        System.out.println();
-        Duration duration = Duration.ofMillis(avgFaceComputationTime);
-        System.out.println("Time of AVG face computation time: " + 
-                String.format("%02d:%02d:%02d,%03d", duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(), duration.toMillisPart()));
-        duration = Duration.ofMillis(icpComputationTime);
-        System.out.println("ICP computation time: " + 
-                String.format("%02d:%02d:%02d,%03d", duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(), duration.toMillisPart()));
-        duration = Duration.ofMillis(hdComputationTime);
-        System.out.println("HD computation time: " + 
-                String.format("%02d:%02d:%02d,%03d", duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(), duration.toMillisPart()));
-        duration = Duration.ofMillis(System.currentTimeMillis() - totalTime);
-        System.out.println("Total computation time: " + 
-                String.format("%02d:%02d:%02d,%03d", duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(), duration.toMillisPart()));
-    }
-
-}
diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java b/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java
deleted file mode 100644
index 1de0990da9bbac754363edc8dcae0e3b62aa528d..0000000000000000000000000000000000000000
--- a/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java
+++ /dev/null
@@ -1,141 +0,0 @@
-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.SymmetryConfig;
-import cz.fidentis.analyst.symmetry.Plane;
-import cz.fidentis.analyst.symmetry.SymmetryEstimator;
-import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
-import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy;
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A class for testing the efficiency of algorithms.
- * 
- * @author Radek Oslejsek
- */
-public class EfficiencyTests {
-    
-    private static File girlFile = new File("src/test/resources/cz/fidentis/analyst/average_girl_17-20.obj");
-    private static File boyFile = new File("src/test/resources/cz/fidentis/analyst/average_boy_17-20.obj");
-    private static File faceFile2 = new File("src/test/resources/cz/fidentis/analyst/00002_01_ECA.obj");
-    private static File faceFile4 = new File("/home/oslejsek/GIT/HCI/analyst2/GUI/src/test/resources/cz/fidentis/analyst/00004_01_ECA.obj");
-    private static File basicFaceFile = new File("src/test/resources/cz/fidentis/analyst/basic-model-04.obj");
-    
-    private static HumanFace face1;
-    private static HumanFace face2;
-    
-    /**
-     * Main method 
-     * @param args Input arguments 
-     * @throws IOException on IO error
-     */
-    public static void main(String[] args) throws IOException, ClassNotFoundException, Exception {
-        face1 = printFaceLoad(faceFile4);
-        face2 = printFaceLoad(faceFile2);
-        
-        face1.getMeshModel().simplifyModel();
-        face2.getMeshModel().simplifyModel();
-        
-        //for (int i = 0; i < 10; i++) {
-        //    printFaceDump(face1);
-        //}
-        
-        boolean relativeDist = false;
-        boolean printDetails = false;
-        
-        
-        //face1.getMeshModel().compute(new GaussianCurvature()); // initialize everything, then measure
-        
-        System.out.println("Symmetry plane calculation:");
-        //printSymmetryPlane(face1, true, CurvatureAlg.MEAN);
-        //printSymmetryPlane(face1, true, CurvatureAlg.GAUSSIAN);
-        //printSymmetryPlane(face1, false, CurvatureAlg.MEAN);
-        //printSymmetryPlane(face1, false, CurvatureAlg.GAUSSIAN);
-        
-        System.out.println();
-        System.out.println(measureKdTreeCreation(face1) + "\tmsec:\tKd-tree creation of first face");
-        System.out.println(measureKdTreeCreation(face2) + "\tmsec:\tKd-tree creation of second face");
-        
-        System.out.println();
-        System.out.println("Hausdorff distance sequentially:");
-        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT, relativeDist, false, false), printDetails);
-        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT_DISTANCE_ONLY, false, false, false), printDetails);
-        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT, relativeDist, false, false), printDetails);
-        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_TRIANGLE_APPROXIMATE, relativeDist, false, false), printDetails);
-
-        System.out.println();
-        System.out.println("Hausdorff distance concurrently:");
-        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT_DISTANCE_ONLY, false, true, false), printDetails);
-        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT, relativeDist, true, false), printDetails);
-        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_TRIANGLE_APPROXIMATE, relativeDist, true, false), printDetails);
-    }
-    
-    protected static void testAndPrint(HumanFace face, HausdorffDistance vis, boolean printDetails) {
-        long startTime = System.currentTimeMillis();
-        face.getMeshModel().compute(vis);
-        long endTime = System.currentTimeMillis();
-        
-        System.out.println(
-                (endTime-startTime) + 
-                "\tmsec: " + 
-                //"\t" + (vis.inParallel() ? "concurrently" : "sequentially") +
-                "\t" + (vis.relativeDistance()? "relative" : "absolute") +
-                "\t" + vis.getStrategy()
-        );
-        
-        if (printDetails) {
-            Map<MeshFacet, List<Double>> results = vis.getDistances();
-            for (MeshFacet facet: results.keySet()) {
-                System.out.println(results.get(facet));
-            }
-        }
-    }
-    
-    private static long measureKdTreeCreation(HumanFace face) {
-        long startTime = System.currentTimeMillis();
-        KdTree kdTree = new KdTree(face.getMeshModel().getFacets());
-        return System.currentTimeMillis() - startTime;
-    }
-    
-    private static void printSymmetryPlane(HumanFace face, boolean concurrently) {
-        long startTime = System.currentTimeMillis();
-        SymmetryEstimator est = new SymmetryEstimator(new SymmetryConfig());
-        face.getMeshModel().compute(est, false);
-        Plane plane = est.getSymmetryPlane(concurrently);
-        long endTime =  System.currentTimeMillis();
-        
-        System.out.println(
-                (endTime-startTime) + 
-                "\tmsec: " + 
-                "\t" + (concurrently ? "concurrently" : "sequentially") +
-//                "\t" + curvatureAlg + " curvature    " +
-                "\t" + plane.getNormal() + ", " + plane.getDistance()
-        );
-    }
-
-    private static void printFaceDump(HumanFace face) throws IOException, ClassNotFoundException, Exception {
-        long startTime = System.currentTimeMillis();
-        File file = face.dumpToFile();
-        long endTime =  System.currentTimeMillis();
-        System.out.println("Human face dumping:\t " +(endTime-startTime) + " msec");
-        
-        startTime = System.currentTimeMillis();
-        HumanFace f = HumanFace.restoreFromFile(file);
-        endTime =  System.currentTimeMillis();
-        System.out.println("Human face restore:\t " +(endTime-startTime) + " msec");
-    }
-    
-    private static HumanFace printFaceLoad(File file) throws IOException {
-        long startTime = System.currentTimeMillis();
-        HumanFace face = new HumanFace(file);
-        long endTime =  System.currentTimeMillis();
-        System.out.println("Human face loading:\t " +(endTime-startTime) + " msec");
-        return face;
-    }
-    
-}
diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/ICPTest.java b/GUI/src/main/java/cz/fidentis/analyst/tests/ICPTest.java
deleted file mode 100644
index 13fa88165cc21a36e28d0c07c150cf24cd2fb545..0000000000000000000000000000000000000000
--- a/GUI/src/main/java/cz/fidentis/analyst/tests/ICPTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package cz.fidentis.analyst.tests;
-
-import cz.fidentis.analyst.face.HumanFace;
-import cz.fidentis.analyst.icp.IcpTransformer;
-import cz.fidentis.analyst.icp.NoUndersampling;
-import cz.fidentis.analyst.kdtree.KdTree;
-import cz.fidentis.analyst.mesh.core.MeshFacet;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- *
- * @author Radek Oslejsek
- */
-public class ICPTest {
-    
-    private static final String DATA_DIR = "../../analyst-data/multi-scan-models-anonymized-fixed/";
-    
-    private static String[] faceFiles = new String[] {
-        DATA_DIR + "02/00002_01_ECA.obj",
-        DATA_DIR + "04/00004_01_ECA.obj",
-        DATA_DIR + "06/00006_01_ECA.obj",
-        DATA_DIR + "07/00007_01_ECA.obj",
-        DATA_DIR + "10/00010_01_ECA.obj"
-    };
-    
-    private static int tests = 0;
-    private static int iters = 0;
-    
-    /**
-     * 
-     * @param args
-     * @throws IOException 
-     */
-    public static void main(String[] args) throws IOException {
-        long time = 0;
-        for (int i = 0; i < faceFiles.length; i++) {
-            time += test(i);
-        }
-        System.out.println("tests: " + tests);
-        System.out.println("iters: " + iters);
-        System.out.println("time: " + time + " ms");
-        System.out.println("AVG iters: " + ((double)iters/tests));
-        System.out.println("AVG time: " + ((double)time/tests) + " ms");
-    }
-    
-    /**
-     * 
-     * @param index
-     * @return
-     * @throws IOException 
-     */
-    public static long test(int index) throws IOException {
-        List<HumanFace> faces = new ArrayList<>();
-        for (int i = 0; i < faceFiles.length; i++) {
-            faces.add(new HumanFace(new File(faceFiles[i])));
-        }
-        HumanFace prim = faces.remove(index);
-        KdTree primKdTree = prim.computeKdTree(true);
-        
-        
-        System.out.println();
-        System.out.println(prim.getId());            
-        long startTime = System.currentTimeMillis();
-        for (HumanFace sec: faces) {
-            tests++;
-            IcpTransformer icpTransformer = new IcpTransformer(primKdTree, 10, false, 0.05, new NoUndersampling());
-            System.out.println(sec.getId());
-            sec.getMeshModel().compute(icpTransformer);
-            
-            for (MeshFacet f: icpTransformer.getTransformations().keySet()) {
-                //System.out.println("AAA"+icpTransformer.getTransformations().get(f).size());
-                iters += icpTransformer.getTransformations().get(f).size();
-            }
-        }
-        long endTime = System.currentTimeMillis();
-        
-        return endTime - startTime;
-    }
-}
diff --git a/GUI/src/main/resources/cz/fidentis/analyst/canvas/toolbar/Bundle.properties b/GUI/src/main/resources/cz/fidentis/analyst/canvas/toolbar/Bundle.properties
index 2aebc13cd2c31cf89cc7ca01a38465004949e788..9ccc35ef4b090c148807585922f896f0b212f078 100644
--- a/GUI/src/main/resources/cz/fidentis/analyst/canvas/toolbar/Bundle.properties
+++ b/GUI/src/main/resources/cz/fidentis/analyst/canvas/toolbar/Bundle.properties
@@ -8,3 +8,4 @@ SceneToolboxSingleFace.landButton.tooltip=show-hide feature points
 SceneToolboxSingleFace.faceButton.tooltip=show-hide face
 SceneToolboxSingleFace.slider.tooltip=change face transparency
 SceneToolboxFaceToFace.distButton.tooltip=show-hide distance heatmap
+SceneToolboxFaceToFace.symmetryButton.tooltip=show-hide symmetry plane
diff --git a/GUI/src/main/resources/cz/fidentis/analyst/registration/Bundle.properties b/GUI/src/main/resources/cz/fidentis/analyst/registration/Bundle.properties
index c9ef96eb1e4e07bd7bb8813cd733d3b00561cf08..d966ae397d3f270a0cb9c713a30fb9e1f3bdbb2b 100644
--- a/GUI/src/main/resources/cz/fidentis/analyst/registration/Bundle.properties
+++ b/GUI/src/main/resources/cz/fidentis/analyst/registration/Bundle.properties
@@ -5,30 +5,15 @@ RegistrationPanel.jLabel5.text=min. error:
 RegistrationPanel.jFormattedTextField2.text=50
 RegistrationPanel.jLabel6.text=iterations:
 RegistrationPanel.jLabel7.text=scale:
-RegistrationPanel.jLabel8.text=undersampling:
+RegistrationPanel.jLabel8.text=undersampling (100% = none)
 RegistrationPanel.thersholdUpButton.text=
 RegistrationPanel.thresholdDownButton.text=
 RegistrationPanel.featurePointsLabel.text=Highlight feature point pairs closer than:
 2
-RegistrationPanel.translationButton.text=
 RegistrationPanel.translationPanel.border.title=translation
-RegistrationPanel.highShiftRB.toolTipText=set high shifting amount
-RegistrationPanel.highShiftRB.text=big
-RegistrationPanel.lowShiftRB.toolTipText=set low shifting amount
-RegistrationPanel.lowShiftRB.text=small
-RegistrationPanel.shiftLabel.toolTipText=transformation amount
-RegistrationPanel.shiftLabel.text=step:
-RegistrationPanel.applyButton.toolTipText=apply transformations
-RegistrationPanel.applyButton.text=Apply changes
-RegistrationPanel.resetAllButton.toolTipText=reset all transformations
-RegistrationPanel.resetAllButton.text=reset all
 RegistrationPanel.scaleMinusButton.text=
-RegistrationPanel.scaleButton.toolTipText=reset scale
-RegistrationPanel.scaleButton.text=
-RegistrationPanel.scaleFTF.toolTipText=
 RegistrationPanel.scalePlusButton.text=
 RegistrationPanel.scalePanel.border.title=scale
-RegistrationPanel.rotationXFTF.toolTipText=
 # To change this license header, choose License Headers in Project Properties.
 # To change this template file, choose Tools | Templates
 # and open the template in the editor.
@@ -36,8 +21,6 @@ RegistrationPanel.rightRotationXButton.text=
 RegistrationPanel.leftRotationZButton.text=
 RegistrationPanel.rightRotationYButton.text=
 RegistrationPanel.rightRotationZButton.text=
-RegistrationPanel.rotationButton.toolTipText=reset rotation
-RegistrationPanel.rotationButton.text=
 RegistrationPanel.rotatXLabel.text=x
 RegistrationPanel.rotatYLabel.text=y
 RegistrationPanel.rotatZLabel.text=z
@@ -52,9 +35,7 @@ RegistrationPanel.translZLabel.text=front-back
 RegistrationPanel.translXLabel.text=horizontal
 RegistrationPanel.rightTranslationYButton.text=
 RegistrationPanel.leftTranslationYButton.text=
-RegistrationPanel.translationXFTF.toolTipText=
 RegistrationPanel.rightTranslationXButton.text=
-RegistrationPanel.translationButton.toolTipText=reset translation
 RegistrationPanel.jButton2.text=Apply
 RegistrationPanel.jButton1.toolTipText=Apply ICP
 RegistrationPanel.jButton2.toolTipText=Apply Procrustes
@@ -62,7 +43,7 @@ RegistrationPanel.jLabel4.text=scale:
 RegistrationPanel.jCheckBox2.text=
 RegistrationPanel.jPanel7.border.title=Feature points alignment (Procrustes):
 RegistrationPanel.jPanel1.border.title=Mesh alignment (ICP):
-RegistrationPanel.transformationPanel.border.title=Fine-tuning the mutual position:
+RegistrationPanel.transformationPanel.border.title=Manual alignment:
 RegistrationPanel.jPanel4.border.title=View:
 RegistrationPanel.jLabel1.text=Hausdorff distance:
 RegistrationPanel.jPanel2.border.title=Measurements:
@@ -72,3 +53,4 @@ RegistrationPanel.jTextField1.text=
 BatchRegistrationPanel.jPanel2.border.title=Dataset
 BatchRegistrationPanel.jCheckBox1.text=compute average face from
 BatchRegistrationPanel.jPanel3.border.title=Similarity
+RegistrationPanel.jButton3.text=Aling symmetry planes
diff --git a/GUI/src/main/resources/na.png b/GUI/src/main/resources/na.png
new file mode 100644
index 0000000000000000000000000000000000000000..d1ea8cf0ab404a5ee1ea10a211027d143e64f677
Binary files /dev/null and b/GUI/src/main/resources/na.png differ
diff --git a/GUI/src/main/resources/na28x28.png b/GUI/src/main/resources/na28x28.png
new file mode 100644
index 0000000000000000000000000000000000000000..07fac02a43b648c2960bc751dbe07ff7737fb97c
Binary files /dev/null and b/GUI/src/main/resources/na28x28.png differ
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacet.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacet.java
index c9f81ed95121b9b5467257d6c989d758646689b8..d590c86f451dd9bc35cdafee9ada1bdbc3f18a54 100644
--- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacet.java
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacet.java
@@ -67,7 +67,7 @@ public interface MeshFacet extends Iterable<MeshTriangle>, Serializable {
      * @return number of triangles
      */
     int getNumTriangles();
-    
+
     /**
      * Return triangle instances. The order corresponds with with the corner
      * table, i.e., the i-th returned triangle corresponds to i-th triangle in 
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java
index baaddfb488f472cdb29cbd4cab3a27a67d74805c..bb0e75f75e5d1293dab21729a5f03ba41eb76120 100644
--- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java
@@ -428,7 +428,7 @@ public class MeshTriangle implements Iterable<MeshPoint> {
      *
      * @param point   vertex from which the projection is created
      * @return projection to plane of triangle
-     * @throws {@code NullPointerException} if the point is {@code null}
+     * @throws NullPointerException if the point is {@code null}
      */
     protected Point3d getProjectionToTrianglePlane(Point3d point) {
         Vector3d normal = computeNormal();
@@ -559,10 +559,10 @@ public class MeshTriangle implements Iterable<MeshPoint> {
      * @return true if the triangle is intersected by the plane
      */
     public boolean checkIntersectionWithPlane(Vector3d normal, double d) {
-        double p1 = (normal.x * getVertex1().x) + (normal.y * getVertex1().y) + (normal.z * getVertex1().z) + d;
-        double p2 = (normal.x * getVertex2().x) + (normal.y * getVertex2().y) + (normal.z * getVertex2().z) + d;
-        double p3 = (normal.x * getVertex3().x) + (normal.y * getVertex3().y) + (normal.z * getVertex3().z) + d;
-
+        double p1 = (normal.x * getVertex1().x) + (normal.y * getVertex1().y) + (normal.z * getVertex1().z) - d;
+        double p2 = (normal.x * getVertex2().x) + (normal.y * getVertex2().y) + (normal.z * getVertex2().z) - d;
+        double p3 = (normal.x * getVertex3().x) + (normal.y * getVertex3().y) + (normal.z * getVertex3().z) - d;
+        
         //If one point is on one side of the plane and the other on the other side
         return ((p1 <= 0 || p2 <= 0 || p3 <= 0) && (p1 >= 0 || p2 >= 0 || p3 >= 0));
     }
diff --git a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/core/MeshTriangleTest.java b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/core/MeshTriangleTest.java
index b7e2b12b983636ed9e84d2f7a8024ec6cea70230..65eba7e832f1d52b2a8344bd2922bbc03c8d79bd 100644
--- a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/core/MeshTriangleTest.java
+++ b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/core/MeshTriangleTest.java
@@ -23,22 +23,25 @@ public class MeshTriangleTest {
         );
         return triangle;
     }
+    */
     
     @Test
     public void getClosestPointTest() {
-        MeshTriangle tri = new MeshTriangle(
-                new MeshPointImpl(new Vector3d(1, 0, 0), null, null),
-                new MeshPointImpl(new Vector3d(1, 2, 0), null, null),
-                new MeshPointImpl(new Vector3d(2, 0, 0), null, null),
-                0, 1, 2
-        );
-        Assertions.assertEquals(new Vector3d(1, 0, 0), tri.getClosestPoint(new Vector3d(0, 0, 0)));
-        Assertions.assertEquals(new Vector3d(1, 1, 0), tri.getClosestPoint(new Vector3d(0, 1, 0)));
-        Assertions.assertEquals(new Vector3d(1, 2, 0), tri.getClosestPoint(new Vector3d(0, 3, 0)));
-        Assertions.assertEquals(new Vector3d(1, 0, 0), tri.getClosestPoint(new Vector3d(1, 0, -1)));
-        Assertions.assertEquals(new Vector3d(1.2, 0.2, 0), tri.getClosestPoint(new Vector3d(1.2, 0.2, -1)));
+        MeshFacet facet = createFacet();
+        MeshTriangle tri = new MeshTriangle(facet, 0, 1, 2);
+        
+        Assertions.assertEquals(new Point3d(0.25, 0.25, 0), tri.getClosestPoint(new Point3d(0, 0.5, -1)));
+        Assertions.assertEquals(new Point3d(0.25, 0.25, 0), tri.getClosestPoint(new Point3d(0, 0.5,  0)));
+        Assertions.assertEquals(new Point3d(0.25, 0.25, 0), tri.getClosestPoint(new Point3d(0, 0.5,  1)));
+
+        Assertions.assertEquals(new Point3d(1, 1, 0), tri.getClosestPoint(new Point3d(1, 1, -1)));
+        Assertions.assertEquals(new Point3d(1, 1, 0), tri.getClosestPoint(new Point3d(1, 1,  0)));
+        Assertions.assertEquals(new Point3d(1, 1, 0), tri.getClosestPoint(new Point3d(1, 1,  1)));
+        
+        Assertions.assertEquals(new Point3d(0.7, 0.7, 0), tri.getClosestPoint(new Point3d(0.7, 0.7, -1)));
+        Assertions.assertEquals(new Point3d(0.7, 0.7, 0), tri.getClosestPoint(new Point3d(0.7, 0.7,  0)));
+        Assertions.assertEquals(new Point3d(0.7, 0.7, 0), tri.getClosestPoint(new Point3d(0.7, 0.7,  1)));
     }
-    */
 
     private MeshFacet createFacet() {
         MeshFacet facet = new MeshFacetImpl();
@@ -114,8 +117,8 @@ public class MeshTriangleTest {
         MeshFacet facet = createFacet();
 
         Vector3d normal = new Vector3d(1, 0, 0);
-        double d1 = -1;
-        double d2 = -0.5;
+        double d1 = 1;
+        double d2 = 0.5;
 
         MeshTriangle tri1 = new MeshTriangle(facet, 0, 1, 2);
         MeshTriangle tri2 = new MeshTriangle(facet, 1, 2, 3);
@@ -131,5 +134,12 @@ public class MeshTriangleTest {
         Assertions.assertFalse(tri2.checkIntersectionWithPlane(normal, d2));
         Assertions.assertFalse(tri3.checkIntersectionWithPlane(normal, d2));
         Assertions.assertFalse(tri4.checkIntersectionWithPlane(normal, d2));
+        
+        Vector3d n2 = new Vector3d(-1, -1, 0);
+        n2.normalize();
+        Assertions.assertTrue(tri1.checkIntersectionWithPlane(n2, -0.5));
+        Assertions.assertFalse(tri2.checkIntersectionWithPlane(n2, -0.5));
+        Assertions.assertFalse(tri3.checkIntersectionWithPlane(n2, -0.5));
+        Assertions.assertFalse(tri4.checkIntersectionWithPlane(n2, -0.5));
     }
 }