Commit 988dfb20 authored by Radek Ošlejšek's avatar Radek Ošlejšek
Browse files

Merge branch '126-create-average-face-contructor-for-octrees' into 'master'

Compute Average Face

Closes #126

See merge request grp-fidentis/analyst2!197
parents 5b39bd6c 8ef1afdd
Loading
Loading
Loading
Loading
+115 −72
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ import cz.fidentis.analyst.feature.services.FeaturePointImportService;
import cz.fidentis.analyst.kdtree.KdTree;
import cz.fidentis.analyst.mesh.core.MeshModel;
import cz.fidentis.analyst.mesh.io.MeshObjLoader;
import cz.fidentis.analyst.octree.Octree;
import cz.fidentis.analyst.symmetry.Plane;
import cz.fidentis.analyst.visitors.face.HumanFaceVisitor;
import cz.fidentis.analyst.visitors.mesh.BoundingBox;
@@ -48,6 +49,8 @@ public class HumanFace implements Serializable {
     */
    private transient KdTree kdTree;

    private transient Octree octree;

    private Plane symmetryPlane;

    //private MeshFacet symmetryPlaneMesh;
@@ -334,6 +337,46 @@ public class HumanFace implements Serializable {
        return name;
    }

    /**
     * Returns already computed octree of the triangular mesh or {@code null}.
     * @return Already computed octree of the triangular mesh or {@code null}
     */
    public Octree getOctree() {
        return this.octree;
    }

    /**
     * Checks if HumanFace has octree calculated
     * @return true if yes and false if not
     */
    public boolean hasOctree() {
        return octree != null;
    }

    /**
     * Computes new octree or returns the existing one.
     *
     * @param recompute If {@code true} and an old octree exists, then it is recomputed again.
     * Otherwise, the tree is computed only if does not exist yet.
     * @return Octree with the triangular mesh.
     */
    public Octree computeOctree(boolean recompute) {
        if (octree == null || recompute) {
            octree = new Octree(new ArrayList<>(meshModel.getFacets()));
        }
        return octree;
    }

    /**
     * Removes Octree from the Human face.
     * @return removed Octree or {@code null}
     */
    public Octree removeOctree() {
        Octree ret = this.octree;
        this.octree = null;
        return ret;
    }

    /**
     * Returns already computed k-d tree of the triangular mesh or {@code null}.
     * @return Already computed k-d tree of the triangular mesh or {@code null}
+1 −1
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ public class HumanFaceUtils {
            boolean recomputeKdTree) {
        
        // transform mesh:
        System.out.println("_AAA " + staticFace.getShortName() + ":" + transformedFace.getShortName());
        //System.out.println("_AAA " + staticFace.getShortName() + ":" + transformedFace.getShortName());
        IcpTransformer icp = new IcpTransformer(
                staticFace.getMeshModel(), 
                maxIterations, 
+30 −0
Original line number Diff line number Diff line
package cz.fidentis.analyst.face.events;

import cz.fidentis.analyst.face.HumanFace;

/**
 * The root type for events relate to the changes in octree.
 * 
 * @author Enkh-Undral EnkhBayar
 */
public class OctreeEvent extends HumanFaceEvent {
    
    /**
     * Constructor.
     * @param face Human face related to the event
     * @param name Event name provided by issuer
     * @param issuer The issuer
     */
    public OctreeEvent(HumanFace face, String name, Object issuer) {
        super(face, name, issuer);
    }

    /**
     * Returns {@code true} if the octree is calculated.
     * @return {@code true} if the octree is calculated.
     */
    public boolean isCalculated() {
        return false;
    }

}
+100 −0
Original line number Diff line number Diff line
package cz.fidentis.analyst.visitors.octree;

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.octree.Octree;
import cz.fidentis.analyst.octree.OctreeVisitor;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * Visitor capable to create an average face by deforming main face template so
 * that its vertices are in the "average position" with respect to the visited
 * faces. The average position is computed as the average position of
 * intersections of visited faces. Intersection are computed using ray tracing
 * <strong>
 * It is supposed that the inspected faces are already registered
 * (superimposed
 * with the template ).
 * </strong>
 *
 * @author Enkh-Undral EnkhBayar
 */
public class AvgFaceConstructorOctree extends OctreeVisitor {

    private MeshModel avgMeshModel = null;

    private final OctreeArrayIntersectionVisitor visitor;

    /**
     * Constructor.
     *
     * @param templateFacet Mesh facet which is transformed to the averaged mesh.
     *        The original mesh remains unchanged. New mesh is allocated instead.
     * @throws IllegalArgumentException if some parameter is wrong
     */
    public AvgFaceConstructorOctree(MeshFacet templateFacet) {
        this(new HashSet<>(Collections.singleton(templateFacet)));
        if (templateFacet == null) {
            throw new IllegalArgumentException("templateFacet");
        }
    }

    /**
     * Constructor.
     *
     * @param templateFacets Mesh facets that are transformed to the averaged mesh
     *        The original mesh remains unchanged. New mesh is allocated instead.
     * @throws IllegalArgumentException if some parameter is wrong
     */
    public AvgFaceConstructorOctree(Set<MeshFacet> templateFacets) {
        if (templateFacets == null || templateFacets.isEmpty()) {
            throw new IllegalArgumentException("templateFacets");
        }

        visitor = new OctreeArrayIntersectionVisitor(templateFacets);
    }

    /**
     * Constructor.
     *
     * @param templateModel Mesh model which is transformed to the averaged mesh
     *        The original mesh remains unchanged. New mesh is allocated instead.
     * @throws IllegalArgumentException if some parameter is wrong
     */
    public AvgFaceConstructorOctree(MeshModel templateModel) {
        this(new HashSet<>(templateModel.getFacets()));
    }

    @Override
    public void visitOctree(Octree octree) {
        avgMeshModel = null;
        visitor.visitOctree(octree);
    }

    /**
     * Computes and returns the averaged Mesh model
     *
     * @return averaged mesh model
     */
    public MeshModel getAveragedMeshModel() {
        if (avgMeshModel != null) {
            return avgMeshModel;
        }

        avgMeshModel = new MeshModel();
        var result = visitor.getDataClass().getData();
        for (var entry : result.entrySet()) {
            MeshFacet transformedFacet = new MeshFacetImpl(entry.getKey());
            for (var innerEntry : entry.getValue().entrySet()) {
                int index = innerEntry.getKey();
                RayIntersectionsData data = innerEntry.getValue();
                transformedFacet.getVertex(index).getPosition().add(data.getAverageVector());
            }
            avgMeshModel.addFacet(transformedFacet);
        }
        return avgMeshModel;
    }
}
+46 −0
Original line number Diff line number Diff line
package cz.fidentis.analyst.visitors.octree;

import cz.fidentis.analyst.mesh.core.MeshFacet;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * This data class is used to hold information about intersections between a
 * ray and a facet
 *
 * @author Enkh-Undral EnkhBayar
 */
public class OctreeArrayIntersectionData {
    private Map<MeshFacet, Map<Integer, RayIntersectionsData>> data = new HashMap<>();

    /**
     * Saves the given data about intersections
     *
     * @param mainFacet facet holding the origin point from which the
     * intersection has been calculated
     * @param index index of the origin point in mainFacet, origin point =
     * mainFacet.getVertex(index)
     * @param intersectionsData data about the intersections
     */
    public void addIntersections(MeshFacet mainFacet, int index, RayIntersectionsData intersectionsData) {
        if (data.containsKey(mainFacet) && data.get(mainFacet).containsKey(index)) {
            data.get(mainFacet).get(index).mergeIntersection(intersectionsData);
        } else if (data.containsKey(mainFacet)) {
            data.get(mainFacet).put(index, intersectionsData);
        } else {
            Map<Integer, RayIntersectionsData> tmp = new HashMap<>();
            tmp.put(index, intersectionsData);
            data.put(mainFacet, tmp);
        }
    }

    /**
     * Returns data about intersections in form of a map
     *
     * @return data about intersections in form of a map
     */
    public Map<MeshFacet, Map<Integer, RayIntersectionsData>> getData() {
        return Collections.unmodifiableMap(data);
    }
}
Loading