Commit 3d3de0f1 authored by Mário Chromík's avatar Mário Chromík
Browse files

Merge branch '272-merge-branch' into 'master'

Resolve "Surface Mask drawing panel"

Closes #272

See merge request grp-fidentis/analyst2!335
parents cc22ab83 4788c4a1
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -201,4 +201,10 @@ public interface HumanFace extends HumanFaceEventBus, Serializable {
     * @return {@code true}, if the bounding box exists
     */
    boolean hasBoundingBox();

    /**
     * Set a surface mask.
     * @param surfaceMask surfaceMask or {@code null}
     */
    void setSurfaceMask(SurfaceMask surfaceMask);
}
+6 −1
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ public class HumanFaceImpl implements HumanFace {

    private final String id;

    private final transient SurfaceMask surfaceMask = new SurfaceMask();
    private transient SurfaceMask surfaceMask = new SurfaceMask();

    private List<Glyph> glyphs;

@@ -314,6 +314,11 @@ public class HumanFaceImpl implements HumanFace {
        return boundingBox != null;
    }

    @Override
    public void setSurfaceMask(SurfaceMask surfaceMask) {
        this.surfaceMask = surfaceMask;
    }

    @Override
    public int hashCode() {
        return id.hashCode();
+216 −0
Original line number Diff line number Diff line
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package cz.fidentis.analyst.gui.elements;

import cz.fidentis.analyst.canvas.Canvas;
import cz.fidentis.analyst.data.face.HumanFace;
import cz.fidentis.analyst.data.shapes.SurfaceMask;
import cz.fidentis.analyst.data.shapes.SurfaceMask2D;
import cz.fidentis.analyst.gui.task.interactivemask.InteractiveMaskTaskNoParallel;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseEvent;


/**
 * A panel to draw an interacitve mask on.
 * @author Mario Chromik
 */
public class SurfaceMaskPanel extends CurveRenderingPanel {
    /**private Canvas canvas;
    private HumanFace face;
    */

    private final SurfaceMask2D surfaceMask = new SurfaceMask2D();

    private ActionListener panelListener;

    /**
     * Constructor setting mouse listeners and drawing an initial mask.
     */
    public SurfaceMaskPanel() {
        setBackground(Color.WHITE);
        Adapter ml = new Adapter();
        addMouseListener(ml);
        addMouseMotionListener(new MotionAdapter());
        drawInitialRectangleSM();
    }
    /**
    /**
     * Sets canvas and face
     * @param canvas input canvas
     * @param face input face
     *
    public void setCanvasAndFace(Canvas canvas, HumanFace face) {
        this.canvas = canvas;
        this.face = face;
    }
    */

    public SurfaceMask2D getSurfaceMask() {
        return surfaceMask;
    }

    /**
     * Draws an initial shape for surface mask
     */
    private void drawInitialRectangleSM(){
        surfaceMask.addPoint(new Point(100, 100));
        surfaceMask.addPoint(new Point(100, 200));
        surfaceMask.addPoint(new Point(200, 200));
        surfaceMask.addPoint(new Point(200, 100));
        repaint();
    }

    /**
     * Draws the shape of an interactive mask
     * @param g panel graphics
     */
    private void drawMaskLines(Graphics g) {
        for (int i = 0; i < surfaceMask.getMaskPoints().size() - 1; i++) {
            g.drawLine(surfaceMask.getMaskPoints().get(i).x, surfaceMask.getMaskPoints().get(i).y,
                    surfaceMask.getMaskPoints().get(i + 1).x, surfaceMask.getMaskPoints().get(i + 1).y);
            g.drawOval(surfaceMask.getMaskPoints().get(i).x - 5,
                    surfaceMask.getMaskPoints().get(i).y - 5, 10, 10);
        }

        //Close the mask
        g.drawOval(surfaceMask.getMaskPoints().get(surfaceMask.getMaskPoints().size() - 1).x - 5,
                surfaceMask.getMaskPoints().get(surfaceMask.getMaskPoints().size() - 1).y - 5, 10, 10);

        if (surfaceMask.getMaskPoints().size() >= 3) {
            g.drawLine(surfaceMask.getMaskPoints().get(surfaceMask.getMaskPoints().size() - 1).x,
                    surfaceMask.getMaskPoints().get(surfaceMask.getMaskPoints().size() - 1).y,
                    surfaceMask.getMaskPoints().get(0).x, surfaceMask.getMaskPoints().get(0).y);
        }
    }

    /**
     * Draws curves between points
     * @param g panel graphics
     * @param controlPoints a list of control points

    private void drawCurves(Graphics g, ArrayList<Point> controlPoints) {
        int n = controlPoints.size();
        if (n >= 3) {
            for (int i = 0; i < n - 3; i += 3) {
                g.setColor(Color.RED); // Set your desired color for Bezier curves
                drawCurve(g, controlPoints.get(i).x, controlPoints.get(i).y,
                        controlPoints.get(i+1).x, controlPoints.get(i+1).y,
                        controlPoints.get(i+2).x, controlPoints.get(i+2).y);
            }
        }
    }


     * Draws a single curve
     * @param g panel graphics
     * @param x the X coordinate of the start point y1
     * @param y the Y coordinate of the start point
     * @param x1 the X coordinate of the control point
     * @param y1 the Y coordinate of the control point
     * @param x2 the X coordinate of the end point
     * @param y2 the Y coordinate of the end point

    private void drawCurve(Graphics g, int x, int y, int x1, int y1, int x2, int y2) {
        Graphics2D g2 = (Graphics2D) g;
        QuadCurve2D q = new QuadCurve2D.Float();
        q.setCurve(x, y, x1, y1, x2, y2);
        g2.draw(q);
    }



    /**
     * Projects points onto face using asynchronous thread
     /
    private void project() {
        /** Code used to intialize task and project points in parellel
        //cancel if task is already running
         task.cancel(false);
         task = new InteractiveMaskTask(canvas, pointsToProject, getPanelWidth(), getPanelHeight());
         task.execute();
        /
        InteractiveMaskTaskNoParallel task = new InteractiveMaskTaskNoParallel(canvas, surfaceMask.getPointsToProject(), getPanelWidth(), getPanelHeight());
        task.project();

    }
    */

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        //face.setSurfaceMask(new SurfaceMask());
        g.setColor(Color.BLACK);

        if (surfaceMask.getMaskPoints().size() >= 2) {
            drawMaskLines(g);
        }
    }

    /**
     * Gets panel width
     * @return integer panel width
     */
    public int getPanelWidth() {
        return (int)this.getSize().getWidth();
    }

    /**
     * Gets panel height
     * @return integer panel height
     */
    public int getPanelHeight() {
        return (int)this.getSize().getHeight();
    }

    public void addActionListener(ActionListener listener) {
        this.panelListener = listener;
    }

    /**
     * Custom mouse listener to handle drawing a mask
     * @author Mario Chromik
     */
    class Adapter extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            if (! surfaceMask.selectPoint(e.getPoint())) {
                surfaceMask.addPoint(e.getPoint());
                repaint();
            }

        }

        @Override
        public void mouseReleased(MouseEvent e) {
            surfaceMask.setSelectedPoint(null);
            //project();
            panelListener.actionPerformed( new ActionEvent(this, ActionEvent.ACTION_PERFORMED, null));
        }
    }

    /**
     * Custom mouse motion listener to hande dragging a point
     * @author Mario Chromik
     */
    class MotionAdapter extends MouseMotionAdapter {
        @Override
        public void mouseDragged(MouseEvent e) {
            if (surfaceMask.getSelectedPoint() != null) {
                surfaceMask.getSelectedPoint().setLocation(e.getPoint());
                repaint();
            }
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -365,9 +365,9 @@ public class FeaturePointsAction extends ControlPanelAction<FeaturePointsPanel>
                    }
                }
            }
        }
            renderScene();
        }
    }

    /**
     * Changes the colors of standard feature points (ON_THE_MESH_COLOR, CLOSE_TO_MESH_COLOR, customFpColor) and custom feature points
+34 −42
Original line number Diff line number Diff line
package cz.fidentis.analyst.gui.task.interactivemask;

import cz.fidentis.analyst.canvas.Canvas;
import cz.fidentis.analyst.engines.face.events.HumanFaceSelectedEvent;
import cz.fidentis.analyst.data.face.HumanFaceEvent;
import cz.fidentis.analyst.data.face.HumanFaceListener;
import cz.fidentis.analyst.data.shapes.SurfaceMask2D;
import cz.fidentis.analyst.engines.face.FaceStateServices;
import cz.fidentis.analyst.engines.interactivemask.MaskProjector;
import cz.fidentis.analyst.engines.interactivemask.MaskProjectorConfig;
import cz.fidentis.analyst.gui.task.ControlPanelAction;
import cz.fidentis.analyst.project.FacesProxy;
import cz.fidentis.analyst.data.ray.RayIntersection;
import cz.fidentis.analyst.rendering.Camera;

import javax.swing.*;
import java.awt.event.ActionEvent;


/**
 *
 * @author Mario Chromik
 */
