首页 > 代码库 > 自定义基本java类-StdDraw.java

自定义基本java类-StdDraw.java

   1 /*************************************************************************   2  *  Compilation:  javac StdDraw.java   3  *  Execution:    java StdDraw   4  *   5  *  Standard drawing library. This class provides a basic capability for   6  *  creating drawings with your programs. It uses a simple graphics model that   7  *  allows you to create drawings consisting of points, lines, and curves   8  *  in a window on your computer and to save the drawings to a file.   9  *  10  *  Todo  11  *  ----  12  *    -  Add support for gradient fill, etc.  13  *    -  Fix setCanvasSize() so that it can only be called once.  14  *    -  On some systems, drawing a line (or other shape) that extends way  15  *       beyond canvas (e.g., to infinity) dimensions does not get drawn.  16  *  17  *  Remarks  18  *  -------  19  *    -  don‘t use AffineTransform for rescaling since it inverts  20  *       images and strings  21  *    -  careful using setFont in inner loop within an animation -  22  *       it can cause flicker  23  *  24  *************************************************************************/  25   26 import java.awt.*;  27 import java.awt.event.*;  28 import java.awt.geom.*;  29 import java.awt.image.*;  30 import java.io.*;  31 import java.net.*;  32 import java.util.LinkedList;  33 import java.util.TreeSet;  34 import javax.imageio.ImageIO;  35 import javax.swing.*;  36   37 /**  38  *  <i>Standard draw</i>. This class provides a basic capability for  39  *  creating drawings with your programs. It uses a simple graphics model that  40  *  allows you to create drawings consisting of points, lines, and curves  41  *  in a window on your computer and to save the drawings to a file.  42  *  <p>  43  *  For additional documentation, see <a href="http://www.mamicode.com/http://introcs.cs.princeton.edu/15inout">Section 1.5</a> of  44  *  <i>Introduction to Programming in Java: An Interdisciplinary Approach</i> by Robert Sedgewick and Kevin Wayne.  45  *  46  *  @author Robert Sedgewick  47  *  @author Kevin Wayne  48  */  49 public final class StdDraw implements ActionListener, MouseListener, MouseMotionListener, KeyListener {  50   51     // pre-defined colors  52     public static final Color BLACK      = Color.BLACK;  53     public static final Color BLUE       = Color.BLUE;  54     public static final Color CYAN       = Color.CYAN;  55     public static final Color DARK_GRAY  = Color.DARK_GRAY;  56     public static final Color GRAY       = Color.GRAY;  57     public static final Color GREEN      = Color.GREEN;  58     public static final Color LIGHT_GRAY = Color.LIGHT_GRAY;  59     public static final Color MAGENTA    = Color.MAGENTA;  60     public static final Color ORANGE     = Color.ORANGE;  61     public static final Color PINK       = Color.PINK;  62     public static final Color RED        = Color.RED;  63     public static final Color WHITE      = Color.WHITE;  64     public static final Color YELLOW     = Color.YELLOW;  65   66     /**  67      * Shade of blue used in Introduction to Programming in Java.  68      * It is Pantone 300U. The RGB values are approximately (9, 90, 166).  69      */  70     public static final Color BOOK_BLUE       = new Color(  9,  90, 166);  71     public static final Color BOOK_LIGHT_BLUE = new Color(103, 198, 243);  72   73     /**  74      * Shade of red used in Algorithms 4th edition.  75      * It is Pantone 1805U. The RGB values are approximately (150, 35, 31).  76      */  77     public static final Color BOOK_RED = new Color(150, 35, 31);  78   79     // default colors  80     private static final Color DEFAULT_PEN_COLOR   = BLACK;  81     private static final Color DEFAULT_CLEAR_COLOR = WHITE;  82   83     // current pen color  84     private static Color penColor;  85   86     // default canvas size is DEFAULT_SIZE-by-DEFAULT_SIZE  87     private static final int DEFAULT_SIZE = 512;  88     private static int width  = DEFAULT_SIZE;  89     private static int height = DEFAULT_SIZE;  90   91     // default pen radius  92     private static final double DEFAULT_PEN_RADIUS = 0.002;  93   94     // current pen radius  95     private static double penRadius;  96   97     // show we draw immediately or wait until next show?  98     private static boolean defer = false;  99  100     // boundary of drawing canvas, 5% border 101     private static final double BORDER = 0.05; 102     private static final double DEFAULT_XMIN = 0.0; 103     private static final double DEFAULT_XMAX = 1.0; 104     private static final double DEFAULT_YMIN = 0.0; 105     private static final double DEFAULT_YMAX = 1.0; 106     private static double xmin, ymin, xmax, ymax; 107  108     // for synchronization 109     private static Object mouseLock = new Object(); 110     private static Object keyLock = new Object(); 111  112     // default font 113     private static final Font DEFAULT_FONT = new Font("SansSerif", Font.PLAIN, 16); 114  115     // current font 116     private static Font font; 117  118     // double buffered graphics 119     private static BufferedImage offscreenImage, onscreenImage; 120     private static Graphics2D offscreen, onscreen; 121  122     // singleton for callbacks: avoids generation of extra .class files 123     private static StdDraw std = new StdDraw(); 124  125     // the frame for drawing to the screen 126     private static JFrame frame; 127  128     // mouse state 129     private static boolean mousePressed = false; 130     private static double mouseX = 0; 131     private static double mouseY = 0; 132  133     // queue of typed key characters 134     private static LinkedList<Character> keysTyped = new LinkedList<Character>(); 135  136     // set of key codes currently pressed down 137     private static TreeSet<Integer> keysDown = new TreeSet<Integer>(); 138    139  140     // singleton pattern: client can‘t instantiate 141     private StdDraw() { } 142  143  144     // static initializer 145     static { init(); } 146  147     /** 148      * Set the window size to the default size 512-by-512 pixels. 149      * This method must be called before any other commands. 150      */ 151     public static void setCanvasSize() { 152         setCanvasSize(DEFAULT_SIZE, DEFAULT_SIZE); 153     } 154  155     /** 156      * Set the window size to w-by-h pixels. 157      * This method must be called before any other commands. 158      * 159      * @param w the width as a number of pixels 160      * @param h the height as a number of pixels 161      * @throws a IllegalArgumentException if the width or height is 0 or negative 162      */ 163     public static void setCanvasSize(int w, int h) { 164         if (w < 1 || h < 1) throw new IllegalArgumentException("width and height must be positive"); 165         width = w; 166         height = h; 167         init(); 168     } 169  170     // init 171     private static void init() { 172         if (frame != null) frame.setVisible(false); 173         frame = new JFrame(); 174         offscreenImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 175         onscreenImage  = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 176         offscreen = offscreenImage.createGraphics(); 177         onscreen  = onscreenImage.createGraphics(); 178         setXscale(); 179         setYscale(); 180         offscreen.setColor(DEFAULT_CLEAR_COLOR); 181         offscreen.fillRect(0, 0, width, height); 182         setPenColor(); 183         setPenRadius(); 184         setFont(); 185         clear(); 186  187         // add antialiasing 188         RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, 189                                                   RenderingHints.VALUE_ANTIALIAS_ON); 190         hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 191         offscreen.addRenderingHints(hints); 192  193         // frame stuff 194         ImageIcon icon = new ImageIcon(onscreenImage); 195         JLabel draw = new JLabel(icon); 196  197         draw.addMouseListener(std); 198         draw.addMouseMotionListener(std); 199  200         frame.setContentPane(draw); 201         frame.addKeyListener(std);    // JLabel cannot get keyboard focus 202         frame.setResizable(false); 203         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);            // closes all windows 204         // frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);      // closes only current window 205         frame.setTitle("Standard Draw"); 206         frame.setJMenuBar(createMenuBar()); 207         frame.pack(); 208         frame.requestFocusInWindow(); 209         frame.setVisible(true); 210     } 211  212     // create the menu bar (changed to private) 213     private static JMenuBar createMenuBar() { 214         JMenuBar menuBar = new JMenuBar(); 215         JMenu menu = new JMenu("File"); 216         menuBar.add(menu); 217         JMenuItem menuItem1 = new JMenuItem(" Save...   "); 218         menuItem1.addActionListener(std); 219         menuItem1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, 220                                 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); 221         menu.add(menuItem1); 222         return menuBar; 223     } 224  225  226    /************************************************************************* 227     *  User and screen coordinate systems 228     *************************************************************************/ 229  230     /** 231      * Set the x-scale to be the default (between 0.0 and 1.0). 232      */ 233     public static void setXscale() { setXscale(DEFAULT_XMIN, DEFAULT_XMAX); } 234  235     /** 236      * Set the y-scale to be the default (between 0.0 and 1.0). 237      */ 238     public static void setYscale() { setYscale(DEFAULT_YMIN, DEFAULT_YMAX); } 239  240     /** 241      * Set the x-scale (a 10% border is added to the values) 242      * @param min the minimum value of the x-scale 243      * @param max the maximum value of the x-scale 244      */ 245     public static void setXscale(double min, double max) { 246         double size = max - min; 247         synchronized (mouseLock) { 248             xmin = min - BORDER * size; 249             xmax = max + BORDER * size; 250         } 251     } 252  253     /** 254      * Set the y-scale (a 10% border is added to the values). 255      * @param min the minimum value of the y-scale 256      * @param max the maximum value of the y-scale 257      */ 258     public static void setYscale(double min, double max) { 259         double size = max - min; 260         synchronized (mouseLock) { 261             ymin = min - BORDER * size; 262             ymax = max + BORDER * size; 263         } 264     } 265  266     /** 267      * Set the x-scale and y-scale (a 10% border is added to the values) 268      * @param min the minimum value of the x- and y-scales 269      * @param max the maximum value of the x- and y-scales 270      */ 271     public static void setScale(double min, double max) { 272         double size = max - min; 273         synchronized (mouseLock) { 274             xmin = min - BORDER * size; 275             xmax = max + BORDER * size; 276             ymin = min - BORDER * size; 277             ymax = max + BORDER * size; 278         } 279     } 280  281     // helper functions that scale from user coordinates to screen coordinates and back 282     private static double  scaleX(double x) { return width  * (x - xmin) / (xmax - xmin); } 283     private static double  scaleY(double y) { return height * (ymax - y) / (ymax - ymin); } 284     private static double factorX(double w) { return w * width  / Math.abs(xmax - xmin);  } 285     private static double factorY(double h) { return h * height / Math.abs(ymax - ymin);  } 286     private static double   userX(double x) { return xmin + x * (xmax - xmin) / width;    } 287     private static double   userY(double y) { return ymax - y * (ymax - ymin) / height;   } 288  289  290     /** 291      * Clear the screen to the default color (white). 292      */ 293     public static void clear() { clear(DEFAULT_CLEAR_COLOR); } 294     /** 295      * Clear the screen to the given color. 296      * @param color the Color to make the background 297      */ 298     public static void clear(Color color) { 299         offscreen.setColor(color); 300         offscreen.fillRect(0, 0, width, height); 301         offscreen.setColor(penColor); 302         draw(); 303     } 304  305     /** 306      * Get the current pen radius. 307      */ 308     public static double getPenRadius() { return penRadius; } 309  310     /** 311      * Set the pen size to the default (.002). 312      */ 313     public static void setPenRadius() { setPenRadius(DEFAULT_PEN_RADIUS); } 314     /** 315      * Set the radius of the pen to the given size. 316      * @param r the radius of the pen 317      * @throws IllegalArgumentException if r is negative 318      */ 319     public static void setPenRadius(double r) { 320         if (r < 0) throw new IllegalArgumentException("pen radius must be nonnegative"); 321         penRadius = r; 322         float scaledPenRadius = (float) (r * DEFAULT_SIZE); 323         BasicStroke stroke = new BasicStroke(scaledPenRadius, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); 324         // BasicStroke stroke = new BasicStroke(scaledPenRadius); 325         offscreen.setStroke(stroke); 326     } 327  328     /** 329      * Get the current pen color. 330      */ 331     public static Color getPenColor() { return penColor; } 332  333     /** 334      * Set the pen color to the default color (black). 335      */ 336     public static void setPenColor() { setPenColor(DEFAULT_PEN_COLOR); } 337  338     /** 339      * Set the pen color to the given color. The available pen colors are 340      * BLACK, BLUE, CYAN, DARK_GRAY, GRAY, GREEN, LIGHT_GRAY, MAGENTA, 341      * ORANGE, PINK, RED, WHITE, and YELLOW. 342      * @param color the Color to make the pen 343      */ 344     public static void setPenColor(Color color) { 345         penColor = color; 346         offscreen.setColor(penColor); 347     } 348  349     /** 350      * Set the pen color to the given RGB color. 351      * @param red the amount of red (between 0 and 255) 352      * @param green the amount of green (between 0 and 255) 353      * @param blue the amount of blue (between 0 and 255) 354      * @throws IllegalArgumentException if the amount of red, green, or blue are outside prescribed range 355      */ 356     public static void setPenColor(int red, int green, int blue) { 357         if (red   < 0 || red   >= 256) throw new IllegalArgumentException("amount of red must be between 0 and 255"); 358         if (green < 0 || green >= 256) throw new IllegalArgumentException("amount of green must be between 0 and 255"); 359         if (blue  < 0 || blue  >= 256) throw new IllegalArgumentException("amount of blue must be between 0 and 255"); 360         setPenColor(new Color(red, green, blue)); 361     } 362  363     /** 364      * Get the current font. 365      */ 366     public static Font getFont() { return font; } 367  368     /** 369      * Set the font to the default font (sans serif, 16 point). 370      */ 371     public static void setFont() { setFont(DEFAULT_FONT); } 372  373     /** 374      * Set the font to the given value. 375      * @param f the font to make text 376      */ 377     public static void setFont(Font f) { font = f; } 378  379  380    /************************************************************************* 381     *  Drawing geometric shapes. 382     *************************************************************************/ 383  384     /** 385      * Draw a line from (x0, y0) to (x1, y1). 386      * @param x0 the x-coordinate of the starting point 387      * @param y0 the y-coordinate of the starting point 388      * @param x1 the x-coordinate of the destination point 389      * @param y1 the y-coordinate of the destination point 390      */ 391     public static void line(double x0, double y0, double x1, double y1) { 392         offscreen.draw(new Line2D.Double(scaleX(x0), scaleY(y0), scaleX(x1), scaleY(y1))); 393         draw(); 394     } 395  396     /** 397      * Draw one pixel at (x, y). 398      * @param x the x-coordinate of the pixel 399      * @param y the y-coordinate of the pixel 400      */ 401     private static void pixel(double x, double y) { 402         offscreen.fillRect((int) Math.round(scaleX(x)), (int) Math.round(scaleY(y)), 1, 1); 403     } 404  405     /** 406      * Draw a point at (x, y). 407      * @param x the x-coordinate of the point 408      * @param y the y-coordinate of the point 409      */ 410     public static void point(double x, double y) { 411         double xs = scaleX(x); 412         double ys = scaleY(y); 413         double r = penRadius; 414         float scaledPenRadius = (float) (r * DEFAULT_SIZE); 415  416         // double ws = factorX(2*r); 417         // double hs = factorY(2*r); 418         // if (ws <= 1 && hs <= 1) pixel(x, y); 419         if (scaledPenRadius <= 1) pixel(x, y); 420         else offscreen.fill(new Ellipse2D.Double(xs - scaledPenRadius/2, ys - scaledPenRadius/2, 421                                                  scaledPenRadius, scaledPenRadius)); 422         draw(); 423     } 424  425     /** 426      * Draw a circle of radius r, centered on (x, y). 427      * @param x the x-coordinate of the center of the circle 428      * @param y the y-coordinate of the center of the circle 429      * @param r the radius of the circle 430      * @throws IllegalArgumentException if the radius of the circle is negative 431      */ 432     public static void circle(double x, double y, double r) { 433         if (r < 0) throw new IllegalArgumentException("circle radius must be nonnegative"); 434         double xs = scaleX(x); 435         double ys = scaleY(y); 436         double ws = factorX(2*r); 437         double hs = factorY(2*r); 438         if (ws <= 1 && hs <= 1) pixel(x, y); 439         else offscreen.draw(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs)); 440         draw(); 441     } 442  443     /** 444      * Draw filled circle of radius r, centered on (x, y). 445      * @param x the x-coordinate of the center of the circle 446      * @param y the y-coordinate of the center of the circle 447      * @param r the radius of the circle 448      * @throws IllegalArgumentException if the radius of the circle is negative 449      */ 450     public static void filledCircle(double x, double y, double r) { 451         if (r < 0) throw new IllegalArgumentException("circle radius must be nonnegative"); 452         double xs = scaleX(x); 453         double ys = scaleY(y); 454         double ws = factorX(2*r); 455         double hs = factorY(2*r); 456         if (ws <= 1 && hs <= 1) pixel(x, y); 457         else offscreen.fill(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs)); 458         draw(); 459     } 460  461  462     /** 463      * Draw an ellipse with given semimajor and semiminor axes, centered on (x, y). 464      * @param x the x-coordinate of the center of the ellipse 465      * @param y the y-coordinate of the center of the ellipse 466      * @param semiMajorAxis is the semimajor axis of the ellipse 467      * @param semiMinorAxis is the semiminor axis of the ellipse 468      * @throws IllegalArgumentException if either of the axes are negative 469      */ 470     public static void ellipse(double x, double y, double semiMajorAxis, double semiMinorAxis) { 471         if (semiMajorAxis < 0) throw new IllegalArgumentException("ellipse semimajor axis must be nonnegative"); 472         if (semiMinorAxis < 0) throw new IllegalArgumentException("ellipse semiminor axis must be nonnegative"); 473         double xs = scaleX(x); 474         double ys = scaleY(y); 475         double ws = factorX(2*semiMajorAxis); 476         double hs = factorY(2*semiMinorAxis); 477         if (ws <= 1 && hs <= 1) pixel(x, y); 478         else offscreen.draw(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs)); 479         draw(); 480     } 481  482     /** 483      * Draw an ellipse with given semimajor and semiminor axes, centered on (x, y). 484      * @param x the x-coordinate of the center of the ellipse 485      * @param y the y-coordinate of the center of the ellipse 486      * @param semiMajorAxis is the semimajor axis of the ellipse 487      * @param semiMinorAxis is the semiminor axis of the ellipse 488      * @throws IllegalArgumentException if either of the axes are negative 489      */ 490     public static void filledEllipse(double x, double y, double semiMajorAxis, double semiMinorAxis) { 491         if (semiMajorAxis < 0) throw new IllegalArgumentException("ellipse semimajor axis must be nonnegative"); 492         if (semiMinorAxis < 0) throw new IllegalArgumentException("ellipse semiminor axis must be nonnegative"); 493         double xs = scaleX(x); 494         double ys = scaleY(y); 495         double ws = factorX(2*semiMajorAxis); 496         double hs = factorY(2*semiMinorAxis); 497         if (ws <= 1 && hs <= 1) pixel(x, y); 498         else offscreen.fill(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs)); 499         draw(); 500     } 501  502  503     /** 504      * Draw an arc of radius r, centered on (x, y), from angle1 to angle2 (in degrees). 505      * @param x the x-coordinate of the center of the circle 506      * @param y the y-coordinate of the center of the circle 507      * @param r the radius of the circle 508      * @param angle1 the starting angle. 0 would mean an arc beginning at 3 o‘clock. 509      * @param angle2 the angle at the end of the arc. For example, if 510      *        you want a 90 degree arc, then angle2 should be angle1 + 90. 511      * @throws IllegalArgumentException if the radius of the circle is negative 512      */ 513     public static void arc(double x, double y, double r, double angle1, double angle2) { 514         if (r < 0) throw new IllegalArgumentException("arc radius must be nonnegative"); 515         while (angle2 < angle1) angle2 += 360; 516         double xs = scaleX(x); 517         double ys = scaleY(y); 518         double ws = factorX(2*r); 519         double hs = factorY(2*r); 520         if (ws <= 1 && hs <= 1) pixel(x, y); 521         else offscreen.draw(new Arc2D.Double(xs - ws/2, ys - hs/2, ws, hs, angle1, angle2 - angle1, Arc2D.OPEN)); 522         draw(); 523     } 524  525     /** 526      * Draw a square of side length 2r, centered on (x, y). 527      * @param x the x-coordinate of the center of the square 528      * @param y the y-coordinate of the center of the square 529      * @param r radius is half the length of any side of the square 530      * @throws IllegalArgumentException if r is negative 531      */ 532     public static void square(double x, double y, double r) { 533         if (r < 0) throw new IllegalArgumentException("square side length must be nonnegative"); 534         double xs = scaleX(x); 535         double ys = scaleY(y); 536         double ws = factorX(2*r); 537         double hs = factorY(2*r); 538         if (ws <= 1 && hs <= 1) pixel(x, y); 539         else offscreen.draw(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs)); 540         draw(); 541     } 542  543     /** 544      * Draw a filled square of side length 2r, centered on (x, y). 545      * @param x the x-coordinate of the center of the square 546      * @param y the y-coordinate of the center of the square 547      * @param r radius is half the length of any side of the square 548      * @throws IllegalArgumentException if r is negative 549      */ 550     public static void filledSquare(double x, double y, double r) { 551         if (r < 0) throw new IllegalArgumentException("square side length must be nonnegative"); 552         double xs = scaleX(x); 553         double ys = scaleY(y); 554         double ws = factorX(2*r); 555         double hs = factorY(2*r); 556         if (ws <= 1 && hs <= 1) pixel(x, y); 557         else offscreen.fill(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs)); 558         draw(); 559     } 560  561  562     /** 563      * Draw a rectangle of given half width and half height, centered on (x, y). 564      * @param x the x-coordinate of the center of the rectangle 565      * @param y the y-coordinate of the center of the rectangle 566      * @param halfWidth is half the width of the rectangle 567      * @param halfHeight is half the height of the rectangle 568      * @throws IllegalArgumentException if halfWidth or halfHeight is negative 569      */ 570     public static void rectangle(double x, double y, double halfWidth, double halfHeight) { 571         if (halfWidth  < 0) throw new IllegalArgumentException("half width must be nonnegative"); 572         if (halfHeight < 0) throw new IllegalArgumentException("half height must be nonnegative"); 573         double xs = scaleX(x); 574         double ys = scaleY(y); 575         double ws = factorX(2*halfWidth); 576         double hs = factorY(2*halfHeight); 577         if (ws <= 1 && hs <= 1) pixel(x, y); 578         else offscreen.draw(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs)); 579         draw(); 580     } 581  582     /** 583      * Draw a filled rectangle of given half width and half height, centered on (x, y). 584      * @param x the x-coordinate of the center of the rectangle 585      * @param y the y-coordinate of the center of the rectangle 586      * @param halfWidth is half the width of the rectangle 587      * @param halfHeight is half the height of the rectangle 588      * @throws IllegalArgumentException if halfWidth or halfHeight is negative 589      */ 590     public static void filledRectangle(double x, double y, double halfWidth, double halfHeight) { 591         if (halfWidth  < 0) throw new IllegalArgumentException("half width must be nonnegative"); 592         if (halfHeight < 0) throw new IllegalArgumentException("half height must be nonnegative"); 593         double xs = scaleX(x); 594         double ys = scaleY(y); 595         double ws = factorX(2*halfWidth); 596         double hs = factorY(2*halfHeight); 597         if (ws <= 1 && hs <= 1) pixel(x, y); 598         else offscreen.fill(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs)); 599         draw(); 600     } 601  602  603     /** 604      * Draw a polygon with the given (x[i], y[i]) coordinates. 605      * @param x an array of all the x-coordindates of the polygon 606      * @param y an array of all the y-coordindates of the polygon 607      */ 608     public static void polygon(double[] x, double[] y) { 609         int N = x.length; 610         GeneralPath path = new GeneralPath(); 611         path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0])); 612         for (int i = 0; i < N; i++) 613             path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i])); 614         path.closePath(); 615         offscreen.draw(path); 616         draw(); 617     } 618  619     /** 620      * Draw a filled polygon with the given (x[i], y[i]) coordinates. 621      * @param x an array of all the x-coordindates of the polygon 622      * @param y an array of all the y-coordindates of the polygon 623      */ 624     public static void filledPolygon(double[] x, double[] y) { 625         int N = x.length; 626         GeneralPath path = new GeneralPath(); 627         path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0])); 628         for (int i = 0; i < N; i++) 629             path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i])); 630         path.closePath(); 631         offscreen.fill(path); 632         draw(); 633     } 634  635  636  637    /************************************************************************* 638     *  Drawing images. 639     *************************************************************************/ 640  641     // get an image from the given filename 642     private static Image getImage(String filename) { 643  644         // to read from file 645         ImageIcon icon = new ImageIcon(filename); 646  647         // try to read from URL 648         if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) { 649             try { 650                 URL url = new URL(filename); 651                 icon = new ImageIcon(url); 652             } catch (Exception e) { /* not a url */ } 653         } 654  655         // in case file is inside a .jar 656         if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) { 657             URL url = StdDraw.class.getResource(filename); 658             if (url == null) throw new IllegalArgumentException("image " + filename + " not found"); 659             icon = new ImageIcon(url); 660         } 661  662         return icon.getImage(); 663     } 664  665     /** 666      * Draw picture (gif, jpg, or png) centered on (x, y). 667      * @param x the center x-coordinate of the image 668      * @param y the center y-coordinate of the image 669      * @param s the name of the image/picture, e.g., "ball.gif" 670      * @throws IllegalArgumentException if the image is corrupt 671      */ 672     public static void picture(double x, double y, String s) { 673         Image image = getImage(s); 674         double xs = scaleX(x); 675         double ys = scaleY(y); 676         int ws = image.getWidth(null); 677         int hs = image.getHeight(null); 678         if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + s + " is corrupt"); 679  680         offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), null); 681         draw(); 682     } 683  684     /** 685      * Draw picture (gif, jpg, or png) centered on (x, y), 686      * rotated given number of degrees 687      * @param x the center x-coordinate of the image 688      * @param y the center y-coordinate of the image 689      * @param s the name of the image/picture, e.g., "ball.gif" 690      * @param degrees is the number of degrees to rotate counterclockwise 691      * @throws IllegalArgumentException if the image is corrupt 692      */ 693     public static void picture(double x, double y, String s, double degrees) { 694         Image image = getImage(s); 695         double xs = scaleX(x); 696         double ys = scaleY(y); 697         int ws = image.getWidth(null); 698         int hs = image.getHeight(null); 699         if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + s + " is corrupt"); 700  701         offscreen.rotate(Math.toRadians(-degrees), xs, ys); 702         offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), null); 703         offscreen.rotate(Math.toRadians(+degrees), xs, ys); 704  705         draw(); 706     } 707  708     /** 709      * Draw picture (gif, jpg, or png) centered on (x, y), rescaled to w-by-h. 710      * @param x the center x coordinate of the image 711      * @param y the center y coordinate of the image 712      * @param s the name of the image/picture, e.g., "ball.gif" 713      * @param w the width of the image 714      * @param h the height of the image 715      * @throws IllegalArgumentException if the width height are negative 716      * @throws IllegalArgumentException if the image is corrupt 717      */ 718     public static void picture(double x, double y, String s, double w, double h) { 719         Image image = getImage(s); 720         double xs = scaleX(x); 721         double ys = scaleY(y); 722         if (w < 0) throw new IllegalArgumentException("width is negative: " + w); 723         if (h < 0) throw new IllegalArgumentException("height is negative: " + h); 724         double ws = factorX(w); 725         double hs = factorY(h); 726         if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + s + " is corrupt"); 727         if (ws <= 1 && hs <= 1) pixel(x, y); 728         else { 729             offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), 730                                        (int) Math.round(ys - hs/2.0), 731                                        (int) Math.round(ws), 732                                        (int) Math.round(hs), null); 733         } 734         draw(); 735     } 736  737  738     /** 739      * Draw picture (gif, jpg, or png) centered on (x, y), rotated 740      * given number of degrees, rescaled to w-by-h. 741      * @param x the center x-coordinate of the image 742      * @param y the center y-coordinate of the image 743      * @param s the name of the image/picture, e.g., "ball.gif" 744      * @param w the width of the image 745      * @param h the height of the image 746      * @param degrees is the number of degrees to rotate counterclockwise 747      * @throws IllegalArgumentException if the image is corrupt 748      */ 749     public static void picture(double x, double y, String s, double w, double h, double degrees) { 750         Image image = getImage(s); 751         double xs = scaleX(x); 752         double ys = scaleY(y); 753         double ws = factorX(w); 754         double hs = factorY(h); 755         if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + s + " is corrupt"); 756         if (ws <= 1 && hs <= 1) pixel(x, y); 757  758         offscreen.rotate(Math.toRadians(-degrees), xs, ys); 759         offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), 760                                    (int) Math.round(ys - hs/2.0), 761                                    (int) Math.round(ws), 762                                    (int) Math.round(hs), null); 763         offscreen.rotate(Math.toRadians(+degrees), xs, ys); 764  765         draw(); 766     } 767  768  769    /************************************************************************* 770     *  Drawing text. 771     *************************************************************************/ 772  773     /** 774      * Write the given text string in the current font, centered on (x, y). 775      * @param x the center x-coordinate of the text 776      * @param y the center y-coordinate of the text 777      * @param s the text 778      */ 779     public static void text(double x, double y, String s) { 780         offscreen.setFont(font); 781         FontMetrics metrics = offscreen.getFontMetrics(); 782         double xs = scaleX(x); 783         double ys = scaleY(y); 784         int ws = metrics.stringWidth(s); 785         int hs = metrics.getDescent(); 786         offscreen.drawString(s, (float) (xs - ws/2.0), (float) (ys + hs)); 787         draw(); 788     } 789  790     /** 791      * Write the given text string in the current font, centered on (x, y) and 792      * rotated by the specified number of degrees   793      * @param x the center x-coordinate of the text 794      * @param y the center y-coordinate of the text 795      * @param s the text 796      * @param degrees is the number of degrees to rotate counterclockwise 797      */ 798     public static void text(double x, double y, String s, double degrees) { 799         double xs = scaleX(x); 800         double ys = scaleY(y); 801         offscreen.rotate(Math.toRadians(-degrees), xs, ys); 802         text(x, y, s); 803         offscreen.rotate(Math.toRadians(+degrees), xs, ys); 804     } 805  806  807     /** 808      * Write the given text string in the current font, left-aligned at (x, y). 809      * @param x the x-coordinate of the text 810      * @param y the y-coordinate of the text 811      * @param s the text 812      */ 813     public static void textLeft(double x, double y, String s) { 814         offscreen.setFont(font); 815         FontMetrics metrics = offscreen.getFontMetrics(); 816         double xs = scaleX(x); 817         double ys = scaleY(y); 818         int hs = metrics.getDescent(); 819         offscreen.drawString(s, (float) (xs), (float) (ys + hs)); 820         draw(); 821     } 822  823     /** 824      * Write the given text string in the current font, right-aligned at (x, y). 825      * @param x the x-coordinate of the text 826      * @param y the y-coordinate of the text 827      * @param s the text 828      */ 829     public static void textRight(double x, double y, String s) { 830         offscreen.setFont(font); 831         FontMetrics metrics = offscreen.getFontMetrics(); 832         double xs = scaleX(x); 833         double ys = scaleY(y); 834         int ws = metrics.stringWidth(s); 835         int hs = metrics.getDescent(); 836         offscreen.drawString(s, (float) (xs - ws), (float) (ys + hs)); 837         draw(); 838     } 839  840  841  842     /** 843      * Display on screen, pause for t milliseconds, and turn on 844      * <em>animation mode</em>: subsequent calls to 845      * drawing methods such as <tt>line()</tt>, <tt>circle()</tt>, and <tt>square()</tt> 846      * will not be displayed on screen until the next call to <tt>show()</tt>. 847      * This is useful for producing animations (clear the screen, draw a bunch of shapes, 848      * display on screen for a fixed amount of time, and repeat). It also speeds up 849      * drawing a huge number of shapes (call <tt>show(0)</tt> to defer drawing 850      * on screen, draw the shapes, and call <tt>show(0)</tt> to display them all 851      * on screen at once). 852      * @param t number of milliseconds 853      */ 854     public static void show(int t) { 855         defer = false; 856         draw(); 857         try { Thread.sleep(t); } 858         catch (InterruptedException e) { System.out.println("Error sleeping"); } 859         defer = true; 860     } 861  862     /** 863      * Display on-screen and turn off animation mode: 864      * subsequent calls to 865      * drawing methods such as <tt>line()</tt>, <tt>circle()</tt>, and <tt>square()</tt> 866      * will be displayed on screen when called. This is the default. 867      */ 868     public static void show() { 869         defer = false; 870         draw(); 871     } 872  873     // draw onscreen if defer is false 874     private static void draw() { 875         if (defer) return; 876         onscreen.drawImage(offscreenImage, 0, 0, null); 877         frame.repaint(); 878     } 879  880  881    /************************************************************************* 882     *  Save drawing to a file. 883     *************************************************************************/ 884  885     /** 886      * Save onscreen image to file - suffix must be png, jpg, or gif. 887      * @param filename the name of the file with one of the required suffixes 888      */ 889     public static void save(String filename) { 890         File file = new File(filename); 891         String suffix = filename.substring(filename.lastIndexOf(‘.‘) + 1); 892  893         // png files 894         if (suffix.toLowerCase().equals("png")) { 895             try { ImageIO.write(onscreenImage, suffix, file); } 896             catch (IOException e) { e.printStackTrace(); } 897         } 898  899         // need to change from ARGB to RGB for jpeg 900         // reference: http://archives.java.sun.com/cgi-bin/wa?A2=ind0404&L=java2d-interest&D=0&P=2727 901         else if (suffix.toLowerCase().equals("jpg")) { 902             WritableRaster raster = onscreenImage.getRaster(); 903             WritableRaster newRaster; 904             newRaster = raster.createWritableChild(0, 0, width, height, 0, 0, new int[] {0, 1, 2}); 905             DirectColorModel cm = (DirectColorModel) onscreenImage.getColorModel(); 906             DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(), 907                                                           cm.getRedMask(), 908                                                           cm.getGreenMask(), 909                                                           cm.getBlueMask()); 910             BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false,  null); 911             try { ImageIO.write(rgbBuffer, suffix, file); } 912             catch (IOException e) { e.printStackTrace(); } 913         } 914  915         else { 916             System.out.println("Invalid image file type: " + suffix); 917         } 918     } 919  920  921     /** 922      * This method cannot be called directly. 923      */ 924     public void actionPerformed(ActionEvent e) { 925         FileDialog chooser = new FileDialog(StdDraw.frame, "Use a .png or .jpg extension", FileDialog.SAVE); 926         chooser.setVisible(true); 927         String filename = chooser.getFile(); 928         if (filename != null) { 929             StdDraw.save(chooser.getDirectory() + File.separator + chooser.getFile()); 930         } 931     } 932  933  934    /************************************************************************* 935     *  Mouse interactions. 936     *************************************************************************/ 937  938     /** 939      * Is the mouse being pressed? 940      * @return true or false 941      */ 942     public static boolean mousePressed() { 943         synchronized (mouseLock) { 944             return mousePressed; 945         } 946     } 947  948     /** 949      * What is the x-coordinate of the mouse? 950      * @return the value of the x-coordinate of the mouse 951      */ 952     public static double mouseX() { 953         synchronized (mouseLock) { 954             return mouseX; 955         } 956     } 957  958     /** 959      * What is the y-coordinate of the mouse? 960      * @return the value of the y-coordinate of the mouse 961      */ 962     public static double mouseY() { 963         synchronized (mouseLock) { 964             return mouseY; 965         } 966     } 967  968  969     /** 970      * This method cannot be called directly. 971      */ 972     public void mouseClicked(MouseEvent e) { } 973  974     /** 975      * This method cannot be called directly. 976      */ 977     public void mouseEntered(MouseEvent e) { } 978  979     /** 980      * This method cannot be called directly. 981      */ 982     public void mouseExited(MouseEvent e) { } 983  984     /** 985      * This method cannot be called directly. 986      */ 987     public void mousePressed(MouseEvent e) { 988         synchronized (mouseLock) { 989             mouseX = StdDraw.userX(e.getX()); 990             mouseY = StdDraw.userY(e.getY()); 991             mousePressed = true; 992         } 993     } 994  995     /** 996      * This method cannot be called directly. 997      */ 998     public void mouseReleased(MouseEvent e) { 999         synchronized (mouseLock) {1000             mousePressed = false;1001         }1002     }1003 1004     /**1005      * This method cannot be called directly.1006      */1007     public void mouseDragged(MouseEvent e)  {1008         synchronized (mouseLock) {1009             mouseX = StdDraw.userX(e.getX());1010             mouseY = StdDraw.userY(e.getY());1011         }1012     }1013 1014     /**1015      * This method cannot be called directly.1016      */1017     public void mouseMoved(MouseEvent e) {1018         synchronized (mouseLock) {1019             mouseX = StdDraw.userX(e.getX());1020             mouseY = StdDraw.userY(e.getY());1021         }1022     }1023 1024 1025    /*************************************************************************1026     *  Keyboard interactions.1027     *************************************************************************/1028 1029     /**1030      * Has the user typed a key?1031      * @return true if the user has typed a key, false otherwise1032      */1033     public static boolean hasNextKeyTyped() {1034         synchronized (keyLock) {1035             return !keysTyped.isEmpty();1036         }1037     }1038 1039     /**1040      * What is the next key that was typed by the user? This method returns1041      * a Unicode character corresponding to the key typed (such as ‘a‘ or ‘A‘).1042      * It cannot identify action keys (such as F11043      * and arrow keys) or modifier keys (such as control).1044      * @return the next Unicode key typed1045      */1046     public static char nextKeyTyped() {1047         synchronized (keyLock) {1048             return keysTyped.removeLast();1049         }1050     }1051 1052     /**1053      * Is the keycode currently being pressed? This method takes as an argument1054      * the keycode (corresponding to a physical key). It can handle action keys1055      * (such as F1 and arrow keys) and modifier keys (such as shift and control).1056      * See <a href = "http://www.mamicode.com/http://download.oracle.com/javase/6/docs/api/java/awt/event/KeyEvent.html">KeyEvent.java</a>1057      * for a description of key codes.1058      * @return true if keycode is currently being pressed, false otherwise1059      */1060     public static boolean isKeyPressed(int keycode) {1061         synchronized (keyLock) {1062             return keysDown.contains(keycode);1063         }1064     }1065 1066 1067     /**1068      * This method cannot be called directly.1069      */1070     public void keyTyped(KeyEvent e) {1071         synchronized (keyLock) {1072             keysTyped.addFirst(e.getKeyChar());1073         }1074     }1075 1076     /**1077      * This method cannot be called directly.1078      */1079     public void keyPressed(KeyEvent e) {1080         synchronized (keyLock) {1081             keysDown.add(e.getKeyCode());1082         }1083     }1084 1085     /**1086      * This method cannot be called directly.1087      */1088     public void keyReleased(KeyEvent e) {1089         synchronized (keyLock) {1090             keysDown.remove(e.getKeyCode());1091         }1092     }1093 1094 1095 1096 1097     /**1098      * Test client.1099      */1100     public static void main(String[] args) {1101         StdDraw.square(.2, .8, .1);1102         StdDraw.filledSquare(.8, .8, .2);1103         StdDraw.circle(.8, .2, .2);1104 1105         StdDraw.setPenColor(StdDraw.BOOK_RED);1106         StdDraw.setPenRadius(.02);1107         StdDraw.arc(.8, .2, .1, 200, 45);1108 1109         // draw a blue diamond1110         StdDraw.setPenRadius();1111         StdDraw.setPenColor(StdDraw.BOOK_BLUE);1112         double[] x = { .1, .2, .3, .2 };1113         double[] y = { .2, .3, .2, .1 };1114         StdDraw.filledPolygon(x, y);1115 1116         // text1117         StdDraw.setPenColor(StdDraw.BLACK);1118         StdDraw.text(0.2, 0.5, "black text");1119         StdDraw.setPenColor(StdDraw.WHITE);1120         StdDraw.text(0.8, 0.8, "white text");1121     }1122 1123 }

 

自定义基本java类-StdDraw.java