Commit fd58f697 authored by Martin Bjaloň's avatar Martin Bjaloň
Browse files

Enable interactive mask point selection and manipulation on 3D face.

Added support for selecting and dragging mask points using Shift + left mouse button.
parent 82d4dbff
Loading
Loading
Loading
Loading
+38 −5
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ package cz.fidentis.analyst.data.surfacemask;

import cz.fidentis.analyst.data.mesh.MeshFacet;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
@@ -31,17 +32,17 @@ public class SurfaceMask {
     */
    public void addPoint(Point3d surfacePoint, MeshFacet facet, Vector3d normal, boolean isSelected, boolean isSampled) {
        if (points.isEmpty()) {
           points.add(new MaskPoint3D(surfacePoint, facet, normal, isSelected, isSampled));
           points.add(new MaskPoint3D(surfacePoint, facet, normal, isSelected, isSampled, Color.WHITE));
           return;
        }
        
        if (points.size() == 1) {
           points.add(new MaskPoint3D(surfacePoint, facet, normal,isSelected, isSampled));
           points.add(new MaskPoint3D(surfacePoint, facet, normal,isSelected, isSampled, Color.WHITE));
           return;
        }

        // add to the end
        points.add(new MaskPoint3D(surfacePoint, facet, normal, isSelected, isSampled));
        points.add(new MaskPoint3D(surfacePoint, facet, normal, isSelected, isSampled, Color.WHITE));
    }
    

@@ -53,6 +54,20 @@ public class SurfaceMask {
        return Collections.unmodifiableList(points);
    }

    /**
     * Shifts the position of a single point by a given offset.
     * @param point the MaskPoint3D to shift
     * @param newPoint new position
     */
    public void shiftPoint(MaskPoint3D point, Point3d newPoint) {
        for (MaskPoint3D maskPoint : points) {
            if (maskPoint == point) {
                maskPoint.setPosition(newPoint);
                break;
            }
        }
    }

    
    /**
     * Class representing a single point of Interactive Mask.
@@ -60,29 +75,35 @@ public class SurfaceMask {
     * @author Mario Chromik
     */
    public static final class MaskPoint3D {
        private final boolean isSelected;
        private boolean isSelected;
        private final boolean isSampled;
        private final Point3d position;
        private final MeshFacet facet;
        private final Vector3d normal;
        private Color color;
        /**
         * Constructor.
         * 
         * @param pos position of an Interactive Mask point in 3D space
         * @param fac facet of IM point
         */
        private MaskPoint3D(Point3d pos, MeshFacet fac, Vector3d norm, boolean isSelected, boolean isSampled) {
        private MaskPoint3D(Point3d pos, MeshFacet fac, Vector3d norm, boolean isSelected, boolean isSampled, Color color) {
            position = pos;
            facet = fac;
            normal = norm;
            this.isSelected = isSelected;
            this.isSampled = isSampled;
            this.color = color;
        }
    
        public Point3d getPosition() {
            return position;
        }

        public void setPosition(Point3d position) {
            this.position.set(position);
        }
        
        public MeshFacet getFacet() {
            return facet;
        }
@@ -98,5 +119,17 @@ public class SurfaceMask {
        public boolean getIsSelected() {
            return isSelected;
        }

        public Color getColor() {
            return color;
        }

        public void setColor(Color color) {
            this.color = color;
        }

        public void setSelected(boolean selected) {
            this.isSelected = selected;
        }
    }
}
 No newline at end of file
+90 −1
Original line number Diff line number Diff line
package cz.fidentis.analyst.canvas;

import cz.fidentis.analyst.data.face.HumanFace;
import cz.fidentis.analyst.data.ray.RayIntersection;
import cz.fidentis.analyst.data.surfacemask.SurfaceMask;
import cz.fidentis.analyst.drawables.DrawableInteractiveMask;
import org.openide.util.Pair;

import javax.swing.*;
import javax.vecmath.Point3d;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
@@ -38,11 +46,12 @@ public class MouseRotationListener extends MouseAdapter {
     * Left mouse button dragging rotates
     * Right mouse button dragging moves
     * Middle mouse button dragging resets rotation and zoom
     * Left mouse button + shift dragging masks point
     * @param evt Mouse position info
     */
    @Override
    public void mouseDragged(MouseEvent evt) {
        if (SwingUtilities.isLeftMouseButton(evt)) {
        if (SwingUtilities.isLeftMouseButton(evt) && !evt.isShiftDown()) {
            double rotateX = -(lastY - evt.getY()) * rotationSpeed;
            double rotateY =  (lastX - evt.getX()) * rotationSpeed;
            if (Math.abs(rotateX) < Math.abs(rotateY)) {
@@ -60,6 +69,22 @@ public class MouseRotationListener extends MouseAdapter {
        if (SwingUtilities.isMiddleMouseButton(evt)) {
            canvas.getCamera().zoomToFit(canvas.getScene());
        }
        if (evt.isShiftDown() && SwingUtilities.isLeftMouseButton(evt)) {
            for (DrawableInteractiveMask mask : canvas.getScene().getDrawableInteractiveMasks()) {
                if (mask == null) {
                    continue;
                }

                for (SurfaceMask.MaskPoint3D point : mask.getMask().getPoints()) {
                    if (point.getIsSelected()) {
                        Pair<HumanFace, RayIntersection> closestFace = canvas.castRayThroughPixel(evt.getX(), evt.getY());
                        Point3d offset = new Point3d(closestFace.second().getX(), closestFace.second().getY(), closestFace.second().getZ());
                        mask.getMask().shiftPoint(point, offset);
                    }
                }
            }
        }

        lastX = evt.getX();
        lastY = evt.getY();
        canvas.renderScene();
@@ -101,6 +126,64 @@ public class MouseRotationListener extends MouseAdapter {
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {
        if (!e.isShiftDown()) {
            return;
        }

        Pair<HumanFace, RayIntersection> closestFace = canvas.castRayThroughPixel(e.getX(), e.getY());

        if (closestFace == null) {
            System.out.println("No face found for pixel " + e.getX() + ", " + e.getY());
            return;
        }

        double threshold = 1.0;

        SurfaceMask.MaskPoint3D closestPoint = null;
        double minDistance = Double.MAX_VALUE;

        for (DrawableInteractiveMask mask : canvas.getScene().getDrawableInteractiveMasks()) {
            if (mask == null) {
                continue;
            }

            for (SurfaceMask.MaskPoint3D point : mask.getMask().getPoints()) {
                double distance = calculate3DDistance(closestFace.second().getPosition(), point.getPosition());

                if (distance < minDistance) {
                    minDistance = distance;
                    closestPoint = point;
                }
            }
        }

        if (closestPoint != null && minDistance <= threshold) {
            closestPoint.setColor(Color.GREEN);
            closestPoint.setSelected(true);
        }

        canvas.renderScene();
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        for (DrawableInteractiveMask mask : canvas.getScene().getDrawableInteractiveMasks()) {
            if (mask == null) {
                continue;
            }

            for (SurfaceMask.MaskPoint3D point : mask.getMask().getPoints()) {
                if (point.getIsSelected()) {
                    point.setColor(Color.WHITE);
                    point.setSelected(false);
                }
            }
        }
        canvas.renderScene();
    }
    
    /**
     * @return Rotation speed
     */
@@ -131,4 +214,10 @@ public class MouseRotationListener extends MouseAdapter {
        MouseRotationListener.moveSpeed = moveSpeed;
    }

    private double calculate3DDistance(Point3d point1, Point3d point2) {
        double dx = point2.x - point1.x;
        double dy = point2.y - point1.y;
        return Math.sqrt(dx * dx + dy * dy);
    }

}
+11 −19
Original line number Diff line number Diff line
@@ -55,27 +55,19 @@ public class DrawableInteractiveMaskRenderer extends AbstractDrawableRenderer<Dr

    @Override
    protected void renderObject(GL2 gl, DrawableInteractiveMask drawableInteractiveMask) {
        drawableInteractiveMask.getColor();
        float[] rgba = {
                defaultColor.getRed() / 255f,
                defaultColor.getGreen() / 255f,
                defaultColor.getBlue() / 255f,
                defaultColor.getTransparency()};

        float[] rgbaSelected = {
                selectedColor.getRed() / 255f,
                selectedColor.getGreen() / 255f,
                selectedColor.getBlue() / 255f,
                selectedColor.getTransparency()};
        gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, rgba, 0);

        // draw mask points
        for (SurfaceMask.MaskPoint3D maskPoint : drawableInteractiveMask.getMask().getPoints()) {
            if (maskPoint.getIsSelected()) {
                gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, rgbaSelected, 0);
            } else {
                gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, rgba, 0);
            }
            Color pointColor = maskPoint.getColor();

            float[] rgbaPoint = {
                    pointColor.getRed() / 255f,
                    pointColor.getGreen() / 255f,
                    pointColor.getBlue() / 255f,
                    pointColor.getAlpha() / 255f
            };

            gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, rgbaPoint, 0);

            gl.glPushMatrix();
            gl.glTranslated(maskPoint.getPosition().x, maskPoint.getPosition().y, maskPoint.getPosition().z);
            GLUquadric center = GLU_CONTEXT.gluNewQuadric();
+5 −1
Original line number Diff line number Diff line
@@ -529,6 +529,10 @@ public class Scene {
        return Collections.unmodifiableList(this.drawableCuttingPlanes);
    }

    public List<DrawableInteractiveMask> getDrawableInteractiveMasks() {
        return Collections.unmodifiableList(this.drawableInteractiveMasks);
    }

    protected Color getColorOfFeaturePoints(Color origColor) {
        return new Color(
                Math.min(255, origColor.getRed() + 40),