From 92a5472c8397a3f555eb6ddf7da639f6a2ae985e Mon Sep 17 00:00:00 2001 From: Daniel Schramm <xschramm@fi.muni.cz> Date: Wed, 8 Sep 2021 23:37:00 +0200 Subject: [PATCH] Variable radii of priority spheres around individual feature points --- .../face/HausdorffDistancePrioritized.java | 68 +++++++++++-------- .../HausdorffDistancePrioritizedTest.java | 54 +++++++++------ 2 files changed, 74 insertions(+), 48 deletions(-) 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 83ed7f1c..52f2949e 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); } /** @@ -309,15 +326,18 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { 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 PrioritySphere priorityVisitor = new PrioritySphere(featurePoint.getPosition(), computeSphereRadius(humanFace)); + final FeaturePoint featurePoint = humanFace.getFeaturePoints().get(featurePointType.getType()); // Get feature point of desired type + + 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 +351,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)) @@ -357,12 +377,4 @@ 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 - } } 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 a7315155..90bfef80 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); -- GitLab