public class InteractiveMaskAction extends ControlPanelAction<InteractiveMaskPanel> implements HumanFaceListener {
public class InteractiveMaskAction extends ControlPanelAction<InteractiveMaskPanel> {

    private String mode = InteractiveMaskPanel.ACTION_VIEW;
    private String mode = InteractiveMaskPanel.ACTION_DRAW;

    /**
     * Constructor
@@ -29,7 +31,9 @@ public class InteractiveMaskAction extends ControlPanelAction<InteractiveMaskPan
     */
    public InteractiveMaskAction(Canvas canvas, FacesProxy faces, JTabbedPane topControlPane) {
        super(canvas, faces, topControlPane);
        setControlPanel(new InteractiveMaskPanel(this));
        InteractiveMaskPanel pl = new InteractiveMaskPanel(this);
        setControlPanel(pl);

        setShowHideCode(
                () -> { // SHOW
                    getCanvas().getScene().showInteractiveMask(getCanvas().getScene().getPrimaryFaceSlot(), true);
@@ -40,17 +44,30 @@ public class InteractiveMaskAction extends ControlPanelAction<InteractiveMaskPan
                    getCanvas().getScene().showInteractiveMask(getCanvas().getScene().getSecondaryFaceSlot(), false);
                }
        );
        getPrimaryDrawableFace().getHumanFace().registerListener(this);
        if (getSecondaryDrawableFace() != null) {
            getSecondaryDrawableFace().getHumanFace().registerListener(this);
    }

    private void project() {
        FaceStateServices.updateOctree(getPrimaryFace(), FaceStateServices.Mode.COMPUTE_IF_ABSENT);
        SurfaceMask2D mask = getControlPanel().getSurfaceMask();
        MaskProjectorConfig config = new MaskProjectorConfig(getCanvas().getWidth(),
                getCanvas().getHeight(), getControlPanel().getSurfaceMaskPanel1().getPanelWidth(),
                getControlPanel().getSurfaceMaskPanel1().getPanelHeight(),Camera.FIELD_OF_VIEW,
                getCanvas().getCamera().getPosition(), getCanvas().getCamera().getCenter(),
                getCanvas().getCamera().getUpDirection());
        MaskProjector mp = new MaskProjector(config, mask);
        getPrimaryFace().getOctree().accept(mp);
        getScene().setDrawableInteractiveMask(getScene().getPrimaryFaceSlot(), mp.getResult());
        renderScene();
    }


    @Override
    public void actionPerformed(ActionEvent ae) {
        String action = ae.getActionCommand();
        
        switch (action) {
            case InteractiveMaskPanel.ACTION_PROJECT:
                project();
                break;
            case InteractiveMaskPanel.ACTION_DRAW:
                mode = InteractiveMaskPanel.ACTION_DRAW;
                break;
@@ -62,29 +79,4 @@ public class InteractiveMaskAction extends ControlPanelAction<InteractiveMaskPan
        }
    }

    @Override
    public void acceptEvent(HumanFaceEvent event) {
        if (event instanceof HumanFaceSelectedEvent huEvent) {
            if (huEvent.getFace().equals(getPrimaryFace())
                    && getPrimaryInteractiveMask() == null) {
                getScene().setDrawableInteractiveMask(getScene().getPrimaryFaceSlot(), 
                        huEvent.getFace());
            } 
            if(huEvent.getFace().equals(getSecondaryFace()) && 
                    getSecondaryInteractiveMask() == null) {
                getScene().setDrawableInteractiveMask(getScene().getSecondaryFaceSlot(), 
                        huEvent.getFace());
            }
            
            RayIntersection closestIntersection = huEvent.getIntersection();
            if (mode.equals(InteractiveMaskPanel.ACTION_DRAW) && closestIntersection != null && huEvent.getFace().getSurfaceMask() != null) {
                huEvent.getFace().getSurfaceMask().addPoint(
                        huEvent.getIntersection().getPosition(),
                        huEvent.getIntersection().getHitTriangle().getFacet()
                );
            }
            renderScene();
       }
    }
    
}
Loading