// file CatmullRom.java // Catmull-Rom Spline Demo. // by Harriet Fell // fell@ccs.neu.edu // August 2004 import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import javax.swing.*; import java.awt.image.*; import java.util.Random; public class CatmullRom extends JComponent implements MouseMotionListener, MouseListener, ActionListener { /* void GetPoints(RPoint P[20], int& numpoints); void GetPoint(RPoint &P, string name); int dotsize = 5; void Bezier(RPoint P, RPoint Q, RPoint R, RPoint S); double ArchSize(RPoint P, RPoint Q, RPoint R, RPoint S); bool InDrawWindow(Point T); bool InDrawWindow(RPoint T); double Distance(RPoint P, Point T); const maxPoints = 20; void MakeArch(RPoint Pts[], int numPoints, int p, RPoint& P, RPoint& Q, RPoint& R, RPoint& S); */ // Control Points Point2D.Double [] controlPoints; int numCP; // number of control points boolean getControlPoints; // Arch Points Point2D.Double P, Q, R, S; // dot size int dSize; // Mouse Points int mmX, mmY; // last mouse moved point coordinates int mdX, mdY; // last mouse dragged point coordinates // Current Attributes Color foreColor; // default color int lineWidth = 1; // default line width public CatmullRom(){ // Listen for mouse motion and clicks addMouseMotionListener(this); addMouseListener(this); // Set foreColor to black foreColor = new Color ( 0, 0, 0 ); // Set dot size dSize = 8; // Array to hold user input control points; controlPoints = new Point2D.Double[20]; numCP = 0; getControlPoints = true; } Bez MakeArch(Point2D.Double [] controlPoints, int numCP, int p){ Point2D.Double P = new Point2D.Double(controlPoints[p].x, controlPoints[p].y); Point2D.Double S = new Point2D.Double(controlPoints[p+1].x, controlPoints[p+1].y); Point2D.Double Q = new Point2D.Double(); Point2D.Double R = new Point2D.Double(); if (p == 0) Q = P; else { Q.x = controlPoints[p].x + (-controlPoints[p-1].x + controlPoints[p+1].x)/6; Q.y = controlPoints[p].y + (-controlPoints[p-1].y + controlPoints[p+1].y)/6; } if (p == numCP -2) R = S; else { R.x = controlPoints[p + 1].x - (-controlPoints[p].x + controlPoints[p+2].x)/6; R.y = controlPoints[p + 1].y - (-controlPoints[p].y + controlPoints[p+2].y)/6; } return (new Bez(P, Q, R, S)); } public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D)g; // These are not currently used but might be useful. int wd = getSize().width; int ht = getSize().height; //Show Arch with dashed lines in blue // Show curve in black for (int cp = 0; cp < numCP-1; cp++) { g2.setPaint(Color.black); g2.setStroke(new BasicStroke(2)); Bez B = MakeArch(controlPoints, numCP, cp); B.draw(g2); g2.setPaint(Color.blue); float[] dashPattern = {10, 5}; g2.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10, dashPattern, 0)); g2.drawLine((int)B.P.getX(),(int)B.P.getY(),(int)B.Q.getX(),(int)B.Q.getY()); g2.drawLine((int)B.Q.getX(),(int)B.Q.getY(),(int)B.R.getX(),(int)B.R.getY()); g2.drawLine((int)B.R.getX(),(int)B.R.getY(),(int)B.S.getX(),(int)B.S.getY()); g2.setPaint(Color.red); g2.fillOval((int)B.Q.getX()-dSize/2, (int)B.Q.getY()-dSize/2, dSize, dSize); g2.fillOval((int)B.R.getX()-dSize/2, (int)B.R.getY()-dSize/2, dSize, dSize); } // Show Control Points g2.setPaint(Color.blue); for (int cp = 0; cp < numCP; cp++) { P = controlPoints[cp]; g2.fillOval((int)P.getX()-dSize, (int)P.getY()-dSize, 2*dSize, 2*dSize); } } private boolean close(int x, int y, Point2D p){ return ((x-p.getX())*(x-p.getX()) + (y-p.getY())*(y-p.getY()) <= dSize*dSize); } public void mouseDragged(MouseEvent e) { mdX = e.getX(); mdY = e.getY(); for (int cp = 0; cp < numCP; cp++) { //System.out.println(mmX + " " + mmY + " " + controlPoints[cp].toString()); if (close(mmX, mmY, controlPoints[cp])) { controlPoints[cp].setLocation(mdX, mdY); mmX = mdX; mmY = mdY; repaint(); break; } } } public void mouseMoved(MouseEvent e) { mmX = e.getX(); mmY = e.getY(); } public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseClicked(MouseEvent e) { // System.out.println("clicked"); int x, y; x = e.getX(); y = e.getY(); // System.out.println(numCP + " " + getControlPoints); if (getControlPoints && numCP < 20){ controlPoints[numCP] = new Point2D.Double(x,y); numCP++; System.out.println(numCP + " " + controlPoints[numCP-1].toString()); } repaint(); } public void actionPerformed(ActionEvent e) { } public static void main(String[] args){ JFrame f = new JFrame("CatmullRom Spline - click to place points - move blue points"); Container c = f.getContentPane(); c.setLayout(new BorderLayout()); c.add(new CatmullRom(), BorderLayout.CENTER); f.setSize(600, 622); f.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e) { System.exit(0); } }); f.setVisible(true); } }