Skip to content
Snippets Groups Projects
Commit 1f62d3d3 authored by Radek Ošlejšek's avatar Radek Ošlejšek
Browse files

Merge branch '68-implement-weighted-HD-sphere-around-feature-point-step-2' into 'master'

Resolve "Implement weighted Hausdorff distance - sphere around feature point (Step 2)"

Closes #68

See merge request grp-fidentis/analyst2!106
parents b10d46a7 d8de4848
No related branches found
No related tags found
No related merge requests found
...@@ -9,30 +9,43 @@ import cz.fidentis.analyst.mesh.core.MeshModel; ...@@ -9,30 +9,43 @@ import cz.fidentis.analyst.mesh.core.MeshModel;
import cz.fidentis.analyst.visitors.mesh.HausdorffDistance; import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy; import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy;
import cz.fidentis.analyst.visitors.mesh.PrioritySphere; import cz.fidentis.analyst.visitors.mesh.PrioritySphere;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.IntStream;
import javax.vecmath.Point3d; import javax.vecmath.Point3d;
/** /**
* Visitor for prioritized Hausdorff distance. * Visitor for prioritized Hausdorff distance with respect to the given types of feature points.
*
* The visitor computes the following:
* <ul>
* <li>Hausdorff distance</li>
* <li>Priorities of the faces' vertices with respect to the given types of feature
* points separately</li>
* <li>Priorities of the faces' vertices with respect to all the given types
* of feature points merged together</li>
* <li>Average weighted Hausdorff distance with respect to the given types of feature
* points for each of the faces' mesh facets</li>
* </ul>
* This visitor is instantiated with a single k-d tree (either given as the input * This visitor is instantiated with a single k-d tree (either given as the input
* parameter, or automatically created from the triangular mesh). * parameter, or automatically created from the triangular mesh).
* When applied to other human faces, it computes prioritized Hausdorff distance from their mesh facets * When applied to other human faces, it computes the Hausdorff distance from their mesh facets
* to the instantiated k-d tree. * to the instantiated k-d tree.
* <p> * <p>
* This visitor is thread-safe, i.e., a single instance of the visitor can be used * The Hausdorff distance is computed either as absolute or relative. Absolute
* to inspect multiple human faces simultaneously. * represents Euclidean distance (all numbers are positive). On the contrary,
* relative distance considers orientation of the visited face's facets (determined by its normal vectors)
* and produces positive or negative distances depending on whether the primary
* mesh is "in front of" or "behind" the given vertex.
* </p> * </p>
* <p> * <p>
* The distance is computed either as absolute or relative. Absolute * This visitor is thread-safe, i.e., a single instance of the visitor can be used
* represents Euclidean distance (all numbers are positive). On the contrary, * to inspect multiple human faces simultaneously.
* relative distance considers orientation of the visited face's facets (determined by its normal vectors)
* and produces positive or negative distances depending on whether the primary
* mesh is "in front of" or "behind" the given vertex.
* </p> * </p>
* *
* @author Daniel Schramm * @author Daniel Schramm
...@@ -41,16 +54,19 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { ...@@ -41,16 +54,19 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor {
private final HausdorffDistance distanceVisitor; private final HausdorffDistance distanceVisitor;
private final FeaturePointType featurePointType; private final Set<FeaturePointType> featurePointTypes;
private final Map<MeshFacet, List<Double>> priorities = new HashMap<>(); 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<>();
private final Map<HumanFace, Map<MeshFacet, List<Double>>> mergedPriorities = new HashMap<>();
/** /**
* Constructor. * Constructor.
* *
* @param mainFacets Facets to which distance from the visited human face's facets is to be computed. * @param mainFacets Facets to which distance from the visited human face's facets is to be computed.
* Must not be {@code null}. * Must not be {@code null}.
* @param featurePoint Feature point according to which the Hausdorff distances will be prioritized * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized.
* Must not be {@code null}.
* @param strategy Strategy of the computation of distance * @param strategy Strategy of the computation of distance
* @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect * @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect
* to the normal vectors of source facets (normal vectors have to present), * to the normal vectors of source facets (normal vectors have to present),
...@@ -58,16 +74,20 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { ...@@ -58,16 +74,20 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor {
* @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores * @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores
* @throws IllegalArgumentException if some parameter is wrong * @throws IllegalArgumentException if some parameter is wrong
*/ */
public HausdorffDistancePrioritized(Set<MeshFacet> mainFacets, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { public HausdorffDistancePrioritized(Set<MeshFacet> mainFacets, Set<FeaturePointType> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
distanceVisitor = new HausdorffDistance(mainFacets, strategy, relativeDistance, parallel); distanceVisitor = new HausdorffDistance(mainFacets, strategy, relativeDistance, parallel);
featurePointType = featurePoint; if (featurePoints == null) {
throw new IllegalArgumentException("featurePoints");
}
featurePointTypes = featurePoints;
} }
/** /**
* Constructor. * 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 mainFacet Primary facet to which distance from the visited human face's facets is to be computed. Must not be {@code null}.
* @param featurePoint Feature point according to which the Hausdorff distances will be prioritized * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized.
* Must not be {@code null}.
* @param strategy Strategy of the computation of distance * @param strategy Strategy of the computation of distance
* @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect * @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect
* to the normal vectors of source facets (normal vectors have to present), * to the normal vectors of source facets (normal vectors have to present),
...@@ -75,8 +95,8 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { ...@@ -75,8 +95,8 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor {
* @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores * @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores
* @throws IllegalArgumentException if some parameter is wrong * @throws IllegalArgumentException if some parameter is wrong
*/ */
public HausdorffDistancePrioritized(MeshFacet mainFacet, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { public HausdorffDistancePrioritized(MeshFacet mainFacet, Set<FeaturePointType> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
this(new HashSet<>(Collections.singleton(mainFacet)), featurePoint, strategy, relativeDistance, parallel); this(new HashSet<>(Collections.singleton(mainFacet)), featurePoints, strategy, relativeDistance, parallel);
} }
/** /**
...@@ -84,7 +104,8 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { ...@@ -84,7 +104,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. * @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. * Must not be {@code null} or empty.
* @param featurePoint Feature point according to which the Hausdorff distances will be prioritized * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized.
* Must not be {@code null}.
* @param strategy Strategy of the computation of distance * @param strategy Strategy of the computation of distance
* @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect * @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect
* to the normal vectors of source facets (normal vectors have to present), * to the normal vectors of source facets (normal vectors have to present),
...@@ -92,15 +113,16 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { ...@@ -92,15 +113,16 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor {
* @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores * @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores
* @throws IllegalArgumentException if some parameter is wrong * @throws IllegalArgumentException if some parameter is wrong
*/ */
public HausdorffDistancePrioritized(MeshModel mainModel, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { public HausdorffDistancePrioritized(MeshModel mainModel, Set<FeaturePointType> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
this(new HashSet<>(mainModel.getFacets()), featurePoint, strategy, relativeDistance, parallel); this(new HashSet<>(mainModel.getFacets()), featurePoints, strategy, relativeDistance, parallel);
} }
/** /**
* Constructor. * Constructor.
* *
* @param face Human face to which distance from other human faces is to be computed. Must not be {@code null}. * @param face Human face to which distance from other human faces is to be computed. Must not be {@code null}.
* @param featurePoint Feature point according to which the Hausdorff distances will be prioritized * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized.
* Must not be {@code null}.
* @param strategy Strategy of the computation of distance * @param strategy Strategy of the computation of distance
* @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect * @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect
* to the normal vectors of source facets (normal vectors have to present), * to the normal vectors of source facets (normal vectors have to present),
...@@ -108,8 +130,8 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { ...@@ -108,8 +130,8 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor {
* @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores * @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores
* @throws IllegalArgumentException if some parameter is wrong * @throws IllegalArgumentException if some parameter is wrong
*/ */
public HausdorffDistancePrioritized(HumanFace face, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { public HausdorffDistancePrioritized(HumanFace face, Set<FeaturePointType> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
this(face.getMeshModel(), featurePoint, strategy, relativeDistance, parallel); this(face.getMeshModel(), featurePoints, strategy, relativeDistance, parallel);
} }
/** /**
...@@ -117,7 +139,8 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { ...@@ -117,7 +139,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. * @param mainKdTree The KD tree to which distance from the visited human face's facets is to be computed.
* Must not be {@code null}. * Must not be {@code null}.
* @param featurePoint Feature point according to which the Hausdorff distances will be prioritized * @param featurePoints Types of feature points according to which the Hausdorff distances will be prioritized.
* Must not be {@code null}.
* @param strategy Strategy of the computation of distance * @param strategy Strategy of the computation of distance
* @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect * @param relativeDistance If {@code true}, then the visitor calculates the relative distances with respect
* to the normal vectors of source facets (normal vectors have to present), * to the normal vectors of source facets (normal vectors have to present),
...@@ -125,13 +148,23 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { ...@@ -125,13 +148,23 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor {
* @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores * @param parallel If {@code true}, then the algorithm runs concurrently utilizing all CPU cores
* @throws IllegalArgumentException if some parameter is wrong * @throws IllegalArgumentException if some parameter is wrong
*/ */
public HausdorffDistancePrioritized(KdTree mainKdTree, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { public HausdorffDistancePrioritized(KdTree mainKdTree, Set<FeaturePointType> featurePoints, Strategy strategy, boolean relativeDistance, boolean parallel) {
distanceVisitor = new HausdorffDistance(mainKdTree, strategy, relativeDistance, parallel); distanceVisitor = new HausdorffDistance(mainKdTree, strategy, relativeDistance, parallel);
featurePointType = featurePoint; if (featurePoints == null) {
throw new IllegalArgumentException("featurePoints");
}
featurePointTypes = featurePoints;
} }
public FeaturePointType getFeaturePointType() { /**
return featurePointType; * Returns types of feature points according to which the computation of Hausdorff
* distance is prioritized.
*
* @return Types of feature points according to which the computation of Hausdorff
* distance is prioritized
*/
public Set<FeaturePointType> getFeaturePointTypes() {
return Collections.unmodifiableSet(featurePointTypes);
} }
/** /**
...@@ -156,7 +189,7 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { ...@@ -156,7 +189,7 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor {
* Keys in the map contain mesh facets that were measured with the * Keys in the map contain mesh facets that were measured with the
* source facets. * source facets.
* For each facet of the visited human face, a list of the nearest points to the source * For each facet of the visited human face, a list of the nearest points to the source
* facets is stored. The order of points corresponds to the order of vertices * facets is stored. The order of points corresponds to the order of vertices
* in the measured facet, i.e., the i-th point is the nearest point of the i-th vertex * in the measured facet, i.e., the i-th point is the nearest point of the i-th vertex
* of the visited face's facet. * of the visited face's facet.
* *
...@@ -167,20 +200,70 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { ...@@ -167,20 +200,70 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor {
} }
/** /**
* Returns priorities of points of the visited faces' mesh facets. * Returns priorities of vertices of the visited faces' mesh facets with respect
* to the given types of feature points.
* Priorities are calculated for each type of feature point separately.
* *
* Keys in the map contain mesh facets of the visited human faces. * Keys in the map contain human faces whose mesh facets were measured with the
* For each facet of the visited human face, a list of priorities is stored. * source facets.
* The order of priorities corresponds to the order of vertices * For each human face, there is a map of examined types of feature points.
* in the visited facet, i.e., the i-th value is the priority of the i-th vertex * Each feature point type then stores a map of priorities of vertices
* of the visited face's facet. * of the face's mesh facets computed with respect to the face's feature point of
* the corresponding type.
* The order of priorities in the innermost map's value (list) corresponds to the order of vertices
* in its corresponding key (facet), i.e., the i-th value in the list is the priority of
* the i-th vertex of the facet.
* *
* @return Priorities of all points of all the visited human faces' facets * @return Priorities of vertices with respect to the given types of feature points
*/ */
public Map<MeshFacet, List<Double>> getPriorities() { public Map<HumanFace, Map<FeaturePointType, Map<MeshFacet, List<Double>>>> getPriorities() {
return Collections.unmodifiableMap(priorities); return Collections.unmodifiableMap(priorities);
} }
/**
* For all visited faces' mesh facets, the method returns the average weighted Hausdorff distance
* with respect to the given types of feature points (i.e. the sum of weighted distances
* of the mesh facet's vertices to the source facets divided by the number of vertices
* located within the feature point's priority sphere).
* The average weighted distances are calculated for each type of feature point separately.
*
* Keys in the map contain human faces whose mesh facets were measured with the
* source facets.
* For each human face, there is a map of examined types of feature points.
* Each feature point type then stores a map of the face's mesh facets together with
* the average weighted distances of their vertices to the source facets.
* The average weighted distances are calculated with respect to the face's feature point
* of the corresponding type.
* <i>If there is no vertex within the priority sphere of a feature point,
* the value of the average weighted Hausdorff distance is {@link Double#NaN}</i>
*
* @return Average weighted Hausdorff distances with respect to the given types
* of feature points
*/
public Map<HumanFace, Map<FeaturePointType, Map<MeshFacet, Double>>> getFeaturePointWeights() {
return Collections.unmodifiableMap(featurePointWeights);
}
/**
* Returns priorities of vertices of the visited faces' mesh facets with respect
* to all the given types of feature points merged together.
*
* Keys in the map contain human faces whose mesh facets were measured with the
* source facets.
* For each human face, there is a map of priorities of vertices of the visited
* face's mesh facets. The priorities are computed with respect to all the face's
* feature points of given types together.
* The order of priorities in the inner map's value (list) corresponds to the order of vertices
* in its corresponding key (facet), i.e., the i-th value in the list is the priority of
* the i-th vertex of the facet.
*
* @return Priorities of vertices with respect to all given types of feature
* points merged together
*/
public Map<HumanFace, Map<MeshFacet, List<Double>>> getMergedPriorities() {
return Collections.unmodifiableMap(mergedPriorities);
}
/** /**
* Returns {@code true} if the distance was computed as relative * Returns {@code true} if the distance was computed as relative
* (with possibly negative values). * (with possibly negative values).
...@@ -194,7 +277,7 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { ...@@ -194,7 +277,7 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor {
/** /**
* Returns the strategy of the computation of distance. * Returns the strategy of the computation of distance.
* *
* @return strategy of the computation of distance * @return Strategy of the computation of distance
*/ */
public Strategy getStrategy() { public Strategy getStrategy() {
return distanceVisitor.getStrategy(); return distanceVisitor.getStrategy();
...@@ -220,23 +303,66 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { ...@@ -220,23 +303,66 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor {
@Override @Override
public void visitHumanFace(HumanFace humanFace) { public void visitHumanFace(HumanFace humanFace) {
// Compute the Hasudorff distance using the 'distanceVisitor'
humanFace.getMeshModel().compute(distanceVisitor, inParallel()); humanFace.getMeshModel().compute(distanceVisitor, inParallel());
final FeaturePoint featurePoint = humanFace.getFeaturePoints().get(featurePointType.getType()); final Map<MeshFacet, List<Double>> hausdorffDistances = distanceVisitor.getDistances();
final PrioritySphere priorityVisitor = new PrioritySphere(featurePoint.getPosition(), computeSphereRadius(humanFace));
humanFace.getMeshModel().compute(priorityVisitor, inParallel()); // Compute priorities of humanFace's vertices for each of the given feature point types
for (final FeaturePointType fpType: featurePointTypes) {
synchronized(this) { final FeaturePoint featurePoint = humanFace.getFeaturePoints().get(fpType.getType()); // Get feature point of desired type
// Retrieve results from the visitor's internal structure
priorities.putAll(priorityVisitor.getPriorities()); final PrioritySphere priorityVisitor = new PrioritySphere(featurePoint.getPosition(), computeSphereRadius(humanFace));
humanFace.getMeshModel().compute(priorityVisitor, inParallel());
synchronized (this) {
priorities.computeIfAbsent(humanFace, face -> new HashMap<>())
.computeIfAbsent(fpType, featurePointType -> new HashMap<>())
.putAll(priorityVisitor.getPriorities());
}
for (final Map.Entry<MeshFacet, List<Double>> entry: priorityVisitor.getPriorities().entrySet()) {
final MeshFacet facet = entry.getKey();
final List<Double> facetPriorities = entry.getValue();
synchronized (this) {
/*
* Calculate the average weighted Hausdorff distance for the feature point.
*/
final List<Double> facetDistances = hausdorffDistances.get(facet);
featurePointWeights.computeIfAbsent(humanFace, face -> new HashMap<>())
.computeIfAbsent(fpType, featurePointType -> 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))
.average()
.orElse(Double.NaN)); // If there is no vertex in the priority sphere
/*
* Merge priorities computed for the current feature point type with the priorities of already computed feature point types.
*/
final List<Double> storedFacetPriorities = mergedPriorities
.computeIfAbsent(humanFace, face -> new HashMap<>())
.get(facet);
if (storedFacetPriorities == null) { // No priorities stored for this facet yet -> there is nothing to be merged
mergedPriorities.get(humanFace).put(facet, new ArrayList<>(facetPriorities));
continue;
}
// Merge priorities -> take the greater value
for (int i = 0; i < storedFacetPriorities.size(); i++) {
storedFacetPriorities.set(i, Double.max(storedFacetPriorities.get(i), facetPriorities.get(i)));
}
}
}
} }
} }
private double computeSphereRadius(HumanFace humanFace) { private double computeSphereRadius(HumanFace humanFace) {
// TODO TEMPORARY // TODO TEMPORARY BEGIN
// Sphere radius needs to be computed dynamically. // Sphere radius needs to be computed dynamically.
// The best way to compute the right radius should be thought out in more depth. // The best way to compute the right radius should be thought out in more depth.
return 1; return 1;
// TODO TEMPORARY // TODO TEMPORARY END
} }
} }
...@@ -221,7 +221,8 @@ public class HausdorffDistance extends MeshVisitor { ...@@ -221,7 +221,8 @@ public class HausdorffDistance extends MeshVisitor {
} }
/** /**
* Returns Hausdorff distance of mesh facets to the source mesh facets. * Returns Hausdorff distance of mesh facets to the source mesh facets.
*
* Keys in the map contain mesh facets that were measured with the * Keys in the map contain mesh facets that were measured with the
* source facets. For each measured facet, a list of distances to the source * source facets. For each measured facet, a list of distances to the source
* facets is stored. The order of distances corresponds to the order of vertices * facets is stored. The order of distances corresponds to the order of vertices
...@@ -236,6 +237,7 @@ public class HausdorffDistance extends MeshVisitor { ...@@ -236,6 +237,7 @@ public class HausdorffDistance extends MeshVisitor {
/** /**
* Returns the nearest points of mesh facets to the source mesh facets. * Returns the nearest points of mesh facets to the source mesh facets.
*
* Keys in the map contain mesh facets that were measured with the * Keys in the map contain mesh facets that were measured with the
* source facets. For each measured facet, a list of the nearest points to the source * source facets. For each measured facet, a list of the nearest points to the source
* facets is stored. The order of points corresponds to the order of vertices * facets is stored. The order of points corresponds to the order of vertices
...@@ -264,6 +266,7 @@ public class HausdorffDistance extends MeshVisitor { ...@@ -264,6 +266,7 @@ public class HausdorffDistance extends MeshVisitor {
/** /**
* Returns {@code true} if the distance computation is parallel. * Returns {@code true} if the distance computation is parallel.
*
* @return {@code true} if the distance computation is parallel. * @return {@code true} if the distance computation is parallel.
*/ */
public boolean inParallel() { public boolean inParallel() {
...@@ -356,12 +359,12 @@ public class HausdorffDistance extends MeshVisitor { ...@@ -356,12 +359,12 @@ public class HausdorffDistance extends MeshVisitor {
if (relativeDist) { // compute sign for relative distance if (relativeDist) { // compute sign for relative distance
Vector3d aux = new Vector3d(closestV); Vector3d aux = new Vector3d(closestV);
aux.sub(point.getPosition()); aux.sub(point.getPosition());
sign = (int) Math.signum(aux.dot(point.getNormal())); sign = aux.dot(point.getNormal()) < 0 ? -1 : 1;
} }
distances.get(facet).add(sign * dist); distances.get(facet).add(sign * dist);
if (nearestPoints.containsKey(facet)) { // only strategies with the closest points are stored in the map if (nearestPoints.containsKey(facet)) { // only strategies with the closest points are stored in the map
nearestPoints.get(facet).add(closestV); nearestPoints.get(facet).add(closestV);
} }
} }
...@@ -370,7 +373,7 @@ public class HausdorffDistance extends MeshVisitor { ...@@ -370,7 +373,7 @@ public class HausdorffDistance extends MeshVisitor {
* @return the only one existing closest vertex or {@code null} * @return the only one existing closest vertex or {@code null}
*/ */
protected Point3d getClosestVertex(DistanceWithNearestPoints vis) { protected Point3d getClosestVertex(DistanceWithNearestPoints vis) {
if (vis.getNearestPoints().size() != 1) { if (vis.getNearestPoints().size() != 1) {
return null; // somethig is wrong because there should be only my inspected facet return null; // somethig is wrong because there should be only my inspected facet
} }
......
...@@ -15,12 +15,13 @@ import javax.vecmath.Point3d; ...@@ -15,12 +15,13 @@ import javax.vecmath.Point3d;
* the given {@link PrioritySphere#sphereCenterPosition} point. * the given {@link PrioritySphere#sphereCenterPosition} point.
* <ul> * <ul>
* <li>1 is maximal priority; 0 is minimal priority</li> * <li>1 is maximal priority; 0 is minimal priority</li>
* <li>The closer a vertex is to {@link PrioritySphere#sphereCenterPosition}, the higher its priority is.</li> * <li>The closer a vertex is to {@link PrioritySphere#sphereCenterPosition},
* <li>Vertices that are further than {@link PrioritySphere#sphereRadius} from {@link PrioritySphere#sphereCenterPosition} * the higher its priority is.</li>
* have priority equal to 0.</li> * <li>Vertices that are further than {@link PrioritySphere#sphereRadius}
* from {@link PrioritySphere#sphereCenterPosition} have priority equal to 0.</li>
* </ul> * </ul>
* <p> * <p>
* The visitor returns all mesh facets together with priorities of all their vertices * The visitor returns all mesh facets together with priorities of all their vertices.
* </p> * </p>
* <p> * <p>
* This visitor is thread-safe. * This visitor is thread-safe.
...@@ -51,7 +52,7 @@ public class PrioritySphere extends MeshVisitor { ...@@ -51,7 +52,7 @@ public class PrioritySphere extends MeshVisitor {
} }
/** /**
* Returns map of visited mesh facets together with a list of priorities of their vertices. * Returns a map of visited mesh facets together with the list of priorities of their vertices.
* *
* The order of priorities corresponds to the order of vertices * The order of priorities corresponds to the order of vertices
* in the visited facet, i.e., the i-th priority is a priority of the i-th vertex * in the visited facet, i.e., the i-th priority is a priority of the i-th vertex
...@@ -67,7 +68,9 @@ public class PrioritySphere extends MeshVisitor { ...@@ -67,7 +68,9 @@ public class PrioritySphere extends MeshVisitor {
public void visitMeshFacet(MeshFacet facet) { public void visitMeshFacet(MeshFacet facet) {
final List<MeshPoint> vertices = facet.getVertices(); final List<MeshPoint> vertices = facet.getVertices();
for (int i = 0; i < vertices.size(); i++) { final List<Double> prioritiesList = new ArrayList<>(vertices.size());
for (int i = 0; i < vertices.size(); i++) { // for each vertex of visited facet
final double distance = sphereCenterPosition.distance(vertices.get(i).getPosition()); final double distance = sphereCenterPosition.distance(vertices.get(i).getPosition());
final double priority; final double priority;
if (distance > sphereRadius) { if (distance > sphereRadius) {
...@@ -76,10 +79,11 @@ public class PrioritySphere extends MeshVisitor { ...@@ -76,10 +79,11 @@ public class PrioritySphere extends MeshVisitor {
priority = 1 - distance / sphereRadius; priority = 1 - distance / sphereRadius;
} }
synchronized(this) { prioritiesList.add(priority);
priorities.computeIfAbsent(facet, meshFacet -> new ArrayList<>()) }
.add(priority);
} synchronized(this) {
priorities.put(facet, prioritiesList);
} }
} }
} }
package cz.fidentis.analyst.visitors.face;
import cz.fidentis.analyst.face.HumanFace;
import cz.fidentis.analyst.feature.FeaturePoint;
import cz.fidentis.analyst.feature.FeaturePointType;
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.MeshModel;
import cz.fidentis.analyst.mesh.core.MeshPointImpl;
import static cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy.POINT_TO_POINT;
import java.io.File;
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 javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
public class HausdorffDistancePrioritizedTest {
private static final double DELTA = 1e-15;
private final File boy = new File("src/test/resources/cz/fidentis/analyst/average_boy_17-20.obj");
private static final int VERTICES_NUM = 12;
private final MeshFacet facet1 = getTrivialFacet(VERTICES_NUM, 0.1, 0, 0, 0);
private final MeshFacet facet2 = getTrivialFacet(VERTICES_NUM, -0.1, 0, 0, 0);
private final MeshFacet facet3 = getTrivialFacet(VERTICES_NUM, 0, 0.1, 0, 0);
private final MeshFacet facet4 = getTrivialFacet(VERTICES_NUM, 0, -0.1, 0, 0);
private final MeshFacet facet5 = getTrivialFacet(VERTICES_NUM, 0, 0, 0.1, 0);
private final MeshFacet facet6 = getTrivialFacet(VERTICES_NUM, 0, 0, -0.1, 0);
private final List<MeshFacet> facets = List.of(facet1, facet2, facet3, facet4, facet5, facet6);
private final List<MeshFacet> facets2 = List.of(getTrivialFacet(1, 0, 0, 0, 0));
private final List<Double> prioritiesListFP1 = List.of(1d, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0d, 0d);
private final double weightedDistanceFP1 = 0 + 0.09 + 0.16 + 0.21 + 0.24 + 0.25 + 0.24 + 0.21 + 0.16 + 0.09 + 0 + 0;
private final double averageWeightedDistanceFP1 = weightedDistanceFP1 / 10; // There are 10 vertices inside the priority sphere
private final Point3d featurePoint1 = new Point3d(0, 0, 0);
private final FeaturePointType fpType1 = new FeaturePointType(0, null, null, null);
private final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP1 = Map.of(facet1, prioritiesListFP1,
facet2, prioritiesListFP1,
facet3, prioritiesListFP1,
facet4, prioritiesListFP1,
facet5, prioritiesListFP1,
facet6, prioritiesListFP1);
private final Map<MeshFacet, Double> expectedWeightedDistancesMapFP1 = Map.of(facet1, averageWeightedDistanceFP1,
facet2, averageWeightedDistanceFP1,
facet3, averageWeightedDistanceFP1,
facet4, averageWeightedDistanceFP1,
facet5, -averageWeightedDistanceFP1,
facet6, averageWeightedDistanceFP1);
private final Map<MeshFacet, Double> expectedAbsoluteWeightedDistancesMapFP1 = expectedWeightedDistancesMapFP1
.entrySet()
.stream()
.collect(Collectors.toMap(entry -> entry.getKey(), entry -> Math.abs(entry.getValue())));
private MeshFacet getTrivialFacet(int count, double xSpace, double ySpace, double zSpace, int offset) {
final MeshFacet facet = new MeshFacetImpl();
for (int i = offset; i < count + offset; i++) {
facet.addVertex(new MeshPointImpl(new Point3d(xSpace * i, ySpace * i, zSpace * i),
new Vector3d(0, 0, 1),
new Vector3d()));
facet.getCornerTable().addRow(new CornerTableRow(i - offset, -1));
}
return facet;
}
private HumanFace getHumanFace(List<MeshFacet> facets,
List<Point3d> featurePoints,
List<FeaturePointType> featurePointTypes) throws IOException {
assertEquals(featurePoints.size(), featurePointTypes.size());
final HumanFace face = new HumanFace(boy);
final MeshModel model = new MeshModel();
for (final MeshFacet facet: facets) {
model.addFacet(facet);
}
face.setMeshModel(model);
final List<FeaturePoint> featurePointsList = new ArrayList<>();
for (int i = 0; i < featurePoints.size(); i++) {
final Point3d fpCoordinates = featurePoints.get(i);
featurePointsList.add(new FeaturePoint(
fpCoordinates.x,
fpCoordinates.y,
fpCoordinates.z,
featurePointTypes.get(i)));
}
face.setFeaturePoints(featurePointsList);
return face;
}
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 List<FeaturePoint> faceFeaturePoints = face.getFeaturePoints();
featurePointTypes.forEach(fpType -> assertTrue(faceFeaturePoints.stream()
.anyMatch(fPoint -> fPoint.getFeaturePointType().equals(fpType))));
face.accept(visitor);
final List<MeshFacet> faceFacets = face.getMeshModel().getFacets();
// ---------------------------------------------------------------------
// Test priorities
// ---------------------------------------------------------------------
final Map<HumanFace, Map<FeaturePointType, Map<MeshFacet, List<Double>>>> priorities =
visitor.getPriorities();
assertTrue(priorities.containsKey(face));
final Map<FeaturePointType, Map<MeshFacet, List<Double>>> facePriorities =
priorities.get(face);
assertEquals(featurePointTypes.size(), facePriorities.size());
for (final FeaturePointType fpType: featurePointTypes) {
assertTrue(facePriorities.containsKey(fpType));
final Map<MeshFacet, List<Double>> facePrioritiesMap = facePriorities.get(fpType);
final Map<MeshFacet, List<Double>> expectedPrioritiesMap = expectedPriorities.get(fpType);
assertEquals(faceFacets.size(), facePrioritiesMap.size());
for (final MeshFacet facet: faceFacets) {
assertTrue(facePrioritiesMap.containsKey(facet));
final List<Double> facePrioritiesList = facePrioritiesMap.get(facet);
final List<Double> expectedPrioritiesList = expectedPrioritiesMap.get(facet);
assertEquals(expectedPrioritiesList.size(), facePrioritiesList.size());
for (int i = 0; i < expectedPrioritiesList.size(); i++) {
assertEquals(expectedPrioritiesList.get(i), facePrioritiesList.get(i), DELTA);
}
}
}
// ---------------------------------------------------------------------
// Test feature point weights
// ---------------------------------------------------------------------
final Map<HumanFace, Map<FeaturePointType, Map<MeshFacet, Double>>> featurePointWeights =
visitor.getFeaturePointWeights();
assertTrue(featurePointWeights.containsKey(face));
final Map<FeaturePointType, Map<MeshFacet, Double>> faceFeaturePointWeights =
featurePointWeights.get(face);
assertEquals(featurePointTypes.size(), faceFeaturePointWeights.size());
for (final FeaturePointType fpType: featurePointTypes) {
assertTrue(faceFeaturePointWeights.containsKey(fpType));
final Map<MeshFacet, Double> faceFPWeightsMap = faceFeaturePointWeights.get(fpType);
final Map<MeshFacet, Double> expectedFPWeightsMap = expectedFeaturePointWeights.get(fpType);
assertEquals(faceFacets.size(), faceFPWeightsMap.size());
for (final MeshFacet facet: faceFacets) {
assertTrue(faceFPWeightsMap.containsKey(facet));
final double expectedWeightedDistance = expectedFPWeightsMap.get(facet);
final double actualWeightedDistance = faceFPWeightsMap.get(facet);
assertEquals(expectedWeightedDistance, actualWeightedDistance, DELTA);
}
}
// ---------------------------------------------------------------------
// Test merged priorities
// ---------------------------------------------------------------------
final Map<HumanFace, Map<MeshFacet, List<Double>>> mergedPriorities =
visitor.getMergedPriorities();
assertTrue(mergedPriorities.containsKey(face));
final Map<MeshFacet, List<Double>> faceMergedPriorities =
mergedPriorities.get(face);
assertEquals(faceFacets.size(), faceMergedPriorities.size());
for (final MeshFacet facet: faceFacets) {
assertTrue(faceMergedPriorities.containsKey(facet));
final List<Double> faceMergedPrioritiesList = faceMergedPriorities.get(facet);
final List<Double> expectedMergedPrioritiesList = expectedMergedPriorities.get(facet);
assertEquals(expectedMergedPrioritiesList.size(), faceMergedPrioritiesList.size());
for (int i = 0; i < expectedMergedPrioritiesList.size(); i++) {
assertEquals(expectedMergedPrioritiesList.get(i), faceMergedPrioritiesList.get(i), DELTA);
}
}
}
@Test
public void singleFeaturePointTest() throws IOException {
final List<Point3d> featurePoints = List.of(featurePoint1);
final List<FeaturePointType> featurePointTypes = List.of(fpType1);
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);
final Map<MeshFacet, List<Double>> expectedMergedPrioritiesMap = new HashMap<>();
for (final MeshFacet facet: facets) {
expectedMergedPrioritiesMap.put(facet, prioritiesListFP1);
}
final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()),
new HashSet<>(featurePointTypes),
POINT_TO_POINT,
true,
false);
performTest(face, expectedPriorities, expectedFeaturePointsWeights, expectedMergedPrioritiesMap, visitor);
}
@Test
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 HumanFace face = getHumanFace(facets, featurePoints, featurePointTypes);
final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP2 = new HashMap<>();
for (final MeshFacet facet: facets) {
expectedPrioritiesMapFP2.put(facet, Collections.nCopies(VERTICES_NUM, 0d));
}
final Map<FeaturePointType, Map<MeshFacet, List<Double>>> expectedPriorities = Map.of(fpType1, expectedPrioritiesMapFP1,
fpType2, expectedPrioritiesMapFP2);
final Map<MeshFacet, Double> expectedWeightedDistancesMapFP2 = new HashMap<>();
for (final MeshFacet facet: facets) {
expectedWeightedDistancesMapFP2.put(facet, Double.NaN);
}
final Map<FeaturePointType, Map<MeshFacet, Double>> expectedFeaturePointsWeights = Map.of(fpType1, expectedAbsoluteWeightedDistancesMapFP1,
fpType2, expectedWeightedDistancesMapFP2);
final Map<MeshFacet, List<Double>> expectedMergedPrioritiesMap = new HashMap<>();
for (final MeshFacet facet: facets) {
expectedMergedPrioritiesMap.put(facet, prioritiesListFP1);
}
final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()),
new HashSet<>(featurePointTypes),
POINT_TO_POINT,
false,
false);
performTest(face, expectedPriorities, expectedFeaturePointsWeights, expectedMergedPrioritiesMap, visitor);
}
@Test
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 HumanFace face = getHumanFace(facets, featurePoints, featurePointTypes);
final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP2 = new HashMap<>();
for (final MeshFacet facet: facets) {
expectedPrioritiesMapFP2.put(facet, Collections.nCopies(VERTICES_NUM, 0d));
}
expectedPrioritiesMapFP2.put(facet1, List.of(0d, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1d, 0.9));
final Map<FeaturePointType, Map<MeshFacet, List<Double>>> expectedPriorities = Map.of(fpType1, expectedPrioritiesMapFP1,
fpType2, expectedPrioritiesMapFP2);
final Map<MeshFacet, Double> expectedWeightedDistancesMapFP2 = new HashMap<>();
for (final MeshFacet facet: facets) {
expectedWeightedDistancesMapFP2.put(facet, Double.NaN);
}
expectedWeightedDistancesMapFP2.put(facet1, (0 + 0.01 + 0.04 + 0.09 + 0.16 + 0.25 + 0.36 + 0.49 + 0.64 + 0.81 + 1 + 0.99) / 11);
final Map<FeaturePointType, Map<MeshFacet, Double>> expectedFeaturePointsWeights = Map.of(fpType1, expectedWeightedDistancesMapFP1,
fpType2, expectedWeightedDistancesMapFP2);
final Map<MeshFacet, List<Double>> expectedMergedPrioritiesMap = new HashMap<>();
for (final MeshFacet facet: facets) {
expectedMergedPrioritiesMap.put(facet, prioritiesListFP1);
}
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),
POINT_TO_POINT,
true,
false);
performTest(face, expectedPriorities, expectedFeaturePointsWeights, expectedMergedPrioritiesMap, visitor);
}
@Test
public void fourFeaturePointsSingleFacetIntersecTest() throws IOException {
final List<Point3d> featurePoints = List.of(featurePoint1, new Point3d(1, 0, 0), new Point3d(0, 1, 0), new Point3d(0, 0, 1));
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 HumanFace face = getHumanFace(facets, featurePoints, featurePointTypes);
final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP2 = new HashMap<>();
final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP3 = new HashMap<>();
final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP4 = new HashMap<>();
final List<Double> allZeroList = Collections.nCopies(VERTICES_NUM, 0d);
for (final MeshFacet facet: facets) {
expectedPrioritiesMapFP2.put(facet, allZeroList);
expectedPrioritiesMapFP3.put(facet, allZeroList);
expectedPrioritiesMapFP4.put(facet, allZeroList);
}
final List<Double> prioritiesList = List.of(0d, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1d, 0.9);
expectedPrioritiesMapFP2.put(facet1, prioritiesList);
expectedPrioritiesMapFP3.put(facet3, prioritiesList);
expectedPrioritiesMapFP4.put(facet5, prioritiesList);
final Map<FeaturePointType, Map<MeshFacet, List<Double>>> expectedPriorities = Map.of(fpType1, expectedPrioritiesMapFP1,
fpType2, expectedPrioritiesMapFP2,
fpType3, expectedPrioritiesMapFP3,
fpType4, expectedPrioritiesMapFP4);
final Map<MeshFacet, Double> expectedWeightedDistancesMapFP2 = new HashMap<>();
final Map<MeshFacet, Double> expectedWeightedDistancesMapFP3 = new HashMap<>();
final Map<MeshFacet, Double> expectedWeightedDistancesMapFP4 = new HashMap<>();
for (final MeshFacet facet: facets) {
expectedWeightedDistancesMapFP2.put(facet, Double.NaN);
expectedWeightedDistancesMapFP3.put(facet, Double.NaN);
expectedWeightedDistancesMapFP4.put(facet, Double.NaN);
}
final double weightedDistance = (0 + 0.01 + 0.04 + 0.09 + 0.16 + 0.25 + 0.36 + 0.49 + 0.64 + 0.81 + 1 + 0.99) / 11;
expectedWeightedDistancesMapFP2.put(facet1, weightedDistance);
expectedWeightedDistancesMapFP3.put(facet3, weightedDistance);
expectedWeightedDistancesMapFP4.put(facet5, -weightedDistance);
final Map<FeaturePointType, Map<MeshFacet, Double>> expectedFeaturePointsWeights = Map.of(fpType1, expectedWeightedDistancesMapFP1,
fpType2, expectedWeightedDistancesMapFP2,
fpType3, expectedWeightedDistancesMapFP3,
fpType4, expectedWeightedDistancesMapFP4);
final Map<MeshFacet, List<Double>> expectedMergedPrioritiesMap = new HashMap<>();
for (final MeshFacet facet: facets) {
expectedMergedPrioritiesMap.put(facet, prioritiesListFP1);
}
final List<Double> mergedPriorities = List.of(1d, 0.9, 0.8, 0.7, 0.6, 0.5, 0.6, 0.7, 0.8, 0.9, 1d, 0.9);
expectedMergedPrioritiesMap.put(facet1, mergedPriorities);
expectedMergedPrioritiesMap.put(facet3, mergedPriorities);
expectedMergedPrioritiesMap.put(facet5, mergedPriorities);
final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()),
new HashSet<>(featurePointTypes),
POINT_TO_POINT,
true,
false);
performTest(face, expectedPriorities, expectedFeaturePointsWeights, expectedMergedPrioritiesMap, visitor);
}
@Test
public void threeFeaturePointsMultiFacetIntersecTest() throws IOException {
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 HumanFace face = getHumanFace(facets, featurePoints, featurePointTypes);
final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP2 = new HashMap<>();
final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP3 = new HashMap<>();
final List<Double> allZeroList = Collections.nCopies(VERTICES_NUM, 0d);
for (final MeshFacet facet: facets) {
expectedPrioritiesMapFP2.put(facet, allZeroList);
expectedPrioritiesMapFP3.put(facet, allZeroList);
}
final double vertexDistance = Math.sqrt(Math.pow(0.999 - 1, 2) + Math.pow(0.999 - 0, 2) + Math.pow(0 - 0, 2));
final double vertexPriority = 1 - vertexDistance / 1;
final List<Double> prioritiesList = List.of(0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, vertexPriority, 0d);
expectedPrioritiesMapFP2.put(facet1, prioritiesList);
expectedPrioritiesMapFP2.put(facet3, prioritiesList);
expectedPrioritiesMapFP3.put(facet1, prioritiesList);
expectedPrioritiesMapFP3.put(facet4, prioritiesList);
final Map<FeaturePointType, Map<MeshFacet, List<Double>>> expectedPriorities = Map.of(fpType1, expectedPrioritiesMapFP1,
fpType2, expectedPrioritiesMapFP2,
fpType3, expectedPrioritiesMapFP3);
final Map<MeshFacet, Double> expectedWeightedDistancesMapFP2 = new HashMap<>();
final Map<MeshFacet, Double> expectedWeightedDistancesMapFP3 = new HashMap<>();
for (final MeshFacet facet: facets) {
expectedWeightedDistancesMapFP2.put(facet, Double.NaN);
expectedWeightedDistancesMapFP3.put(facet, Double.NaN);
}
final double weightedDistance = 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 * vertexPriority + 0;
expectedWeightedDistancesMapFP2.put(facet1, weightedDistance);
expectedWeightedDistancesMapFP2.put(facet3, weightedDistance);
expectedWeightedDistancesMapFP3.put(facet1, weightedDistance);
expectedWeightedDistancesMapFP3.put(facet4, weightedDistance);
final Map<FeaturePointType, Map<MeshFacet, Double>> expectedFeaturePointsWeights = Map.of(fpType1, expectedWeightedDistancesMapFP1,
fpType2, expectedWeightedDistancesMapFP2,
fpType3, expectedWeightedDistancesMapFP3);
final Map<MeshFacet, List<Double>> expectedMergedPrioritiesMap = new HashMap<>();
for (final MeshFacet facet: facets) {
expectedMergedPrioritiesMap.put(facet, prioritiesListFP1);
}
final List<Double> mergedPriorities = List.of(1d, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, vertexPriority, 0d);
expectedMergedPrioritiesMap.put(facet1, mergedPriorities);
expectedMergedPrioritiesMap.put(facet3, mergedPriorities);
expectedMergedPrioritiesMap.put(facet4, mergedPriorities);
final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()),
new HashSet<>(featurePointTypes),
POINT_TO_POINT,
true,
false);
performTest(face, expectedPriorities, expectedFeaturePointsWeights, expectedMergedPrioritiesMap, visitor);
}
@Test
public void fourFeaturePointsSingleFacetIntersecParallelTest() throws IOException {
final List<Point3d> featurePoints = List.of(featurePoint1, new Point3d(1, 0, 0), new Point3d(0, 1, 0), new Point3d(0, 0, 1));
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 HumanFace face = getHumanFace(facets, featurePoints, featurePointTypes);
final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP2 = new HashMap<>();
final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP3 = new HashMap<>();
final Map<MeshFacet, List<Double>> expectedPrioritiesMapFP4 = new HashMap<>();
final List<Double> allZeroList = Collections.nCopies(VERTICES_NUM, 0d);
for (final MeshFacet facet: facets) {
expectedPrioritiesMapFP2.put(facet, allZeroList);
expectedPrioritiesMapFP3.put(facet, allZeroList);
expectedPrioritiesMapFP4.put(facet, allZeroList);
}
final List<Double> prioritiesList = List.of(0d, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1d, 0.9);
expectedPrioritiesMapFP2.put(facet1, prioritiesList);
expectedPrioritiesMapFP3.put(facet3, prioritiesList);
expectedPrioritiesMapFP4.put(facet5, prioritiesList);
final Map<FeaturePointType, Map<MeshFacet, List<Double>>> expectedPriorities = Map.of(fpType1, expectedPrioritiesMapFP1,
fpType2, expectedPrioritiesMapFP2,
fpType3, expectedPrioritiesMapFP3,
fpType4, expectedPrioritiesMapFP4);
final Map<MeshFacet, Double> expectedWeightedDistancesMapFP2 = new HashMap<>();
final Map<MeshFacet, Double> expectedWeightedDistancesMapFP3 = new HashMap<>();
final Map<MeshFacet, Double> expectedWeightedDistancesMapFP4 = new HashMap<>();
for (final MeshFacet facet: facets) {
expectedWeightedDistancesMapFP2.put(facet, Double.NaN);
expectedWeightedDistancesMapFP3.put(facet, Double.NaN);
expectedWeightedDistancesMapFP4.put(facet, Double.NaN);
}
final double weightedDistance = (0 + 0.01 + 0.04 + 0.09 + 0.16 + 0.25 + 0.36 + 0.49 + 0.64 + 0.81 + 1 + 0.99) / 11;
expectedWeightedDistancesMapFP2.put(facet1, weightedDistance);
expectedWeightedDistancesMapFP3.put(facet3, weightedDistance);
expectedWeightedDistancesMapFP4.put(facet5, -weightedDistance);
final Map<FeaturePointType, Map<MeshFacet, Double>> expectedFeaturePointsWeights = Map.of(fpType1, expectedWeightedDistancesMapFP1,
fpType2, expectedWeightedDistancesMapFP2,
fpType3, expectedWeightedDistancesMapFP3,
fpType4, expectedWeightedDistancesMapFP4);
final Map<MeshFacet, List<Double>> expectedMergedPrioritiesMap = new HashMap<>();
for (final MeshFacet facet: facets) {
expectedMergedPrioritiesMap.put(facet, prioritiesListFP1);
}
final List<Double> mergedPriorities = List.of(1d, 0.9, 0.8, 0.7, 0.6, 0.5, 0.6, 0.7, 0.8, 0.9, 1d, 0.9);
expectedMergedPrioritiesMap.put(facet1, mergedPriorities);
expectedMergedPrioritiesMap.put(facet3, mergedPriorities);
expectedMergedPrioritiesMap.put(facet5, mergedPriorities);
final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()),
new HashSet<>(featurePointTypes),
POINT_TO_POINT,
true,
true);
performTest(face, expectedPriorities, expectedFeaturePointsWeights, expectedMergedPrioritiesMap, visitor);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment