// // $Id: BezierCanvas.java,v 1.5 1997/03/03 20:28:02 min Exp min $ // package bezier; import java.awt.*; import java.lang.*; import vectors.*; import myutil.*; public class BezierCanvas extends Panel { private BezierPoint points[]; private static final int MAX_POINTS = 34; private int nr_points = 0; private int closest_point = -1; private static final int CLOSE_DISTANCE = 10; private Image offscreen = null; private int image_width = 0; private int image_height = 0; private boolean display_hull = false; private boolean display_hint = false; private boolean display_points = true; private Font my_font = new Font("Helvetica", Font.BOLD, 24); private Graphics off_g; public BezierCanvas() { points = new BezierPoint[MAX_POINTS]; for(int i=0; i < MAX_POINTS; i++) points[i] = new BezierPoint(); } // constructor public void toggle_hull() { display_hull = !display_hull; } // toggle_hull public void toggle_hint() { display_hint = !display_hint; } // toggle_hint public void clear() // removes all points { nr_points = 0; } // clear public void paint(Graphics g) { Dimension d = this.size(); if ((offscreen == null) || (d.width != image_width) || (d.height != image_height)) { if ((d.width < 1) || (d.height < 1)) return; offscreen = this.createImage(d.width, d.height); off_g = offscreen.getGraphics(); off_g.setFont(my_font); if (nr_points > 0) { double x_scale = (double) d.width / (double) image_width; double y_scale = (double) d.height / (double) image_height; for(int i=0; i= 4) { draw_curve(off_g, 0); // draw first section if (display_hull) draw_hull(off_g, 0); for(int i=3; (i+3) < nr_points; i += 3) { // draw remaining sections draw_curve(off_g, i); if (display_hull) draw_hull(off_g, i); } } Graphics my_g = this.getGraphics(); my_g.drawImage(offscreen, 0, 0, this); } // paint(Graphics g) public void paint() { paint(this.getGraphics()); } // paint() public boolean mouseDown(Event e, int x, int y) { find_closest(x, y); if ((e.modifiers & Event.ALT_MASK) != 0) { display_points = !display_points; paint(); return true; } if (e.metaDown()) { // right mouse button was clicked if (closest_point >= 0) { // delete closest point for(int i=closest_point+1; i < nr_points; i++) points[i-1].moveto(points[i].get_x(), points[i].get_y()); nr_points--; } } else { if (closest_point >= 0) points[closest_point].setstate(BezierPoint.MOVING); else { if (nr_points < MAX_POINTS) { points[nr_points].moveto(x, y); nr_points++; } } } paint(); return true; } // mouseDown public boolean mouseDrag(Event e, int x, int y) { if ((closest_point >= 0) && (locate(x, y) == this)) { points[closest_point].moveto(x, y); paint(); } return true; } // mouseDrag public boolean mouseUp(Event e, int x, int y) { if (closest_point >= 0) { points[closest_point].setstate(BezierPoint.SET); paint(); } return true; } // mouseUp private Color get_curve_colour(int index) { index /= 3; if ((index % 2) == 0) return new Color(255, 0, 0); else return new Color(0, 255, 0); } // get_curve_color private Color get_hull_colour(int index) { index /= 3; if ((index % 2) == 0) return Color.lightGray; else return new Color(200, 200, 0); } // get_hull_colour public void draw_curve(Graphics g, int start_index) { int x[] = new int[4]; int y[] = new int[4]; for(int i = start_index; i < (start_index + 4); i++) { x[i - start_index] = points[i].get_x(); y[i - start_index] = points[i].get_y(); } g.setColor(get_curve_colour(start_index)); double t; double old_x = x[0]; double old_y = y[0]; for(t=0.0; t <= 1.0; t += 0.05) // should do this recursively... { double f0 = (1-t)*(1-t)*(1-t); double f1 = 3*t*(1-t)*(1-t); double f2 = 3*t*t*(1-t); double f3 = t*t*t; double new_x = f0*x[0] + f1*x[1] + f2*x[2] + f3*x[3]; double new_y = f0*y[0] + f1*y[1] + f2*y[2] + f3*y[3]; g.drawLine((int) old_x, (int) old_y, (int) new_x, (int) new_y); old_x = new_x; old_y = new_y; } g.drawLine((int) old_x, (int) old_y, x[3], y[3]); if (display_hint) { int x_start = x[2]; int y_start = y[2]; int x_end = x[3] + x[3] - x[2]; int y_end = y[3] + y[3] - y[2]; g.setColor(Color.gray); g.drawLine(x_start, y_start, x_end, y_end); } } // draw_curve private void find_closest(int x, int y) { int closest_so_far = 10000; closest_point = -1; for(int i=0; i 0) { if (p[0].ccw(p[1],p[3]) > 0) { if (p[0].ccw(p[2],p[3]) > 0) { seq[1] = 1; seq[2] = 2; seq[3] = 3; } else { seq[1] = 1; seq[2] = 3; seq[3] = 2; } } else { seq[1] = 3; seq[2] = 1; seq[3] = 2; } } else if (p[0].ccw(p[1],p[3]) > 0) { seq[1] = 2; seq[2] = 1; seq[3] = 3; } else if (p[0].ccw(p[2],p[3]) > 0) { seq[1] = 2; seq[2] = 3; seq[3] = 1; } else { seq[1] = 3; seq[2] = 2; seq[3] = 1; } int remove_point = -1; for(int i=0; i<4; i++) { int next = (i+1) % 4; int second = (i+2) % 4; if (p[seq[i]].ccw(p[seq[next]], p[seq[second]]) < 0) { remove_point = next; break; } } // for, find possible point not on convex hull g.setColor(get_hull_colour(start_index)); // now draw hull, skipping the inside point if there is one for(int i=0; i<4; i++) { if (i == remove_point) i++; int x1 = points[start_index + seq[i]].get_x(); int y1 = points[start_index + seq[i]].get_y(); if (((i+1) % 4) == remove_point) i++; int x2 = points[start_index + seq[(i+1) % 4]].get_x(); int y2 = points[start_index + seq[(i+1) % 4]].get_y(); g.drawLine(x1, y1, x2, y2); } } // draw_hull } // BezierCanvas class