ベジエ曲線

以下のプログラムは2次ベジェ曲線を書きます.

PicturePanel.java
package beziercurve;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;

public class PicturePanel extends JPanel implements Runnable {
    Thread refresh = null;
    List<Ball> ball;
    List<Ball> p;
    Ball bezierBall;
    List<Point> locusPoint;
    double[] vx, vy;
    double d;   // 線分の分割数
    double t;   // 時刻
    
    public PicturePanel() {
        
        if( refresh == null ) {
            refresh = new Thread(this);
            refresh.start();
        }
        
        t = 0;
        d = 200;
        
        p = new ArrayList<Ball>();
        p.add(new Ball(new Point(100, 350), 10, 0, 0, Color.black));
        p.add(new Ball(new Point(300, 80), 10, 0, 0, Color.black));
        p.add(new Ball(new Point(500, 400), 10, 0, 0, Color.black));
        
        vx = new double[p.size() - 1];
        vy = new double[p.size() - 1];
        for( int i = 0; i < p.size() - 1; i++ ) {
            vx[i] = (p.get(i + 1).getCenterPoint().x - p.get(i).getCenterPoint().x) / d;
            vy[i] = (p.get(i + 1).getCenterPoint().y - p.get(i).getCenterPoint().y) / d;
        }
        
        ball = new ArrayList<Ball>();
        for( int i = 0; i < p.size() - 1; i++ ) {
            ball.add(new Ball(p.get(i).getCenterPoint(), 15, vx[i], vy[i], Color.CYAN));
        }
        
        bezierBall = new Ball(p.get(0).getCenterPoint(), 2, vx[0], vy[0], Color.BLACK);
        
        locusPoint = new ArrayList<Point>();
    }
    
    @Override
    public void paintComponent(Graphics g) {
        double vx, vy;
        
        super.paintComponent(g);
        
        // 線分の描画
        for( int i = 0; i < p.size() - 1; i++ ) {
            g.setColor(Color.BLACK);
            g.drawLine(p.get(i).getCenterPoint().x, p.get(i).getCenterPoint().y, 
                     p.get(i + 1).getCenterPoint().x, p.get(i + 1).getCenterPoint().y);
        }
        for( int i = 0; i < p.size() - 2; i++ ) {
            g.setColor(Color.red);
            g.drawLine(ball.get(i).getCenterPoint().x, ball.get(i).getCenterPoint().y, 
                    ball.get(i + 1).getCenterPoint().x, ball.get(i + 1).getCenterPoint().y);
        }
        
        // 始点・終点の描画
        for( Ball elemBall : p ) {
            g.setColor(elemBall.getColor());
            g.fillOval(elemBall.getRectangle().x, elemBall.getRectangle().y, 
                    elemBall.getRectangle().width, elemBall.getRectangle().height);
        }
        
        // 線分上を動く円の描画
        for( int i = 0; i < p.size() - 1; i++ ) {
            g.setColor(ball.get(i).getColor());
            g.fillOval(ball.get(i).getPoint().x, ball.get(i).getPoint().y, 
                    ball.get(i).getRectangle().width, ball.get(i).getRectangle().height);
            
            ball.get(i).Move(p.get(i), t);
        }
        
        vx = (ball.get(1).getCenterPoint().x - ball.get(0).getCenterPoint().x) / d;
        vy = (ball.get(1).getCenterPoint().y - ball.get(0).getCenterPoint().y) / d;        
        bezierBall.setV(vx, vy);
        bezierBall.Move(ball.get(0), t);
        
        g.setColor(bezierBall.getColor());
        g.fillOval(bezierBall.getPoint().x, bezierBall.getPoint().y, 
                bezierBall.getRectangle().width, bezierBall.getRectangle().height);

        g.setColor(bezierBall.getColor());
        for( Point p : locusPoint ) {
            g.fillOval(p.x, p.y, bezierBall.getRectangle().width, bezierBall.getRectangle().height);
        }

        if( t > d ) {
            t = 0;
            locusPoint.clear();
        } else {
            t += 1.0;
            locusPoint.add(bezierBall.getPoint());
        }
    }

    @Override
    public void run() {
        
        while( true ) {
            repaint();
            try {
                if( t > d ) {
                    Thread.sleep(300);
                } else {
                    Thread.sleep(10);
                }
            } catch (Exception e) {
            }
        }
    }
}
Ball.java
package beziercurve;

import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;

public class Ball {
    private Point point;
    private int r;
    private Rectangle rectangle;
    private double vx, vy;
    private Color color;
    
    public Ball(Point point, int r, double vx, double vy, Color color) {
        
        this.point = new Point(point.x - r, point.y - r);
        this.r = r;
        this.rectangle = new Rectangle(this.point.x, this.point.y, 2 * r, 2 * r);
        this.vx = vx;
        this.vy = vy;
        this.color = color;
    }
    
    public Point getPoint() {
        return new Point(point);
    }
    
    public Point getCenterPoint() {
        return new Point(point.x + r, point.y + r);
    }
    
    public Rectangle getRectangle() {
        return rectangle;
    }
    
    public Color getColor() {
        return color;
    }
    
    public void setV(double vx, double vy) {
        
        this.vx = vx;
        this.vy = vy;
    }
    
    public void Move(Ball p1, double t) {

        this.point.x = p1.getCenterPoint().x - r + (int)(vx * t);
        this.point.y = p1.getCenterPoint().y - r + (int)(vy * t);
    }
}
BezierCurve.java
package beziercurve;

import java.awt.Color;
import javax.swing.JFrame;

public class BezierCurve {

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setBounds(200, 200, 640, 480);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        PicturePanel panel = new PicturePanel();
        panel.setBackground(Color.white);
        frame.getContentPane().add(panel);
        frame.setVisible(true);
    }    
}