Drawing a curve in Java using mouse drag

我的梦境 提交于 2019-12-13 07:46:52

问题


I am new to java and I am trying to draw a curve. The functionality I am trying to implement is that the curves should be defined by a mouse drag followed by a mouse click. Once the drag action is done, I want a line to be drawn from the start of the drag to the end. Clicking on the canvas after that should be considered the third point necessary to define the curve and the line drawn should be changed into a curve.
How do I do that? I've gone through different posts here about how to draw Bezier curves but I am super confused. Here's a chunk of my code to draw rectangles, ovals and lines using mouse events:

   public void mousePressed(MouseEvent e) {

        xCoordinateInitial = e.getX(); //Initialize x-coordinate to the mouse x-coordinate
        yCoordinateInitial = e.getY() + shiftInY; //Initialize y-coordinate to the mouse y-coordinate
        System.out.println("X-coordinate: " + xCoordinateInitial);
        System.out.println("Y-coordinate: " + yCoordinateInitial);
    }

    public void mouseReleased(MouseEvent e) {

        Graphics2D G = (Graphics2D) getGraphics();
        G.setStroke(new BasicStroke(lineThickness));
        G.setColor(colorSelected);
        G.setPaint(colorSelected);
        xCoordinateFinal = e.getX(); //Set final x-coordinate to the mouse x-coordinate after drag
        yCoordinateFinal = e.getY() + shiftInY; //Set final y-coordinate to the mouse y-coordinate after drag
        int x = xCoordinateInitial;
        int y = yCoordinateInitial;
        int width = xCoordinateFinal - xCoordinateInitial; //Setting width
        int height = yCoordinateFinal - yCoordinateInitial; //Setting height



        if (yCoordinateFinal < yCoordinateInitial) {
            y = yCoordinateFinal;
            height = yCoordinateInitial - yCoordinateFinal;
        }

        if (xCoordinateFinal < xCoordinateInitial) {
            x = xCoordinateFinal;
            width = xCoordinateInitial - xCoordinateFinal;
        }


        // Shape Selection
        switch (shapeSelected) {
            case Line:

                G.drawLine(xCoordinateInitial, yCoordinateInitial, xCoordinateFinal, yCoordinateFinal);
                break;

            case Rectangle:
                G.fillRect(x, y, width, height);
                break;

            case Oval:
                G.fillOval(x, y, width, height);
                break;

            case Curve :

                // To implement

        }

    }
});

I tried to understand the following but I couldn't make it work:

                        Path2D p = new GeneralPath();
                        p.moveTo(x1, y1);
                        p.curveTo(bx1, by1, bx2, by2, x2, y2);
                        G.draw(p);

回答1:


Let's start by having a read through the JavaDocs for Path2D#curveTo

public final void curveTo(double x1,
double y1,
double x2,
double y2,
double x3,
double y3)

Adds a curved segment, defined by three new points, to the path by drawing a Bézier curve that intersects both the current coordinates and the specified coordinates (x3,y3), using the specified points (x1,y1) and (x2,y2) as Bézier control points. All coordinates are specified in double precision.

Okay, let's be fair, that takes a little bit of reading to understand, which is probably better addressed with some graphics.

The basic concept is, you have three control points, one of which is acting as a "look at" constraint.

Let's assume you have three points, anchor, target and click. anchor is the first point, target is the point dragged to and click is the point which was clicked AFTER the drag operation completed.

If we use the order anchor, target, click, we end up with a curve looking something like

where P1 == anchor, P2 == target and P3 == click. As you can see, the P2 is acting as the "look at constraint" and is trying to pull the resulting curve towards it.

However, if, instead, we use anchor, click, target, we end up within something more like...

where P1 == anchor, P2 == click and P3 == target. As you can see, the P2 is acting as the "look at constraint" and is trying to pull the resulting curve towards it.

This is essentially how a Bézier curve works

Example...

Okay, so to put it all together, I wrote some test code, which you can use to change the parameter and test the idea

One thing this example does is it paints a "fake" example of the intended curve as the mouse is moved, after the first two points are established, giving you some visual feed back of what the curve will look like, until the user clicks the mouse and the path is set

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private boolean dragging = false;

        private Point anchor;
        private Point target;

        private Shape fakePath;

        private List<Shape> shapes = new ArrayList<>(25);

        public TestPane() {
            addMouseMotionListener(new MouseAdapter() {
                @Override
                public void mouseDragged(MouseEvent e) {
                    dragging = true;
                    target = new Point(e.getPoint());
                    repaint();
                }

                @Override
                public void mouseMoved(MouseEvent e) {
                    if (target != null && anchor != null) {
                        fakePath = makePath(anchor, e.getPoint(), target);
                        repaint();
                    }
                }

            });

            addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    if (anchor == null) {
                        target = null;
                        anchor = new Point(e.getPoint());
                    }
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    dragging = false;
                }

                @Override
                public void mouseClicked(MouseEvent e) {
                    if (anchor != null && target != null) {
                        fakePath = null;

                        shapes.add(makePath(anchor, e.getPoint(), target));

                        anchor = null;
                        target = null;

                        repaint();
                    }
                }
            });
        }

        protected Path2D makePath(Point p1, Point p2, Point p3) {
            Path2D p = new GeneralPath();
            p.moveTo(p1.getX(), p1.getY());
            p.curveTo(p1.getX(), p1.getY(),
                            p2.getX(), p2.getY(),
                            p3.getX(), p3.getY());

            return p;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
            g2d.setColor(Color.BLACK);
            for (Shape shape : shapes) {
                g2d.draw(shape);
            }
            if (anchor != null && target != null) {
                g2d.setColor(Color.GREEN);
                g2d.draw(new Line2D.Double(anchor, target));
            }
            if (fakePath != null) {
                g2d.setColor(Color.BLUE);
                g2d.draw(fakePath);
            }
            g2d.dispose();
        }

    }

}


来源:https://stackoverflow.com/questions/48847352/drawing-a-curve-in-java-using-mouse-drag

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!