📄 mandelbrotdisplay.java
字号:
/** * Set the type of palette that is used to color the pixels to one of the constants * MandelbrotDispaly.PALETTE_SPECTRUM, MandelbrotDispaly.PALETTE_PALE_SPECTRUM, * MandelbrotDispaly.PALETTE_GRAYSCALE, or MandelbrotDispaly.PALETTE_REVERSE_GRAYSCALE. * Other values for the parameter will be ignored. The new palette is applied * immediately. If a computation is underway, the palette is applied to the part * of the image that has been computed and the computation continues. Note that * this method CANNOT be used to set a gradient palette. */ synchronized public void setPaletteType(int type) { if (type == paletteType) return; if (type != PALETTE_SPECTRUM && type != PALETTE_PALE_SPECTRUM && type != PALETTE_GRAYSCALE && type != PALETTE_REVERSE_GRAYSCALE) return; gradientPaletteColor1 = gradientPaletteColor2 = null; paletteType = type; palette = null; // Forces computation of a new palette. recomputeColors(); // Applies new palette to the image, or the part that has been computed. } /** * Set the type of palette that is used to color the pixels to be a gradient palette * (paletteType = MandelbrotDisplay.PALETTE_GRADIENT), and specify the start and end * colors for the gradient. The new palette is applied * immediately. If a computation is underway, the palette is applied to the part * of the image that has been computed and the computation continues. * @param color1 start color for gradient; if null, the call to this method is ignored. * @param color2 end color for gradient; if null, the call to this method is ignored. */ synchronized public void setGradientPalette(Color color1, Color color2) { if (paletteType == PALETTE_GRADIENT && gradientPaletteColor1.equals(color1) && gradientPaletteColor2.equals(color2)) return; if (color1 == null || color2 == null) return; paletteType = PALETTE_GRADIENT; gradientPaletteColor1 = color1; gradientPaletteColor2 = color2; palette = null; // Forces computation of a new palette. recomputeColors(); // Applies new palette to the image, or the part that has been computed. } /** * Returns the current palette type, one of the constants MandelbrotDisplay.PALETTE_GRADIENT, * MandelbrotDisplay.PALETTE_SPECTRUM, MandelbrotDisplay.PALETTE_PALE_SPECTRUM, * MandelbrotDisplay.PALETTE_GRAYSCALE, or MandelbrotDisplay.PALETTE_REVERSE_GRAYSCALE. */ public int getPaletteType() { return paletteType; } /** * If the current palette type is MandelbrotDispaly.PALETTE_GRADIENT, this returns * the start color of the gradient. If one of the other types of palettes is being * used, the return value is null. */ public Color getGradientPaletteColor1() { return gradientPaletteColor1; } /** * If the current palette type is MandelbrotDispaly.PALETTE_GRADIENT, this returns * the end color of the gradient. If one of the other types of palettes is being * used, the return value is null. */ public Color getGradientPaletteColor2() { return gradientPaletteColor2; } /** * Set the palette lengths. If the length is set to 0, then the palette length will * always be set to be the same as maxIterations. That is, there will be one color * for each possible value of the iteration count. If it is set to some positive * value, that that number of colors is used. When the number of colors in the * palette is smaller than maxIterations, the palette will be repeated as many times * as necessary to cover the full range of values; this makes the colors vary faster * as the interation count changes, which can reveal a greater range of colors * in the image. When the number of colors in the palette is larger than maxIterations, * the effect is to make the colors vary more slowly. If a computation is in progress * when this method is called, the change is applied immediately to the part of the * image that has been computed, and the computation continues. */ synchronized void setPaletteLength(int length) { if (length <= 0) length = 0; if (length == paletteLength) return; paletteLength = length; palette = null; // Force construction of new palette. recomputeColors(); // Apply new palette to image. } /** * Return the current value of paletteLength. */ public int getPaletteLength() { return paletteLength; } /** * Used to draw a rectangle around a portion of the image. If the parameter is null, * then nothing is drawn (and the rect that was there before, if any is removed). * Otherwise, the specified rectangle will be drawn on top of the image. */ public boolean drawZoomBox(Rectangle rect) { if (zoomBox != null) repaint( zoomBox.x - 1, zoomBox.y - 1, zoomBox.width + 3, zoomBox.height + 3); if (OSC == null) { zoomBox = null; return false; } zoomBox = rect; if (zoomBox != null) repaint( zoomBox.x - 1, zoomBox.y - 1, zoomBox.width + 3, zoomBox.height + 3); return true; } /** * If a rectangle has been specified using the drawZoomBox, this method will zoom the * image into or out of the box. The rectangle is then discarded. If there is no * zoom box, nothing isdone. * @param zoomOut if false, the part of the image inside the zoom rectangle is magnified * to fill the entire image; if true, the entire image is shrunk down to fit inside * the zoom box and new parts of the picture become visible. */ public void applyZoom(boolean zoomOut) { if (zoomBox == null) return; if (zoomBox.width == 0 || zoomBox.height == 0) { zoomBox = null; repaint(); return; } double x1, x2, y1, y2; // coordinates of corners of zoombox double cx, cy; // coordinates of center of zoombox double newWidth, newHeight; x1 = xmin + ((double)zoomBox.x)/getWidth()*(xmax-xmin); x2 = xmin + ((double)(zoomBox.x+zoomBox.width))/getWidth()*(xmax-xmin); y1 = ymax - ((double)zoomBox.y+zoomBox.height)/getHeight()*(ymax-ymin); y2 = ymax - ((double)(zoomBox.y))/getHeight()*(ymax-ymin); cx = (x1+x2)/2; cy = (y1+y2)/2; if (zoomOut) { // (some heavy math) double newXmin = xmin + (xmin-x1)/(x2-x1)*(xmax-xmin); double newXmax = xmin + (xmax-x1)/(x2-x1)*(xmax-xmin); double newYmin = ymin + (ymin-y1)/(y2-y1)*(ymax-ymin); double newYmax = ymin + (ymax-y1)/(y2-y1)*(ymax-ymin); setLimits(newXmin,newXmax,newYmin,newYmax); } else { newWidth = x2 - x1; newHeight = y2 - y1; setLimits( cx-newWidth/2, cx+newWidth/2, cy-newHeight/2, cy+newHeight/2 ); } zoomBox = null; } /** * This method can be called to tell all the threads that are used by the display * to terminate cleanly. This method should be called only when the display is * being discarded. It is not usually necessary to call this method. It might * allow a cleaner shutdown if the program is being run as an applet. * */ synchronized public void shutDownThreads() { shutDown = true; notifyAll(); } /** * Draws the image onto the screen. (This, of course, is meant to be called * by the system, not by the user.) */ public void paintComponent(Graphics g) { if (delayedResizeTimer != null) { // If a resize times is running, don't resize the image, just show the one we have, if any. super.paintComponent(g); if (OSC != null) g.drawImage(OSC, 0, 0, null); zoomBox = null; } else { checkOSC(); if (OSC == null) { // Could not create the data structures; show an error message. super.paintComponent(g); g.setColor(Color.RED); g.drawString(I18n.tr("error.memory"),20,50); zoomBox = null; } else { g.drawImage(OSC, 0, 0, null); if (zoomBox != null) { // A zoom box has been specified by the drawZoomBox() method, so draw it. g.setColor(Color.WHITE); g.drawRect(zoomBox.x-1, zoomBox.y-1, zoomBox.width+2, zoomBox.height+2); g.setColor(Color.BLACK); g.drawRect(zoomBox.x, zoomBox.y, zoomBox.width, zoomBox.height); g.setColor(Color.WHITE); g.drawRect(zoomBox.x+1, zoomBox.y+1, zoomBox.width-2, zoomBox.height-2); } } } } //-------------------------- PRIVATE METHODS (and private nested classes) ----------------------- /** * Used internally to set the current status. Note that when the status is * changed, a PropertyChangeEvent with property name MandelbrotDisplay.STATUS_PROPERTY * is fired. */ private void setStatus(String status) { if (status == this.status) return; String oldStatus = this.status; this.status = status; firePropertyChange(STATUS_PROPERTY, oldStatus, status); } /** * Called by the paintComponent method to check whehter a new off-screen canvas * is needed. (This is a separate method mainly because it needs to be synchronized). */ synchronized private void checkOSC() { if (OSC == null || OSC.getWidth() != getWidth() || OSC.getHeight() != getHeight()) { stopComputing(); // Abort current computation -- it only applied to the old canvas. OSC = null; // Free up memory currently used bby OSC so it can be reused. iterationCounts = null; // Free up memory currently used by iterationCounts, so it can be reused. try { int width = getWidth(); int height = getHeight(); OSC = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); iterationCounts = new int[height][width]; // Note that first index is pixel row number. rgb = new int[width]; imageWidth = width; startComputing(); } catch (OutOfMemoryError e) { // It was not possible to create all the memory that we need. // No image can be displayed. The paintComponent method will show an error message. OSC = null; iterationCounts = null; setStatus(STATUS_OUT_OF_MEMORY); } } } /** * This is the method that is called periodically (in response to a timer event) * to check the queue of finished jobs. All finished jobs are removed from the * queue and are applied to the image. */ synchronized void applyFinishedJobsToImage() { ArrayList<Job> temp; synchronized(this) { if (finishedJobs == null) return; // First, get the jobs from the queue; has to be done in synchronized part of the method. temp = new ArrayList<Job>(); while (!finishedJobs.isEmpty()) temp.add(finishedJobs.removeFirst()); } // Now apply the data from the jobs to the image; this doesn't have to be synchronized // since this method is the only one that touches the image. for (Job job : temp) { iterationCounts[job.rowNumber] = job.iterationCounts; if (palette == null) createPalette(); for (int i = 0; i < imageWidth; i++) rgb[i] = getColorForIterationCount(job.iterationCounts[i]); OSC.setRGB(0, job.rowNumber, imageWidth, 1, rgb, 0, imageWidth); repaint(0,job.rowNumber,imageWidth,1); } } /** * Get the correct color from the palette to color a point with the given * interation count. */ private int getColorForIterationCount(int ct) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -