Commit 4c4bf4ee authored by Radek Ošlejšek's avatar Radek Ošlejšek
Browse files

Merge branch 'master' of gitlab.fi.muni.cz:grp-fidentis/analyst2 into 98-setup-basic-layout

parents 32d757bc fb2638eb
Loading
Loading
Loading
Loading
+47 −1
Original line number Diff line number Diff line
package cz.fidentis.analyst.face;

import com.google.common.eventbus.EventBus;
import cz.fidentis.analyst.feature.FeaturePoint;
import cz.fidentis.analyst.feature.services.FeaturePointImportExportService;
import cz.fidentis.analyst.kdtree.KdTree;
import cz.fidentis.analyst.mesh.core.MeshFacet;
import cz.fidentis.analyst.mesh.core.MeshModel;
@@ -8,6 +10,7 @@ import cz.fidentis.analyst.mesh.events.MeshEvent;
import cz.fidentis.analyst.mesh.events.MeshListener;
import cz.fidentis.analyst.mesh.io.MeshObjLoader;
import cz.fidentis.analyst.symmetry.Plane;
import cz.fidentis.analyst.visitors.face.HumanFaceVisitor;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;

@@ -18,6 +21,8 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Objects;
//import org.nustaq.serialization.FSTConfiguration;
@@ -57,6 +62,8 @@ public class HumanFace implements MeshListener, Serializable {

    private MeshFacet cuttingPlane;
    
    private List<FeaturePoint> featurePoints;
    
    private final transient EventBus eventBus = new EventBus();
    
    private final String id;
@@ -134,7 +141,7 @@ public class HumanFace implements MeshListener, Serializable {
    /**
     *
     * @param plane The new symmetry plane
     * @param paneFacet The symmetry plane mesh
     * @param planeFacet The symmetry plane mesh
     */
    public void setSymmetryPlane(Plane plane, MeshFacet planeFacet) {
        this.symmetryPlane = plane;
@@ -169,6 +176,36 @@ public class HumanFace implements MeshListener, Serializable {
        return cuttingPlane;
    }
    
    /**
     * 
     * @param points List of feature points
     */
    public void setFeaturePoints(List<FeaturePoint> points) {
        featurePoints = points;
    }
    
    /**
     * Reads feature points from a file on the given path.
     * 
     * @param path Directory where the file is located
     * @param fileName Name of the file
     * @throws IOException on I/O failure
     */
    public void loadFeaturePoints(String path, String fileName) throws IOException {
        featurePoints = FeaturePointImportExportService.importFeaturePoints(path, fileName);
    }
    
    /**
     * 
     * @return The face's feature points.
     */
    public List<FeaturePoint> getFeaturePoints() {
        if (featurePoints == null) {
            return Collections.emptyList();
        }
        return Collections.unmodifiableList(featurePoints);
    }
    
    /**
     * Returns unique ID of the face.
     * 
@@ -268,6 +305,15 @@ public class HumanFace implements MeshListener, Serializable {
        */
    }
    
    /**
     * Visits this face.
     * 
     * @param visitor Visitor
     */
    public void accept(HumanFaceVisitor visitor) {
        visitor.visitHumanFace(this);
    }

    @Override
    public int hashCode() {
        int hash = 7;
+3 −0
Original line number Diff line number Diff line
@@ -227,6 +227,9 @@ public class HumanFaceFactory {
        HumanFace face = inMemoryFaces.get(oldTime);
        
        long newTime = System.currentTimeMillis();
        while (inMemoryFaces.containsKey(newTime)) { // wait until we get unique ms
            newTime = System.currentTimeMillis();
        }
        inMemoryFaces.remove(oldTime);
        inMemoryFaces.put(newTime, face);
        usage.put(faceId, newTime);
+242 −0
Original line number Diff line number Diff line
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.kdtree.KdTree;
import cz.fidentis.analyst.mesh.core.MeshFacet;
import cz.fidentis.analyst.mesh.core.MeshModel;
import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy;
import cz.fidentis.analyst.visitors.mesh.PrioritySphere;
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 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 computed 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
 */
public class HausdorffDistancePrioritized extends HumanFaceVisitor  {
    
    private final HausdorffDistance distanceVisitor;
    
    private final FeaturePointType featurePointType;
    
    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;
    }

    public FeaturePointType getFeaturePointType() {
        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();
    }

    @Override
    public void visitHumanFace(HumanFace humanFace) {
        humanFace.getMeshModel().compute(distanceVisitor, inParallel());
        
        final FeaturePoint featurePoint = humanFace.getFeaturePoints().get(featurePointType.getType());
        final PrioritySphere priorityVisitor = new PrioritySphere(featurePoint.getPosition(), computeSphereRadius(humanFace));
        humanFace.getMeshModel().compute(priorityVisitor, inParallel());
        
        synchronized(this) {
            // Retrieve results from the visitor's internal structure
            priorities.putAll(priorityVisitor.getPriorities());
        }
    }
    
    private double computeSphereRadius(HumanFace humanFace) {
        // TODO TEMPORARY
        // 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
    }
}
+42 −0
Original line number Diff line number Diff line
package cz.fidentis.analyst.visitors.face;

import cz.fidentis.analyst.face.HumanFace;

/**
 * A functor. When instantiated, it can be gradually applied to multiple faces.
 * It inspects the state of the human face one by one, and (cumulatively) computes results.
 * <p>
 * Implement this interface whenever you want to define new algorithm over a human face.
 * </p>
 * <p>
 * If the visitor is thread-safe, then a single instance of the visitor
 * can visit concurrently (and asynchronously) multiple faces. Otherwise, 
 * the parallel inspection is still possible, but a new instance of the visitor 
 * has to be used for each human face.
 * </p>
 *
 * @author Daniel Schramm
 */
public abstract class HumanFaceVisitor {
    
    /**
     * Returns {@code true} if the implementation is thread-safe and then
     * <b>a single visitor instance</b> can be applied to multiple faces simultaneously.
     * <p>
     * Thread-safe implementation means that any read or write from/to the visitor's 
     * state is protected by {@code synchronized}.
     * </p>
     * 
     * @return {@code true} if the implementation is thread-safe.
     */
    public boolean isThreadSafe() {
        return true;
    }
    
    /**
     * The main inspection method to be implemented by specific visitors.
     * 
     * @param humanFace Face to be visited
     */
    public abstract void visitHumanFace(HumanFace humanFace);
}
+5 −0
Original line number Diff line number Diff line
/**
 * Visitors used to explore the human face (i.e., implementing the 
 * {@link cz.fidentis.analyst.visitors.face.HumanFaceVisitor}).
 */
package cz.fidentis.analyst.visitors.face;
 No newline at end of file
Loading