📄 mandelbrotdisplay.java
字号:
package edu.hws.eck.mdb;import java.awt.*;import java.awt.event.*;import javax.swing.*;import java.awt.image.BufferedImage;import java.util.ArrayList;import java.util.LinkedList;/** * A MandelbrotDisplay is a panel that shows a region of the xy-plane that * is colored to show a visualiztion of the Mandelbrot set. The Mandelbrot set * always appears in black. Other points are colored based on the number of * iterations of the Mandelbrot formula that are needed to move the point * to a distance of more than sqrt(4.1) units away from (0,0). Different * palettes of colors can be applied to the non-Mandelbrot points. Furthermore, * the length of the palette can be adjusted. (See the setPaletteLength() command.) * The setLimits() method can be used to change the range of x and y values that * are shown in the display, but the range will always be adjusted to fit the * shape of the display (so that units of measure in the x and y directions are * the same). * * Because the computation of an image can take quite a while, the computation is * done in separate threads (one thread is used for each available processor). * * The display is also capable of drawing a "zoom box" on top of the image. This * is just a box whose position and location are given by the drawZoomBox() method. * The applyZoom() method makes the picture zoom into or out of the current zoom box, * but management of the box is left to some other class (the one that calls these * methods.) * * Note: The class uses a relatively large amount of memory. When thelargedata * structurs are created, there is a small possibility that the program might not * have enough memory. If this happens, the error is caught and the display will * show an error message instead of an image. */public class MandelbrotDisplay extends JPanel { //------------------------- PUBLIC CONSTANTS ---------------------------------- /** * Constant used to identify one of the types of color palettes that can * be used for coloring the points in the image. See setPaletteType() * and setGradientPaletteType(). */ public final static int PALETTE_SPECTRUM = 0; public final static int PALETTE_PALE_SPECTRUM = 1; public final static int PALETTE_GRAYSCALE = 2; public final static int PALETTE_REVERSE_GRAYSCALE = 3; public final static int PALETTE_GRADIENT = 4; /** * The property name for the property change event that is generated * when the xy-limits on the display are changed. */ public final static String LIMITS_PROPERTY = "MandelbrotLimits"; /** * The property name for the property change that is generated when * the status of the display changes. The possible status values are * STATUS_WORKING, meaning that a computation is in progress; * STATUS_READY, whihc means that the image is complete and the * display is currently doing nothing; and STATUS_OUT_OF_MEMORY, * which will be the stats in the unlikely event that there is not * enough memory available to create the data structures used by the * display. */ public final static String STATUS_PROPERTY = "MandelbrotStatus"; /** * Constant representing a possible value of the STATUS property. */ public final static String STATUS_WORKING = "working"; public final static String STATUS_READY = "ready"; public final static String STATUS_OUT_OF_MEMORY = "out of memory"; //------------------------- PRIVATE INSTANCE VARIABLES -------------------------- private String status = STATUS_READY; // Current value of the STATUS property. private BufferedImage OSC; // The off-csreen canvas in which the image is constucted. private int[][] iterationCounts; // The interation count for each pixel in the display; // colors of pixels are set based on contents of this array. private int imageWidth; // Number of columns in the image; same as OSC.getWidth(); private int maxIterations = 50; // Current maximum number of iterations that will be used // in the Mandelbrot computation loop. Pixels that require // more iterations are colored black. private int paletteType; // Current palette type; one of the constants like PALETTE_SPECTRUM. private Color gradientPaletteColor1; // If palette type is PALETTE_GRADIENT, this is the gradient start color. private Color gradientPaletteColor2; // If palette type is PALETTE_GRADIENT, this is the gradient end color. private int paletteLength; // The number of colors in the palette. private int[] palette; // The colors in the palette, expressed as RGB color codes. private double xmin, xmax, ymin, ymax; // Ranges of xy values currently visible in the image. private double dx, dy; // Width and height of one pixel in xy-coords (should be the same). private double xmin_requested = -2.5; // These are the values that were requested in the setLimits() private double xmax_requested = 1.1; // command. They are adjusted in the checkAspect() method to private double ymin_requested = -1.35; // fit the aspect ratio of the display, and the actual values private double ymax_requested = 1.35; // that are used for the image are stored in xmin, xmax, ymin, // and ymax. If the image changes size, the REQUESTED values // are re-applied. private Rectangle zoomBox; // If non-null, then this rectangle is drawn on top of the // the image. The image can be zoomed into or out of this box. private Timer delayedResizeTimer; // This timer is used to avoid createing new BufferedImages // continually as the display is resized. The image will // not be resized until 1/3 second after the last size // change. private volatile boolean computing; // True when a computation is underway. private ComputeThread[] workerThreads; // The threads that do the actual computing. Worker threads // perform the "jobs" that make up an image computation. private int jobs; // The number of jobs that make up a computation. Same as // the height of the image, since each job consists of // computing iteration counts for one row of pixels. private int jobsAssigned; // The number of jobs that have assigned to threads so far // during the current computation. private int jobsCompleted; // The number of jobs that have been completed so far. private LinkedList<Job> finishedJobs; // When a job is completed, it is placed in this list, which // is used as a queue. A finished job contains data for // part of the image. Every so often, the main thread // and applies the data from any finished jobs to the image. private int computationNumber; // Each time a computation is started, this variable is // incremented. Because computations are done by threads, // when a computation is aborted and a new one started, // it's possible that a thread might continue working on // part of the previous computation. When that happens, // the result of that computation should be discarded and // not applied to the current picuture. By associating each // job with a computation number, out-of-date jobs can // recognized. private boolean shutDown; // Used to send a message to the threads to tell them to shut down. private int[] rgb; // Used for applying color to the BufferedImage; this could be // a local variable. private Timer applyJobsToImageTimer; // A Timer that generates events every 1/2 second during a computation. // These events wake up the main thread so it can apply completed // jobs to the image. //-------------------------- PUBLIC CONSTRUCTOR AND METHODS ------------------------ /** * Create a display with preferred size 800-by-600. */ public MandelbrotDisplay() { setPreferredSize( new Dimension(800,600) ); setBackground(Color.LIGHT_GRAY); addComponentListener( new ComponentAdapter() { public void componentResized(ComponentEvent e) { // Stops previous timer, if any, and starts a new timer // that will go off in 1/3 second. The BufferedImage will // not be recreated until a timer actually has time to go off, // that is, 1/3 second after the last size change in a series. if (delayedResizeTimer != null) { delayedResizeTimer.stop(); delayedResizeTimer = null; } if (OSC != null) { delayedResizeTimer = new Timer(100,new ActionListener() { public void actionPerformed(ActionEvent e) { delayedResizeTimer = null; repaint(); } }); delayedResizeTimer.setInitialDelay(333); delayedResizeTimer.setRepeats(false); delayedResizeTimer.start(); } } }); applyJobsToImageTimer = new Timer(500, new ActionListener() { public void actionPerformed(ActionEvent e) { applyFinishedJobsToImage(); } }); } /** * Returns a reference to the off-screen image. It is possible for the * value to be null. (In the Mandelbrot Viewer program, this is used only * for implementing the Save Image command.) */ public BufferedImage getImage() { return OSC; } /** * Returns the current value of the STATUS property. The return value is one of * the constants MandelbrotDisplay.STATUS_READY, MandelbrotDisplay.STATUS_WORKING, * or MandelbrotDisplay.OUT_OF_MEMORY. */ public String getStatus() { return status; } /** * Set the desired range of xy-values to be visible in the image. The values * might be adjusted to reflect the aspect ration of the display. When the * limits change, a PropertyChangeEvent with property name MandelbrotDisplay.STATUS_LIMITS * is generated; the values associated with the property change are arrays. The * array is an array of double of lengthe four containing xmin, xmax, ymin, and ymax. * Note that calling this method causes a new computation to begin. * The default values for the limits are -2.5, 1.1, -1.35, 1.35. */ public void setLimits(double xmin, double xmax, double ymin, double ymax) { if (xmin == this.xmin && xmax == this.xmax && ymin == this.ymin && ymax == this.ymax) return; double[] oldLimits = { this.xmin, this.xmax, this.ymin, this.ymax }; stopComputing(); xmin_requested = xmin; xmax_requested = xmax; ymin_requested = ymin; ymax_requested = ymax; startComputing(); // Calls checkAspect, which sets new values for this.xmin, etc. repaint(); double[] newLimits = { this.xmin, this.xmax, this.ymin, this.ymax }; firePropertyChange(LIMITS_PROPERTY, oldLimits, newLimits); } /** * Return the current xy limits as an array of four doubles containing * xmin, xmax, ymin, and ymax. */ public double[] getLimits() { return new double[] { xmin, xmax, ymin, ymax }; } /** * Return the current value of xmin, the lower limit on the range of x values currently shown. */ public double getXmin() { return xmin; } /** * Return the current value of xmax, the upper limit on the range of x values currently shown. */ public double getXmax() { return xmax; } /** * Return the current value of ymin, the lower limit on the range of y values currently shown. */ public double getYmin() { return ymin; } /** * Return the current value of ymax, the upper limit on the range of y values currently shown. */ public double getYmax() { return ymax; } /** * Set the maximum number of iterations to be used in the Mandelbrot computation loop. * The default value is 50. Calling this method causes a new computation to begin. */ synchronized public void setMaxIterations( int max ) { if (max == maxIterations) return; stopComputing(); maxIterations = max; if (paletteLength == 0) palette = null; startComputing(); } /** * Returns the current maximum number of iterations to be used in the Mandelbrot computation loop. */ public int getMaxIterations() { return maxIterations; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -