package sc;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import sc.math.BezierCurve;
import sc.math.Spline2D;
/**
* C-1 continuous Bezier spline
* Stephen Carmody
* J2SE 5
*/
public final class beziercurves extends JFrame implements MouseListener,
MouseMotionListener {
private static final long serialVersionUID = 1L;
private static Spline2D spline;
private static int selected;
private static boolean mousePressed;
private static boolean mouseDragged;
private static Point mouse;
private static Point delta;
/** Constructs an instance of beziercurves */
public beziercurves(int width, int height) {
setSize(width, height);
setTitle("Bezier Curves");
setResizable(false);
addMouseListener(this);
addMouseMotionListener(this);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setVisible(true);
spline = new Spline2D(new BezierCurve());
selected = -1;
mouse = new Point();
delta = new Point();
// start with one randomly generated curve
for (int i = 0; i < 2; i++) {
int x = 40 + (int) (Math.random() * (width - 80));
int y = 40 + (int) (Math.random() * (height - 80));
spline.points.add(new Point(x, y));
spline.points.add(new Point(x + (int) (Math.random() * 40) - 20, y
+ (int) (Math.random() * 40) - 20));
}
spline.updateIntervals();
}
/** Adjust positions of points to be collinear */
private static void forceCollinear(int i) {
Point pi, pj, pk;
// i is a shared end point
if (i % 3 == 0 && i < spline.points.size() - 1 && i > 0) {
// adjust neighbouring control points by deltas
pi = spline.points.get(i - 1);
pi.x += delta.x;
pi.y += delta.y;
pi = spline.points.get(i + 1);
pi.x += delta.x;
pi.y += delta.y;
}
// i is a control point following a shared end
else if (i % 3 == 1 && i > 1) {
pi = spline.points.get(i);
pj = spline.points.get(i - 1);
pk = spline.points.get(i - 2);
forceCollinear(pi, pj, pk);
}
// i is a control point preceeding a shared end
else if (i % 3 == 2 && i < spline.points.size() - 2) {
pi = spline.points.get(i);
pj = spline.points.get(i + 1);
pk = spline.points.get(i + 2);
forceCollinear(pi, pj, pk);
}
}
/** Moves control point k such that it is collinear with i and j */
private static void forceCollinear(Point i, Point j, Point k) {
float ij = distance(i, j);
float jk = distance(j, k);
float r = jk / ij;
k.x = Math.round(j.x + r * (j.x - i.x));
k.y = Math.round(j.y + r * (j.y - i.y));
}
/** Calculates distance between control points i and j */
private static float distance(Point i, Point j) {
int ixjx = i.x - j.x;
int iyjy = i.y - j.y;
return (float) Math.sqrt(ixjx * ixjx + iyjy * iyjy);
}
/** Listens for mouse button pressed events */
public void mousePressed(MouseEvent e) {
mousePressed = true;
}
/** Listens for mouse button released events */
public void mouseReleased(MouseEvent e) {
mousePressed = false;
selected = -1;
}
/** Listens for mouse move events */
public void mouseMoved(MouseEvent e) {
mouse.x = e.getX();
mouse.y = e.getY();
}
/** Listens for mouse drag events */
public void mouseDragged(MouseEvent e) {
mouseDragged = true;
mouse.x = e.getX();
mouse.y = e.getY();
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public static void main(String[] args) {
beziercurves b = new beziercurves(640, 480);
// framerate info buffer
long[] framerate = new long[4];
// create a double-buffering buffer stragey
b.createBufferStrategy(2);
BufferStrategy s = b.getBufferStrategy();
Graphics2D g;
while (b.isVisible()) {
// get the off screen graphics context and clear it
g = (Graphics2D) s.getDrawGraphics();
g.setColor(new Color(0xffffff));
g.fillRect(0, 0, b.getWidth(), b.getHeight());
g.setColor(new Color(0x000000));
// draw the spline
Point prev = null;
for (Point next : spline.intervals) {
if (prev != null)
g.drawLine(prev.x, prev.y, next.x, next.y);
prev = next;
}
int i = 0;
for (Point p : spline.points) {
g.drawString(i + "", p.x, p.y);
if (mousePressed) {
int x = mouse.x - p.x;
int y = mouse.y - p.y;
if (x >= 0 && x <= 9 && y <= 0 && y >= -9)
selected = i;
}
i++;
}
// When mouse has been dragged and a point is selected
if (mouseDragged && selected != -1) {
Point p = spline.points.get(selected);
delta.x = mouse.x - p.x;
delta.y = mouse.y - p.y;
p.x = mouse.x;
p.y = mouse.y;
forceCollinear(selected);
spline.updateIntervals();
}
// Else when mouse pressed over unoccupied space
else if (mousePressed && selected == -1) {
spline.points.add(new Point(mouse.x, mouse.y));
forceCollinear(spline.points.size() - 1);
spline.updateIntervals();
}
// calculate and draw the framerate
framerate[1]++;
framerate[3] = System.currentTimeMillis();
if ((framerate[3] - framerate[2]) > 1000) {
framerate[0] = framerate[1];
framerate[1] = 0;
framerate[2] = framerate[3];
}
g.drawString(framerate[0] + " fps", 10, 40);
// swap the buffers
s.show();
}
}
}