import java.awt.*; import java.applet.*; import java.util.Vector; public class FourierDescrip extends Applet { public void init() { setLayout(new BorderLayout()); DrawPanel dp = new DrawPanel(); add("Center", dp); add("South", new DrawControls(dp)); } public boolean handleEvent(Event e) { switch (e.id) { case Event.WINDOW_DESTROY: System.exit(0); return true; default: return false; } } public static void main(String args[]) { Frame f = new Frame("DrawTest"); FourierDescrip fourierDescrip = new FourierDescrip(); fourierDescrip.init(); fourierDescrip.start(); f.add("Center", fourierDescrip); f.resize(300, 300); f.show(); } } class Point { public Point() { setP(0, 0); } public Point(int x_coor, int y_coor) { setP(x_coor, y_coor); } public Point(Point pt) { setP(pt.getX(), pt.getY()); } public int getX() { return x; } public int getY() { return y; } public void setP(int x_coor, int y_coor) { x = x_coor; y = y_coor; } private int x; private int y; } class Line { public Line(Point p1, Point p2) { point1 = new Point(p1); point2 = new Point(p2); } public Point getP1() { return point1; } public Point getP2() { return point2; } public void setL(Point p1, Point p2) { point1.setP(p1.getX(), p1.getY()); point2.setP(p2.getX(), p2.getY()); } public void drawL(Graphics g, Color color, Panel panel) { g.drawLine(point1.getX(), point1.getY(), point2.getX(), point2.getY()); panel.setForeground(color); g.setColor(panel.getForeground()); } private Point point1; private Point point2; } class Circle { public Circle(Point p, int r) { centre = new Point(p); ray = r; } public void drawC(Graphics g, Color color, Panel panel) { g.drawArc(centre.getX()-ray, centre.getY()-ray, 2*ray, 2*ray, 0, 360); panel.setForeground(color); g.setColor(panel.getForeground()); } private Point centre; private int ray; } class Compute { private int nbr_pts; private Vector points = new Vector(); private double Bk[]; private double Lk[]; private double L = 0; private int numFD; private int dl; public Compute(Vector pts, int nFD, int inc) { if (pts == null) System.exit(1); numFD = nFD; dl = inc; copyVector(pts); cleanVector(); computeUnitVectors(); computeLength(); computeCumDiff(); } private void copyVector(Vector pts) { nbr_pts = pts.size(); for (int i=0; i < nbr_pts; i++) points.addElement((Point)pts.elementAt(i)); } public void cleanVector() { /* remove potential double vertices */ for (int i=0; i < nbr_pts - 1; i++) { Point pt1 = (Point)points.elementAt(i); Point pt2 = (Point)points.elementAt(i+1); if ((pt1.getX() == pt2.getX()) && (pt1.getY() == pt2.getY())) points.removeElementAt(i + 1); } /* close curve */ Point pt0 = (Point)points.elementAt(0); points.addElement(new Point(pt0)); nbr_pts = points.size(); } /* compute sequence of unit vector */ private void computeUnitVectors() { Bk = new double[nbr_pts*2]; int xd, yd; for (int i=0; i < nbr_pts - 1; i++) { Point pt1 = (Point)points.elementAt(i); Point pt2 = (Point)points.elementAt(i+1); xd = pt2.getX() - pt1.getX(); yd = pt2.getY() - pt1.getY(); Bk[i] = xd / Math.sqrt(xd*xd + yd*yd); Bk[i + nbr_pts] = yd / Math.sqrt(xd*xd + yd*yd); } Bk[nbr_pts - 1] = Bk[0]; Bk[nbr_pts*2 - 1] = Bk[nbr_pts]; } /* compute total length of the curve */ private void computeLength() { int xd, yd; for (int i=0; i < nbr_pts - 1; i++) { Point pt1 = (Point)points.elementAt(i); Point pt2 = (Point)points.elementAt(i+1); xd = pt2.getX() - pt1.getX(); yd = pt2.getY() - pt1.getY(); L += Math.sqrt(xd*xd + yd*yd); } } /* compute sequence of cumulative differences */ private void computeCumDiff() { int xd, yd; Lk = new double[nbr_pts]; for (int i = 0; i < nbr_pts; i++) Lk[i] = 0; for (int i = 1; i < nbr_pts; i++) for (int j = 1; j <= i; j++) { Point pt1 = (Point)points.elementAt(j-1); Point pt2 = (Point)points.elementAt(j); xd = pt2.getX() - pt1.getX(); yd = pt2.getY() - pt1.getY(); Lk[i] += Math.sqrt(xd*xd + yd*yd); } Lk[0] = 0; } /* compute approximation */ public Vector computeApp() { double[] Xl = new double[(int)Math.round(L)]; double[] Yl = new double[(int)Math.round(L)]; double coefn; double sinnk, cosnk; double pi = 3.1416; double dBkx, dBky; for (int l = 0; l < (int)Math.round(L); l+=dl) { Xl[l] = 0; Yl[l] = 0; } for (int l = 0; l < (int)Math.round(L); l+=dl) for(int n = -(int)numFD/2; n <= (int)numFD/2; n++) { if (n != 0) { coefn = 1/(L*(n*2*pi/L)*(n*2*pi/L)); for (int k = 0; k < nbr_pts; k++) { if (k == 0) { dBkx = Bk[nbr_pts - 1] - Bk[0]; dBky = Bk[2*nbr_pts - 1] - Bk[nbr_pts]; } else { dBkx = Bk[k-1] - Bk[k]; dBky = Bk[(k-1)+nbr_pts] - Bk[k+nbr_pts]; } sinnk = Math.sin(n*2*pi*(l-Lk[k])/L); cosnk = Math.cos(n*2*pi*(l-Lk[k])/L); Xl[l] += (dBkx*cosnk-dBky*sinnk)*coefn; Yl[l] += (dBkx*sinnk+dBky*cosnk)*coefn; } } else { double XA = 0; double YA = 0; for (int i=0; i < nbr_pts - 1; i++) { Point pt = (Point)points.elementAt(i); XA += pt.getX(); YA += pt.getY(); } XA /= nbr_pts - 1; YA /= nbr_pts - 1; Xl[l] += XA; Yl[l] += YA; } } Vector app_pts = new Vector(); for (int l = 0; l < (int)Math.round(L); l+=dl) app_pts.addElement(new Point((int)Math.round(Xl[l]), (int)Math.round(Yl[l]))); return app_pts; } } class DrawPanel extends Panel { Vector drawing_app = new Vector(); Vector drawing = new Vector(); Vector points = new Vector(); private Point point1 = new Point(); private Point point2 = new Point(); private boolean poly_start = true; private boolean mouse_move = false; private boolean is_drawing = true; private boolean is_appro = false; int num_FD = 40; int inc = 4; public DrawPanel() { setBackground(Color.white); setForeground(Color.black); } public boolean handleEvent(Event evt) { if (evt.id == Event.WINDOW_DESTROY) System.exit(0); return super.handleEvent(evt); } public boolean mouseDown(Event evt, int x, int y) { if (is_drawing) { if (poly_start) { point1.setP(x, y); points.addElement(new Point(point1)); drawing.addElement(new Circle(point1, 2)); point2.setP(x, y); mouse_move = true; repaint(); poly_start = false; /* trace */ System.out.println("poly_start = false"); } else { points.addElement(new Point(point2)); drawing.addElement(new Line(point1, point2)); drawing.addElement(new Circle(point2, 2)); point1.setP(point2.getX(), point2.getY()); repaint(); } if (evt.clickCount >= 2){ int nbr_pts = points.size(); if (nbr_pts >= 4) { Point pt1 = (Point)points.elementAt(0); Point pt2 = (Point)points.elementAt(nbr_pts - 1); drawing.addElement(new Line(pt1, pt2)); mouse_move = false; repaint(); is_drawing = false; poly_start = true; /* trace */ System.out.println("evt.clickCount >= 2 && nbr_pts >= 3"); } } return true; } else return false; } public boolean mouseMove(Event evt, int x, int y) { if (is_drawing && mouse_move) { point2.setP(x, y); repaint(); return true; } else return false; } public void paint(Graphics g) { g.setPaintMode(); /* draw original polygon */ int nbr_elem = drawing.size(); if (nbr_elem >= 1) for (int i=0; i < nbr_elem; i++) { Object obj = drawing.elementAt(i); if (obj instanceof Circle) { Circle circle = (Circle)drawing.elementAt(i); circle.drawC(g, Color.blue, this); } else if (obj instanceof Line) { Line line = (Line)drawing.elementAt(i); line.drawL(g, Color.cyan, this); } } /* draw undecided line */ if (mouse_move) { Line temp_line = new Line(point1, point2); temp_line.drawL(g, Color.cyan, this); } /* put approximation in vector */ if (is_appro) { /* trace */ System.out.println("Approximating"); Compute approximate = new Compute(points, num_FD, inc); Vector app_pts = new Vector(); app_pts = approximate.computeApp(); int nbr_pts = app_pts.size(); /* trace */ System.out.println("Num of approximating points = " + nbr_pts); for (int i=0; i < nbr_pts-1; i++) { Point pt1 = (Point)app_pts.elementAt(i); Point pt2 = (Point)app_pts.elementAt(i+1); drawing_app.addElement(new Circle(pt1, 2)); drawing_app.addElement(new Line(pt1, pt2)); } is_appro = false; } /* draw approximation */ int nbr_pts = drawing_app.size(); if (nbr_pts >= 1) for (int i=0; i < nbr_pts; i++) { Object obj = drawing_app.elementAt(i); if (obj instanceof Circle) { Circle circle = (Circle)drawing_app.elementAt(i); circle.drawC(g, Color.red, this); } else if (obj instanceof Line) { Line line = (Line)drawing_app.elementAt(i); line.drawL(g, Color.pink, this); } } } public void clear() { points.removeAllElements(); drawing.removeAllElements(); drawing_app.removeAllElements(); is_appro = false; repaint(); is_drawing = true; poly_start = true; } public void approximate() { drawing_app.removeAllElements(); /* trace */ System.out.println("call approximate function"); if (!is_drawing) { is_appro = true; repaint(); } } } class DrawControls extends Panel { private DrawPanel target; private TextField disp_numFD; private TextField disp_inc; public DrawControls(DrawPanel target) { this.target = target; setLayout(new FlowLayout()); setBackground(Color.lightGray); Button clear = new Button("clear"); add(clear); Button approximate = new Button("approximate"); add(approximate); Button setFD = new Button("set num of FD"); add(setFD); disp_numFD = new TextField("40",3); disp_numFD.setEditable(true); add(disp_numFD); Button setInc = new Button("set increment"); add(setInc); disp_inc = new TextField("4",2); disp_inc.setEditable(true); add(disp_inc); repaint(); } public void paint(Graphics g) { Rectangle r = bounds(); g.setColor(Color.lightGray); g.draw3DRect(0, 0, r.width, r.height, false); } public boolean action(Event e, Object arg) { switch (e.id) { case Event.ACTION_EVENT: if (e.target instanceof Button) { String choice = (String)arg; if (choice.equals("approximate")) { /* trace */ System.out.println("Approximating button"); target.approximate(); } else if (choice.equals("clear")) { target.clear(); } else if (choice.equals("set num of FD")) { int FD_temp = Integer.parseInt(disp_numFD.getText().trim()); if (FD_temp > 0) target.num_FD = FD_temp; } else if (choice.equals("set increment")) { int inc_temp = Integer.parseInt(disp_inc.getText().trim()); if (inc_temp > 0) target.inc = inc_temp; } } return true; default: return false; } } }