package myutil; import java.awt.*; import java.applet.*; import java.awt.image.*; import java.awt.FontMetrics.*; import java.awt.Font.*; import java.awt.geom.Point2D; import java.awt.event.MouseEvent; import java.awt.Point; /** * This class provides a 2D graphics environment in which * the coordinate system has the "normal" orientation, * namely, the all-positive quadrant lies in the upper * right-hand corner of the system; furthermore, the * coordinates are specified in (double) floating * point values. * This class follows the SINGLETON pattern. * * Author: Robert Vanderbei (extended by Hugo Simao) * */ public class GL { // the (external) graphics context static Graphics g = null; // the dimensions of the (external) graphics context static double width, height; // the boundaries of the original coordinate system // of the graphics context static double xmin, xmax, ymin, ymax; // the current (x, y) position of the drawing "pen" static double c_x, c_y; // the current filled polygon being drawn static Polygon c_fp; // the default Font to be used to draw strings static Font fnt; // the (x, y) position of the baseline of the leftmost // character of a string to be drawn static int strXpos, strYpos; // the 'hidden' graphics context in which images // are actually initially drawn (the backbuffer), // when in double buffering mode static Image bi; static Graphics bg; static Component c; /** Initializes the new graphics context */ static public synchronized void ginit(Graphics gg, int w, int h, Component cc) { ginit(gg, w, h, cc, true); } /** Initializes the new graphics context */ static public synchronized void ginit(Graphics gg, int w, int h, Component cc, boolean dblBuffer) { if (g != null) { System.out.print("Class GL has already been "); System.out.println("initialized!"); System.out.print("There cannot exist more than "); System.out.println("one GL context per application."); return; } // initialize the graphics context g = gg; c = cc; // setup the backbuffer, if in double buffering mode if (dblBuffer) { bi = c.createImage(w, h); bg = bi.getGraphics(); } else { bg = g; } // setup the boundaries of the graphics context width = w; height = h; xmin = 0; xmax = width; ymin = 0; ymax = height; c_x = 0; c_y = 0; c_fp = null; // setup the default Font fnt = new Font("Courier",Font.BOLD,12); bg.setFont(fnt); strXpos = 0; strYpos = 0; } /** Displays the image currently drawn in the 'hidden' graphics context */ static public synchronized void swapbuffers() { g.drawImage(bi,0,0,c); } /** Defines the boundaries of the internal orthogonal coordinate system */ static public synchronized void ortho2(double xmin1, double xmax1, double ymin1, double ymax1) { xmin = xmin1; xmax = xmax1; ymin = ymin1; ymax = ymax1; } /** Returns the boundaries of the internal coordinate system */ static public synchronized double getXmin() {return xmin;} static public synchronized double getXmax() {return xmax;} static public synchronized double getYmin() {return ymin;} static public synchronized double getYmax() {return ymax;} /** Returns the redefined x-coordinate value corresponding to the given original x-coordinate value */ static public synchronized double xi( int x) { return ( ((xmax-xmin)*x)/width + xmin); } /** Returns the redefined y-coordinate value corresponding to the given original y-coordinate value */ static public synchronized double yi( int y) { return ( ymax - ((ymax-ymin)*y)/height); } /** Returns the redefined delta-x value corresponding to the given original delta-x value */ static public synchronized double dltXi( int dltX) { return (((xmax-xmin)*dltX)/width); } /** Returns the redefined delta-y value corresponding to the given original delta-y value */ static public synchronized double dltYi( int dltY) { return (((ymax-ymin)*dltY)/height); } /** Returns the original x-coordinate value corresponding to the given redefined x-coordinate value */ static public synchronized int x( double x) { return (int)(( x - xmin )*(width/(xmax-xmin))); } /** Returns the original y-coordinate value corresponding to the given redefined y-coordinate value */ static public synchronized int y( double y) { return (int)(( ymax - y )*(height/(ymax-ymin))); } /** Returns the original delta-x value corresponding to the given redefined delta-x value */ static public synchronized int dltX( double dltX) { return (int)(dltX*(width/(xmax-xmin))); } /** Returns the original delta-y value corresponding to the given redefined delta-y value */ static public synchronized int dltY( double dltY) { return (int)(dltY*(height/(ymax-ymin))); } /** Resets the "current" color of the graphics context to the given one */ static public synchronized void setColor(Color c) { bg.setColor(c); } static public synchronized void color(Color c) { bg.setColor(c); } /** Repaints the whole area of the graphics context with the "current" color */ static public synchronized void clear() { int x1 = x(xmin), y1 = y(ymin); int x2 = x(xmax), y2 = y(ymax); Polygon fp = new Polygon(); fp.addPoint(x1, y1); fp.addPoint(x2, y1); fp.addPoint(x2, y2); fp.addPoint(x1, y2); bg.fillPolygon(fp); } /** Returns the (x, y) position where the given mouse event occurred */ static public synchronized Point2D.Double mouseLoc( MouseEvent event) { Point first = event.getPoint(); return new Point2D.Double(xi(first.x), yi(first.y)); } /** Draws a filled square with a 3-pixel side at the given (x, y) position */ static public synchronized void pnt2(double x, double y) { bg.fillRect(x(x)-1,y(y)-1,3,3); } /** Moves the drawing "pen" to the given (x, y) position */ static public synchronized void move2(double xx, double yy) { c_x = xx; c_y = yy; } /** Draws a line from the current "pen" position to the given (x, y) position; afterwards, the "pen" will rest at the new position */ static public synchronized void draw2(double xx, double yy) { bg.drawLine(x(c_x),y(c_y),x(xx),y(yy)); c_x = xx; c_y = yy; } /** Initializes the drawing of a filled polygon at the given (x, y) position */ static public synchronized void pmv2(double xx, double yy) { c_fp = new Polygon(); c_fp.addPoint(x(xx), y(yy)); } /** Adds the given (x, y) position as a vertex of the filled polygon being drawn */ static public synchronized void pdr2(double xx, double yy) { c_fp.addPoint(x(xx), y(yy)); } /** Finishes the filled polygon being drawn */ static public synchronized void pclos() { bg.fillPolygon(c_fp); c_fp = null; } /** Draws an unfilled rectangle with upper left hand corner at the given (x, y) position and the given width and height */ static public synchronized void drawRect(double x1, double y1, double width, double height) { bg.drawRect(x(x1),y(y1),dltX(width),dltY(height)); } /** Draws a filled rectangle with upper left hand corner at the given (x, y) position and the given width and height */ static public synchronized void fillRect(double x1, double y1, double width, double height) { bg.fillRect(x(x1),y(y1),dltX(width),dltY(height)); } /** Draws an unfilled rectangle bounded by the given coordinates */ static public synchronized void rect(double x1, double y1, double x2, double y2) { int xx1 = x(x1), yy1 = y(y1), xx2 = x(x2), yy2 = y(y2); bg.drawRect(Math.min(xx1,xx2),Math.min(yy1,yy2), Math.abs(xx2-xx1),Math.abs(yy1-yy2)); } /** Draws a filled rectangle bounded by the given coordinates */ static public synchronized void rectf(double x1, double y1, double x2, double y2) { int xx1 = x(x1), yy1 = y(y1), xx2 = x(x2), yy2 = y(y2); bg.fillRect(Math.min(xx1,xx2),Math.min(yy1,yy2), Math.abs(xx2-xx1),Math.abs(yy1-yy2)); } /** Draws an unfilled oval bounded by a rectangle with upper left hand corner at the given (x, y) position and the given width and height */ static public synchronized void drawOval(double x1, double y1, double width, double height) { bg.drawOval(x(x1),y(y1),dltX(width),dltY(height)); } /** Draws a filled oval bounded by a rectangle with upper left hand corner at the given (x, y) position and the given width and height */ static public synchronized void fillOval(double x1, double y1, double width, double height) { bg.fillOval(x(x1),y(y1),dltX(width),dltY(height)); } /** Draws an unfilled arc centered at the center of a rectangle with upper left hand corner at the given (x, y) position and the given width and height, starting at the given start angle (in degrees) and for as long as the given arc angle */ static public synchronized void drawArc(double x1, double y1, double width, double height, double startAngle, double arcAngle) { bg.drawArc(x(x1),y(y1),dltX(width),dltY(height), (int)startAngle,(int)arcAngle); } /** Draws a filled arc centered at the center of a rectangle with upper left hand corner at the given (x, y) position and the given width and height, starting at the given start angle (in degrees) and for as long as the given arc angle */ static public synchronized void fillArc(double x1, double y1, double width, double height, double startAngle, double arcAngle) { bg.fillArc(x(x1),y(y1),dltX(width),dltY(height), (int)startAngle,(int)arcAngle); } /** Draws an unfilled circle centered at the given (x, y) position and with the given radius r */ static public synchronized void circ(double x, double y, double r) { int xxr = x(x-r), yyr = y(y+r); bg.drawArc(xxr,yyr,x(x+r)-xxr,y(y-r)-yyr,0,360); } /** Draws a filled circle centered at the given (x, y) position and with the given radius r */ static public synchronized void circf(double x, double y, double r) { int xxr = x(x-r), yyr = y(y+r); bg.fillArc(xxr,yyr,x(x+r)-xxr,y(y-r)-yyr,0,360); } /** Draws the given string, with the default Font, so that the given (x, y) position is located relatively to the string according to the given specifications (LEFT/CENTER/RIGHT, TOP/CENTER/BOTTOM) */ static public synchronized void drawString(String str, double xx, double yy, String xpos, String ypos) { int h, w; int dx=0, dy=0; h = bg.getFontMetrics().getHeight(); w = bg.getFontMetrics().stringWidth(str); if (xpos.equals( "LEFT" )) { dx = 0; } else if (xpos.equals("CENTER")) { dx = w/2; } else if (xpos.equals( "RIGHT")) { dx = w; } if (ypos.equals( "TOP" )) { dy = -h/2;} else if (ypos.equals("CENTER")) { dy = -h/4; } else if (ypos.equals("BOTTOM")) { dy = 0; } strXpos = x(xx)-dx; strYpos = y(yy)-dy; if (strXpos + w > (int) width) { strXpos = 0; strYpos += h; } bg.drawString(str, strXpos, strYpos); strXpos += w; } /** Draws the given string, with the given Font size, so that the given (x, y) position is located relatively to the string according to the given specifications (LEFT/CENTER/RIGHT, TOP/CENTER/BOTTOM) */ static public synchronized void drawString(String str, double xx, double yy, String xpos, String ypos, int fntSize) { bg.setFont(new Font("Courier",Font.BOLD,fntSize)); drawString(str, xx, yy, xpos, ypos); bg.setFont(fnt); } /** Draws the given string, with the default Font, from the (x, y) position of the rightmost character of the last string drawn */ static public synchronized void drawString(String str) { int h, w; h = bg.getFontMetrics().getHeight(); w = bg.getFontMetrics().stringWidth(str); if (strXpos + w > (int) width) { strXpos = 0; strYpos += h; } bg.drawString(str, strXpos, strYpos); strXpos += w; } /** Draws the given image, with the given dimensions, so that the given (x, y) position is located relatively to the image according to the given specifications (LEFT/CENTER/RIGHT, TOP/CENTER/BOTTOM) */ static public synchronized void drawImage(Image img, double x0, double y0, int w, int h, String xpos, String ypos, ImageObserver io) { int dx=0, dy=0; if (xpos.equals( "LEFT" )) { dx = 0; } else if (xpos.equals("CENTER")) { dx = w/2; } else if (xpos.equals( "RIGHT")) { dx = w; } if (ypos.equals( "TOP" )) { dy = 0; } else if (ypos.equals("CENTER")) { dy = h/2; } else if (ypos.equals("BOTTOM")) { dy = h; } bg.drawImage(img, x(x0)-dx, y(y0)-dy, w, h, io); } }