Commit b59349d4 authored by Adam Majzlík's avatar Adam Majzlík Committed by Radek Ošlejšek
Browse files

Refactor Point2SurfaceDistance

parent 6217607d
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ import cz.fidentis.analyst.engines.face.FaceStateServices;
import cz.fidentis.analyst.engines.icp.IcpConfig;
import cz.fidentis.analyst.engines.icp.IcpServices;
import cz.fidentis.analyst.engines.point2surface.PointToSurfaceDistanceConfig;
import cz.fidentis.analyst.engines.point2surface.PointToSurfaceDistanceServices;
import cz.fidentis.analyst.engines.point2surface.impl.ClosestMeshVerticesService;
import cz.fidentis.analyst.engines.sampling.PointSamplingConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -34,10 +34,12 @@ import java.util.Collection;
public class FaceStateServicesImpl implements FaceStateServices {

    private IcpServices icpServices;
    private ClosestMeshVerticesService closestMeshVerticesService;

    @Autowired
    public FaceStateServicesImpl(IcpServices icpServices) {
    public FaceStateServicesImpl(IcpServices icpServices, ClosestMeshVerticesService closestMeshVerticesService) {
        this.icpServices = icpServices;
        this.closestMeshVerticesService = closestMeshVerticesService;
    }

    /**
@@ -192,7 +194,7 @@ public class FaceStateServicesImpl implements FaceStateServices {
                    PointToSurfaceDistanceConfig.Method.POINT_TO_VERTICES,
                    landmark.getPosition(),
                    true);
            var distInfo = PointToSurfaceDistanceServices.measure(face.getKdTree(), config);
            var distInfo = closestMeshVerticesService.measure(face.getKdTree(), config);
            var vicinity = new MeshVicinity(
                    distInfo.getLeft(),
                    distInfo.getRight().values().stream()
+53 −55
Original line number Diff line number Diff line
package cz.fidentis.analyst.engines.distance.impl;

import cz.fidentis.analyst.data.face.Aca;
import cz.fidentis.analyst.data.kdtree.KdTree;
import cz.fidentis.analyst.data.kdtree.KdTreeVisitor;
import cz.fidentis.analyst.data.mesh.MeshFacet;
import cz.fidentis.analyst.data.mesh.MeshPoint;
import cz.fidentis.analyst.data.mesh.measurement.RawFacetDistances;
import cz.fidentis.analyst.engines.point2surface.PointToSurfaceDistanceConfig;
import cz.fidentis.analyst.engines.point2surface.PointToSurfaceDistanceVisitor;
import cz.fidentis.analyst.engines.point2surface.impl.ClosestMeshVerticesService;
import cz.fidentis.analyst.engines.point2surface.impl.ClosestSurfacePointsService;
import org.apache.commons.lang3.tuple.Pair;

import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -59,6 +62,9 @@ public class MeshDistanceNN extends MeshDistanceVisitorImpl {
     */
    private final KdTree kdTree;

    private final ClosestMeshVerticesService closestMeshVerticesService;
    private final ClosestSurfacePointsService closestSurfacePointsService;
    
    /**
     * Constructor.
     * 
@@ -82,6 +88,8 @@ public class MeshDistanceNN extends MeshDistanceVisitorImpl {
        }
        this.kdTree = mainKdTree;
        this.crop = crop;
        this.closestMeshVerticesService = Aca.getInstance().getBean(ClosestMeshVerticesService.class);
        this.closestSurfacePointsService = Aca.getInstance().getBean(ClosestSurfacePointsService.class);
    }
    
    /**
@@ -111,15 +119,14 @@ public class MeshDistanceNN extends MeshDistanceVisitorImpl {
        final List<MeshPoint> vertices = comparedFacet.getVertices();

        ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        final List<Future<KdTreeVisitor>> results = new ArrayList<>(vertices.size());
        final List<Future<Pair<Double, Map<MeshFacet, List<MeshPoint>>>>> results = new ArrayList<>(vertices.size());

        for (var vert: vertices) { // for each vertex of comparedFacet
            KdTreeVisitor visitor = instantiateVisitor(vert.getPosition());
            if (inParallel()) { // fork and continue
                results.add(executor.submit(new CallableVisitor(visitor)));
                results.add(executor.submit(() -> measureAtPoint(vert.getPosition())));
            } else { // process distance results immediately
                this.kdTree.accept(visitor); // compute the distance for i-th vertex or prepare the visitor for computation
                updateResults((PointToSurfaceDistanceVisitor) visitor, vert, distList, nearestPointsList);
                Pair<Double, Map<MeshFacet, List<MeshPoint>>> result = measureAtPoint(vert.getPosition()); // compute the distance for i-th vertex
                updateResults(result, vert, distList, nearestPointsList);
            }
        }
    
@@ -128,9 +135,9 @@ public class MeshDistanceNN extends MeshDistanceVisitorImpl {
            while (!executor.isTerminated()){}
            try {
                int i = 0;
                for (Future<KdTreeVisitor> res: results) {
                    final KdTreeVisitor visitor = res.get(); // waits until all computations are finished
                    updateResults((PointToSurfaceDistanceVisitor) visitor, vertices.get(i), distList, nearestPointsList);
                for (Future<Pair<Double, Map<MeshFacet, List<MeshPoint>>>> result : results) {
                    Pair<Double, Map<MeshFacet, List<MeshPoint>>> measurement = result.get();
                    updateResults(measurement, vertices.get(i), distList, nearestPointsList);
                    i++;
                }
            } catch (final InterruptedException | ExecutionException ex) {
@@ -143,24 +150,33 @@ public class MeshDistanceNN extends MeshDistanceVisitorImpl {
        }
    }

    protected KdTreeVisitor instantiateVisitor(Point3d inspectedPoint) {
        return (new PointToSurfaceDistanceConfig(
    /**
     * Measure at a single inspected point using the selected Spring service.
     */
    private Pair<Double, Map<MeshFacet, List<MeshPoint>>> measureAtPoint(Point3d inspectedPoint) {
        PointToSurfaceDistanceConfig.Method method =
                pointToPoint
                        ? PointToSurfaceDistanceConfig.Method.POINT_TO_VERTICES
                        : PointToSurfaceDistanceConfig.Method.POINT_TO_SURFACE,
                inspectedPoint,
                crop)).getVisitor();
                        : PointToSurfaceDistanceConfig.Method.POINT_TO_SURFACE;

