diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java
index 27d4396722094d37c5a4fcfce3ca00863b7789ac..3c91d5b5524ed0554cb6874e52b9a99e4fadcb29 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java
@@ -319,9 +319,9 @@ public class HumanFaceUtils {
         }
 
         point.set(
-                (rotQuat.x + translation.x) * scale,
-                (rotQuat.y + translation.y) * scale,
-                (rotQuat.z + translation.z) * scale
+                rotQuat.x * scale + translation.x,
+                rotQuat.y * scale + translation.y,
+                rotQuat.z * scale + translation.z
         );
     }
 
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 363ee1e8b7666b1fffcd1cf8def6965f391d20f7..cc7386c20b2f462ce7f369ebb92bfdfe70af0abd 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformation.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformation.java
@@ -82,9 +82,9 @@ public class IcpTransformation {
         
         if(scale && !Double.isNaN(getScaleFactor())) {
             return new Point3d(
-                    (rotQuat.x + getTranslation().x) * getScaleFactor(),
-                    (rotQuat.y + getTranslation().y) * getScaleFactor(),
-                    (rotQuat.z + getTranslation().z) * getScaleFactor()
+                    rotQuat.x * getScaleFactor() + getTranslation().x,
+                    rotQuat.y * getScaleFactor() + getTranslation().y,
+                    rotQuat.z * getScaleFactor() + getTranslation().z
             );
         } 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 5c47b7e9700ba9317bcb13a7e5bc8dbd81a1dbbc..345c62e138d4bde06ccadbb97b1d1eaae3a4c860 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java
@@ -17,7 +17,10 @@ import java.util.Objects;
 import java.util.Set;
 import javax.vecmath.Matrix4d;
 import javax.vecmath.Point3d;
+import javax.vecmath.Tuple3d;
+import javax.vecmath.Tuple4d;
 import javax.vecmath.Vector3d;
+import javax.vecmath.Vector4d;
 
 /**
  * Visitor applying the Iterative Closest Point (ICP) algorithm to minimize 
@@ -32,9 +35,19 @@ import javax.vecmath.Vector3d;
  * Sequential inspection of multiple facets using a single visitor's instance 
  * is possible.
  * </p>
+ * <p>
+ * This implementation is based on 
+ * <pre>
+ * Ferkova, Z. Comparison and Analysis of Multiple 3D Shapes [online]. 
+ * Brno, 2016 [cit. 2022-02-08]. 
+ * Available from: <a href="https://is.muni.cz/th/wx40f/">https://is.muni.cz/th/wx40f/</a>. 
+ * Master's thesis. Masaryk University, Faculty of Informatics.
+ * </pre>
+ * </p>
  * 
  * @author Maria Kocurekova
  * @author Radek Oslejsek
+ * @author Zuzana Ferkova
  */
 public class IcpTransformer extends MeshVisitor   {
     
@@ -267,7 +280,7 @@ public class IcpTransformer extends MeshVisitor   {
                 prevMeanD = transformation.getMeanD();
             }
 
-            transformation = computeIcpTransformation(nearestPoints, distances, reducedFacet);
+            transformation = computeIcpTransformation(nearestPoints, distances, reducedFacet.getVertices());
             transformations.get(transformedFacet).add(transformation);
             applyTransformation(transformedFacet, transformation);
             currentIteration ++;
@@ -277,84 +290,80 @@ public class IcpTransformer extends MeshVisitor   {
     /***********************************************************
      *  PRIVATE METHODS
      ***********************************************************/
-
+    
     /**
-     * Compute transformation parameters( translation, rotation and scale factor).
+     * Compute transformation parameters (translation, rotation, and scale factor).
      * Based on old FIDENTIS implementation
      *
      * @param nearestPoints List of nearest points computed by Hausdorff distance.
      * @param distances list of distances computed by Hausdorff distance
      * @return Return ICP transformation which is represented by computed parameters.
-
      */
-    private IcpTransformation computeIcpTransformation(List<Point3d> nearestPoints, List<Double> distances, MeshFacet transformedFacet) {
-        List<MeshPoint>comparedPoints = transformedFacet.getVertices();
+    private IcpTransformation computeIcpTransformation(List<Point3d> nearestPoints, List<Double> distances, List<MeshPoint>trPoints) {
+        //
+        // Compute translation and mean distance from centroids:
+        //
         double meanD = 0;
-        double countOfNotNullPoints = 0;
-
-        List<Point3d>centers = computeCenterBothFacets(nearestPoints, comparedPoints);
-        Point3d mainCenter = centers.get(0);
-        Point3d comparedCenter = centers.get(1);
-        
-        Matrix4d sumMatrix = new Matrix4d();
-        Matrix4d multipleMatrix = new Matrix4d();
-
-        for(int i = 0; i < comparedPoints.size(); i++) {
-            if (nearestPoints.get(i) == null || !Doubles.isFinite(distances.get(i))) {
-                continue;
+        Point3d mainCenter = new Point3d(0, 0, 0);
+        Point3d trCenter = new Point3d(0, 0, 0);
+        int countOfNotNullPoints = 0;
+        for (int i = 0; i < nearestPoints.size(); i++) {
+            if (nearestPoints.get(i) != null && Doubles.isFinite(distances.get(i))) {
+                mainCenter.add(nearestPoints.get(i));
+                trCenter.add(trPoints.get(i).getPosition());
+                countOfNotNullPoints++;
+                meanD += distances.get(i);
             }
-            // START computing Translation coordinates
-            meanD += distances.get(i);
-
-            Point3d relativeC = relativeCoordinate(comparedPoints.get(i).getPosition(),comparedCenter);
-            Point3d relativeN = relativeCoordinate(nearestPoints.get(i),mainCenter);
-
-            // START computing Rotation parameters
-            multipleMatrix.mulTransposeLeft(sumMatrixComp(relativeC), sumMatrixMain(relativeN));
-            sumMatrix.add(multipleMatrix);
-
-            countOfNotNullPoints ++;
         }
-
-        meanD /= countOfNotNullPoints;
+        mainCenter.scale(1.0 / countOfNotNullPoints);
+        trCenter.scale(1.0 / countOfNotNullPoints);
 
         Vector3d translation = new Vector3d(
-                mainCenter.x - comparedCenter.x,
-                mainCenter.y - comparedCenter.y, 
-                mainCenter.z - comparedCenter.z);
-
-        // END computing translation parameter
+                mainCenter.x - trCenter.x,
+                mainCenter.y - trCenter.y, 
+                mainCenter.z - trCenter.z
+        );
+        
+        meanD /= countOfNotNullPoints;
 
-        Quaternion q = new Quaternion(new EigenvalueDecomposition(sumMatrix));
+        //
+        // Compute rotation:
+        //
+        Matrix4d sumMat = new Matrix4d();
+        for (int i = 0; i < trPoints.size(); i++) {
+            if (nearestPoints.get(i) != null && Doubles.isFinite(distances.get(i))) {
+                //Matrix4d tmpMat = sumMatrixComp(relativeCoord4d(trPoints.get(i).getPosition(), trCenter));
+                //tmpMat.mul(sumMatrixMain(relativeCoord4d(nearestPoints.get(i), mainCenter)));
+                //sumMat.add(tmpMat);            
+                sumMat.add(multMat(
+                        relativeCoord4d(trPoints.get(i).getPosition(), trCenter),
+                        relativeCoord4d(nearestPoints.get(i), mainCenter)
+                ));
+            }
+        }
+        
+        Quaternion q = new Quaternion(new EigenvalueDecomposition(sumMat));
         q.normalize();
-        // END computing rotation parameter
 
-        //computing SCALE parameter
+        //
+        // compute scale
+        //
         double scaleFactor = 1.0;
         if (scale) {
             double sxUp = 0;
             double sxDown = 0;
-            Matrix4d rotationMatrix = q.toMatrix();
+            Matrix4d rotMat = q.toMatrix();
             for (int i = 0; i < nearestPoints.size(); i++) {
-                if (nearestPoints.get(i) == null || !Doubles.isFinite(distances.get(i))) {
-                    continue;
+                if (nearestPoints.get(i) != null && Doubles.isFinite(distances.get(i))) {
+                    Vector4d relC = relativeCoord4d(nearestPoints.get(i), mainCenter);
+                    Vector4d relA = relativeCoord4d(trPoints.get(i).getPosition(), trCenter);
+                    rotMat.transform(relA);                
+                    sxUp += relC.dot(relA);
+                    sxDown += relA.dot(relA);
                 }
-
-                Matrix4d matrixPoint = pointToMatrix(relativeCoordinate(nearestPoints.get(i), mainCenter));
-                Matrix4d matrixPointCompare = pointToMatrix(relativeCoordinate(comparedPoints.get(i).getPosition(), comparedCenter));
-
-                matrixPointCompare.mul(rotationMatrix);
-                
-                matrixPoint.mulTransposeLeft(matrixPoint, matrixPointCompare);
-                matrixPointCompare.mulTransposeLeft(matrixPointCompare, matrixPointCompare);
-
-                sxUp += matrixPoint.getElement(0, 0);
-                sxDown += matrixPointCompare.getElement(0,0);
             }
-
             scaleFactor = sxUp / sxDown;
-
-        } // end computing scale parameter
+        }
 
         return new IcpTransformation(translation, q, scaleFactor, meanD);
     }
@@ -366,55 +375,15 @@ public class IcpTransformer extends MeshVisitor   {
      * @param transformation Computed transformation.
      */
     private void applyTransformation(MeshFacet transformedFacet, IcpTransformation transformation) {
-        transformedFacet.getVertices().parallelStream().forEach(
-                p -> {
+        transformedFacet.getVertices().parallelStream()
+                .forEach(p -> {
                     p.setPosition(transformation.transformPoint(p.getPosition(), scale));
                 }
         );
     }
 
-    /**
-     * Compute center of both given objects which are represents by list of Vector3d.
-     * Return list of two centers points.
-     *
-     * @param nearestPoints list of the nearest neighbours
-     * @param comparedPoints list fo compared points
-     * @return List with two points. The first one represents center of main facet
-     * and the second one represents center of compared facet.
-     */
-    private List<Point3d> computeCenterBothFacets(List<Point3d> nearestPoints, List<MeshPoint> comparedPoints) {
-        //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) {
-                continue;
-            }
-            n.add(nearestPoints.get(i));
-            c.add(comparedPoints.get(i).getPosition());
-            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.
-     *
-     * @param p Point of which relative coordinates we want to be computed.
-     * @param center Vector3d which represents center of object.
-     * @return Vector3d which represents coordinates of new point according to center.
-     */
-    private Point3d relativeCoordinate(Point3d p, Point3d center) {
-        return new Point3d(p.x - center.x, p.y - center.y, p.z - center.z);
+    private Vector4d relativeCoord4d(Point3d p, Point3d center) {
+        return new Vector4d(p.x - center.x, p.y - center.y, p.z - center.z, 1.0);
     }
 
     /**
@@ -423,40 +392,49 @@ public class IcpTransformer extends MeshVisitor   {
      * @param p Compared point
      * @return Sum matrix of given point
      */
-    private Matrix4d sumMatrixComp(Point3d p) {
+    @Deprecated
+    private Matrix4d sumMatrixComp(Tuple4d p) {
         return new Matrix4d(
-                0,   -p.x, -p.y, -p.z,
-                p.x,  0,    p.z, -p.y,
-                p.y, -p.z,  0,    p.x,
-                p.z,  p.y, -p.x,  0);
+                0,    p.x,  p.y,  p.z,
+               -p.x,  0,   -p.z,  p.y,
+               -p.y,  p.z,  0,   -p.x,
+               -p.z, -p.y,  p.x,  0);
     }
+    
     /**
      * Compute sum matrix of given point. Given point is point from main facet.
      *
      * @param p Compared point
      * @return Sum matrix of given point
      */
-    private Matrix4d sumMatrixMain(Point3d p) {
+    @Deprecated
+    private Matrix4d sumMatrixMain(Tuple4d p) {
         return new Matrix4d(
                 0,   -p.x, -p.y, -p.z,
                 p.x,  0,   -p.z,  p.y,
                 p.y,  p.z,  0,   -p.x,
                 p.z, -p.y,  p.x,  0);
     }
-
+    
     /**
-     * Convert point (Vector3d) to matrix(Matrix4d).
-     *
-     * @param p Point, we want to be converted.
-     * @return Matrix of point.
+     * Fast implementation of <pre>sumMatrixComp(a).mult(sumMatrixMain(b));</pre>
      */
-    private Matrix4d pointToMatrix(Point3d p){
+    private Matrix4d multMat(Tuple4d a, Tuple4d b) {
+        double axbx = a.x * b.x;
+        double axby = a.x * b.y;
+        double axbz = a.x * b.z;
+        double aybx = a.y * b.x;
+        double ayby = a.y * b.y;
+        double aybz = a.y * b.z;
+        double azbx = a.z * b.x;
+        double azby = a.z * b.y;
+        double azbz = a.z * b.z;
+        
         return new Matrix4d(
-                p.x, p.y, p.z, 1,
-                0,   0,   0,   0, 
-                0,   0,   0,   0,
-                0,   0,   0,   0);
+                axbx+ayby+azbz,       aybz-azby,      -axbz+azbx,       axby-aybx,
+                    -azby+aybz,  axbx-azbz-ayby,       axby+aybx,       axbz+azbx,
+                     azbx-axbz,       aybx+axby,  ayby-azbz-axbx,       aybz+azby,
+                    -aybx+axby,       azbx+axbz,       azby+aybz,  azbz-ayby-axbx
+        );
     }
-
-    
 }
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/icp/Quaternion.java b/Comparison/src/main/java/cz/fidentis/analyst/icp/Quaternion.java
index 0e7c603ab5340d1dad0256d891a85a399f1893fe..f99bfb4b9ee3d76b05acab57303ebf7bed7f6791 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/icp/Quaternion.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/icp/Quaternion.java
@@ -99,12 +99,21 @@ public final class Quaternion extends Quat4d {
         double zz = z * z;
         double zw = z * w;
 
+        return new Matrix4d(
+                1 - 2 * ( yy + zz ), 2 * ( xy - zw ),     2 * ( xz + yw ),     0,
+                2 * ( xy + zw),      1 - 2 * ( xx + zz ), 2 * ( yz - xw ),     0,
+                2 * ( xz - yw),      2 * ( yz + xw ),     1 - 2 * ( xx + yy ), 0,
+                0,                   0,                   0,                   1
+        );
+        
+        /*
         return new Matrix4d(
                 1 - 2 * ( yy + zz ), 2 * ( xy + zw),      2 * ( xz - yw),      0,
                 2 * ( xy - zw ),     1 - 2 * ( xx + zz ), 2 * ( yz + xw ),     0,
                 2 * ( xz + yw ),     2 * ( yz - xw ),     1 - 2 * ( xx + yy ), 0,
                 0,                   0,                   0,                   1
         );
+        */
     }
 
 }