首页 > 代码库 > 自定义基本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
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。