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

Merge branch '130-split-a-profile-curve-with-respect-to-feature-points' into 'master'

Resolve "Split a profile curve with respect to feature points"

Closes #130

See merge request grp-fidentis/analyst2!143
parents 55e33200 5c67269f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ import java.util.Objects;
 * <p>
 * Changes in the human face and its data structures (e.g., mesh model, etc.)
 * can be monitored by listeners. Listeners have to implement the 
 * {@link cz.fidentis.analyst.face.HumanFaceListener} interface and they have to be
 * {@link cz.fidentis.analyst.face.events.HumanFaceListener} interface and they have to be
 * registered using the {@link cz.fidentis.analyst.face.HumanFace#registerListener} method.
 * Then they are informed about changes in the human automatically via methods 
 * prescribed by the interface.
+219 −0
Original line number Diff line number Diff line
package cz.fidentis.analyst.symmetry;

import cz.fidentis.analyst.mesh.core.MeshPoint;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.vecmath.Point3d;

/**
 * A 3D curve produced by a plane cutting a human face.
 * 
 * @author Radek Oslejsek
 */
public class CrossSectionCurve {
    
    private final List<List<Point3d>> segments = new ArrayList<>();
    private final List<Point3d> fpProjections = new ArrayList<>();
    
    /**
     * Add a new point to the beginning of the curve segment.
     * 
     * @param segment Index of the segment
     * @param point A 3D point to be inserted
     * @throws IllegalArgumentException if the segment does not exist or the point is {@code null}
     */
    public void addPointToSegmentStart(int segment, Point3d point) {
        if (segment < 0 || segment > segments.size() - 1) {
            throw new IllegalArgumentException("segment");
        }
        
        if (point == null) {
            throw new IllegalArgumentException("point");
        }
        
        segments.get(segment).add(0, point);
    }
    
    /**
     * Add a new point to the end of the curve segment.
     * 
     * @param segment Index of the segment
     * @param point A 3D point to be inserted
     * @throws IllegalArgumentException if the segment does not exist or the point is {@code null}
     */
    public void addPointToSegmentEnd(int segment, Point3d point) {
        if (segment < 0 || segment > segments.size() - 1) {
            throw new IllegalArgumentException("segment");
        }
        
        if (point == null) {
            throw new IllegalArgumentException("point");
        }
        
        segments.get(segment).add(point);
    }
    
    /**
     * Adds a new segment to the curve.
     * 
     * @return Index of the new segment
     */
    public int addNewSegment() {
        segments.add(new ArrayList<>());
        return segments.size() - 1;
    }
    
    /**
     * Returns number of segments.
     * @return number of segments.
     */
    public int getNumSegments() {
        return segments.size();
    }
    
    /**
     * Returns number of points in given segment.
     * 
     * @param segment Index of the segment
     * @return number of points in given segment.
     * @throws IllegalArgumentException if the segment does not exist
     */
    public int getSegmentSize(int segment) {
        if (segment < 0 || segment > segments.size() - 1) {
            throw new IllegalArgumentException("segment");
        }
        return segments.get(segment).size();
    }
    
    /**
     * Returns given segment.
     * 
     * @param segment Index of the segment
     * @return Points of the segment
     * @throws IllegalArgumentException if the segment does not exist
     */
    public List<Point3d> getSegment(int segment) {
        if (segment < 0 || segment > segments.size() - 1) {
            throw new IllegalArgumentException("segment");
        }
        return Collections.unmodifiableList(segments.get(segment));
    }
    
    /**
     * Returns all segments.
     * @return Curve segments
     */
    public List<List<Point3d>> getSegments() {
        return Collections.unmodifiableList(segments);
    }
    
    /**
     * Returns given point of in given segment.
     * 
     * @param segment Index of the segment
     * @param point Index of the point in the segment
     * @return Points of the curve
     * @throws IndexOutOfBoundsException if the input arguments are out of range
     */
    public Point3d getPoint(int segment, int point) {
        return segments.get(segment).get(point);
    }
    
    /**
     * Find the closest point of the curve to the given point.
     * Returned list contains two indexes. The first one is the index of 
     * curve segment, the second one is the index of the closest point in the segment.
     * 
     * @param point A 3D point
     * @return The closest point of the curve or {@code null}
     * @throws NullPointerException if the input argument is {@code null}
     */
    public Point3d getClosestPoint(Point3d point) {
        Point3d ret = null;
        double minDist = Double.POSITIVE_INFINITY;
        
        for (int i = 0; i < getNumSegments(); i++) {
            for (int j = 0; j < getSegmentSize(i); j++) {
                double dist = MeshPoint.distance(point, getPoint(i, j));
                if (dist < minDist) {
                    minDist = dist;
                    ret = getPoint(i, j);
                }
            }
        }
        
        return ret;
    }
    
    /**
     * Finds points of the curve that are the closest the the given list of 3D points
     * (locations of feature points) and returns them.
     * 
     * @param candidatePoints (Feature) points to be projected to the curve
     * @return projections, i.e., points of the curve that are the closest to the candidate points.
     */
    public List<Point3d> projectFeaturePointsToCurve(List<Point3d> candidatePoints) {
        this.fpProjections.clear();
        for (Point3d p: candidatePoints) {
            this.fpProjections.add(getClosestPoint(p));
        }
        return Collections.unmodifiableList(fpProjections);
    }
    
    /**
     * Returns projected feature points.
     * @return projected feature points.
     */
    public List<Point3d> getProjectedFeaturePoints() {
        return Collections.unmodifiableList(fpProjections);
    }
    
    /**
     * Finds the closest point (see {@link #getClosestPoint(javax.vecmath.Point3d)}.
     * If the point is inside of some segment, the segment is split. 
     * 
     * @param point A 3D point whose closeness is calculated
     * @return The index of the original segment that has been split. -1 if no slitting has been made.
     * @throws NullPointerException if the input argument is {@code null}
     */
    /*
    public int splitByClosestPoint(Point3d point) {
        List<Integer> closest = getClosestPoint(point);
        int clSegment = closest.get(0);
        int clPoint = closest.get(1);
        
        if (closest == null) {
            return -1;
        }
        
        if (clPoint == 0 || clPoint == getSegmentSize(clSegment)-1) { // bordery points
            return -1;
        }
        
        List<Point3d> newSegment = new ArrayList<>();
        newSegment.add(new Point3d(getPoint(clSegment, clPoint)));
        int i = clPoint + 1;
        while (i < getSegmentSize(closest.get(0))) {
            newSegment.add(segments.get(clSegment).remove(i));
        }
        segments.add(clSegment+1, newSegment);
        
        return clSegment;
    }
    */
    
    /**
     * Joints neighboring segments. Independent segments (separated by a whole)
     * remain separated.
     */
    public void joinSegments() {
        for (int i = 0; i < getNumSegments() -1 ; i++) {
            if (getPoint(i, getSegmentSize(i)-1).equals(getPoint(i+1, 0))) {
                segments.get(i+1).remove(0);
                segments.get(i).addAll(segments.remove(i+1));
                i--;
            }
        }
    }
}
+13 −6
Original line number Diff line number Diff line
@@ -129,6 +129,17 @@ public class Plane implements Serializable {
        this.distance = dist;
    }
    
    /**
     * Returns distance of the point from the plane.
     * @param point Point whose distance is to be computed
     * @return Point's distance. If the point is on the opposite side with
     * the respect to the plane's normal, the negative distance is returned
     */
    public double getPointDistance(Point3d point) {
        return ((normal.x * point.x) + (normal.y * point.y) + (normal.z * point.z) + distance)
                / Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
    }

    /**
     * Calculates an intersection of a plane and a line given by two points
     *
@@ -137,12 +148,8 @@ public class Plane implements Serializable {
     * @return The point of intersection of null if no point found
     */
    public Point3d getIntersectionWithLine(Point3d p1, Point3d p2) {
        double distance1 = ((normal.x * p1.x) + (normal.y * p1.y) + (normal.z * p1.z) + distance)
                / Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);

        double distance2 = ((normal.x * p2.x) + (normal.y * p2.y) + (normal.z * p2.z) + distance)
                / Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);

        double distance1 = getPointDistance(p1);
        double distance2 = getPointDistance(p2);
        double t = distance1 / (distance1 - distance2);

        if (distance1 * distance2 > 0) {
+2 −47
Original line number Diff line number Diff line
package cz.fidentis.analyst.symmetry;

import cz.fidentis.analyst.mesh.MeshVisitor;
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.MeshPointImpl;
import cz.fidentis.analyst.mesh.core.MeshRectangleFacet;
import cz.fidentis.analyst.visitors.mesh.BoundingBox;
import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox;
import java.util.ArrayList;
@@ -141,7 +139,7 @@ public class SymmetryEstimator extends MeshVisitor {
        
        double scale = bbox.getMaxPoint().x - bbox.getMinPoint().x;
        
        return createMeshFacet(midPointOnPlane, frontDir, upDir, symmetryPlane.getNormal(), scale);
        return new MeshRectangleFacet(midPointOnPlane, frontDir, upDir, symmetryPlane.getNormal(), 2*scale, 2*scale);
    }
    
    /**
@@ -230,49 +228,6 @@ public class SymmetryEstimator extends MeshVisitor {
        setSymmetryPlane(planes);
    }
    
    protected static MeshFacet createMeshFacet(Point3d centroid, Vector3d frontDir, Vector3d upDir, Vector3d normal, double scale) {
        
        Point3d[] points = new Point3d[4];
        
        Point3d aScaled = new Point3d(frontDir);
        Point3d bScaled = new Point3d(upDir);
        aScaled.scale(scale);
        bScaled.scale(scale);
        
        points[0] = new Point3d(centroid);
        points[0].sub(aScaled);
        points[0].sub(bScaled);
        
        points[1] = new Point3d(centroid);
        points[1].sub(aScaled);
        points[1].add(bScaled);
        
        points[2] = new Point3d(centroid);
        points[2].add(aScaled);
        points[2].add(bScaled);
        
        points[3] = new Point3d(centroid);
        points[3].add(aScaled);
        points[3].sub(bScaled);
        
        MeshFacet facet = new MeshFacetImpl();
        for (Point3d point : points) {
            facet.addVertex(new MeshPointImpl(point, normal, null));
        }

        //Create a simple square cornerTable
        facet.getCornerTable().addRow(new CornerTableRow(0, 5));
        facet.getCornerTable().addRow(new CornerTableRow(1, -1));
        facet.getCornerTable().addRow(new CornerTableRow(3, -1));
        facet.getCornerTable().addRow(new CornerTableRow(3, -1));
        facet.getCornerTable().addRow(new CornerTableRow(1, -1));
        facet.getCornerTable().addRow(new CornerTableRow(2, 0));

        //facet.calculateVertexNormals();
        
        return facet;
    }

    protected int checkAndUpdatePlanes(List<Plane> planes, ApproxSymmetryPlane newPlane, int maxVotes) {
        if (newPlane.getVotes() > maxVotes) {
            planes.clear();
+12 −11
Original line number Diff line number Diff line
package cz.fidentis.analyst.visitors.mesh;

import cz.fidentis.analyst.Logger;
import cz.fidentis.analyst.mesh.MeshVisitor;
import cz.fidentis.analyst.mesh.core.MeshFacet;
import cz.fidentis.analyst.mesh.core.MeshTriangle;
import cz.fidentis.analyst.symmetry.CrossSectionCurve;
import cz.fidentis.analyst.symmetry.Plane;

import javax.vecmath.Point3d;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -25,7 +23,7 @@ import java.util.stream.Collectors;
 * @author Radek Oslejsek
 */
public class CrossSectionZigZag extends MeshVisitor {
    private List<List<Point3d>> segments;
    private CrossSectionCurve curve;
    private Set<Point3d> usedPoints;
    private Set<MeshTriangle> visited;
    private Set<MeshTriangle> toVisit;
@@ -40,7 +38,7 @@ public class CrossSectionZigZag extends MeshVisitor {
    public CrossSectionZigZag(Plane plane) {
        this.plane = plane;
        //this.points = new ArrayList<>();
        this.segments = new ArrayList<>();
        this.curve = new CrossSectionCurve();
        this.usedPoints = new HashSet<>();
    }

@@ -49,9 +47,9 @@ public class CrossSectionZigZag extends MeshVisitor {
            usedPoints.add(p);

            if (direction) {
                segments.get(segment).add(p);
                curve.addPointToSegmentEnd(segment, p);
            } else {
                segments.get(segment).add(0, p);
                curve.addPointToSegmentStart(segment, p);
            }
        }
    }
@@ -113,8 +111,7 @@ public class CrossSectionZigZag extends MeshVisitor {
            while (!toVisit.isEmpty()) {
                MeshTriangle tri = toVisit.iterator().next();
                toVisit.remove(tri);
                segments.add(new ArrayList<>());
                int segment = segments.size() - 1;
                int segment = curve.addNewSegment();
                
                // Figure out which lines are intersected
                Point3d intersection1 = plane.getIntersectionWithLine(tri.getVertex1(), tri.getVertex2());
@@ -156,7 +153,11 @@ public class CrossSectionZigZag extends MeshVisitor {
        //out.printDuration("Cross section with zigzag method");
    }

    public List<List<Point3d>> getSegments() {
        return Collections.unmodifiableList(segments);
    /**
     * Returns computed cross section curve.
     * @return cross section curve
     */
    public CrossSectionCurve getCrossSectionCurve() {
        return curve;
    }
}
Loading