Loading Comparison/src/main/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritized.java +143 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,22 @@ import java.util.concurrent.Executors; import javax.vecmath.Point3d; /** * Visitor for prioritized Hausdorff distance. * This visitor is instantiated with a single k-d tree (either given as the input * parameter, or automatically created from the triangular mesh). * When applied to other human faces, it computes prioritized Hausdorff distance from their mesh facets * to the instantiated k-d tree. * <p> * This visitor is thread-safe, i.e., a single instance of the visitor can be used * to inspect multiple human faces simultaneously. * </p> * <p> * The distance is computer either as absolute or relative. Absolute * 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> * * @author Daniel Schramm */ Loading @@ -31,23 +47,86 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { private final Map<MeshFacet, List<Double>> priorities = new HashMap<>(); /** * Constructor. * * @param mainFacets Facets 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 strategy Strategy of the computation of distance * @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), * i.e., we can get negative distances. * @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, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { distanceVisitor = new HausdorffDistance(mainFacets, strategy, relativeDistance, parallel); featurePointType = featurePoint; } /** * 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 featurePoint Feature point according to which the Hausdorff distances will be prioritized * @param strategy Strategy of the computation of distance * @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), * i.e., we can get negative distances. * @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, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { this(new HashSet<>(Collections.singleton(mainFacet)), featurePoint, strategy, relativeDistance, parallel); } /** * Constructor. * * @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 featurePoint Feature point according to which the Hausdorff distances will be prioritized * @param strategy Strategy of the computation of distance * @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), * i.e., we can get negative distances. * @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, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { this(new HashSet<>(mainModel.getFacets()), featurePoint, strategy, relativeDistance, parallel); } /** * Constructor. * * @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 strategy Strategy of the computation of distance * @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), * i.e., we can get negative distances. * @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, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { this(face.getMeshModel(), featurePoint, strategy, relativeDistance, parallel); } /** * Constructor. * * @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 featurePoint Feature point according to which the Hausdorff distances will be prioritized * @param strategy Strategy of the computation of distance * @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), * i.e., we can get negative distances. * @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, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { distanceVisitor = new HausdorffDistance(mainKdTree, strategy, relativeDistance, parallel); featurePointType = featurePoint; Loading @@ -57,30 +136,86 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { return featurePointType; } /** * Returns Hausdorff distance of the visited faces' mesh facets to the source mesh facets. * * Keys in the map contain mesh facets that were measured with the * source facets. * For each facet of the visited human face, a list of distances to the source * facets is stored. The order of distances corresponds to the order of vertices * in the measured facet, i.e., the i-th value is the distance of the i-th vertex * of the visited face's facet. * * @return Hausdorff distance for all points of all the visited human faces' facets */ public Map<MeshFacet, List<Double>> getDistances() { return distanceVisitor.getDistances(); } /** * Returns the nearest points of the visited faces' mesh facets to the source mesh facets. * * Keys in the map contain mesh facets that were measured with the * source facets. * 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 * 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. * * @return The nearest points for all points of all the visited human faces' facets */ public Map<MeshFacet, List<Point3d>> getNearestPoints() { return distanceVisitor.getNearestPoints(); } /** * Returns priorities of points of the visited faces' mesh facets. * * Keys in the map contain mesh facets of the visited human faces. * For each facet of the visited human face, a list of priorities is stored. * The order of priorities corresponds to the order of vertices * in the visited facet, i.e., the i-th value is the priority of the i-th vertex * of the visited face's facet. * * @return Priorities of all points of all the visited human faces' facets */ public Map<MeshFacet, List<Double>> getPriorities() { return Collections.unmodifiableMap(priorities); } /** * Returns {@code true} if the distance was computed as relative * (with possibly negative values). * * @return {@code true} if the distance is computed as relative, {@code false} otherwise */ public boolean relativeDistance() { return distanceVisitor.relativeDistance(); } /** * Returns the strategy of the computation of distance. * * @return strategy of the computation of distance */ public Strategy getStrategy() { return distanceVisitor.getStrategy(); } /** * Returns {@code true} if the distance computation is parallel. * * @return {@code true} if the distance computation is parallel */ public boolean inParallel() { return distanceVisitor.inParallel(); } /** * Return the KD tree to which distances are computed. * * @return KD tree to which distances are computed */ public KdTree getMainKdTree() { return distanceVisitor.getMainKdTree(); } Loading @@ -93,25 +228,27 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); final PrioritySphere priorityVisitor = new PrioritySphere(featurePoint.getPosition(), 1 /*TODO TEMPORARY - sphere radius needs to be computed dynamically*/); for (final MeshFacet comparedFacet: facets) { for (final MeshFacet comparedFacet: facets) { // For each mesh facet of the visited human face if (inParallel() && distanceVisitor.isThreadSafe()) { executor.execute(() -> comparedFacet.accept(distanceVisitor)); executor.execute(() -> comparedFacet.accept(distanceVisitor)); // Fork and continue } else { comparedFacet.accept(distanceVisitor); comparedFacet.accept(distanceVisitor); // Process immediately } if (inParallel() && priorityVisitor.isThreadSafe()) { executor.execute(() -> comparedFacet.accept(priorityVisitor)); executor.execute(() -> comparedFacet.accept(priorityVisitor)); // Fork and continue } else { comparedFacet.accept(priorityVisitor); comparedFacet.accept(priorityVisitor); // Proces immediately } // Visitors store results into their internal structure } if (inParallel()) { executor.shutdown(); while (!executor.isTerminated()){} while (!executor.isTerminated()){} // Wait until all computations are finished } synchronized(this) { // Retrieve results from the visitor's internal structure priorities.putAll(priorityVisitor.getPriorities()); } } Loading Loading
Comparison/src/main/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritized.java +143 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,22 @@ import java.util.concurrent.Executors; import javax.vecmath.Point3d; /** * Visitor for prioritized Hausdorff distance. * This visitor is instantiated with a single k-d tree (either given as the input * parameter, or automatically created from the triangular mesh). * When applied to other human faces, it computes prioritized Hausdorff distance from their mesh facets * to the instantiated k-d tree. * <p> * This visitor is thread-safe, i.e., a single instance of the visitor can be used * to inspect multiple human faces simultaneously. * </p> * <p> * The distance is computer either as absolute or relative. Absolute * 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> * * @author Daniel Schramm */ Loading @@ -31,23 +47,86 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { private final Map<MeshFacet, List<Double>> priorities = new HashMap<>(); /** * Constructor. * * @param mainFacets Facets 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 strategy Strategy of the computation of distance * @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), * i.e., we can get negative distances. * @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, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { distanceVisitor = new HausdorffDistance(mainFacets, strategy, relativeDistance, parallel); featurePointType = featurePoint; } /** * 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 featurePoint Feature point according to which the Hausdorff distances will be prioritized * @param strategy Strategy of the computation of distance * @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), * i.e., we can get negative distances. * @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, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { this(new HashSet<>(Collections.singleton(mainFacet)), featurePoint, strategy, relativeDistance, parallel); } /** * Constructor. * * @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 featurePoint Feature point according to which the Hausdorff distances will be prioritized * @param strategy Strategy of the computation of distance * @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), * i.e., we can get negative distances. * @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, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { this(new HashSet<>(mainModel.getFacets()), featurePoint, strategy, relativeDistance, parallel); } /** * Constructor. * * @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 strategy Strategy of the computation of distance * @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), * i.e., we can get negative distances. * @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, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { this(face.getMeshModel(), featurePoint, strategy, relativeDistance, parallel); } /** * Constructor. * * @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 featurePoint Feature point according to which the Hausdorff distances will be prioritized * @param strategy Strategy of the computation of distance * @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), * i.e., we can get negative distances. * @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, FeaturePointType featurePoint, Strategy strategy, boolean relativeDistance, boolean parallel) { distanceVisitor = new HausdorffDistance(mainKdTree, strategy, relativeDistance, parallel); featurePointType = featurePoint; Loading @@ -57,30 +136,86 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { return featurePointType; } /** * Returns Hausdorff distance of the visited faces' mesh facets to the source mesh facets. * * Keys in the map contain mesh facets that were measured with the * source facets. * For each facet of the visited human face, a list of distances to the source * facets is stored. The order of distances corresponds to the order of vertices * in the measured facet, i.e., the i-th value is the distance of the i-th vertex * of the visited face's facet. * * @return Hausdorff distance for all points of all the visited human faces' facets */ public Map<MeshFacet, List<Double>> getDistances() { return distanceVisitor.getDistances(); } /** * Returns the nearest points of the visited faces' mesh facets to the source mesh facets. * * Keys in the map contain mesh facets that were measured with the * source facets. * 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 * 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. * * @return The nearest points for all points of all the visited human faces' facets */ public Map<MeshFacet, List<Point3d>> getNearestPoints() { return distanceVisitor.getNearestPoints(); } /** * Returns priorities of points of the visited faces' mesh facets. * * Keys in the map contain mesh facets of the visited human faces. * For each facet of the visited human face, a list of priorities is stored. * The order of priorities corresponds to the order of vertices * in the visited facet, i.e., the i-th value is the priority of the i-th vertex * of the visited face's facet. * * @return Priorities of all points of all the visited human faces' facets */ public Map<MeshFacet, List<Double>> getPriorities() { return Collections.unmodifiableMap(priorities); } /** * Returns {@code true} if the distance was computed as relative * (with possibly negative values). * * @return {@code true} if the distance is computed as relative, {@code false} otherwise */ public boolean relativeDistance() { return distanceVisitor.relativeDistance(); } /** * Returns the strategy of the computation of distance. * * @return strategy of the computation of distance */ public Strategy getStrategy() { return distanceVisitor.getStrategy(); } /** * Returns {@code true} if the distance computation is parallel. * * @return {@code true} if the distance computation is parallel */ public boolean inParallel() { return distanceVisitor.inParallel(); } /** * Return the KD tree to which distances are computed. * * @return KD tree to which distances are computed */ public KdTree getMainKdTree() { return distanceVisitor.getMainKdTree(); } Loading @@ -93,25 +228,27 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); final PrioritySphere priorityVisitor = new PrioritySphere(featurePoint.getPosition(), 1 /*TODO TEMPORARY - sphere radius needs to be computed dynamically*/); for (final MeshFacet comparedFacet: facets) { for (final MeshFacet comparedFacet: facets) { // For each mesh facet of the visited human face if (inParallel() && distanceVisitor.isThreadSafe()) { executor.execute(() -> comparedFacet.accept(distanceVisitor)); executor.execute(() -> comparedFacet.accept(distanceVisitor)); // Fork and continue } else { comparedFacet.accept(distanceVisitor); comparedFacet.accept(distanceVisitor); // Process immediately } if (inParallel() && priorityVisitor.isThreadSafe()) { executor.execute(() -> comparedFacet.accept(priorityVisitor)); executor.execute(() -> comparedFacet.accept(priorityVisitor)); // Fork and continue } else { comparedFacet.accept(priorityVisitor); comparedFacet.accept(priorityVisitor); // Proces immediately } // Visitors store results into their internal structure } if (inParallel()) { executor.shutdown(); while (!executor.isTerminated()){} while (!executor.isTerminated()){} // Wait until all computations are finished } synchronized(this) { // Retrieve results from the visitor's internal structure priorities.putAll(priorityVisitor.getPriorities()); } } Loading