2007-12-03

Java2D Curves Control Point

大家刚接触Java图形编程的可能对 二次曲线、贝尔曲线 的几个控制点有点迷惑,我下面有段示例方便大家理解这两个曲线的几个控制点的作用:
package test.draw;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.GeneralPath;

import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * 方便理解Quadratic/Bezier曲线的几个控制点作用
 *
 * @author h_Davy [dave3068 AT gmail DOT com]
 * @version 2007-11-27 上午01:41:23
 */
public class CurvesTest extends JPanel
        implements MouseListener, MouseMotionListener, FocusListener {

    private static final long serialVersionUID = 1L;

    public CurvesTest() {
        super(true);
        init();
    }
    private void init() {
        setBackground(Color.white);
        setFocusable(true);
        addFocusListener(this);
        addMouseListener(this);
        addMouseMotionListener(this);
    }



    // 二次曲线
    private QuadCurve q = new QuadCurve(new Point(50, 100),
                new Point(200, 150), new Point(300, 100));
    // 贝尔曲线
    private BezierCurve b = new BezierCurve(
            new Point(100, 300), new Point(200, 400),
            new Point(300, 200), new Point(400, 300));


    public void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D)g;
        g2.setRenderingHint(
                RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setStroke(new BasicStroke(2.f));

        // draw background
        g2.setColor(getBackground());
        g2.fillRect(0, 0, getWidth(), getHeight());
        g2.setColor(Color.blue);
        g2.drawRect(5, 5, getWidth()-10, getHeight()-10);

        // draw curves
        g2.draw(q.getPath());
        g2.draw(b.getPath());
        // fill path area
        g2.setColor(Color.lightGray);
        g2.fill(q.getPath());
        g2.fill(b.getPath());

        // paint drag handles
        g2.setColor(Color.orange);
        DragHandle []dhs = q.getDragHandles();
        for (int i = 0; i<dhs.length; i++)
            g2.fill(dhs[i]);
        dhs = b.getDragHandles();
        for (int i = 0; i<dhs.length; i++)
            g2.fill(dhs[i]);

    }

    private boolean isDrag = false; // 是否在拖动控制点
    private DragHandle curDrag = null; // 当前拖动中的控制点



    public void mousePressed(MouseEvent e) {
        // find out is mousePoint in any DragHandle
        DragHandle dh = q.findDragHandle(e.getPoint());
        if (dh != null) {
            curDrag = dh;
            isDrag = true;
            return;
        }
        dh = b.findDragHandle(e.getPoint());
        if (dh != null) {
            curDrag = dh;
            isDrag = true;
            return;
        }
    }
    public void mouseReleased(MouseEvent e) {
        isDrag = false;
    }
    public void mouseDragged(MouseEvent e) {
        if (isDrag) {
            curDrag.setPoint(e.getPoint());
            q.refresh();
            b.refresh();
            repaint();
        }
    }
    public void focusLost(FocusEvent e) {
        isDrag = false;
    }



    // 控制点区域
    @SuppressWarnings("serial")
    private class DragHandle extends Rectangle {
        private Point pt = new Point();

        DragHandle() {
            width = 5;
            height = 5;
        }
        DragHandle(Point p) {
            this();
            pt.x = p.x;
            pt.y = p.y;
            calcRect();
        }

        private void calcRect() {
            x = pt.x - 2;
            y = pt.y - 2;
        }
        public void setPoint(Point p) {
            pt.x = p.x;
            pt.y = p.y;
            calcRect();
        }
        public Point getPoint() {
            return pt;
        }
    }




    // Quadratic 曲线
    private class QuadCurve {
        // 曲线路径
        protected GeneralPath gp = new GeneralPath();
        // 曲线的几个控制点
        protected DragHandle []pt = null;

        protected QuadCurve () {}
        QuadCurve(Point p1, Point p2, Point p3) {
            pt = new DragHandle[3];
            pt[0] = new DragHandle(p1);
            pt[1] = new DragHandle(p2);
            pt[2] = new DragHandle(p3);
            refresh();
        }

        // 更新曲线
        public void refresh() {
            gp.reset();
            gp.moveTo((float) pt[0].getX(), (float) pt[0].getY());
            gp.quadTo((float) pt[1].getX(), (float) pt[1].getY(),
                    (float) pt[2].getX(), (float) pt[2].getY());
        }

        // 指定点是否在控制点区域内
        public DragHandle findDragHandle(Point p) {
            for (int i = 0; i<pt.length; i++)
                if (pt[i].contains(p)) return pt[i];
            return null;
        }
        // 获得所有控制点
        public DragHandle[] getDragHandles() {
            return pt;
        }
        // 获得该曲线的Path
        public GeneralPath getPath() {
            return gp;
        }
    }
    // Bezier 曲线
    private class BezierCurve extends QuadCurve {

        protected BezierCurve(Point p1, Point p2, Point p3) {}
        BezierCurve (Point p1, Point p2, Point p3, Point p4) {
            pt = new DragHandle[4];
            pt[0] = new DragHandle(p1);
            pt[1] = new DragHandle(p2);
            pt[2] = new DragHandle(p3);
            pt[3] = new DragHandle(p4);
            refresh();
        }

        public void refresh() {
            gp.reset();
            gp.moveTo((float) pt[0].getX(), (float) pt[0].getY());
            gp.curveTo((float) pt[1].getX(), (float) pt[1].getY(),
                    (float) pt[2].getX(), (float) pt[2].getY(),
                    (float) pt[3].getX(), (float) pt[3].getY());
        }
    }





    public void mouseClicked(MouseEvent e) {
    }
    public void mouseEntered(MouseEvent e) {
    }
    public void mouseExited(MouseEvent e) {
    }
    public void mouseMoved(MouseEvent e) {
    }
    public void focusGained(FocusEvent e) {
    }


    /**
     * @param args
     */
    public static void main(String[] args) {
        JFrame f = new JFrame("拖动几个橙色的小点看看 ^_^");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(640, 480);
        f.setLocationRelativeTo(null);
        f.add(new CurvesTest());
        f.setVisible(true);
    }

}

//EOF

0 comments: