From ae3af2beafad68ace4227d8793cd3fc1610a9120 Mon Sep 17 00:00:00 2001
From: Radek Oslejsek <oslejsek@fi.muni.cz>
Date: Sun, 4 Apr 2021 11:37:14 +0200
Subject: [PATCH] Curvature algorithms merged to a single class

---
 .../analyst/symmetry/SignificantPoints.java   |  48 ++++-
 .../analyst/symmetry/SymmetryEstimator.java   |  32 +--
 .../analyst/tests/CurvatureTests.java         |  53 ++++-
 .../analyst/tests/EfficiencyTests.java        |  14 +-
 .../analyst/visitors/mesh/Curvature.java      | 116 +++++++---
 .../analyst/visitors/mesh/DeltaCurvature.java | 198 ------------------
 .../visitors/mesh/GaussianCurvature.java      |  89 --------
 .../analyst/visitors/mesh/MeanCurvature.java  |  45 ----
 .../gui/ComparisonGLEventListener.java        |  14 +-
 .../analyst/gui/GeneralGLEventListener.java   |   3 +-
 .../fidentis/analyst/gui/SymmetryPanel.java   |   3 +-
 .../fidentis/analyst/mesh/core/MeshModel.java |   9 +
 12 files changed, 203 insertions(+), 421 deletions(-)
 delete mode 100644 Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/DeltaCurvature.java
 delete mode 100644 Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/GaussianCurvature.java
 delete mode 100644 Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/MeanCurvature.java

