diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritized.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritized.java
index 83ed7f1c7ce671694f97e4f66067e24cefe4d2b8..4402d79bc6c8b6a203563fcb75206e924390ac1e 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritized.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritized.java
@@ -54,7 +54,7 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
     
     private final HausdorffDistance distanceVisitor;
     
-    private final Set<FeaturePointType> featurePointTypes;
+    private final Map<FeaturePointType, Double> featurePointTypes;
     
     private final Map<HumanFace, Map<FeaturePointType, Map<MeshFacet, List<Double>>>> priorities = new HashMap<>();
     private final Map<HumanFace, Map<FeaturePointType, Map<MeshFacet, Double>>> featurePointWeights = new HashMap<>();
@@ -65,7 +65,8 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
      * 
      * @param mainFacets Facets to which distance from the visited human face's facets is to be computed.
      * Must not be {@code null}.
-     * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized.
+     * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized
+     * together with the radii of priority spheres around the feature points of the corresponding type.
      * Must not be {@code null}.
      * @param strategy Strategy of the computation of distance
      * @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect 
@@ -74,11 +75,16 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
      * @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores
      * @throws IllegalArgumentException if some parameter is wrong
      */
-    public HausdorffDistancePrioritized(Set<MeshFacet> mainFacets, Set<FeaturePointType> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
+    public HausdorffDistancePrioritized(Set<MeshFacet> mainFacets, Map<FeaturePointType, Double> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
         distanceVisitor = new HausdorffDistance(mainFacets, strategy, relativeDistance, parallel);
         if (featurePoints == null) {
             throw new IllegalArgumentException("featurePoints");
         }
+        for (final Double radius: featurePoints.values()) {
+            if (radius == null || radius < 0) {
+                throw new IllegalArgumentException("featurePoints");
+            }
+        }
         featurePointTypes = featurePoints;
     }
     
@@ -86,7 +92,8 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
      * Constructor.
      * 
      * @param mainFacet Primary facet to which distance from the visited human face's facets is to be computed. Must not be {@code null}.
-     * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized.
+     * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized
+     * together with the radii of priority spheres around the feature points of the corresponding type.
      * Must not be {@code null}.
      * @param strategy Strategy of the computation of distance
      * @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect 
@@ -95,7 +102,7 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
      * @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores
      * @throws IllegalArgumentException if some parameter is wrong
      */
-    public HausdorffDistancePrioritized(MeshFacet mainFacet, Set<FeaturePointType> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
+    public HausdorffDistancePrioritized(MeshFacet mainFacet, Map<FeaturePointType, Double> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
         this(new HashSet<>(Collections.singleton(mainFacet)), featurePoints, strategy, relativeDistance, parallel);
     }
     
@@ -104,7 +111,8 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
      * 
      * @param mainModel The mesh model with primary facets to which distance from the visited human face's facets is to be computed.
      * Must not be {@code null} or empty.
-     * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized.
+     * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized
+     * together with the radii of priority spheres around the feature points of the corresponding type.
      * Must not be {@code null}.
      * @param strategy Strategy of the computation of distance
      * @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect 
@@ -113,7 +121,7 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
      * @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores
      * @throws IllegalArgumentException if some parameter is wrong
      */
-    public HausdorffDistancePrioritized(MeshModel mainModel, Set<FeaturePointType> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
+    public HausdorffDistancePrioritized(MeshModel mainModel, Map<FeaturePointType, Double> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
         this(new HashSet<>(mainModel.getFacets()), featurePoints, strategy, relativeDistance, parallel);
     }
     
@@ -121,7 +129,8 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
      * Constructor.
      * 
      * @param face Human face to which distance from other human faces is to be computed. Must not be {@code null}.
-     * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized.
+     * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized
+     * together with the radii of priority spheres around the feature points of the corresponding type.
      * Must not be {@code null}.
      * @param strategy Strategy of the computation of distance
      * @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect 
@@ -130,7 +139,7 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
      * @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores
      * @throws IllegalArgumentException if some parameter is wrong
      */
-    public HausdorffDistancePrioritized(HumanFace face, Set<FeaturePointType> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
+    public HausdorffDistancePrioritized(HumanFace face, Map<FeaturePointType, Double> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
         this(face.getMeshModel(), featurePoints, strategy, relativeDistance, parallel);
     }
     
@@ -139,7 +148,8 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
      * 
      * @param mainKdTree The KD tree to which distance from the visited human face's facets is to be computed.
      * Must not be {@code null}.
-     * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized.
+     * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized
+     * together with the radii of priority spheres around the feature points of the corresponding type.
      * Must not be {@code null}.
      * @param strategy Strategy of the computation of distance
      * @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect 
@@ -148,23 +158,30 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
      * @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores
      * @throws IllegalArgumentException if some parameter is wrong
      */
-    public HausdorffDistancePrioritized(KdTree mainKdTree, Set<FeaturePointType> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
+    public HausdorffDistancePrioritized(KdTree mainKdTree, Map<FeaturePointType, Double> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
         distanceVisitor = new HausdorffDistance(mainKdTree, strategy, relativeDistance, parallel);
         if (featurePoints == null) {
             throw new IllegalArgumentException("featurePoints");
         }
+        for (final Double radius: featurePoints.values()) {
+            if (radius == null || radius < 0) {
+                throw new IllegalArgumentException("featurePoints");
+            }
+        }
         featurePointTypes = featurePoints;
     }
 
     /**
      * Returns types of feature points according to which the computation of Hausdorff
-     * distance is prioritized.
+     * distance is prioritized together with the radii of priority spheres around
+     * the feature points of the corresponding type.
      * 
      * @return Types of feature points according to which the computation of Hausdorff
-     * distance is prioritized
+     * distance is prioritized together with the radii of priority spheres around
+     * the feature points of the corresponding type
      */
-    public Set<FeaturePointType> getFeaturePointTypes() {
-        return Collections.unmodifiableSet(featurePointTypes);
+    public Map<FeaturePointType, Double> getFeaturePointTypes() {
+        return Collections.unmodifiableMap(featurePointTypes);
     }
     
     /**
@@ -305,19 +322,45 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
     public void visitHumanFace(HumanFace humanFace) {
         // Compute the Hasudorff distance using the 'distanceVisitor'
         humanFace.getMeshModel().compute(distanceVisitor, inParallel());
+
+        /*
+         * If there are no feature points to be computed
+         */
+        if (featurePointTypes.isEmpty()) {
+            final List<MeshFacet> faceFacets = humanFace.getMeshModel().getFacets();
+            final Map<MeshFacet, List<Double>> faceMergedPriorities = new HashMap<>(faceFacets.size());
+            for (final MeshFacet facet: faceFacets) {
+                faceMergedPriorities.put(facet, Collections.nCopies(facet.getNumberOfVertices(), 0d));
+            }
+
+            synchronized (this) {
+                priorities.put(humanFace, Map.of());
+                featurePointWeights.put(humanFace, Map.of());
+                mergedPriorities.put(humanFace, faceMergedPriorities);
+            }
+
+            return;
+        }
         
+        /*
+         * Compute priorities of humanFace's vertices for each of the given feature point types
+         */
         final Map<MeshFacet, List<Double>> hausdorffDistances = distanceVisitor.getDistances();
-                
-        // Compute priorities of humanFace's vertices for each of the given feature point types
-        for (final FeaturePointType fpType: featurePointTypes) {
-            final FeaturePoint featurePoint = humanFace.getFeaturePoints().get(fpType.getType()); // Get feature point of desired type
+        for (final Map.Entry<FeaturePointType, Double> fpType: featurePointTypes.entrySet()) {
+            final FeaturePointType featurePointType = fpType.getKey();
+            final double featurePointRadius = fpType.getValue();
+            
+            final FeaturePoint featurePoint = getFeaturePointByType(humanFace, featurePointType);
+            if (featurePoint == null) {
+                continue;
+            }
             
-            final PrioritySphere priorityVisitor = new PrioritySphere(featurePoint.getPosition(), computeSphereRadius(humanFace));
+            final PrioritySphere priorityVisitor = new PrioritySphere(featurePoint.getPosition(), featurePointRadius);
             humanFace.getMeshModel().compute(priorityVisitor, inParallel());
 
             synchronized (this) {
                 priorities.computeIfAbsent(humanFace, face -> new HashMap<>())
-                        .computeIfAbsent(fpType, featurePointType -> new HashMap<>())
+                        .computeIfAbsent(featurePointType, fPointType -> new HashMap<>())
                         .putAll(priorityVisitor.getPriorities());
             }
             
@@ -331,7 +374,7 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
                      */
                     final List<Double> facetDistances = hausdorffDistances.get(facet);
                     featurePointWeights.computeIfAbsent(humanFace, face -> new HashMap<>())
-                            .computeIfAbsent(fpType, featurePointType -> new HashMap<>())
+                            .computeIfAbsent(featurePointType, fPointType -> new HashMap<>())
                             .put(facet, IntStream.range(0, facetDistances.size())
                                     .filter(i -> facetPriorities.get(i) > 0) // Filter out vertices that are outside of the priority sphere
                                     .mapToDouble(i -> facetDistances.get(i) * facetPriorities.get(i))
@@ -358,11 +401,20 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
         }
     }
     
-    private double computeSphereRadius(HumanFace humanFace) {
-        // TODO TEMPORARY BEGIN
-        // Sphere radius needs to be computed dynamically.
-        // The best way to compute the right radius should be thought out in more depth.
-        return 1;
-        // TODO TEMPORARY END
+    /**
+     * Finds and returns a feature point of the desired type in the given human face.
+     * 
+     * @param face Face containing the desired feature point
+     * @param type Type of the feature point to be obtained
+     * @return Feature point of the desired type
+     */
+    protected FeaturePoint getFeaturePointByType(HumanFace face, FeaturePointType type) {
+        for (final FeaturePoint featurePoint: face.getFeaturePoints()) {
+            if (type.getType() == featurePoint.getFeaturePointType().getType()) {
+                return featurePoint;
+            }
+        }
+        
+        return null;
     }
 }
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/PrioritySphere.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/PrioritySphere.java
index 81d0cfa0c6df54fc543fe82a5a0fa349a8a2682c..31c3b647c80261ce3c453b14a8ec3e7e9622493c 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/PrioritySphere.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/PrioritySphere.java
@@ -41,13 +41,16 @@ public class PrioritySphere extends MeshVisitor  {
      * 
      * @param sphereCenterPosition Position of the center of the sphere in which
      *                             the priorities will be calculated
-     * @param sphereRadius Radius of the sphere
+     * @param sphereRadius Radius of the sphere (must be greater than or equal to 0)
      */
     public PrioritySphere(Point3d sphereCenterPosition, double sphereRadius) {
         if (sphereCenterPosition == null) {
             throw new IllegalArgumentException("sphereCenterPosition");
         }
         this.sphereCenterPosition = sphereCenterPosition;
+        if (sphereRadius < 0) {
+            throw new IllegalArgumentException("sphereRadius");
+        }
         this.sphereRadius = sphereRadius;
     }
 
diff --git a/Comparison/src/test/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritizedTest.java b/Comparison/src/test/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritizedTest.java
index a7315155e3a19555cbc843478ef336863fab7ffa..90bfef802aefa36c307f1dca9b2894d72e2f8803 100644
--- a/Comparison/src/test/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritizedTest.java
+++ b/Comparison/src/test/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritizedTest.java
@@ -14,11 +14,11 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 import javax.vecmath.Point3d;
 import javax.vecmath.Vector3d;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -106,13 +106,20 @@ public class HausdorffDistancePrioritizedTest {
         return face;
     }
     
+    private static Map<FeaturePointType, Double> zipListsToMap(List<FeaturePointType> fpTypes, List<Double> fpRadii) {
+        assertEquals(fpTypes.size(), fpRadii.size());
+        return IntStream.range(0, fpTypes.size())
+                .boxed()
+                .collect(Collectors.toMap(fpTypes::get, fpRadii::get));
+    }
+    
     protected void performTest(HumanFace face,
             Map<FeaturePointType, Map<MeshFacet, List<Double>>> expectedPriorities,
             Map<FeaturePointType, Map<MeshFacet, Double>> expectedFeaturePointWeights,
             Map<MeshFacet, List<Double>> expectedMergedPriorities,
             HausdorffDistancePrioritized visitor) {
         
-        final Set<FeaturePointType> featurePointTypes = visitor.getFeaturePointTypes();
+        final Set<FeaturePointType> featurePointTypes = visitor.getFeaturePointTypes().keySet();
         final List<FeaturePoint> faceFeaturePoints = face.getFeaturePoints();
         featurePointTypes.forEach(fpType -> assertTrue(faceFeaturePoints.stream()
                 .anyMatch(fPoint -> fPoint.getFeaturePointType().equals(fpType))));
@@ -203,9 +210,11 @@ public class HausdorffDistancePrioritizedTest {
     @Test
     public void singleFeaturePointTest() throws IOException {
         final List<Point3d> featurePoints = List.of(featurePoint1);
-        final List<FeaturePointType> featurePointTypes = List.of(fpType1);
+        final List<FeaturePointType> fpTypes = List.of(fpType1);
+        final Map<FeaturePointType, Double> featurePointTypes = zipListsToMap(fpTypes, List.of(1d));
+        
+        final HumanFace face = getHumanFace(facets, featurePoints, fpTypes);
         
-        final HumanFace face = getHumanFace(facets, featurePoints, featurePointTypes);
         final Map<FeaturePointType, Map<MeshFacet, List<Double>>> expectedPriorities = Map.of(fpType1, expectedPrioritiesMapFP1);
         final Map<FeaturePointType, Map<MeshFacet, Double>> expectedFeaturePointsWeights = Map.of(fpType1, expectedWeightedDistancesMapFP1);
         
@@ -215,7 +224,7 @@ public class HausdorffDistancePrioritizedTest {
         }
         
         final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()),
-                new HashSet<>(featurePointTypes),
+                featurePointTypes,
                 POINT_TO_POINT,
                 true,
                 false);
@@ -227,9 +236,10 @@ public class HausdorffDistancePrioritizedTest {
     public void twoFeaturePointsNoFacetIntersecTest() throws IOException {
         final List<Point3d> featurePoints = List.of(featurePoint1, new Point3d(3, 0, 0));
         final FeaturePointType fpType2 = new FeaturePointType(1, null, null, null);
-        final List<FeaturePointType> featurePointTypes = List.of(fpType1, fpType2);
+        final List<FeaturePointType> fpTypes = List.of(fpType1, fpType2);
+        final Map<FeaturePointType, Double> featurePointTypes = zipListsToMap(fpTypes, List.of(1d, 1d));
         
-        final HumanFace face = getHumanFace(facets, featurePoints, featurePointTypes);
+        final HumanFace face = getHumanFace(facets, featurePoints, fpTypes);
         
         final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP2 = new HashMap<>();
         for (final MeshFacet facet: facets) {
@@ -251,7 +261,7 @@ public class HausdorffDistancePrioritizedTest {
         }
         
         final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()),
-                new HashSet<>(featurePointTypes),
+                featurePointTypes,
                 POINT_TO_POINT,
                 false,
                 false);
@@ -263,9 +273,10 @@ public class HausdorffDistancePrioritizedTest {
     public void twoFeaturePointsSingleFacetIntersecTest() throws IOException {
         final List<Point3d> featurePoints = List.of(featurePoint1, new Point3d(1, 0, 0));
         final FeaturePointType fpType2 = new FeaturePointType(1, null, null, null);
-        final List<FeaturePointType> featurePointTypes = List.of(fpType1, fpType2);
+        final List<FeaturePointType> fpTypes = List.of(fpType1, fpType2);
+        final Map<FeaturePointType, Double> featurePointTypes = zipListsToMap(fpTypes, List.of(1d, 1d));
         
-        final HumanFace face = getHumanFace(facets, featurePoints, featurePointTypes);
+        final HumanFace face = getHumanFace(facets, featurePoints, fpTypes);
         
         final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP2 = new HashMap<>();
         for (final MeshFacet facet: facets) {
@@ -290,7 +301,7 @@ public class HausdorffDistancePrioritizedTest {
         expectedMergedPrioritiesMap.put(facet1, List.of(1d, 0.9, 0.8, 0.7, 0.6, 0.5, 0.6, 0.7, 0.8, 0.9, 1d, 0.9));
         
         final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()),
-                new HashSet<>(featurePointTypes),
+                featurePointTypes,
                 POINT_TO_POINT,
                 true,
                 false);
@@ -304,9 +315,10 @@ public class HausdorffDistancePrioritizedTest {
         final FeaturePointType fpType2 = new FeaturePointType(1, null, null, null);
         final FeaturePointType fpType3 = new FeaturePointType(2, null, null, null);
         final FeaturePointType fpType4 = new FeaturePointType(3, null, null, null);
-        final List<FeaturePointType> featurePointTypes = List.of(fpType1, fpType2, fpType3, fpType4);
+        final List<FeaturePointType> fpTypes = List.of(fpType1, fpType2, fpType3, fpType4);
+        final Map<FeaturePointType, Double> featurePointTypes = zipListsToMap(fpTypes, List.of(1d, 1d, 1d, 1d));
         
-        final HumanFace face = getHumanFace(facets, featurePoints, featurePointTypes);
+        final HumanFace face = getHumanFace(facets, featurePoints, fpTypes);
         
         final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP2 = new HashMap<>();
         final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP3 = new HashMap<>();
@@ -353,7 +365,7 @@ public class HausdorffDistancePrioritizedTest {
         expectedMergedPrioritiesMap.put(facet5, mergedPriorities);
         
         final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()),
-                new HashSet<>(featurePointTypes),
+                featurePointTypes,
                 POINT_TO_POINT,
                 true,
                 false);
@@ -366,9 +378,10 @@ public class HausdorffDistancePrioritizedTest {
         final List<Point3d> featurePoints = List.of(featurePoint1, new Point3d(0.999, 0.999, 0), new Point3d(0.999, -0.999, 0));
         final FeaturePointType fpType2 = new FeaturePointType(1, null, null, null);
         final FeaturePointType fpType3 = new FeaturePointType(2, null, null, null);
-        final List<FeaturePointType> featurePointTypes = List.of(fpType1, fpType2, fpType3);
+        final List<FeaturePointType> fpTypes = List.of(fpType1, fpType2, fpType3);
+        final Map<FeaturePointType, Double> featurePointTypes = zipListsToMap(fpTypes, List.of(1d, 1d, 1d));
         
-        final HumanFace face = getHumanFace(facets, featurePoints, featurePointTypes);
+        final HumanFace face = getHumanFace(facets, featurePoints, fpTypes);
         
         final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP2 = new HashMap<>();
         final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP3 = new HashMap<>();
@@ -415,7 +428,7 @@ public class HausdorffDistancePrioritizedTest {
         expectedMergedPrioritiesMap.put(facet4, mergedPriorities);
         
         final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()),
-                new HashSet<>(featurePointTypes),
+                featurePointTypes,
                 POINT_TO_POINT,
                 true,
                 false);
@@ -429,9 +442,10 @@ public class HausdorffDistancePrioritizedTest {
         final FeaturePointType fpType2 = new FeaturePointType(1, null, null, null);
         final FeaturePointType fpType3 = new FeaturePointType(2, null, null, null);
         final FeaturePointType fpType4 = new FeaturePointType(3, null, null, null);
-        final List<FeaturePointType> featurePointTypes = List.of(fpType1, fpType2, fpType3, fpType4);
+        final List<FeaturePointType> fpTypes = List.of(fpType1, fpType2, fpType3, fpType4);
+        final Map<FeaturePointType, Double> featurePointTypes = zipListsToMap(fpTypes, List.of(1d, 1d, 1d, 1d));
         
-        final HumanFace face = getHumanFace(facets, featurePoints, featurePointTypes);
+        final HumanFace face = getHumanFace(facets, featurePoints, fpTypes);
         
         final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP2 = new HashMap<>();
         final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP3 = new HashMap<>();
@@ -478,7 +492,7 @@ public class HausdorffDistancePrioritizedTest {
         expectedMergedPrioritiesMap.put(facet5, mergedPriorities);
         
         final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()),
-                new HashSet<>(featurePointTypes),
+                featurePointTypes,
                 POINT_TO_POINT,
                 true,
                 true);
diff --git a/GUI/src/main/java/cz/fidentis/analyst/core/ControlPanel.java b/GUI/src/main/java/cz/fidentis/analyst/core/ControlPanel.java
index 02017a8501bff1c9ce5d0dc39c5a1f6dfc6aefd1..65eab763b3aafd2d5caa29bde27cd0b710aeaf65 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/core/ControlPanel.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/core/ControlPanel.java
@@ -58,4 +58,29 @@ public abstract class ControlPanel extends JPanel {
             }  
         };
     }
+    
+    /**
+     * Creates and returns action listener that can be connected with a low-level 
+     * GUI element (e.g., a button). Action event of the low-level element is then
+     * re-directed to the given {@code ControlPanelAction} as given command.
+     * The listener may also carry additional data as a payload.
+     * 
+     * @param action An instance of the {@link ControlPanelAction}
+     * @param command Control panel command
+     * @param data Payload data of the action listener
+     * @return Action listener
+     */
+    protected final ActionListener createListener(ActionListener action, String command, Object data) {
+        return new AbstractAction() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                action.actionPerformed(new LoadedActionEvent(
+                        e.getSource(), 
+                        ActionEvent.ACTION_PERFORMED, 
+                        command,
+                        data)
+                ); 
+            }  
+        };
+    }
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/core/ControlPanelBuilder.java b/GUI/src/main/java/cz/fidentis/analyst/core/ControlPanelBuilder.java
index 5abef3e79f8d59530bc1c4902868257ab4309845..56a92405bbe223515e824557a3c99b2f36935620 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/core/ControlPanelBuilder.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/core/ControlPanelBuilder.java
@@ -22,6 +22,7 @@ import javax.swing.JComboBox;
 import javax.swing.JFormattedTextField;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
+import javax.swing.JScrollPane;
 import javax.swing.JSlider;
 import javax.swing.JTextField;
 import javax.swing.event.ChangeEvent;
@@ -34,7 +35,7 @@ import javax.swing.text.NumberFormatter;
  */
 public class ControlPanelBuilder {
     
-    public static final Font CAPTION_FONT= new Font("Arial", 1, 18);
+    public static final Font CAPTION_FONT = new Font("Arial", 1, 18);
     public static final Insets CAPTION_PADDING = new Insets(20, 0, 20, 0);  // top, left, bottom, right
     public static final ImageIcon HELP_ICON = new ImageIcon(ControlPanelBuilder.class.getResource("/info.png"));
     public static final Font OPTION_TEXT_FONT = new Font("Arial", 1, 14);
@@ -123,30 +124,57 @@ public class ControlPanelBuilder {
      * Adds a line with caption.
      * 
      * @param caption Caption text.
-     * @return This new  GUI object
+     * @return This new GUI object
      */
     public JLabel addCaptionLine(String caption) {
         GridBagConstraints c = new GridBagConstraints();
         c.insets = CAPTION_PADDING; 
-        c.gridwidth = GridBagConstraints.REMAINDER;
-        c.gridx = col;
-        c.gridy = row;
-        c.anchor = GridBagConstraints.LINE_START;
-        c.fill = GridBagConstraints.NONE;
-        JLabel label = new JLabel(caption);
+        
+        JLabel label = addLabelLineCustom(caption, c);
         label.setFont(CAPTION_FONT);
-        controlPanel.add(label, c);
+        
         //addLine();
         return label;
     }
     
+    /**
+     * Adds a line with a plain text label.
+     * 
+     * @param text Text of the label
+     * @return This new GUI object
+     */
+    public JLabel addLabelLine(String text) {
+        return addLabelLineCustom(text, new GridBagConstraints());
+    }
+    
+    /**
+     * Adds a line with a plain text label whose appearance can be further
+     * customized by {@code constraints}.
+     * 
+     * @param text Text of the label
+     * @param constraints {@code GridBagConstraints} to customize the label
+     * @return This new GUI object
+     */
+    private JLabel addLabelLineCustom(String text, GridBagConstraints constraints) {
+        constraints.gridwidth = GridBagConstraints.REMAINDER;
+        constraints.gridx = col;
+        constraints.gridy = row;
+        constraints.anchor = GridBagConstraints.LINE_START;
+        constraints.fill = GridBagConstraints.NONE;
+        
+        JLabel label = new JLabel(text);
+        controlPanel.add(label, constraints);
+        
+        return label;
+    }
+    
     /**
      * Adds a line with slider option.
      * 
      * @param helpAction Action listener invoked when the help icon is clicked. If {@code null}, then no help is shown.
      * @param text Option text.
      * @param sliderMax Max value of the slider (and the value field). If {@code -1}, then percentage slider is shown with 100 as the max. value.
-     * @param helpAction Action listener invoked when the input field is changed
+     * @param inputAction Action listener invoked when the input field is changed
      * @return Creates slider
      */
     public JTextField addSliderOptionLine(ActionListener helpAction, String text, int sliderMax, ActionListener inputAction) {
@@ -233,25 +261,51 @@ public class ControlPanelBuilder {
         GridBagConstraints c = new GridBagConstraints();
         c.insets = new Insets(2, 0, 40, 0); // small external space on top and bottom
         c.weighty = 1.0;   //request any extra vertical space
-        c.gridwidth = BUTTON_WIDTH;
-        c.gridy = row;
         c.anchor = GridBagConstraints.PAGE_END;
-        c.fill = GridBagConstraints.NONE;
         
         List<JButton> retButtons = new ArrayList<>();
         for (int i = 0; i < buttons.size(); i++) {
-            JButton button = new JButton();
-            button.setText(buttons.get(i));
-            button.addActionListener(actions.get(i));
-            c.gridx = col;
-            col += BUTTON_WIDTH;
-            controlPanel.add(button, c);
+            JButton button = addButtonCustom(buttons.get(i), actions.get(i), c);
             retButtons.add(button);
         }
 
         return retButtons;
     }
     
+    /**
+     * Adds a simple button.
+     * 
+     * @param caption Label
+     * @param action Action listener invoked when the corresponding button is clicked
+     * @return This new GUI object
+     */
+    public JButton addButton(String caption, ActionListener action) {
+        return addButtonCustom(caption, action, new GridBagConstraints());
+    }
+
+    /**
+     * Adds a simple button whose appearance can be further customized by {@code constraints}.
+     * 
+     * @param caption Label
+     * @param action Action listener invoked when the corresponding button is clicked
+     * @param constraints {@code GridBagConstraints} to customize the button
+     * @return This new GUI object
+     */
+    private JButton addButtonCustom(String caption, ActionListener action, GridBagConstraints constraints) {
+        JButton button = new JButton();
+        button.setText(caption);
+        button.addActionListener(action);
+        
+        constraints.gridwidth = BUTTON_WIDTH;
+        constraints.gridy = row;
+        constraints.gridx = col;
+        col += BUTTON_WIDTH;
+        constraints.fill = GridBagConstraints.NONE;
+        controlPanel.add(button, constraints);
+        
+        return button;
+    }
+    
     /**
      * Adds a combo box
      * @param items Items
@@ -307,7 +361,7 @@ public class ControlPanelBuilder {
      * Adds a check box.
      * 
      * @param selected Initial state
-     * @param actions Action listener invoked when the checkbox is clicked.
+     * @param action Action listener invoked when the checkbox is clicked.
      * @return This builder
      */
     public JCheckBox addCheckBox(boolean selected, ActionListener action) {
@@ -330,7 +384,7 @@ public class ControlPanelBuilder {
     /**
      * Adds a help icon.
      * 
-     * @param actions Action listener invoked when the icon is clicked.
+     * @param action Action listener invoked when the icon is clicked.
      * @return This builder
      */
     public JButton addOptionHelpIcon(ActionListener action) {
@@ -429,4 +483,25 @@ public class ControlPanelBuilder {
         return slider;
     }
     
+    /**
+     * Adds a scrollable pane that carries the given panel as its content.
+     * 
+     * @param content Panel to be made scrollable
+     * @return This new GUI object
+     */
+    public JScrollPane addScrollPane(JPanel content) {
+        JScrollPane scrollPane = new JScrollPane(content);
+        
+        GridBagConstraints c = new GridBagConstraints();
+        c.weighty = 1.0;
+        c.gridwidth = GridBagConstraints.REMAINDER;
+        c.gridy = row;
+        c.gridx = col;
+        c.anchor = GridBagConstraints.CENTER;
+        c.fill = GridBagConstraints.BOTH;
+        controlPanel.add(scrollPane, c);
+        
+        return scrollPane;
+    }
+    
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/core/LoadedActionEvent.java b/GUI/src/main/java/cz/fidentis/analyst/core/LoadedActionEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..05b7c390a07fec6f137cc08b81beb01296b9dea8
--- /dev/null
+++ b/GUI/src/main/java/cz/fidentis/analyst/core/LoadedActionEvent.java
@@ -0,0 +1,81 @@
+package cz.fidentis.analyst.core;
+
+import java.awt.event.ActionEvent;
+
+/**
+ * A subclass of {@link ActionEvent} extended to carry additional data as a payload.
+ * 
+ * @author Daniel Schramm
+ */
+public class LoadedActionEvent extends ActionEvent {
+    
+    private final Object data;
+
+    /**
+     * Constructor.
+     *
+     * @param source The object that originated the event
+     * @param id An integer that identifies the event.
+     *           For information on allowable values, see the class description
+     *           for {@link ActionEvent}
+     * @param command A string that may specify a command (possibly one
+     *                of several) associated with the event
+     * @param data Payload data of the event
+     * @throws IllegalArgumentException if {@code source} is null
+     */
+    public LoadedActionEvent(Object source, int id, String command, Object data) {
+        super(source, id, command);
+        this.data = data;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param source The object that originated the event
+     * @param id An integer that identifies the event.
+     *           For information on allowable values, see the class description
+     *           for {@link ActionEvent}
+     * @param command A string that may specify a command (possibly one
+     *                of several) associated with the event
+     * @param modifiers The modifier keys down during event (shift, ctrl, alt, meta).
+     *                  Passing negative parameter is not recommended.
+     *                  Zero value means that no modifiers were passed
+     * @param data Payload data of the event
+     * @throws IllegalArgumentException if {@code source} is null
+     */
+    public LoadedActionEvent(Object source, int id, String command, int modifiers, Object data) {
+        super(source, id, command, modifiers);
+        this.data = data;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param source The object that originated the event
+     * @param id An integer that identifies the event.
+     *           For information on allowable values, see the class description
+     *           for {@link ActionEvent}
+     * @param command A string that may specify a command (possibly one
+     *                of several) associated with the event
+     * @param modifiers The modifier keys down during event (shift, ctrl, alt, meta).
+     *                  Passing negative parameter is not recommended.
+     *                  Zero value means that no modifiers were passed
+     * @param when A long that gives the time the event occurred.
+     *             Passing negative or zero value is not recommended
+     * @param data Payload data of the event
+     * @throws IllegalArgumentException if {@code source} is null
+     */
+    public LoadedActionEvent(Object source, int id, String command, long when, int modifiers, Object data) {
+        super(source, id, command, when, modifiers);
+        this.data = data;
+    }
+
+    /**
+     * Returns payload data of the action event.
+     * 
+     * @return Payload data of the action event
+     */
+    public Object getData() {
+        return data;
+    }
+}
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 8e4b6723b39d61d1742266ca7c00fe7b94e18ad0..d1d4d488e4bb06f67a1cb7e04cdf06a946521f45 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java
@@ -1,27 +1,45 @@
 package cz.fidentis.analyst.distance;
 
 import cz.fidentis.analyst.canvas.Canvas;
+import cz.fidentis.analyst.core.LoadedActionEvent;
 import cz.fidentis.analyst.core.ControlPanelAction;
-import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
+import cz.fidentis.analyst.feature.FeaturePoint;
+import cz.fidentis.analyst.feature.FeaturePointType;
+import cz.fidentis.analyst.mesh.core.MeshFacet;
+import cz.fidentis.analyst.scene.DrawableFeaturePoints;
+import cz.fidentis.analyst.visitors.face.HausdorffDistancePrioritized;
 import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy;
+import java.awt.Color;
 import java.awt.event.ActionEvent;
+import java.util.DoubleSummaryStatistics;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 import javax.swing.JComboBox;
 import javax.swing.JTabbedPane;
+import javax.swing.JTextField;
 import javax.swing.JToggleButton;
 
 /**
  * Action listener for the curvature computation.
  * 
  * @author Radek Oslejsek
+ * @author Daniel Schramm
  */
 public class DistanceAction extends ControlPanelAction {
     
     /*
      * Attributes handling the state
      */
-    private HausdorffDistance visitor = null;
+    private HausdorffDistancePrioritized visitor = null;
+    private final Map<FeaturePointType, Double> featurePointTypes = new HashMap<>();
     private String strategy = DistancePanel.STRATEGY_POINT_TO_POINT;
     private boolean relativeDist = false;
+    private boolean weightedDist = false;
+    
+    private Map<MeshFacet, List<Double>> hausdorffDistance = null;
     
     private final DistancePanel controlPanel;
     
@@ -33,12 +51,12 @@ public class DistanceAction extends ControlPanelAction {
      */
     public DistanceAction(Canvas canvas, JTabbedPane topControlPanel) {
         super(canvas, topControlPanel);
-        this.controlPanel = new DistancePanel(this);
+        this.controlPanel = new DistancePanel(this, getSecondaryFeaturePoints().getFeaturePoints());
     }
 
     @Override
     public void actionPerformed(ActionEvent ae) {
-        String action = ae.getActionCommand();
+        final String action = ae.getActionCommand();
         
         switch (action) {
             case DistancePanel.ACTION_COMMAND_SHOW_HIDE_PANEL:
@@ -46,7 +64,7 @@ public class DistanceAction extends ControlPanelAction {
                 break;
             case DistancePanel.ACTION_COMMAND_SHOW_HIDE_HEATMAP:
                 if (((JToggleButton) ae.getSource()).isSelected()) {
-                    setHeatmap();
+                    calculateHausdorffDistance();
                     getSecondaryDrawableFace().setRenderHeatmap(true);
                 } else {
                     getSecondaryDrawableFace().setRenderHeatmap(false);
@@ -55,12 +73,27 @@ public class DistanceAction extends ControlPanelAction {
             case DistancePanel.ACTION_COMMAND_SET_DISTANCE_STRATEGY:
                 strategy = (String) ((JComboBox) ae.getSource()).getSelectedItem();
                 this.visitor = null; // recompute
-                setHeatmap();
+                calculateHausdorffDistance();
                 break;
             case DistancePanel.ACTION_COMMAND_RELATIVE_ABSOLUTE_DIST:
                 this.relativeDist = ((JToggleButton) ae.getSource()).isSelected();
                 this.visitor = null; // recompute
-                setHeatmap();
+                calculateHausdorffDistance();
+                break;
+            case DistancePanel.ACTION_COMMAND_FEATURE_POINT_HIGHLIGHT:
+                highlightFeaturePoint((LoadedActionEvent) ae);
+                break;
+            case DistancePanel.ACTION_COMMAND_FEATURE_POINT_RESIZE:
+                resizeFeaturePoint((LoadedActionEvent) ae);
+                break;
+            case DistancePanel.ACTION_COMMAND_WEIGHTED_DISTANCE:
+                this.weightedDist = ((JToggleButton) ae.getSource()).isSelected();
+                this.hausdorffDistance = null; // recompute only priorities
+                calculateHausdorffDistance();
+                break;
+            case DistancePanel.ACTION_COMMAND_WEIGHTED_DIST_RECOMPUTE:
+                this.visitor = null; // recompute
+                calculateHausdorffDistance();
                 break;
             default:
                 // to nothing
@@ -68,8 +101,12 @@ public class DistanceAction extends ControlPanelAction {
         renderScene();
     }
     
-    protected void setHeatmap() {
-        Strategy useStrategy;
+    /**
+     * (Re)calculates the Hausdorff distance and updates the heat map of the secondary face
+     * as well as values of all appropriate GUI elements of {@link DistancePanel}.
+     */
+    protected void calculateHausdorffDistance() {
+        final Strategy useStrategy;
         switch (strategy) {
             case DistancePanel.STRATEGY_POINT_TO_POINT:
                 useStrategy = Strategy.POINT_TO_POINT;
@@ -81,11 +118,145 @@ public class DistanceAction extends ControlPanelAction {
                 throw new UnsupportedOperationException(strategy);
         }
         
-        if (visitor == null) { 
-            this.visitor = new HausdorffDistance(getPrimaryDrawableFace().getModel(), useStrategy, relativeDist, true);
-            getSecondaryDrawableFace().getModel().compute(visitor);
+        if (visitor == null) {
+            this.visitor = new HausdorffDistancePrioritized(getPrimaryDrawableFace().getModel(),
+                    featurePointTypes,
+                    useStrategy,
+                    relativeDist,
+                    true);
+            getSecondaryDrawableFace().getHumanFace().accept(visitor);
+            hausdorffDistance = null;
+        }
+        
+        // Update GUI elements that display the calculated Hausdorff distance
+        if (hausdorffDistance == null) {
+            hausdorffDistance = getWeightedDistance();
+            setHausdorffDistanceStatistics();
+            setFeaturePointWeigths();
+        }
+        getSecondaryDrawableFace().setHeatMap(hausdorffDistance);
+    }
+    
+    /**
+     * Calculates weighted (or regular) Hausdorff distance of the face.
+     * 
+     * @return weighted Hausdorff distance
+     */
+    private Map<MeshFacet, List<Double>> getWeightedDistance() {
+        if (!weightedDist) {
+            return visitor.getDistances();
+        }
+        
+        // Merge the map of distances with the map of priorities
+        final Map<MeshFacet, List<Double>> weightedDistances = new HashMap<>(visitor.getDistances());
+
+        final Map<MeshFacet, List<Double>> mergedPriorities = visitor.getMergedPriorities()
+                .get(getSecondaryDrawableFace().getHumanFace());
+        for (final Map.Entry<MeshFacet, List<Double>> facetPriorities: mergedPriorities.entrySet()) {
+            weightedDistances.merge(
+                    facetPriorities.getKey(),
+                    facetPriorities.getValue(),
+                    (distancesList, prioritiesList) ->
+                            IntStream.range(0, distancesList.size())
+                                    .mapToDouble(i -> distancesList.get(i) * prioritiesList.get(i))
+                                    .boxed()
+                                    .collect(Collectors.toList()));
+        }
+
+        return weightedDistances;
+    }
+
+    /**
+     * Updates the GUI elements of {@link DistancePanel} elements that display
+     * statistical data about the calculated Hausdorff distance.
+     */
+    private void setHausdorffDistanceStatistics() {
+        final DoubleSummaryStatistics distanceStats = hausdorffDistance.values()
+                .stream()
+                .flatMap(List::stream)
+                .mapToDouble(distance -> distance)
+                .summaryStatistics();
+        
+        controlPanel.updateHausdorffDistanceStats(
+                distanceStats.getAverage(),
+                distanceStats.getMax(),
+                distanceStats.getMin()
+        );
+    }
+    
+    /**
+     * Updates the GUI elements of {@link DistancePanel} that display
+     * the weights of feature points used to calculate the weighted Hausdorff distance.
+     */
+    private void setFeaturePointWeigths() {
+        if (!weightedDist) {
+            controlPanel.updateFeaturePointWeights(Map.of());
+            return;
+        }
+        
+        controlPanel.updateFeaturePointWeights(
+                visitor.getFeaturePointWeights()
+                        .get(getSecondaryDrawableFace().getHumanFace()) // Get FP weights for the secondary face
+                        .entrySet()
+                        .stream()
+                        .collect(
+                                Collectors.toMap(
+                                        Map.Entry::getKey,            // For each FP type at the secondary face...
+                                        weights -> weights.getValue() // ... compute average FP weight over all its facets
+                                                .values()
+                                                .stream()
+                                                .mapToDouble(weight -> weight)
+                                                .average()
+                                                .orElse(Double.NaN))));
+    }
+    
+    /**
+     * Changes the colour of the secondary face's feature point at the given index.
+     * The index is received as the data payload of {@code actionEvent}.
+     * 
+     * @param actionEvent Action event with the index of the feature point as its payload data
+     */
+    private void highlightFeaturePoint(LoadedActionEvent actionEvent) {
+        final int index = (int) actionEvent.getData();
+        final FeaturePointType fpType = getTypeOfFeaturePoint(index);
+        final DrawableFeaturePoints secondaryFeaturePoints = getSecondaryFeaturePoints();
+        
+        if (((JToggleButton) actionEvent.getSource()).isSelected()) {
+            secondaryFeaturePoints.setColor(index, Color.MAGENTA);
+            featurePointTypes.put(fpType, secondaryFeaturePoints.getSize(index));
+        } else {
+            secondaryFeaturePoints.resetColorToDefault(index);
+            featurePointTypes.remove(fpType);
+        }
+    }
+
+    /**
+     * Changes the size of the secondary face's feature point at the given index.
+     * The index is received as the data payload of {@code actionEvent}.
+     * 
+     * @param actionEvent Action event with the index of the feature point as its payload data
+     */
+    private void resizeFeaturePoint(LoadedActionEvent actionEvent) {
+        final int index = (int) actionEvent.getData();
+        final double size = Double.parseDouble(((JTextField) actionEvent.getSource()).getText());
+        
+        getSecondaryFeaturePoints().setSize(index, size);
+        featurePointTypes.replace(getTypeOfFeaturePoint(index), size);
+    }
+    
+    /**
+     * Returns type of the feature point at the given index in the secondary face.
+     * 
+     * @param index Index of the feature point
+     * @return Type of the feature point or {@code null}
+     */
+    private FeaturePointType getTypeOfFeaturePoint(int index) {
+        final List<FeaturePoint> featurePoints = getSecondaryFeaturePoints().getFeaturePoints();
+        if (index < 0 || index >= featurePoints.size()) {
+            return null;
         }
         
-        getSecondaryDrawableFace().setHeatMap(visitor.getDistances());
+        return featurePoints.get(index)
+                .getFeaturePointType();
     }
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/distance/DistancePanel.java b/GUI/src/main/java/cz/fidentis/analyst/distance/DistancePanel.java
index fe8f5da82d2b1fa30f5a146794d19fcdf1cc75ca..035a8274f3f007166f1eb7cd11ae3ce9ce1a5796 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/distance/DistancePanel.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/distance/DistancePanel.java
@@ -2,15 +2,29 @@ package cz.fidentis.analyst.distance;
 
 import cz.fidentis.analyst.core.ControlPanel;
 import cz.fidentis.analyst.core.ControlPanelBuilder;
+import cz.fidentis.analyst.feature.FeaturePoint;
+import cz.fidentis.analyst.feature.FeaturePointType;
+import cz.fidentis.analyst.scene.DrawableFeaturePoints;
 import cz.fidentis.analyst.symmetry.SymmetryPanel;
+import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import javax.swing.BorderFactory;
 import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
 
 /**
  * Control panel for Hausdorff distance.
  * 
  * @author Radek Oslejsek
+ * @author Daniel Schramm
  */
 public class DistancePanel extends ControlPanel {
     
@@ -26,21 +40,28 @@ public class DistancePanel extends ControlPanel {
     public static final String ACTION_COMMAND_SHOW_HIDE_HEATMAP = "show-hide heatmap";
     public static final String ACTION_COMMAND_SET_DISTANCE_STRATEGY = "set strategy";
     public static final String ACTION_COMMAND_RELATIVE_ABSOLUTE_DIST = "switch abosulte-relative distance";
+    public static final String ACTION_COMMAND_WEIGHTED_DISTANCE = "switch weighted distance on/off";
+    public static final String ACTION_COMMAND_FEATURE_POINT_HIGHLIGHT = "highlight feature point with color";
+    public static final String ACTION_COMMAND_FEATURE_POINT_RESIZE = "set size of feature point";
+    public static final String ACTION_COMMAND_WEIGHTED_DIST_RECOMPUTE = "recompute weighted distance";
     
     /*
      * 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 String STRATEGY_POINT_TO_POINT = "Point to point";
+    public static final String STRATEGY_POINT_TO_TRIANGLE = "Point to triangle";
+    
+    private final JPanel featurePointsStats;
+    private final JLabel avgHD, maxHD, minHD;
     
     /**
      * Constructor.
      * @param action Action listener
      */
-    public DistancePanel(ActionListener action) {
+    public DistancePanel(ActionListener action, List<FeaturePoint> featurePoints) {
         this.setName(NAME);
         
-        ControlPanelBuilder builder = new ControlPanelBuilder(this);
+        final ControlPanelBuilder builder = new ControlPanelBuilder(this);
         
         builder.addCaptionLine("Computation options:");
         builder.addLine();
@@ -61,6 +82,75 @@ public class DistancePanel extends ControlPanel {
         builder.addGap();
         builder.addLine();
         
+        final JCheckBox weightedDistChBx = builder.addCheckBoxOptionLine(
+                null,
+                "Weighted Hausdorff distance",
+                false,
+                createListener(action, ACTION_COMMAND_WEIGHTED_DISTANCE)
+        );
+        builder.addLine();
+        
+        final JPanel featurePointsPanel = new JPanel();
+        final ControlPanelBuilder fpBuilder = new ControlPanelBuilder(featurePointsPanel);
+        final List<JCheckBox> fpCheckBoxes = new ArrayList<>(featurePoints.size());
+        final List<JTextField> fpSliderInputs = new ArrayList<>(featurePoints.size());
+        for (int i = 0; i < featurePoints.size(); i++) {
+            final FeaturePoint featurePoint = featurePoints.get(i);
+            
+            final JCheckBox checkBox = fpBuilder.addCheckBox(
+                    false,
+                    createListener(action, ACTION_COMMAND_FEATURE_POINT_HIGHLIGHT, i)
+            );
+            checkBox.setText(featurePoint.getFeaturePointType().getName());
+            fpCheckBoxes.add(checkBox);
+
+            final JTextField sliderInput = fpBuilder.addSliderOptionLine(
+                    null,
+                    null,
+                    100,
+                    createListener(action, ACTION_COMMAND_FEATURE_POINT_RESIZE, i)
+            );
+            sliderInput.setText(ControlPanelBuilder.doubleToStringLocale(DrawableFeaturePoints.DEFAULT_SIZE));
+            sliderInput.postActionEvent();
+            fpSliderInputs.add(sliderInput);
+            
+            fpBuilder.addLine();
+        }
+        builder.addScrollPane(featurePointsPanel)
+                .setBorder(BorderFactory.createTitledBorder("Feature points"));
+        builder.addLine();
+        
+        final JButton recomputeButton = builder.addButton(
+                "Recompute",
+                createListener(action, ACTION_COMMAND_WEIGHTED_DIST_RECOMPUTE)
+        );
+        recomputeButton.setEnabled(false);
+        recomputeButton.addActionListener((ActionEvent ae) -> 
+            recomputeButton.setEnabled(false)
+        );
+        weightedDistChBx.addActionListener((ActionEvent ae) -> {
+            if (!weightedDistChBx.isSelected()) {
+                recomputeButton.setEnabled(false);
+            }
+        });
+        for (final JCheckBox checkBox: fpCheckBoxes) {
+            checkBox.addActionListener((ActionEvent ae) -> {
+                if (weightedDistChBx.isSelected()) {
+                    recomputeButton.setEnabled(true);
+                }
+            });
+        }
+        for (int i = 0; i < fpSliderInputs.size(); i++) {
+            final JTextField sliderInput = fpSliderInputs.get(i);
+            final JCheckBox sliderCheckBox = fpCheckBoxes.get(i);
+            sliderInput.addActionListener((ActionEvent ae) -> {
+                if (weightedDistChBx.isSelected() && sliderCheckBox.isSelected()) {
+                    recomputeButton.setEnabled(true);
+                }
+            });
+        }
+        builder.addLine();
+        
         builder.addCaptionLine("Visualization options:");
         builder.addLine();
         builder.addCheckBoxOptionLine(
@@ -70,6 +160,35 @@ public class DistancePanel extends ControlPanel {
                 createListener(action, ACTION_COMMAND_SHOW_HIDE_HEATMAP)
         ); 
         builder.addLine();
+        
+        builder.addCaptionLine("Hausdorff distance:");
+        builder.addLine();
+        
+        builder.addOptionText("Average");
+        builder.addGap();
+        avgHD = builder.addLabelLine("");
+        builder.addGap();
+        builder.addLine();
+        builder.addOptionText("Maximum");
+        builder.addGap();
+        maxHD = builder.addLabelLine("");
+        builder.addGap();
+        builder.addLine();
+        builder.addOptionText("Minimum");
+        builder.addGap();
+        minHD = builder.addLabelLine("");
+        builder.addGap();
+        builder.addLine();
+        
+        featurePointsStats = new JPanel();
+        final JScrollPane fpStatsScrollPanel = builder.addScrollPane(featurePointsStats);
+        fpStatsScrollPanel.setBorder(BorderFactory.createTitledBorder("Feature point weights"));
+        fpStatsScrollPanel.setVisible(false);
+        weightedDistChBx.addActionListener((ActionEvent ae) -> {
+            fpStatsScrollPanel.setVisible(weightedDistChBx.isSelected());
+        });
+        builder.addLine();
+        
         builder.addVerticalStrut();
     }
     
@@ -86,4 +205,38 @@ public class DistancePanel extends ControlPanel {
     public static ImageIcon getStaticIcon() {
         return new ImageIcon(SymmetryPanel.class.getClassLoader().getResource("/" + ICON));
     }
+    
+    /**
+     * Updates GUI elements that display statistical data about the calculated Hausdorff distance.
+     * 
+     * @param averageDist Average distance
+     * @param maxDist Maximum distance
+     * @param minDist Minimum distance
+     */
+    public void updateHausdorffDistanceStats(double averageDist, double maxDist, double minDist) {
+        avgHD.setText(Double.toString(averageDist));
+        maxHD.setText(Double.toString(maxDist));
+        minHD.setText(Double.toString(minDist));
+    }
+    
+    /**
+     * Updates GUI elements that display the weights of feature points
+     * used to calculate the weighted Hausdorff distance.
+     * 
+     * @param featurePointWeights Map of feature point types and their weights
+     */
+    public void updateFeaturePointWeights(Map<FeaturePointType, Double> featurePointWeights) {
+        featurePointsStats.removeAll();
+        
+        final ControlPanelBuilder fpBuilder = new ControlPanelBuilder(featurePointsStats);
+        for (final Map.Entry<FeaturePointType, Double> fpStats: featurePointWeights.entrySet()) {
+            fpBuilder.addOptionText(fpStats.getKey().getName());
+            fpBuilder.addGap();
+            
+            fpBuilder.addLabelLine(Double.toString(fpStats.getValue()));
+            fpBuilder.addGap();
+            fpBuilder.addLine();
+        }
+    }
+
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFace.java b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFace.java
index 9b7d6f1198e8aa0ab9e9f486856b76ab1e6bb46f..84bc48f766b69b2444ca4fbc73f00815ee5744e0 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFace.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFace.java
@@ -1,8 +1,8 @@
 package cz.fidentis.analyst.scene;
 
 import com.jogamp.opengl.GL2;
+import cz.fidentis.analyst.face.HumanFace;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
-import cz.fidentis.analyst.mesh.core.MeshModel;
 import java.awt.Color;
 import java.util.Collections;
 import java.util.HashMap;
@@ -19,10 +19,7 @@ public class DrawableFace extends DrawableMesh {
     public static final Color SKIN_COLOR_PRIMARY = new Color(224, 172, 105);
     public static final Color SKIN_COLOR_SECONDARY = new Color(236, 188, 180);
     
-    /* feature points */
-    //private List<FeaturePoint> featurePoints = new ArrayList<>();
-    //private List<Color> featurePointsColor = new ArrayList<>();
-    //private boolean renderFeaturePoints = false;
+    private final HumanFace humanFace;
     private boolean renderHeatMap = false;
     
     /**
@@ -31,13 +28,15 @@ public class DrawableFace extends DrawableMesh {
     private Map<MeshFacet, List<Double>> heatmap = new HashMap<>();
     
     /**
-     * Constructor. 
+     * Constructor.
      * 
-     * @param model Drawable mesh model of the face
-     * @throws IllegalArgumentException if the model is {@code null}
+     * @param face Drawable human face
+     * @throws IllegalArgumentException if the mesh model
+     *         of the human face is {@code null}
      */
-    public DrawableFace(MeshModel model) {
-        super(model);
+    public DrawableFace(HumanFace face) {
+        super(face.getMeshModel());
+        humanFace = face;
         setColor(SKIN_COLOR_PRIMARY);
     }
     
@@ -50,12 +49,28 @@ public class DrawableFace extends DrawableMesh {
         this.heatmap = heatmap;
     }
     
+    /**
+     * Returns heatmap of the face
+     * (values at mesh vertices that are to be transferred to colors).
+     * 
+     * @return Heatmap of the face
+     */
     public Map<MeshFacet, List<Double>> getHeatMap() {
         return Collections.unmodifiableMap(heatmap);
     }
+
+    /**
+     * Returns the human face.
+     * 
+     * @return {@link HumanFace}
+     */
+    public HumanFace getHumanFace() {
+        return humanFace;
+    }
     
     /**
      * Sets if the heatmap should be rendered or not.
+     * 
      * @param render The switch
      */
     public void setRenderHeatmap(boolean render) {
@@ -64,6 +79,7 @@ public class DrawableFace extends DrawableMesh {
     
     /**
      * Determines whether the heatmap is set to be rendered.
+     * 
      * @return id the heatmap will be rendered
      */
     public boolean isHeatmapRendered() {
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 dceacfbde5e02c92a43aeeda63c041dbd2258f73..d17f2c3936988a3ecc6e1bcad3fac2076849be04 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFeaturePoints.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFeaturePoints.java
@@ -14,10 +14,12 @@ import java.util.Map;
  * Drawable feature points.
  * 
  * @author Radek Oslejsek
+ * @author Daniel Schramm
  */
 public class DrawableFeaturePoints extends Drawable {
     
     public static final Color DEFAULT_COLOR = Color.LIGHT_GRAY;
+    public static final double DEFAULT_SIZE = 3f;
     
     private static final GLU GLU_CONTEXT = new GLU();
     
@@ -27,10 +29,16 @@ public class DrawableFeaturePoints extends Drawable {
     /**
      * feature points with color different from the default color
      */
-    private Map<Integer, Color> specialColors = new HashMap<>();
+    private final Map<Integer, Color> specialColors = new HashMap<>();
+    
+    /**
+     * feature points with size different from the default size
+     */
+    private final Map<Integer, Double> specialSizes = new HashMap<>();
     
     /**
      * Constructor.
+     * 
      * @param featurePoints Feature points
      */
     public DrawableFeaturePoints(List<FeaturePoint> featurePoints) {
@@ -39,9 +47,10 @@ public class DrawableFeaturePoints extends Drawable {
     }
     
     /**
-     * Returns color of given feature point
+     * Returns color of the feature point.
+     * 
      * @param index Index of the feature point
-     * @return the color or {@code null}
+     * @return The color or {@code null}
      */
     public Color getColor(int index) {
         if (index < 0 || index >= featurePoints.size()) {
@@ -55,9 +64,10 @@ public class DrawableFeaturePoints extends Drawable {
     }
     
     /**
-     * Sets color of the feature point. 
+     * Sets color of the feature point.
+     * 
      * @param index Index of the feature point
-     * @param color Color
+     * @param color New color of the feature point
      */
     public void setColor(int index, Color color) {
         if (index < 0 || index >= featurePoints.size() || color == null) {
@@ -71,7 +81,9 @@ public class DrawableFeaturePoints extends Drawable {
     }
     
     /**
-     * Removes (possible) special color of given feature point.
+     * Removes (possible) special color of the feature point.
+     * 
+     * @param index Index of the feature point
      */
     public void resetColorToDefault(int index) {
         setColor(index, getColor());
@@ -83,6 +95,56 @@ public class DrawableFeaturePoints extends Drawable {
     public void resetAllColorsToDefault() {
         this.specialColors.clear();
     }
+    
+    /**
+     * Returns size of the feature point.
+     * 
+     * @param index Index of the feature point
+     * @return The size or {@code null}
+     */
+    public Double getSize(int index) {
+        if (index < 0 || index >= featurePoints.size()) {
+            return null;
+        }
+        if (specialSizes.containsKey(index)) {
+            return specialSizes.get(index);
+        } else {
+            return DEFAULT_SIZE;
+        }
+    }
+    
+    /**
+     * Sets size of the feature point.
+     * 
+     * @param index Index of the feature point
+     * @param size New size of the feature point
+     */
+    public void setSize(int index, double size) {
+        if (index < 0 || index >= featurePoints.size()) {
+            return;
+        }
+        if (size == DEFAULT_SIZE) {
+            specialSizes.remove(index);
+        } else {
+            specialSizes.put(index, size);
+        }
+    }
+    
+    /**
+     * Removes (possible) special size of the feature point.
+     * 
+     * @param index Index of the feature point
+     */
+    public void resetSizeToDefault(int index) {
+        setSize(index, DEFAULT_SIZE);
+    }
+    
+    /**
+     * Removes all individual sizes of feature points.
+     */
+    public void resetAllSizesToDefault() {
+        specialSizes.clear();
+    }
 
     @Override
     protected void renderObject(GL2 gl) {
@@ -108,7 +170,7 @@ public class DrawableFeaturePoints extends Drawable {
             GLU_CONTEXT.gluQuadricDrawStyle(center, GLU.GLU_FILL);
             GLU_CONTEXT.gluQuadricNormals(center, GLU.GLU_FLAT);
             GLU_CONTEXT.gluQuadricOrientation(center, GLU.GLU_OUTSIDE);
-            GLU_CONTEXT.gluSphere(center, 3f, 16, 16);
+            GLU_CONTEXT.gluSphere(center, specialSizes.getOrDefault(i, DEFAULT_SIZE), 16, 16);
             GLU_CONTEXT.gluDeleteQuadric(center);
             gl.glPopMatrix();
     
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 7ada8326754119e88649888babf15afc87991b6f..ab19624d5e94aab63bc1796d6c4d606ea7a8c86d 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java
@@ -29,7 +29,7 @@ public class Scene {
         }
 
         faces.add(face);
-        drawableFaces.add(new DrawableFace(face.getMeshModel()));
+        drawableFaces.add(new DrawableFace(face));
         if (face.getFeaturePoints() != null) {
             drawableFeaturePoints.add(new DrawableFeaturePoints(face.getFeaturePoints()));
         } else {
@@ -44,7 +44,7 @@ public class Scene {
      * Constructor for one-to-one analysis.
      * 
      * @param primary Primary face to be analyzed
-     * @param primary Secondary face to be analyzed
+     * @param secondary Secondary face to be analyzed
      * @throws IllegalArgumentException if some face is {@code null}
      */
     public Scene(HumanFace primary, HumanFace secondary) {
@@ -58,8 +58,8 @@ public class Scene {
         faces.add(primary);
         faces.add(secondary);
         
-        drawableFaces.add(new DrawableFace(primary.getMeshModel()));
-        drawableFaces.add(new DrawableFace(secondary.getMeshModel()));
+        drawableFaces.add(new DrawableFace(primary));
+        drawableFaces.add(new DrawableFace(secondary));
         
         if (primary.getFeaturePoints() != null) {
             drawableFeaturePoints.add(new DrawableFeaturePoints(primary.getFeaturePoints()));