jdk/test/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/spinner/JMandelbrot.java
changeset 36744 a00905527ec2
equal deleted inserted replaced
36743:bdc3f1b79fb7 36744:a00905527ec2
       
     1 /*
       
     2  * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 package com.sun.swingset3.demos.spinner;
       
    24 
       
    25 import javax.swing.*;
       
    26 import java.awt.*;
       
    27 import java.awt.event.*;
       
    28 import java.awt.geom.Point2D;
       
    29 import java.awt.image.BufferedImage;
       
    30 import java.awt.image.DataBufferInt;
       
    31 import java.util.List;
       
    32 
       
    33 import com.sun.swingset3.demos.ResourceManager;
       
    34 
       
    35 /**
       
    36  * @author Mikhail Lapshin
       
    37  */
       
    38 public class JMandelbrot extends JComponent {
       
    39 
       
    40     private static final double EPSILON = 1E-16;
       
    41     private static final int MIN_WIDTH = 50;
       
    42     private static final int MIN_HEIGHT = 50;
       
    43     private static final double ZOOM_RATE = 3;
       
    44     private static final int NUM_OF_THREADS = 4;
       
    45 
       
    46     private Point2D center;
       
    47     public static final String CENTER_PROPERTY_NAME = "center";
       
    48 
       
    49     private int maxIteration = 300;
       
    50     public static final String MAX_ITERATION_PROPERTY_NAME = "maxIteration";
       
    51 
       
    52     private Palette palette;
       
    53     public static final String PALETTE_PROPERTY_NAME = "palette";
       
    54 
       
    55     private BufferedImage buffer;
       
    56     private final MandelbrotCalculator[] calculators
       
    57             = new MandelbrotCalculator[NUM_OF_THREADS];
       
    58 
       
    59     private double xLowLimit = -2;
       
    60     private double xHighLimit = 2;
       
    61     private double yLowLimit = -2;
       
    62     private double yHighLimit = 2;
       
    63     private double xScale = 100;
       
    64     private double yScale = 100;
       
    65     private int oldComponentWidth = (int) (xScale * (xHighLimit - xLowLimit));
       
    66     private int oldComponentHeight = (int) (yScale * (yHighLimit - yLowLimit));
       
    67 
       
    68     public JMandelbrot(int width, int height, Palette palette,
       
    69             ResourceManager resourceManager) {
       
    70         setPreferredSize(new Dimension(width, height));
       
    71         setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
       
    72         calcConstants(width, height);
       
    73         setPalette(palette);
       
    74         setToolTipText(resourceManager.getString("SpinnerDemo.toolTip"));
       
    75         installListeners();
       
    76     }
       
    77 
       
    78     private void calcConstants() {
       
    79         calcConstants(getWidth(), getHeight());
       
    80     }
       
    81 
       
    82     private void calcConstants(int width, int height) {
       
    83         if ((width >= MIN_WIDTH) && (height >= MIN_HEIGHT)) {
       
    84             double oldIntervalWidth = xHighLimit - xLowLimit;
       
    85             double oldIntervalHeight = yHighLimit - yLowLimit;
       
    86             double newIntervalWidth
       
    87                     = width * oldIntervalWidth / oldComponentWidth;
       
    88             double newIntervalHeight
       
    89                     = height * oldIntervalHeight / oldComponentHeight;
       
    90             double xDiff = newIntervalWidth - oldIntervalWidth;
       
    91             double yDiff = newIntervalHeight - oldIntervalHeight;
       
    92             xLowLimit -= xDiff / 2;
       
    93             xHighLimit += xDiff / 2;
       
    94             yLowLimit -= yDiff / 2;
       
    95             yHighLimit += yDiff / 2;
       
    96             buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
       
    97             oldComponentWidth = width;
       
    98             oldComponentHeight = height;
       
    99             setCenter(calcCenter());
       
   100         }
       
   101     }
       
   102 
       
   103     private void installListeners() {
       
   104         addMouseListener(new MouseAdapter() {
       
   105             @Override
       
   106             public void mousePressed(MouseEvent e) {
       
   107                 int xCoord = e.getX();
       
   108                 int yCoord = e.getY();
       
   109                 double intervalWidth = xHighLimit - xLowLimit;
       
   110                 double intervalHeight = yHighLimit - yLowLimit;
       
   111                 double x = intervalWidth * xCoord / getWidth() + xLowLimit;
       
   112                 double y = intervalHeight * yCoord / getHeight() + yLowLimit;
       
   113 
       
   114                 double newIntervalWidth;
       
   115                 double newIntervalHeight;
       
   116                 if (e.getButton() == MouseEvent.BUTTON1) {
       
   117                     boolean limitReached = false;
       
   118                     newIntervalWidth = intervalWidth / ZOOM_RATE;
       
   119                     if ((newIntervalWidth / getWidth()) < EPSILON) {
       
   120                         newIntervalWidth = intervalWidth;
       
   121                         limitReached = true;
       
   122                     }
       
   123                     newIntervalHeight = intervalHeight / ZOOM_RATE;
       
   124                     if ((newIntervalHeight / getHeight()) < EPSILON) {
       
   125                         newIntervalHeight = intervalHeight;
       
   126                         limitReached = true;
       
   127                     }
       
   128                     if (!limitReached) {
       
   129                         xLowLimit = x - (x - xLowLimit) / ZOOM_RATE;
       
   130                         yLowLimit = y - (y - yLowLimit) / ZOOM_RATE;
       
   131                     }
       
   132                 } else {
       
   133                     newIntervalWidth = intervalWidth * ZOOM_RATE;
       
   134                     newIntervalHeight = intervalHeight * ZOOM_RATE;
       
   135                     xLowLimit = x - (x - xLowLimit) * ZOOM_RATE;
       
   136                     yLowLimit = y - (y - yLowLimit) * ZOOM_RATE;
       
   137                 }
       
   138 
       
   139                 xHighLimit = xLowLimit + newIntervalWidth;
       
   140                 yHighLimit = yLowLimit + newIntervalHeight;
       
   141 
       
   142                 setCenter(calcCenter());
       
   143 
       
   144                 xScale = getWidth() / newIntervalWidth;
       
   145                 yScale = getHeight() / newIntervalHeight;
       
   146 
       
   147                 calculatePicture();
       
   148             }
       
   149         });
       
   150 
       
   151         addComponentListener(new ComponentListener() {
       
   152             @Override
       
   153             public void componentResized(ComponentEvent e) {
       
   154                 calcConstants();
       
   155                 calculatePicture();
       
   156                 repaint();
       
   157             }
       
   158 
       
   159             @Override
       
   160             public void componentMoved(ComponentEvent e) {
       
   161             }
       
   162 
       
   163             @Override
       
   164             public void componentShown(ComponentEvent e) {
       
   165             }
       
   166 
       
   167             @Override
       
   168             public void componentHidden(ComponentEvent e) {
       
   169             }
       
   170         });
       
   171     }
       
   172 
       
   173     //<snip>Use SwingWorker to asynchronously calculate parts of the picture
       
   174     public void calculatePicture() {
       
   175         int yStep = getHeight() / NUM_OF_THREADS;
       
   176         int yStart = 0;
       
   177         for (int i = 0; i < calculators.length; i++) {
       
   178             if ((calculators[i] != null) && !calculators[i].isDone()) {
       
   179                 calculators[i].cancel(true);
       
   180             }
       
   181             int yEnd = i == calculators.length - 1 ? getHeight() : yStart + yStep;
       
   182             calculators[i] = new MandelbrotCalculator(yStart, yEnd);
       
   183             calculators[i].execute();
       
   184             yStart = yEnd;
       
   185         }
       
   186     }
       
   187     //</snip>
       
   188 
       
   189     private Point2D calcCenter() {
       
   190         return new Point2D.Double(xLowLimit + (xHighLimit - xLowLimit) / 2,
       
   191                 yLowLimit + (yHighLimit - yLowLimit) / 2);
       
   192     }
       
   193 
       
   194     @Override
       
   195     protected void paintComponent(Graphics g) {
       
   196         super.paintComponent(g);
       
   197         g.drawImage(buffer, 0, 0, null);
       
   198     }
       
   199 
       
   200     //<snip>Use SwingWorker to asynchronously calculate parts of the picture
       
   201     private class MandelbrotCalculator extends SwingWorker<Object, Object> {
       
   202 
       
   203         private final int yStart;
       
   204         private final int yEnd;
       
   205 
       
   206         public MandelbrotCalculator(int yStart, int yEnd) {
       
   207             this.yStart = yStart;
       
   208             this.yEnd = yEnd;
       
   209         }
       
   210 
       
   211         @Override
       
   212         protected Object doInBackground() throws Exception {
       
   213             int[] data = ((DataBufferInt) buffer.getRaster().getDataBuffer()).getData();
       
   214 
       
   215             double xArr[] = new double[buffer.getWidth()];
       
   216 
       
   217             for (int i = 0; i < xArr.length; i++) {
       
   218                 xArr[i] = i / xScale + xLowLimit;
       
   219             }
       
   220 
       
   221             double yArr[] = new double[yEnd - yStart];
       
   222 
       
   223             for (int i = 0; i < yArr.length; i++) {
       
   224                 yArr[i] = (yStart + i) / yScale + yLowLimit;
       
   225             }
       
   226 
       
   227             int i = yStart * buffer.getWidth();
       
   228 
       
   229             for (double y : yArr) {
       
   230                 for (double x : xArr) {
       
   231                     int value = calcValue(x, y);
       
   232 
       
   233                     data[i] = value == maxIteration ? 0 : palette.getRgbColor(value);
       
   234 
       
   235                     i++;
       
   236                 }
       
   237                 if (Thread.currentThread().isInterrupted()) {
       
   238                     return null;
       
   239                 }
       
   240                 publish();
       
   241             }
       
   242             return null;
       
   243         }
       
   244 
       
   245         private int calcValue(double x, double y) {
       
   246             double x0 = x;
       
   247             double y0 = y;
       
   248 
       
   249             for (int i = 0; i < maxIteration; i++) {
       
   250                 double x2 = x * x;
       
   251                 double y2 = y * y;
       
   252 
       
   253                 if (x2 + y2 > 4) {
       
   254                     return i;
       
   255                 }
       
   256 
       
   257                 y = 2 * x * y + y0;
       
   258                 x = x2 - y2 + x0;
       
   259             }
       
   260 
       
   261             return maxIteration;
       
   262         }
       
   263 
       
   264         @Override
       
   265         protected void process(List<Object> chunks) {
       
   266             repaint();
       
   267         }
       
   268     }
       
   269     //</snip>
       
   270 
       
   271     // Getters and Setters
       
   272     public int getMaxIteration() {
       
   273         return maxIteration;
       
   274     }
       
   275 
       
   276     public void setMaxIteration(int maxIteration) {
       
   277         int oldValue = this.maxIteration;
       
   278         this.maxIteration = maxIteration;
       
   279         firePropertyChange(MAX_ITERATION_PROPERTY_NAME, oldValue, maxIteration);
       
   280         palette.setSize(maxIteration);
       
   281     }
       
   282 
       
   283     public double getXHighLimit() {
       
   284         return xHighLimit;
       
   285     }
       
   286 
       
   287     public double getXLowLimit() {
       
   288         return xLowLimit;
       
   289     }
       
   290 
       
   291     public double getYLowLimit() {
       
   292         return yLowLimit;
       
   293     }
       
   294 
       
   295     public double getYHighLimit() {
       
   296         return yHighLimit;
       
   297     }
       
   298 
       
   299     public Point2D getCenter() {
       
   300         return center;
       
   301     }
       
   302 
       
   303     public void setCenter(Point2D coords) {
       
   304         Point2D oldValue = this.center;
       
   305         this.center = coords;
       
   306 
       
   307         double width = xHighLimit - xLowLimit;
       
   308         double height = yHighLimit - yLowLimit;
       
   309 
       
   310         xLowLimit = coords.getX() - width / 2;
       
   311         xHighLimit = xLowLimit + width;
       
   312         yLowLimit = coords.getY() - height / 2;
       
   313         yHighLimit = yLowLimit + height;
       
   314 
       
   315         firePropertyChange(CENTER_PROPERTY_NAME, oldValue, coords);
       
   316     }
       
   317 
       
   318     public Palette getPalette() {
       
   319         return palette;
       
   320     }
       
   321 
       
   322     public void setPalette(Palette palette) {
       
   323         Palette oldValue = this.palette;
       
   324         palette.setSize(maxIteration);
       
   325         this.palette = palette;
       
   326         firePropertyChange(PALETTE_PROPERTY_NAME, oldValue, palette);
       
   327     }
       
   328 }