diff --git a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SignificantPoints.java b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SignificantPoints.java
index 6bf6bc04..6169d48c 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SignificantPoints.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SignificantPoints.java
@@ -23,11 +23,20 @@ import javax.vecmath.Vector3d;
  * @author Natalia Bebjakova
  */
 public class SignificantPoints extends MeshVisitor {
-
+    
+    public enum CurvatureAlg {
+        MEAN,
+        GAUSSIAN,
+        MAX,
+        MIN
+    };
+    
     private final int maxPoints;
     
     private final Curvature curvatureVisitor;
     
+    private final CurvatureAlg curvatureAlg;
+    
     private List<VertCurvature> significantPoints;
     
     private List<List<Vector3d>> normCosVecCache;
@@ -39,19 +48,32 @@ public class SignificantPoints extends MeshVisitor {
     /**
      * Constructor.
      * 
-     * @param curvatureVisitor Curvature computation strategy. If the object has
+     * @param cAlg Curvature strategy to be used for the selection of significant points.
+     * @param max Maximal number of significant points
+     * @throws IllegalArgumentException if the {@code curbatureVisitor} is missing
+     */
+    public SignificantPoints(CurvatureAlg cAlg, int max) {
+        this(new Curvature(), cAlg, max);
+    }
+    
+    /**
+     * Constructor.
+     * 
+     * @param curvatureVisitor Curvature. If the object has
      * pre-filled curvatures of meshes, then they are used also used for the computation
      * of significant points. In this way, it is possible to reuse already computed
      * curvatures and skip calling the {@link #visitMeshFacet} inspection method.
+     * @param cAlg Curvature strategy to be used for the selection of significant points.
      * @param max Maximal number of significant points
      * @throws IllegalArgumentException if the {@code curbatureVisitor} is missing
      */
-    public SignificantPoints(Curvature curvatureVisitor, int max) {
+    public SignificantPoints(Curvature curvatureVisitor, CurvatureAlg cAlg, int max) {
         if (curvatureVisitor == null) {
             throw new IllegalArgumentException("curvatureVisitor");
         }
         this.maxPoints = max;
         this.curvatureVisitor = curvatureVisitor;
+        this.curvatureAlg = cAlg;
     }
     
     @Override
@@ -168,7 +190,25 @@ public class SignificantPoints extends MeshVisitor {
         
         // fill the priority queue
         final PriorityQueue<VertCurvature> priorityQueue = new PriorityQueue<>();
-        Map<MeshFacet, List<Double>> curvMap = curvatureVisitor.getCurvatures();
+        
+        Map<MeshFacet, List<Double>> curvMap = null;
+        switch (curvatureAlg) {
+            case MEAN: 
+                curvMap = curvatureVisitor.getMeanCurvatures();
+                break;
+            case GAUSSIAN: 
+                curvMap = curvatureVisitor.getGaussianCurvatures();
+                break;
+            case MAX: 
+                curvMap = curvatureVisitor.getMaxPrincipalCurvatures();
+                break;
+            case MIN: 
+                curvMap = curvatureVisitor.getMinPrincipalCurvatures();
+                break;
+            default:
+                throw new IllegalArgumentException("curvatureAlg");
+        }
+
         for (MeshFacet facet: curvMap.keySet()) {
             List<Double> curvs = curvMap.get(facet);
             for (int i = 0; i < curvs.size(); i++) { 
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java
index 8e3c82f4..cbfbfe35 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java
@@ -5,12 +5,10 @@ import cz.fidentis.analyst.mesh.core.CornerTableRow;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
 import cz.fidentis.analyst.mesh.core.MeshFacetImpl;
 import cz.fidentis.analyst.mesh.core.MeshPointImpl;
+import cz.fidentis.analyst.symmetry.SignificantPoints.CurvatureAlg;
 import cz.fidentis.analyst.visitors.mesh.BoundingBox;
 import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox;
 import cz.fidentis.analyst.visitors.mesh.Curvature;
-import cz.fidentis.analyst.visitors.mesh.GaussianCurvature;
-import cz.fidentis.analyst.visitors.mesh.DeltaCurvature;
-import cz.fidentis.analyst.visitors.mesh.MeanCurvature;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Callable;
@@ -41,13 +39,6 @@ public class SymmetryEstimator extends MeshVisitor {
     private final SignificantPoints sigPointsVisitor;
     private final BoundingBox bbVisitor = new BoundingBox();
     
-    public enum CurvatureAlg {
-        MEAN,
-        GAUSSIAN,
-        MAX,
-        MIN
-    };
-    
     private CurvatureAlg curvatureAlg;
     
     private Plane symmetryPlane;
@@ -65,26 +56,7 @@ public class SymmetryEstimator extends MeshVisitor {
             throw new IllegalArgumentException("config");
         }
         this.config = config;
-        
-        // create the visitor of significant points with required curvate computation strategy
-        Curvature curvatureVisitor = null;
-        switch (curvatureAlg) {
-            case MEAN: 
-                curvatureVisitor = new MeanCurvature();
-                break;
-            case GAUSSIAN: 
-                curvatureVisitor = new GaussianCurvature();
-                break;
-            case MAX: 
-                curvatureVisitor = new DeltaCurvature(true);
-                break;
-            case MIN: 
-                curvatureVisitor = new DeltaCurvature(false);
-                break;
-            default:
-                throw new IllegalArgumentException("curvatureAlg");
-        }
-        this.sigPointsVisitor = new SignificantPoints(curvatureVisitor, config.getSignificantPointCount());
+        this.sigPointsVisitor = new SignificantPoints(curvatureAlg, config.getSignificantPointCount());
     }
     
     @Override
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/tests/CurvatureTests.java b/Comparison/src/main/java/cz/fidentis/analyst/tests/CurvatureTests.java
index 9fc85226..fc2d8cb6 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/tests/CurvatureTests.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/tests/CurvatureTests.java
@@ -2,14 +2,15 @@ package cz.fidentis.analyst.tests;
 
 import cz.fidentis.analyst.face.HumanFace;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
+import cz.fidentis.analyst.mesh.core.MeshPoint;
 import cz.fidentis.analyst.visitors.mesh.Curvature;
-import cz.fidentis.analyst.visitors.mesh.DeltaCurvature;
-import cz.fidentis.analyst.visitors.mesh.GaussianCurvature;
-import cz.fidentis.analyst.visitors.mesh.MeanCurvature;
 import java.io.File;
 import java.io.IOException;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import javax.vecmath.Vector3d;
 
 /**
  * A class for testing curvature algorithms.
@@ -19,6 +20,7 @@ import java.util.Map;
 public class CurvatureTests {
 
     private static File faceFile2 = new File("src/test/resources/cz/fidentis/analyst/00002_01_ECA.obj");
+    private static File girlFile = new File("src/test/resources/cz/fidentis/analyst/average_girl_17-20.obj");
     
     /**
      * Main method 
@@ -26,28 +28,57 @@ public class CurvatureTests {
      * @throws IOException on IO error
      */
     public static void main(String[] args) throws IOException {
+        //HumanFace face = new HumanFace(girlFile);
         HumanFace face = new HumanFace(faceFile2);
         
+        System.out.println("MODEL: " + face.getMeshModel());
+        
+        Set<MeshPoint> uniqueVerts = new HashSet<>(face.getMeshModel().getFacets().get(0).getVertices());
+        System.out.println("UNIQUE VERTICES: " + uniqueVerts.size());
+        Set<Vector3d> unique2 = new HashSet<>();
+        for (MeshPoint p: face.getMeshModel().getFacets().get(0).getVertices()) {
+            unique2.add(p.getPosition());
+        }
+        //System.out.println("UNIQUE VERTICES: " + unique2.size());
+        //for (Vector3d v: unique2) {
+        //    for (MeshPoint p: uniqueVerts) {
+        //        if (v.equals(p.getPosition())) {
+        //            System.out.println(p);
+        //        }
+        //    }
+        //    System.out.println("----------------");
+        //}
+        
         boolean print = false;
         
         System.out.println();
         System.out.println("Curvature calculation:");
-        System.out.println(measureCurvature(face, new GaussianCurvature(), print) + "\tmsec:\tGaussian curvature");
-        System.out.println(measureCurvature(face, new MeanCurvature(), print) + "\tmsec:\tMean curvature");
-        System.out.println(measureCurvature(face, new DeltaCurvature(true), print) + "\tmsec:\tMax curvature");
-        System.out.println(measureCurvature(face, new DeltaCurvature(false), print) + "\tmsec:\tMin curvature");
+        System.out.println(measureCurvature(face, print) + "\tmsec:\tCurvature");
         System.out.println();
     }
     
-    private static long measureCurvature(HumanFace face, Curvature vis, boolean printDetails) {
+    private static long measureCurvature(HumanFace face, boolean printDetails) {
+        Curvature vis = new Curvature();
         long startTime = System.currentTimeMillis();
         face.getMeshModel().compute(vis);
         long retTime =  System.currentTimeMillis() - startTime;
         
         if (printDetails) {
-            Map<MeshFacet, List<Double>> results = vis.getCurvatures();
-            for (MeshFacet facet: results.keySet()) {
-                System.out.println(results.get(facet));
+            Map<MeshFacet, List<Double>> gaus = vis.getGaussianCurvatures();
+            for (MeshFacet facet: gaus.keySet()) {
+                System.out.println(gaus.get(facet));
+            }
+            Map<MeshFacet, List<Double>> mean = vis.getMeanCurvatures();
+            for (MeshFacet facet: mean.keySet()) {
+                System.out.println(mean.get(facet));
+            }
+            Map<MeshFacet, List<Double>> max = vis.getMaxPrincipalCurvatures();
+            for (MeshFacet facet: max.keySet()) {
+                System.out.println(max.get(facet));
+            }
+            Map<MeshFacet, List<Double>> min = vis.getMinPrincipalCurvatures();
+            for (MeshFacet facet: min.keySet()) {
+                System.out.println(min.get(facet));
             }
         }
         
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java b/Comparison/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java
index 59bd6d0b..6ee0437f 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java
@@ -5,13 +5,11 @@ import cz.fidentis.analyst.kdtree.KdTree;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
 import cz.fidentis.analyst.symmetry.Config;
 import cz.fidentis.analyst.symmetry.Plane;
+import cz.fidentis.analyst.symmetry.SignificantPoints;
 import cz.fidentis.analyst.symmetry.SymmetryEstimator;
 import cz.fidentis.analyst.visitors.mesh.Curvature;
-import cz.fidentis.analyst.visitors.mesh.GaussianCurvature;
 import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
 import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy;
-import cz.fidentis.analyst.visitors.mesh.DeltaCurvature;
-import cz.fidentis.analyst.visitors.mesh.MeanCurvature;
 import java.io.File;
 import java.io.IOException;
 import java.util.List;
@@ -48,10 +46,10 @@ public class EfficiencyTests {
         //face1.getMeshModel().compute(new GaussianCurvature()); // initialize everything, then measure
         
         System.out.println("Symmetry plane calculation:");
-        printSymmetryPlane(face1, true, SymmetryEstimator.CurvatureAlg.MEAN);
-        printSymmetryPlane(face1, true, SymmetryEstimator.CurvatureAlg.GAUSSIAN);
-        printSymmetryPlane(face1, false, SymmetryEstimator.CurvatureAlg.MEAN);
-        printSymmetryPlane(face1, false, SymmetryEstimator.CurvatureAlg.GAUSSIAN);
+        printSymmetryPlane(face1, true, SignificantPoints.CurvatureAlg.MEAN);
+        printSymmetryPlane(face1, true, SignificantPoints.CurvatureAlg.GAUSSIAN);
+        printSymmetryPlane(face1, false, SignificantPoints.CurvatureAlg.MEAN);
+        printSymmetryPlane(face1, false, SignificantPoints.CurvatureAlg.GAUSSIAN);
         
         System.out.println();
         System.out.println(measureKdTreeCreation(face1) + "\tmsec:\tKd-tree creation of first face");
@@ -97,7 +95,7 @@ public class EfficiencyTests {
         return System.currentTimeMillis() - startTime;
     }
     
-    private static void printSymmetryPlane(HumanFace face, boolean concurrently, SymmetryEstimator.CurvatureAlg curvatureAlg) {
+    private static void printSymmetryPlane(HumanFace face, boolean concurrently, SignificantPoints.CurvatureAlg curvatureAlg) {
         long startTime = System.currentTimeMillis();
         SymmetryEstimator est = new SymmetryEstimator(Config.getDefault(), curvatureAlg);
         face.getMeshModel().compute(est, false);
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/Curvature.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/Curvature.java
index 64e6853b..cfdf97b7 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/Curvature.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/Curvature.java
@@ -14,59 +14,123 @@ import javax.vecmath.Vector3d;
 /**
  * Abstract class for algorithms calculating curvatures of mesh vertices.
  * @see https://computergraphics.stackexchange.com/questions/1718/what-is-the-simplest-way-to-compute-principal-curvature-for-a-mesh-triangle
+ * @see http://rodolphe-vaillant.fr/?e=20
  * <p>
  * <b>All curvature algorithms suppose that the triangle vertices are oriented clockwise!</b>
  * </p>
  * 
- * TODO: FeaturePoints/src/cz/fidentis/featurepoints/curvature/Curvature_jv.java
- * TODO: http://rodolphe-vaillant.fr/?e=20
- * 
  * @author Natalia Bebjakova
  * @author Radek Oslejsek
  */
-public abstract class Curvature extends MeshVisitor {
+public class Curvature extends MeshVisitor {
+    
+    private final Map<MeshFacet, List<Double>> gaussian = new HashMap<>();
+    private final Map<MeshFacet, List<Double>> mean = new HashMap<>();
+    private final Map<MeshFacet, List<Double>> minPrincipal = new HashMap<>();
+    private final Map<MeshFacet, List<Double>> maxPrincipal = new HashMap<>();
     
-    private final Map<MeshFacet, List<Double>> curvatures = new HashMap<>();
+    /**
+     * Returns Gaussian curvatures for all inspected mesh facets. The order corresponds to
+     * the order of vertices, i.e., i-th value represents the curvature of i-th mesh vertex.
+     * 
+     * @return Gaussian curvatures of inspected mesh facets.
+     */
+    public Map<MeshFacet, List<Double>> getGaussianCurvatures() {
+        return Collections.unmodifiableMap(gaussian);
+    }
+    
+    /**
+     * Returns mean curvatures for all inspected mesh facets. The order corresponds to
+     * the order of vertices, i.e., i-th value represents the curvature of i-th mesh vertex.
+     * 
+     * @return Mean curvatures of inspected mesh facets.
+     */
+    public Map<MeshFacet, List<Double>> getMeanCurvatures() {
+        return Collections.unmodifiableMap(mean);
+    }
+    
+    /**
+     * Returns minimum principal curvatures for all inspected mesh facets. The order corresponds to
+     * the order of vertices, i.e., i-th value represents the curvature of i-th mesh vertex.
+     * 
+     * @return Minimum principal curvatures of inspected mesh facets.
+     */
+    public Map<MeshFacet, List<Double>> getMinPrincipalCurvatures() {
+        return Collections.unmodifiableMap(minPrincipal);
+    }
     
     /**
-     * Returns curvatures for all inspected mesh facets. The order corresponds to
+     * Returns maximu principal curvatures for all inspected mesh facets. The order corresponds to
      * the order of vertices, i.e., i-th value represents the curvature of i-th mesh vertex.
      * 
-     * @return curvatures of inspected mesh facets.
+     * @return Maximum principal curvatures of inspected mesh facets.
      */
-    public Map<MeshFacet, List<Double>> getCurvatures() {
-        return Collections.unmodifiableMap(curvatures);
+    public Map<MeshFacet, List<Double>> getMaxPrincipalCurvatures() {
+        return Collections.unmodifiableMap(maxPrincipal);
     }
     
     @Override
     public void visitMeshFacet(final MeshFacet facet) {
         synchronized (this) {
-            if (curvatures.containsKey(facet)) {
+            if (gaussian.containsKey(facet)) {
                 return; // already visited facet
             }
-            curvatures.put(facet, new ArrayList<>());
-            if (!facet.hasVertexNormals()) {
-                facet.calculateVertexNormals();
-            }
+            gaussian.put(facet, new ArrayList<>());
+            mean.put(facet, new ArrayList<>());
+            minPrincipal.put(facet, new ArrayList<>());
+            maxPrincipal.put(facet, new ArrayList<>());
+            //if (!facet.hasVertexNormals()) {
+            //    facet.calculateVertexNormals();
+            //}
             //facet.calculateVoronoiPoints();
         }
         
         //final List<MeshTriangle> triangles = facet.getTriangles();
         final List<CurvTriangle> triangles = precomputeTriangles(facet);
-        for (int i = 0; i < facet.getNumberOfVertices(); i++) {
-            curvatures.get(facet).add(calculateCurvature(facet, triangles, i));
+        for (int vertA = 0; vertA < facet.getNumberOfVertices(); vertA++) {
+            //curvatures.get(facet).add(calculateCurvature(facet, triangles, i));
+            
+            List<Integer> neighbouringTriangles = facet.getCornerTable().getTriangleIndexesByVertexIndex(vertA);
+        
+            if (neighbouringTriangles.isEmpty()) {
+                this.gaussian.get(facet).add(Double.NaN);
+                this.mean.get(facet).add(Double.NaN);
+                this.minPrincipal.get(facet).add(Double.NaN);
+                this.maxPrincipal.get(facet).add(Double.NaN);
+                continue;
+            }
+        
+            double sumArea = 0.0;
+            double sumAngles = 0.0;
+            Vector3d pointSum = new Vector3d();
+        
+            // for all surrounding triangles:
+            for (int i = 0; i < neighbouringTriangles.size(); i++) {
+                CurvTriangle ctri = triangles.get(neighbouringTriangles.get(i));
+                CurvTriangle tNext = triangles.get(neighbouringTriangles.get((i + 1) % neighbouringTriangles.size()));
+            
+                sumArea += computeArea(ctri, facet.getVertex(vertA));
+                sumAngles +=  ctri.alpha(facet.getVertex(vertA));
+            
+                Vector3d aux = new Vector3d(ctri.vertC(facet.getVertex(vertA)));
+                aux.sub(ctri.vertA(facet.getVertex(vertA)));
+                aux.scale(ctri.betaCotan(facet.getVertex(vertA)) + tNext.gammaCotan(facet.getVertex(vertA)));
+                pointSum.add(aux);
+            }
+        
+            double gaussian = (2.0 * Math.PI - sumAngles) / sumArea;
+            double mean = 0.25 * sumArea * pointSum.length();
+            double delta = Math.max(0, Math.pow(mean, 2) - gaussian);
+            double minPrincipal = mean - Math.sqrt(delta);
+            double maxPrincipal = mean + Math.sqrt(delta);
+            
+            this.gaussian.get(facet).add(gaussian);
+            this.mean.get(facet).add(mean);
+            this.minPrincipal.get(facet).add(minPrincipal);
+            this.maxPrincipal.get(facet).add(maxPrincipal);
         }
     }
     
-    /**
-     * 
-     * @param facet
-     * @param triangles
-     * @param vertA The "central point" for the 1-ring neighborhood
-     * @return 
-     */
-    protected abstract double calculateCurvature(MeshFacet facet, List<CurvTriangle> triangles, int vertA);
-    
     protected List<CurvTriangle> precomputeTriangles(MeshFacet facet) {
         List<CurvTriangle> ret = new ArrayList<>(facet.getNumTriangles());
         for (MeshTriangle tri: facet) {
@@ -93,7 +157,7 @@ public abstract class Curvature extends MeshVisitor {
     }
     
     /**
-     * Helper class that caches values used multiples times in triangle during the curvature computation.
+     * Helper class that caches triangle characteristics used multiples times during the curvature computation.
      * <ul>
      * <li>A = central point of the 1-ring neighborhood</li>
      * <li>B = point "on the left" (previous point in the clockwise orientation of the triangle</li>
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/DeltaCurvature.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/DeltaCurvature.java
deleted file mode 100644
index 22d07fa4..00000000
--- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/DeltaCurvature.java
+++ /dev/null
@@ -1,198 +0,0 @@
-package cz.fidentis.analyst.visitors.mesh;
-
-import cz.fidentis.analyst.mesh.core.MeshFacet;
-import java.util.List;
-import javax.vecmath.Vector3d;
-
-/**
- * Calculates maximum or minimum curvatures of mesh vertices using the combination
- * of Gaussian and mean curvatures.
- * 
- * @author Natalia Bebjakova
- * @author Radek Oslejsek
- */
-public class DeltaCurvature extends GaussianCurvature {
-    
-    private boolean maxCurvature = true;
-    
-    /**
-     * Constructor.
-     * @param max If {@code true}, then maximum curvature is return. 
-     * Otherwise, minimum curvature is computed.
-     */
-    public DeltaCurvature(boolean max) {
-        this.maxCurvature = max;
-    }
-    
-    @Override
-    protected double calculateCurvature(MeshFacet facet, List<CurvTriangle> triangles, int vertA) {
-        List<Integer> neighbouringTriangles = facet.getCornerTable().getTriangleIndexesByVertexIndex(vertA);
-        
-        if (neighbouringTriangles.isEmpty()) {
-            return Double.NaN;
-        }
-        
-        double sumArea = 0.0;
-        double sumAngles = 0.0;
-        Vector3d pointSum = new Vector3d();
-        
-        // for all surrounding triangles:
-        for (int i = 0; i < neighbouringTriangles.size(); i++) {
-            CurvTriangle ctri = triangles.get(neighbouringTriangles.get(i));
-            CurvTriangle tNext = triangles.get(neighbouringTriangles.get((i + 1) % neighbouringTriangles.size()));
-            
-            sumArea += computeArea(ctri, facet.getVertex(vertA));
-            sumAngles +=  ctri.alpha(facet.getVertex(vertA));
-            
-            Vector3d aux = new Vector3d(ctri.vertC(facet.getVertex(vertA)));
-            aux.sub(ctri.vertA(facet.getVertex(vertA)));
-            aux.scale(ctri.betaCotan(facet.getVertex(vertA)) + tNext.gammaCotan(facet.getVertex(vertA)));
-            pointSum.add(aux);
-        }
-        
-        double gaussian = (2.0 * Math.PI - sumAngles) / sumArea;
-        double mean = 0.25 * sumArea * pointSum.length();
-        double delta = Math.max(0, Math.pow(mean, 2) - gaussian);
-        
-        return (maxCurvature) ? mean + Math.sqrt(delta) : mean - Math.sqrt(delta);
-        
-        
-        /*
-        double gaussianCurvature = super.calculateCurvature(facet, triangles, centerIndex);
-        if (Double.isNaN(gaussianCurvature)) {
-            return Double.NaN;
-        }
-        double meanCurvature = getMeanCurvature(facet, triangles, centerIndex);
-        double meanCurvatureSqr = meanCurvature * meanCurvature;
-        if (meanCurvatureSqr <= gaussianCurvature) { 
-            return meanCurvature;
-        }
-        return meanCurvature + Math.sqrt(meanCurvatureSqr - gaussianCurvature);
-        */
-    }
-    
-    /*
-    private Vector3d computeLaplaceBeltrami(MeshFacet facet, List<MeshTriangle> triangles, int centerIndex) {
-        List<Integer> neighbouringTriangles = facet.getCornerTable().getTriangleIndexesByVertexIndex(centerIndex);
-
-        if (neighbouringTriangles.isEmpty()) {
-            return new Vector3d();
-        }
-        
-        double areaSum = 0;
-        Vector3d pointSum = new Vector3d();
-        List<Vector3d> voronoiPoints = facet.calculateVoronoiPoints();
-        
-        for (int i = 0; i < neighbouringTriangles.size(); i++) {
-            MeshTriangle t = triangles.get(neighbouringTriangles.get(i));
-            MeshTriangle tNext = triangles.get(neighbouringTriangles.get((i + 1) % neighbouringTriangles.size()));
-            double area = 0;
-            
-            MeshPoint centerPoint = facet.getVertices().get(centerIndex);
-            Vector3d voronoiPoint = voronoiPoints.get(neighbouringTriangles.get(i));
-
-            Vector3d aux = null;
-            if (t.vertex1 == facet.getVertex(centerIndex)) {
-                area = voronoiPoint.x;
-                aux = new Vector3d(t.vertex2.getPosition());
-            } else if (t.vertex2 == facet.getVertex(centerIndex)) {
-                area = voronoiPoint.y;
-                aux = new Vector3d(t.vertex3.getPosition());
-            } else if (t.vertex3 == facet.getVertex(centerIndex)) {
-                area = voronoiPoint.z;
-                aux = new Vector3d(t.vertex1.getPosition());
-            }
-            aux.sub(centerPoint.getPosition());
-            aux.scale(cotAlfa(centerPoint, t) + cotBeta(centerPoint, tNext));
-            pointSum.add(aux);
-            areaSum += area;
-        }
-        pointSum.scale(1.0 / (2.0 * areaSum));
-        return pointSum;
-    }
-    */
-    
-    /**
-     * Calculates angle of the triangle according to center point
-     * TODO: optimize @see https://stackoverflow.com/questions/31159016/how-to-efficiently-calculate-cotangents-from-vectors
-     * 
-     * @param centerPoint center point
-     * @param t triangle
-     * @return angle
-     */
-    /*
-    private double cotAlfa(MeshPoint centerPoint, MeshTriangle t) {        
-        double alfaCos = 0;
-        
-        if (t.vertex1 == centerPoint) {
-            MeshPoint e1 = t.vertex1.subtractPosition(t.vertex3);
-            e1 = e1.dividePosition(e1.abs());
-            
-            MeshPoint e2 = t.vertex2.subtractPosition(t.vertex3);
-            e2 = e2.dividePosition(e2.abs());
-            
-            alfaCos = e1.dotProduct(e2);
-        } else if (t.vertex2 == centerPoint) {
-            MeshPoint e1 = t.vertex2.subtractPosition(t.vertex1);
-            e1 = e1.dividePosition(e1.abs());
-            
-            MeshPoint e2 = t.vertex3.subtractPosition(t.vertex1);
-            e2 = e2.dividePosition(e2.abs());
-            
-            alfaCos = e1.dotProduct(e2);
-        } else if (t.vertex3 == centerPoint){
-            MeshPoint e1 = t.vertex3.subtractPosition(t.vertex2);
-            e1 = e1.dividePosition(e1.abs());
-                
-            MeshPoint e2 = t.vertex1.subtractPosition(t.vertex2);
-            e2 = e2.dividePosition(e2.abs());
-            
-            alfaCos = e1.dotProduct(e2);
-        }
-        double alfa = Math.acos(alfaCos);
-        return 1 / Math.tan(alfa); // cotangent alpha
-    }
-    */
-    
-    /**
-     * Calculates angle of the triangle according to center point
-     * TODO: optimize @see https://stackoverflow.com/questions/31159016/how-to-efficiently-calculate-cotangents-from-vectors
-     * 
-     * @param centerPoint center point
-     * @param t triangle
-     * @return angle
-     */
-    /*
-    private double cotBeta(MeshPoint centerPoint, MeshTriangle t) {
-        double betaCos = 0;
-            
-        if (t.vertex1 == centerPoint) {
-            MeshPoint e1 = t.vertex1.subtractPosition(t.vertex2);
-            e1 = e1.dividePosition(e1.abs());
-            
-            MeshPoint e2 = t.vertex3.subtractPosition(t.vertex2);
-            e2 = e2.dividePosition(e2.abs());
-            
-            betaCos = e1.dotProduct(e2);
-        } else if (t.vertex2 == centerPoint) {
-            MeshPoint e1 = t.vertex2.subtractPosition(t.vertex3);
-            e1 = e1.dividePosition(e1.abs());
-            
-            MeshPoint e2 = t.vertex1.subtractPosition(t.vertex3);
-            e2 = e2.dividePosition(e2.abs());
-            
-            betaCos = e1.dotProduct(e2);
-        } else if (t.vertex3 == centerPoint){
-            MeshPoint e1 = t.vertex3.subtractPosition(t.vertex1);
-            e1 = e1.dividePosition(e1.abs());
-                
-            MeshPoint e2 = t.vertex2.subtractPosition(t.vertex1);
-            e2 = e2.dividePosition(e2.abs());
-            
-            betaCos = e1.dotProduct(e2);
-        }
-            double beta = Math.acos(betaCos);
-            return 1 / Math.tan(beta); // cotangent beta
-    }
-    */
-}
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/GaussianCurvature.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/GaussianCurvature.java
deleted file mode 100644
index 56999829..00000000
--- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/GaussianCurvature.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package cz.fidentis.analyst.visitors.mesh;
-
-import cz.fidentis.analyst.mesh.core.MeshFacet;
-import java.util.List;
-
-/**
- * Gaussian curvatures. 
- * @see https://computergraphics.stackexchange.com/questions/1718/what-is-the-simplest-way-to-compute-principal-curvature-for-a-mesh-triangle
- * 
- * @author Natalia Bebjakova
- * @author Radek Oslejsek
- */
-public class GaussianCurvature extends Curvature {
-    
-    @Override
-    protected double calculateCurvature(MeshFacet facet, List<CurvTriangle> triangles, int vertA) {
-        List<Integer> neighbouringTriangles = facet.getCornerTable().getTriangleIndexesByVertexIndex(vertA);
-        
-        if (neighbouringTriangles.isEmpty()) {
-            return Double.NaN;
-        }
-        
-        double sumArea = 0.0;
-        double sumAngles = 0.0;
-        
-        // for all surrounding triangles:
-        for (int i = 0; i < neighbouringTriangles.size(); i++) {
-            CurvTriangle ctri = triangles.get(neighbouringTriangles.get(i));
-            sumAngles +=  ctri.alpha(facet.getVertex(vertA));
-            sumArea += computeArea(ctri, facet.getVertex(vertA));
-        }
-        
-        return (2.0 * Math.PI - sumAngles) / sumArea;        
-    }
-    
-    
-    /*
-    @Override
-    protected double calculateCurvature(MeshFacet facet, List<MeshTriangle> triangles, int centerIndex) {
-        List<Integer> neighbouringTriangles = facet.getCornerTable().getTriangleIndexesByVertexIndex(centerIndex);
-        
-        if (neighbouringTriangles.isEmpty()) {
-            return Double.NaN;
-        }
-        
-        double sum = 2 * Math.PI;
-        double areaSum = 0;
-
-        // fro all surrounding triangles:
-        List<Vector3d> voronoiPoints = facet.calculateVoronoiPoints();
-        for (int i = 0; i < neighbouringTriangles.size(); i++) {
-            Vector3d v1 = new Vector3d();
-            Vector3d v2 = new Vector3d();
-            MeshTriangle tri = triangles.get(neighbouringTriangles.get(i));
-            Vector3d voronoiPoint = voronoiPoints.get(neighbouringTriangles.get(i));
-            
-            double area = 0;
-            if (tri.vertex1 ==  facet.getVertex(centerIndex)) {
-                v1 = new Vector3d(tri.vertex2.getPosition());
-                v2 = new Vector3d(tri.vertex3.getPosition());
-                v1.sub(tri.vertex1.getPosition());
-                v2.sub(tri.vertex1.getPosition());
-                area = voronoiPoint.x;
-            } else if (tri.vertex2 == facet.getVertex(centerIndex)) {
-                v1 = new Vector3d(tri.vertex1.getPosition());
-                v2 = new Vector3d(tri.vertex3.getPosition());
-                v1.sub(tri.vertex2.getPosition());
-                v2.sub(tri.vertex2.getPosition());
-                area = voronoiPoint.y;
-            } else if (tri.vertex3 == facet.getVertex(centerIndex)) {
-                v1 = new Vector3d(tri.vertex2.getPosition());
-                v2 = new Vector3d(tri.vertex1.getPosition());
-                v1.sub(tri.vertex3.getPosition());
-                v2.sub(tri.vertex3.getPosition());
-                area = voronoiPoint.z;
-            }
-            
-            areaSum += area;
-            v1.normalize();
-            v2.normalize();
-            
-            sum -= Math.acos(v1.dot(v2));
-        } 
-        double value = sum * (1.0 / areaSum);
-        
-        return value;        
-    }
-    */
-}
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/MeanCurvature.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/MeanCurvature.java
deleted file mode 100644
index f7ff3316..00000000
--- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/MeanCurvature.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package cz.fidentis.analyst.visitors.mesh;
-
-import cz.fidentis.analyst.mesh.core.MeshFacet;
-import java.util.List;
-import javax.vecmath.Vector3d;
-
-/**
- * Mean curvature based on solving Laplace-Beltrami mean operator by cotangent discretization.
- * 
- * @see https://computergraphics.stackexchange.com/questions/1718/what-is-the-simplest-way-to-compute-principal-curvature-for-a-mesh-triangle
- * @see http://rodolphe-vaillant.fr/?e=20
- * 
- * @author Natalia Bebjakova
- * @author Radek Oslejsek
- */
-public class MeanCurvature extends Curvature {
-    
-    @Override
-    protected double calculateCurvature(MeshFacet facet, List<CurvTriangle> triangles, int vertA) {
-        List<Integer> neighbouringTriangles = facet.getCornerTable().getTriangleIndexesByVertexIndex(vertA);
-        
-        if (neighbouringTriangles.isEmpty()) {
-            return Double.NaN;
-        }
-        
-        double sumArea = 0.0;
-        Vector3d pointSum = new Vector3d();
-        
-        // for all surrounding triangles:
-        for (int i = 0; i < neighbouringTriangles.size(); i++) {
-            CurvTriangle ctri = triangles.get(neighbouringTriangles.get(i));
-            CurvTriangle tNext = triangles.get(neighbouringTriangles.get((i + 1) % neighbouringTriangles.size()));
-            
-            sumArea += computeArea(ctri, facet.getVertex(vertA));
-            
-            Vector3d aux = new Vector3d(ctri.vertC(facet.getVertex(vertA)));
-            aux.sub(ctri.vertA(facet.getVertex(vertA)));
-            aux.scale(ctri.betaCotan(facet.getVertex(vertA)) + tNext.gammaCotan(facet.getVertex(vertA)));
-            pointSum.add(aux);
-        }
-        
-        return 0.25 * sumArea * pointSum.length();
-            
-    }
-}
diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/ComparisonGLEventListener.java b/GUI/src/main/java/cz/fidentis/analyst/gui/ComparisonGLEventListener.java
index 0864c3ad..2caa7052 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/gui/ComparisonGLEventListener.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/gui/ComparisonGLEventListener.java
@@ -6,7 +6,6 @@ import com.jogamp.opengl.GLAutoDrawable;
 import cz.fidentis.analyst.face.HumanFace;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
 import cz.fidentis.analyst.mesh.core.MeshModel;
-import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
 
 import javax.vecmath.Vector3d;
 import java.awt.*;
@@ -21,8 +20,7 @@ import static com.jogamp.opengl.GL2GL3.GL_LINE;
 import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_MODELVIEW_MATRIX;
 import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_PROJECTION_MATRIX;
 import cz.fidentis.analyst.visitors.mesh.Curvature;
-import cz.fidentis.analyst.visitors.mesh.GaussianCurvature;
-import cz.fidentis.analyst.visitors.mesh.DeltaCurvature;
+import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
 
 /**
  * 
@@ -52,9 +50,9 @@ public class ComparisonGLEventListener extends GeneralGLEventListener {
         //HausdorffDistance hVisitor = new HausdorffDistance(getModel(), HausdorffDistance.Strategy.POINT_TO_POINT, false, false);
         //comparedFace.getMeshModel().compute(hVisitor);
         //distances = hVisitor.getDistances();
-        Curvature visitor = new GaussianCurvature();
+        Curvature visitor = new Curvature();
         comparedFace.getMeshModel().compute(visitor);
-        distances = visitor.getCurvatures();
+        distances = visitor.getGaussianCurvatures();
         renderHeatmap = true;
         this.minColor = minColor;
         this.maxColor = maxColor;
@@ -135,13 +133,13 @@ public class ComparisonGLEventListener extends GeneralGLEventListener {
 
     Color getColor(Double currentDistance, Double minDistance, Double maxDistance) {
         double currentParameter = ((currentDistance - minDistance) / (maxDistance - minDistance));
-        //System.out.println("AAA " + currentParameter + " " + minDistance + " " + maxDistance);
         //return new Color((float)currentParameter, 0.5f, 0.5f);
         
-        //currentParameter *= 100;
-        //if (currentParameter > 1) {
+        //currentParameter *= 10;
+        //if (currentParameter > maxDistance) {
         //    currentParameter = 1.0;
         //}
+        //System.out.println("AAA " + currentParameter + " " + minDistance + " " + maxDistance);
         
         float[] hsb1 = Color.RGBtoHSB(minColor.getRed(), minColor.getGreen(), minColor.getBlue(), null);
         double h1 = hsb1[0];
diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java b/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java
index 28275cea..9354ceb7 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java
@@ -15,6 +15,7 @@ import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_MODELVIEW_MATRIX;
 import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_PROJECTION_MATRIX;
 import com.jogamp.opengl.glu.GLU;
 import cz.fidentis.analyst.symmetry.Config;
+import cz.fidentis.analyst.symmetry.SignificantPoints;
 import cz.fidentis.analyst.symmetry.SymmetryEstimator;
 
 import javax.vecmath.Vector3d;
@@ -241,7 +242,7 @@ public class GeneralGLEventListener implements GLEventListener {
 
         //Generate SymmetryPlane first time we request to see it
         if (symmetryPlane && symmetryPlaneFacet == null) {
-            SymmetryEstimator estimator = new SymmetryEstimator(Config.getDefault(), SymmetryEstimator.CurvatureAlg.GAUSSIAN);
+            SymmetryEstimator estimator = new SymmetryEstimator(Config.getDefault(), SignificantPoints.CurvatureAlg.GAUSSIAN);
             model.getFacets().get(0).accept(estimator);
             symmetryPlaneFacet = estimator.getSymmetryPlaneMesh();
 
diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/SymmetryPanel.java b/GUI/src/main/java/cz/fidentis/analyst/gui/SymmetryPanel.java
index 019378d9..af8c975b 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/gui/SymmetryPanel.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/gui/SymmetryPanel.java
@@ -5,6 +5,7 @@ import cz.fidentis.analyst.mesh.core.MeshFacet;
 import cz.fidentis.analyst.mesh.core.MeshModel;
 import cz.fidentis.analyst.symmetry.Config;
 import cz.fidentis.analyst.symmetry.Plane;
+import cz.fidentis.analyst.symmetry.SignificantPoints;
 import cz.fidentis.analyst.symmetry.SymmetryEstimator;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -153,7 +154,7 @@ public final class SymmetryPanel extends javax.swing.JPanel {
     private void computeSymmetryPlane() throws InterruptedException {
         MeshModel model = new MeshModel();
         canvas.changeModel(canvas.getLoadedFace().getMeshModel());
-        SymmetryEstimator est = new SymmetryEstimator(config, SymmetryEstimator.CurvatureAlg.GAUSSIAN); // MISTO TRUE MUSI BYT VYBER STRATEGIE VYPOCTU ZAKRIVENI!!!
+        SymmetryEstimator est = new SymmetryEstimator(config, SignificantPoints.CurvatureAlg.GAUSSIAN); // MISTO TRUE MUSI BYT VYBER STRATEGIE VYPOCTU ZAKRIVENI!!!
         canvas.getLoadedFace().getMeshModel().getFacets().get(0).accept(est);
         symmetryPlane = est.getSymmetryPlane();
         MeshFacet facet = est.getSymmetryPlaneMesh();
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java
index 4d35e069..99e4f36f 100644
--- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java
@@ -134,4 +134,13 @@ public class MeshModel {
     public void unregisterListener(MeshListener listener) {
         eventBus.unregister(listener);
     }
+    
+    @Override
+    public String toString() {
+        int verts = 0;
+        for (MeshFacet f: facets) {
+            verts += f.getNumberOfVertices();
+        }
+        return facets.size() + " facets with " + verts + " vertices";
+    }
 }
-- 
GitLab