Commit 0c46a688 authored by Peter Čonga's avatar Peter Čonga
Browse files

Feat: distance span for batch processing without registration

parent 92eb9b71
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -203,7 +203,7 @@ public class BatchCurveRenderingPanel extends JPanel {
            g2.setColor(Color.GRAY);
            for (Line2D line : normalVectors) {
                double length = Math.sqrt(Math.pow(line.getX1() - line.getX2(), 2) + Math.pow(line.getY1() - line.getY2(), 2));
                if (length > 18) {
                if (length > 28) {
                    continue;
                }
                double x1 = line.getX1() * scale + offsetX;
+95 −18
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import org.json.simple.JSONObject;

import static cz.fidentis.analyst.symmetry.CuttingPlanesUtils.*;
import java.awt.geom.Line2D;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
@@ -179,6 +180,10 @@ public class BatchCuttingPlanesAction extends ControlPanelAction<BatchCuttingPla
                break;
            case BatchCuttingPlanesPanel.ACTION_COMMAND_SHOW_SELECTED_FACE:
                showSelectedFace();
                if (getControlPanel().getSelectedFace() != null) {
                    getControlPanel().getCurveRenderingPanel().setFaceBoundingBox(getControlPanel().getFacesProxyDecorator().haveAvgFace() ? getControlPanel().getFacesProxyDecorator().getAvgFace().getBoundingBox() : getControlPanel().getSelectedFace().getBoundingBox());
                    getControlPanel().getCurveRenderingPanel().setCurrentCuttingPlane(getControlPanel().getCurveRenderingPanel().getCurrentCuttingPlane());
                }
                computeCrossSections(getCuttingPlanes(getControlPanel().getCurveRenderingPanel().getCurrentCuttingPlane()));
                break;
            default:
@@ -331,15 +336,17 @@ public class BatchCuttingPlanesAction extends ControlPanelAction<BatchCuttingPla
        List<List<Curve2d>> curvesOfSelectedFace = CuttingPlanesUtils.computeCrossSections(crossSectionPlanes, getControlPanel().getSelectedFace(),
                null, FEATURE_POINTS_CLOSENESS);
        List<List<Curve2d>> curvesOfFaces = new ArrayList<>();
        List<HumanFace> faceList = new ArrayList<>();
        for (int i = 0; i <  getControlPanel().getFacesProxyDecorator().getNumFaces(); i++) {
            curvesOfFaces.add(CuttingPlanesUtils.computeCrossSections(crossSectionPlanes, getControlPanel().getFacesProxyDecorator().getFace(i),
                    null, FEATURE_POINTS_CLOSENESS).get(0));
            faceList.add(getControlPanel().getFacesProxyDecorator().getFace(i));
        }
        
        getControlPanel().getCurveRenderingPanel().setCurves(findNearestNeighbors(curvesOfSelectedFace.get(0), curvesOfFaces));
        getControlPanel().getCurveRenderingPanel().setCurves(calculateDeviation(curvesOfSelectedFace.get(0), curvesOfFaces, faceList));
    }
    
    private List<Curve2d> findNearestNeighbors(List<Curve2d> avg, List<List<Curve2d>> faces) {
    private List<Curve2d> calculateDeviation(List<Curve2d> avg, List<List<Curve2d>> faceCurves, List<HumanFace> faceList) {
        List<Curve2d> reducedCurves = new ArrayList<>();
        for (int i = 0; i < avg.size(); i++) {
            if (avg.get(i) == null) {
@@ -348,7 +355,7 @@ public class BatchCuttingPlanesAction extends ControlPanelAction<BatchCuttingPla
            Curve2d avgCurve = avg.get(i).subSample(sampling);
            reducedCurves.add(avgCurve);
            List<Curve2d> curves = new ArrayList<>();
            for (List<Curve2d> curvesOfFace : faces) {
            for (List<Curve2d> curvesOfFace : faceCurves) {
                curves.add(curvesOfFace.get(i));
            }

@@ -358,27 +365,36 @@ public class BatchCuttingPlanesAction extends ControlPanelAction<BatchCuttingPla
                    int curCounter = counter.getAndIncrement();
                    if (curCounter < avgCurveSegment.size() - 1) {
                        // Find nearest neighbors in parallel
                        List<Point2d> nearestNeighbors = curves.parallelStream()
                            .map(curve -> curve.getCurveSegments().stream()
                            .flatMap(Collection::stream)
                            .min(Comparator.comparingDouble(point -> Math.sqrt(Math.pow((point.x - avgPoint.x), 2) + Math.pow((point.y - avgPoint.y), 2))))
                            .orElse(null))
                            .filter(Objects::nonNull)
                            .collect(Collectors.toList());
                        List<Point2d> nearestNeighbors;
                        
                        Line2D normal = avgCurve.getNormals().get(curCounter);
                        
                        double maxDistance = Double.MIN_VALUE;
                        double minDistance = Double.MAX_VALUE;
                        for (Point2d p : nearestNeighbors) {
                            double dx = p.x - avgPoint.x;
                            double dy = p.y - avgPoint.y;
                            double relativeDistance = dx * normal.getX2() + dy * normal.getY2();
                        double maxDistance;
                        double minDistance;
                        if (getControlPanel().getFacesProxyDecorator().haveAvgFace()) {
                            nearestNeighbors = findNearestNeighbors(curves, avgPoint);
                                                        
                            maxDistance = relativeDistance > maxDistance ? relativeDistance : maxDistance;
                            minDistance = relativeDistance < minDistance ? relativeDistance : minDistance;
                            double[] distances = calculateMinMaxDistances(nearestNeighbors, avgPoint, normal, Arrays.asList(1.0, 0.0, 0.0));
                            maxDistance = distances[0];
                            minDistance = distances[1];
                            
                        } else {
                            BoundingBox2D avgBox2D = getBoundingBox2D(getControlPanel().getCurveRenderingPanel().getPreferredSize().width, 
                                                    getControlPanel().getCurveRenderingPanel().getPreferredSize().height, 
                                                    getControlPanel().getSelectedFace().getBoundingBox(), 
                                                    getControlPanel().getCurveRenderingPanel().getCurrentCuttingPlane());
                            double selScale = avgBox2D.scale();
                            double selOffsetX = avgBox2D.offsetX();
                            double selOffsetY = avgBox2D.offsetY();
                            
                            nearestNeighbors = findNearestNeighbors(curves, avgPoint, faceList, Arrays.asList(selScale, selOffsetX, selOffsetY));
                            
                            double[] distances = calculateMinMaxDistances(nearestNeighbors, avgPoint, normal, Arrays.asList(selScale, selOffsetX, selOffsetY));
                            maxDistance = distances[0];
                            minDistance = distances[1];
                        }
                        
                        
                        normal.setLine(
                            normal.getX1() + (normal.getX2() * minDistance),
                            normal.getY1() + (normal.getY2() * minDistance),
@@ -394,6 +410,67 @@ public class BatchCuttingPlanesAction extends ControlPanelAction<BatchCuttingPla
        return reducedCurves;
    }
    
    private List<Point2d> findNearestNeighbors(List<Curve2d> curves, Point2d avgPoint) {
        return curves.parallelStream()
                .map(curve -> curve.getCurveSegments().stream()
                .flatMap(Collection::stream)
                .min(Comparator.comparingDouble(point -> Math.pow((point.x - avgPoint.x), 2) + Math.pow((point.y - avgPoint.y), 2)))
                .orElse(null))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
    
    private List<Point2d> findNearestNeighbors(List<Curve2d> curves, Point2d avgPoint, List<HumanFace> faceList, List<Double> scaleOffset) {
        List<Point2d> nearestNeighbors = new ArrayList<>();
        double selScale = scaleOffset.get(0);
        double selOffsetX = scaleOffset.get(1);
        double selOffsetY = scaleOffset.get(2);
        Point2d transformedAvgPoint = new Point2d(avgPoint.x * selScale + selOffsetX, avgPoint.y * selScale + selOffsetY);
        for (int faceIndex = 0; faceIndex < getControlPanel().getFacesProxyDecorator().getNumFaces(); faceIndex++) {
            BoundingBox2D box2D = getBoundingBox2D(getControlPanel().getCurveRenderingPanel().getPreferredSize().width, 
                                                    getControlPanel().getCurveRenderingPanel().getPreferredSize().height, 
                                                    faceList.get(faceIndex).getBoundingBox(), 
                                                    getControlPanel().getCurveRenderingPanel().getCurrentCuttingPlane());
            double scale = box2D.scale();
            double offsetX = box2D.offsetX();
            double offsetY = box2D.offsetY();

            Curve2d curve = curves.get(faceIndex);
            Point2d nearestPoint = curve.getCurveSegments().parallelStream()
                .flatMap(Collection::stream)
                .min(Comparator.comparingDouble(point -> {
                    double dx = (point.x * scale + offsetX) - transformedAvgPoint.x;
                    double dy = (point.y * scale + offsetY) - transformedAvgPoint.y;
                    return dx * dx + dy * dy; // Compare squared distances
                }))
                .orElse(null);
            if (nearestPoint != null) {
                nearestNeighbors.add(new Point2d(nearestPoint.x * scale + offsetX, nearestPoint.y * scale + offsetY));
            }
        }
        return nearestNeighbors;
    }
    
    private double[] calculateMinMaxDistances(List<Point2d> nearestNeighbors, Point2d avgPoint, Line2D normal, List<Double> scaleOffset) {
        double selScale = scaleOffset.get(0);
        double selOffsetX = scaleOffset.get(1);
        double selOffsetY = scaleOffset.get(2);
        double maxDistance = Double.MIN_VALUE;
        double minDistance = Double.MAX_VALUE;
        for (Point2d p : nearestNeighbors) {
            double dx = p.x - (avgPoint.x * selScale + selOffsetX);
            double dy = p.y - (avgPoint.y * selScale + selOffsetY);
            double relativeDistance = dx * normal.getX2() + dy * normal.getY2();

            maxDistance = relativeDistance > maxDistance ? relativeDistance : maxDistance;
            minDistance = relativeDistance < minDistance ? relativeDistance : minDistance;
        }
        maxDistance /= selScale;
        minDistance /= selScale;
        
        return new double[] {maxDistance, minDistance};
    }
    
    /**
     * Computes Hausdorff distances of all visible curves. 
     * @param primaryCurves cross sections with primary face
+0 −5
Original line number Diff line number Diff line
@@ -663,11 +663,6 @@ public class BatchCuttingPlanesPanel extends ControlPanel {
    }//GEN-LAST:event_removeFronBackPMPButtonActionPerformed

    private void showDeviationCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showDeviationCheckBoxActionPerformed
        if (!this.getFacesProxyDecorator().haveAvgFace()) {
            JOptionPane.showMessageDialog(this, "Please use registration before accessing this feature");
            showDeviationCheckBox.setSelected(false);
            return;
        }
        polylinePanel1.setShowNormals(showDeviationCheckBox.isSelected());
        repaint();
    }//GEN-LAST:event_showDeviationCheckBoxActionPerformed