        PointToSurfaceDistanceConfig cfg = new PointToSurfaceDistanceConfig(method, inspectedPoint, crop);

        // Use the same single KD tree as before (the primary one)
        if (pointToPoint) {
            return closestMeshVerticesService.measure(kdTree, cfg);
        }
        return closestSurfacePointsService.measure(kdTree, cfg);
    }

    protected void updateResults(PointToSurfaceDistanceVisitor vis, MeshPoint point, List<Double> distList, List<MeshPoint> nearestPointsList) {
        MeshPoint closestV = getClosestMeshPoint(vis);
    protected void updateResults(Pair<Double, Map<MeshFacet, List<MeshPoint>>> result, MeshPoint point, List<Double> distList, List<MeshPoint> nearestPointsList) {
        MeshPoint closestV = getClosestMeshPoint(result);
        if (closestV == null) { // unable to get a single closest point
            distList.add(Double.POSITIVE_INFINITY);
            nearestPointsList.add(null);
            return;
        }

        double dist = vis.getDistance();
        double dist = result.getLeft();
        int sign = 1;

        if (relativeDistance()) { // compute sign for relative distance
@@ -174,52 +190,34 @@ public class MeshDistanceNN extends MeshDistanceVisitorImpl {
    }

    /**
     * @param vis visitor
     * @param result service output
     * @return the only one existing closest vertex or {@code null}
     */
    protected MeshPoint getClosestMeshPoint(PointToSurfaceDistanceVisitor vis) {
        if (!Double.isFinite(vis.getDistance())) {
    protected MeshPoint getClosestMeshPoint(Pair<Double, Map<MeshFacet, List<MeshPoint>>> result) {
        if (result == null) {
            return null;
        }

        if (!Double.isFinite(result.getLeft())) {
            return null; 
        }
        
        if (vis.getNearestPoints().size() != 1) {
        if (result.getRight() == null || result.getRight().size() != 1) {
            return null; // something is wrong because there should be only my inspected facet
        }

        MeshFacet myInspectedFacet = vis.getNearestPoints().keySet().stream().findFirst().get();
        MeshFacet myInspectedFacet = result.getRight().keySet().stream().findFirst().orElse(null);
        if (myInspectedFacet == null) {
            return null;
        }

        if (vis.getNearestPoints().get(myInspectedFacet).size() != 1) {
        List<MeshPoint> points = result.getRight().get(myInspectedFacet);
        if (points == null || points.size() != 1) {
            return null; // multiple closest points; we don't know which one to choose
        }
        
        // return the only one closest vertex
        return vis.getNearestPoints().get(myInspectedFacet).get(0);
        return points.getFirst();
    }

    /**
     * Helper call for asynchronous invocation of visitors.
     * 
     * @author Radek Oslejsek
     */
    private class CallableVisitor implements Callable<KdTreeVisitor> {
        private final KdTreeVisitor vis;
        
        /**
         * Constructor.
         * @param vis visitor to be called asynchronously
         */
        CallableVisitor(KdTreeVisitor vis) {
            this.vis = vis;
        }
        
        @Override
        public KdTreeVisitor call() throws Exception {
            try {
                kdTree.accept(vis); 
                return vis;
            } catch(UnsupportedOperationException ex) {
                return null;
            }
        }
    }
}
+0 −15
Original line number Diff line number Diff line
package cz.fidentis.analyst.engines.point2surface;

import cz.fidentis.analyst.engines.point2surface.impl.ClosestMeshVerticesImpl;
import cz.fidentis.analyst.engines.point2surface.impl.ClosestSurfacePointsImpl;

import javax.vecmath.Point3d;

/**
@@ -17,18 +14,6 @@ import javax.vecmath.Point3d;
 */
public record PointToSurfaceDistanceConfig(Method method, Point3d point, boolean checkOverlay) {

    /**
     * Instantiates and returns a point sampling visitor.
     *
     * @return a point sampling visitor
     */
    public PointToSurfaceDistanceVisitor getVisitor() {
        return switch (method) {
            case POINT_TO_VERTICES -> new ClosestMeshVerticesImpl(point, checkOverlay);
            case POINT_TO_SURFACE -> new ClosestSurfacePointsImpl(point, checkOverlay);
        };
    }

    /**
     * Sampling method.
     *
+7 −26
Original line number Diff line number Diff line
@@ -6,13 +6,11 @@ import cz.fidentis.analyst.data.mesh.MeshPoint;
import org.apache.commons.lang3.tuple.Pair;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Stateless services for point-to-mesh distance measurement.
 * It is a wrapper to the stateful implementation of {@link cz.fidentis.analyst.engines.point2surface.PointToSurfaceDistanceVisitor}.
 *
 * @author Radek Oslejsek
 */
@@ -25,11 +23,7 @@ public interface PointToSurfaceDistanceServices {
     * @param config Configuration of the service
     * @return the distance from a 3D point
     */
    static double measureDistance(Collection<KdTree> kdTrees, PointToSurfaceDistanceConfig config) {
        var visitor = config.getVisitor();
        kdTrees.forEach(kdTree -> kdTree.accept(visitor));
        return visitor.getDistance();
    }
    double measureDistance(Collection<KdTree> kdTrees, PointToSurfaceDistanceConfig config);

    /**
     * Returns the distance from the 3D point and the mesh stored in th k-D tree.
@@ -38,9 +32,7 @@ public interface PointToSurfaceDistanceServices {
     * @param config Configuration of the service
     * @return the distance from a 3D
     */
    static double measureDistance(KdTree kdTree, PointToSurfaceDistanceConfig config) {
        return measureDistance(Collections.singleton(kdTree), config);
    }
    double measureDistance(KdTree kdTree, PointToSurfaceDistanceConfig config);

    /**
     * Returns the closest point from the meshes stored in the k-D trees and the 3D point.
@@ -49,11 +41,7 @@ public interface PointToSurfaceDistanceServices {
     * @param config Configuration of the service
     * @return the closest points from visited meshes to the 3D point
     */
    static Map<MeshFacet, List<MeshPoint>> findNearestPoints(Collection<KdTree> kdTrees, PointToSurfaceDistanceConfig config) {
        var visitor = config.getVisitor();
        kdTrees.forEach(kdTree -> kdTree.accept(visitor));
        return visitor.getNearestPoints();
    }
    Map<MeshFacet, List<MeshPoint>> findNearestPoints(Collection<KdTree> kdTrees, PointToSurfaceDistanceConfig config);

    /**
     * Returns the closest point from the mesh stored in the k-D tree and the 3D point.
@@ -62,9 +50,7 @@ public interface PointToSurfaceDistanceServices {
     * @param config Configuration of the service
     * @return the closest points from visited meshes to the 3D point
     */
    static Map<MeshFacet, List<MeshPoint>> findNearestPoints(KdTree kdTree, PointToSurfaceDistanceConfig config) {
        return findNearestPoints(Collections.singleton(kdTree), config);
    }
    Map<MeshFacet, List<MeshPoint>> findNearestPoints(KdTree kdTree, PointToSurfaceDistanceConfig config);

    /**
     * Returns the distance and the closest points
@@ -73,11 +59,7 @@ public interface PointToSurfaceDistanceServices {
     * @param config Configuration of the service
     * @return the distance and closest points
     */
    static Pair<Double, Map<MeshFacet, List<MeshPoint>>> measure(Collection<KdTree> kdTrees, PointToSurfaceDistanceConfig config) {
        var visitor = config.getVisitor();
        kdTrees.forEach(kdTree -> kdTree.accept(visitor));
        return Pair.of(visitor.getDistance(), visitor.getNearestPoints());
    }
    Pair<Double, Map<MeshFacet, List<MeshPoint>>> measure(Collection<KdTree> kdTrees, PointToSurfaceDistanceConfig config);

    /**
     * Returns the distance and the closest points
@@ -86,7 +68,6 @@ public interface PointToSurfaceDistanceServices {
     * @param config Configuration of the service
     * @return the distance and closest points
     */
    static Pair<Double, Map<MeshFacet, List<MeshPoint>>> measure(KdTree kdTree, PointToSurfaceDistanceConfig config) {
        return  measure(Collections.singleton(kdTree), config);
    }
    Pair<Double, Map<MeshFacet, List<MeshPoint>>> measure(KdTree kdTree, PointToSurfaceDistanceConfig config);

}
+0 −47
Original line number Diff line number Diff line
package cz.fidentis.analyst.engines.point2surface;

import cz.fidentis.analyst.data.kdtree.KdTreeVisitor;
import cz.fidentis.analyst.data.mesh.MeshFacet;
import cz.fidentis.analyst.data.mesh.MeshPoint;

import java.util.List;
import java.util.Map;

/**
 * Classes implementing this interface can compute minimal distance between a 3D point (set in a constructor)
 * to a mesh facets.
 * <p>
 * The distance computation can be either absolute or relative. Absolute means
 * that the Euclidean distance between 3D points in space is used. Because only
 * positive distances are taken into calculation, then the minimum distance is
 * the smallest found distance.
 * </p>
 * <p>
 * Relative distance also takes the normal vector of the 3D point into account.
 * If the "measured" point is located in the half space of the normal direction,
 * then the distance is positive. Otherwise, the distance is negative.
 * The minimum distance is a value "closest to zero".
 * </p>
 * 
 * @author Radek Oslejsek
 */
public interface PointToSurfaceDistanceVisitor extends KdTreeVisitor {

    /**
     * Returns the minimal found distance between a 3D point (set in a constructor) and visited mesh facets.
     * 
     * @return the minimal found distance, 
     * {@code Double.POSITIVE_INFINITY} if no distance has been computed so far
     */
    double getDistance();

    /**
     * Returns the closest mesh facets and their closest points.
     * As there can be more point in the same (smallest) distance, the method returns
     * a list instead of a single point. Similarly, as the closest point(s) can belong to
     * multiple facets, a map of facet is returned instead of a single facet.
     *
     * @return closest mesh facets and their closest points.
     */
    Map<MeshFacet, List<MeshPoint>> getNearestPoints();
}
Loading