zoukankan      html  css  js  c++  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://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 otherwise
    1032      */
    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 returns
    1041      * a Unicode character corresponding to the key typed (such as 'a' or 'A').
    1042      * It cannot identify action keys (such as F1
    1043      * and arrow keys) or modifier keys (such as control).
    1044      * @return the next Unicode key typed
    1045      */
    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 argument
    1054      * the keycode (corresponding to a physical key). It can handle action keys
    1055      * (such as F1 and arrow keys) and modifier keys (such as shift and control).
    1056      * See <a href = "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 otherwise
    1059      */
    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 diamond
    1110         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         // text
    1117         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 }
  • 相关阅读:
    C# 之 HttpRequest 类
    C# 之 日常问题积累(一)
    DataGrid前台数据绑定技巧
    [转]C,C++开源项目中的100个Bugs
    10行Python代码解决约瑟夫环(模拟)
    基于ASP.NET的comet简单实现 http长连接,IAsyncResult
    架构设计分享之权限系统(看图说话)
    内核request_mem_region 和 ioremap的理解
    【调侃】IOC前世今生 工厂模式 反射 依赖倒置
    ecos内核概览--bakayi译
  • 原文地址:https://www.cnblogs.com/pacoson/p/4003912.html
Copyright © 2011-2022 走看看