diff options
author | Camil Staps | 2015-06-04 22:33:05 +0200 |
---|---|---|
committer | Camil Staps | 2015-06-04 22:33:30 +0200 |
commit | 85751141b5705dba503b507ab34cc4ee734a9e6a (patch) | |
tree | 03fd9ccca1cc3af668bd2ee2b3510ba32268cb33 /Week15 Mandelbrot/src/com/camilstaps/mandelbrot | |
parent | Start week15 (diff) |
Started own version
Diffstat (limited to 'Week15 Mandelbrot/src/com/camilstaps/mandelbrot')
6 files changed, 455 insertions, 0 deletions
diff --git a/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/DrawView.java b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/DrawView.java new file mode 100644 index 0000000..16500f5 --- /dev/null +++ b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/DrawView.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2015 Camil Staps + */ +package com.camilstaps.mandelbrot; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.awt.image.WritableRaster; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Observable; +import java.util.Observer; +import javax.swing.JPanel; +import javax.swing.SwingWorker; + +/** + * + * @author camilstaps + */ +public class DrawView extends JPanel implements Observer { + + private final FractalModel fractalModel; + + private final BufferedImage image; + private final WritableRaster raster; + private final int width, height; + private static final int DEFAULT_WIDTH = 500, DEFAULT_HEIGHT = 500; + + private int pixelCounter; + private static final int COUNTER_MAX = 1000; + + private static final int REPETITIONS_MAX = 150; + + public DrawView(FractalModel fractalModel) { + this.fractalModel = fractalModel; + fractalModel.addObserver(this); + + width = DEFAULT_WIDTH; + height = DEFAULT_HEIGHT; + + image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + raster = image.getRaster(); + + setPreferredSize(new Dimension(width, height)); + + update(fractalModel, null); + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public void update(Observable o, Object o1) { + Updater task = new Updater(); + task.execute(); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + g.drawImage(image, 0, 0, null); + } + + public void setPixel(int x, int y, int[] rgb) { + raster.setPixel(x, y, rgb); + pixelCounter++; + if (pixelCounter > COUNTER_MAX) { + pixelCounter = 0; + repaint(); + } + } + + protected double getRealX(int pixel_x) { + return ((double) pixel_x * (fractalModel.getEndX() - fractalModel.getStartX()) / width) + fractalModel.getStartX(); + } + + protected double getRealY(int pixel_y) { + return ((double) pixel_y * (fractalModel.getEndY() - fractalModel.getStartY()) / height) + fractalModel.getStartY(); + } + + protected class Updater extends SwingWorker<Map<Point,Double>, Map<Point,Double>> { + private boolean doneProcessing = true; + + @Override + protected Map<Point, Double> doInBackground() throws Exception { + Map<Point,Double> results = new HashMap<>(); + + for (int repetitions = 1; repetitions < REPETITIONS_MAX; repetitions++) { + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + // Convert mandel number to some number in [0,pi] to let the colourise below work nicely + double mandel = ((double) fractalModel.getMandelNumber(getRealX(x), getRealY(y), repetitions) * Math.PI) / repetitions; + + //System.err.println("x,y : " + getRealX(x) + "," + getRealY(y) + "; " + mandel); + + Point p = new Point(x, y); + results.put(p, mandel); + } + } + + System.out.println("Rep " + repetitions); + + if (doneProcessing) { + doneProcessing = false; + publish(results); + } + setProgress(repetitions * 100 / REPETITIONS_MAX); + } + + return results; + } + + @Override + protected synchronized void process(List<Map<Point,Double>> results) { + for (Map<Point,Double> resultMap : results) { + for (Entry<Point,Double> result : resultMap.entrySet()) { + double value = result.getValue(); + + // Different mandel numbers have different colours +// int[] rgb = { +// (int) (30 + 220 * Math.sin(value)), +// (int) (30 + 220 * Math.sin(value + 2 * Math.PI / 3)), +// (int) (30 + 220 * Math.sin(value + 4 * Math.PI / 3))}; + // This is a grayscale version: + int[] rgb = {(int) (255 * value), (int) (255 * value), (int) (255 * value)}; + + setPixel(result.getKey().x, result.getKey().y, rgb); + } + } + doneProcessing = true; + } + } + + protected class Point { + int x, y; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + + @Override + public boolean equals(Object another) { + if (another == null || another.getClass() != Point.class) { + return false; + } + Point that = (Point) another; + return that.x == x && that.y == y; + } + + @Override + public int hashCode() { + return (x << 8) | y; + } + } + +} diff --git a/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/FractalModel.java b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/FractalModel.java new file mode 100644 index 0000000..184913d --- /dev/null +++ b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/FractalModel.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015 Camil Staps + */ +package com.camilstaps.mandelbrot; + +import java.util.Observable; + +/** + * + * @author camilstaps + */ +public class FractalModel extends Observable { + + private double start_x, start_y, end_x, end_y; + + public FractalModel() { + start_x = -1; + start_y = -1; + end_x = 1; + end_y = 1; + } + + public int getMandelNumber(Fractal.Point p, int repetitions) { + return Fractal.mandelNumber(p, repetitions); + } + + public int getMandelNumber(double x, double y, int repetitions) { + return Fractal.mandelNumber(x, y, repetitions); + } + + public double getStartX() { + return start_x; + } + + public double getStartY() { + return start_y; + } + + public double getEndX() { + return end_x; + } + + public double getEndY() { + return end_y; + } + + public void setStartX(double x) { + start_x = x; + notifyObservers(); + } + + public void setStartY(double y) { + start_y = y; + notifyObservers(); + } + + public void setEndX(double x) { + end_x = x; + notifyObservers(); + } + + public void setEndY(double y) { + end_y = y; + notifyObservers(); + } + +} diff --git a/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/MandelbrotController.java b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/MandelbrotController.java new file mode 100644 index 0000000..9233cc8 --- /dev/null +++ b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/MandelbrotController.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2015 Camil Staps + */ +package com.camilstaps.mandelbrot; + +/** + * + * @author camilstaps + */ +public class MandelbrotController { + + private final Fractal fractal; + + public MandelbrotController(Fractal fractal) { + this.fractal = fractal; + } + +} diff --git a/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/MandelbrotFractal.java b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/MandelbrotFractal.java new file mode 100644 index 0000000..72c3d7a --- /dev/null +++ b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/MandelbrotFractal.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015 Camil Staps + */ +package com.camilstaps.mandelbrot; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author camilstaps + */ +public class MandelbrotFractal { + + private static final Map<Point,Result> mandelNumbers = new HashMap<>(); + + public static int mandelNumber(double x, double y, int repetitions) { + Point p = new Point(x, y); + return mandelNumber(p, repetitions); + } + + public static int mandelNumber(Point p, int repetitions) { + if (mandelNumbers.containsKey(p)) { + Result result = mandelNumbers.get(p); + if (repetitions < result.repetitions || + result.mandelNumber < result.repetitions) { + return result.mandelNumber; + } else { + calculateMandelNumber(p, repetitions, result); + return result.mandelNumber; + } + } else { + Result result = calculateMandelNumber(p, repetitions); + mandelNumbers.put(p, result); + return result.mandelNumber; + } + } + + protected static Result calculateMandelNumber(Point p, int repetitions) { + Result start = new Result(); + start.x = p.x; + start.y = p.y; + calculateMandelNumber(p, repetitions, start); + return start; + } + + protected static void calculateMandelNumber(Point p, int repetitions, Result start) { + int n = start.repetitions; + + while (start.x * start.x + start.y * start.y <= 4 && n <= repetitions) { + double new_x = start.x * start.x - start.y * start.y + p.x; + start.y = 2 * start.x * start.y + p.y; + start.x = new_x; + n++; + } + + start.mandelNumber = n; + } + + public static class Point { + double x, y; + + public Point(double x, double y) { + this.x = x; + this.y = y; + } + + @Override + public boolean equals(Object another) { + if (another == null || another.getClass() != Point.class) { + return false; + } + Point that = (Point) another; + return that.x == x && that.y == y; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32)); + hash = 97 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32)); + return hash; + } + + @Override + public String toString() { + return String.format("(%f,%f)", x, y); + } + } + + protected static class Result { + int mandelNumber = -1, repetitions = -1; + double x, y; + } + +} diff --git a/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/MandelbrotWindow.java b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/MandelbrotWindow.java new file mode 100644 index 0000000..163dca9 --- /dev/null +++ b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/MandelbrotWindow.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015 Camil Staps + */ +package com.camilstaps.mandelbrot; + +import javax.swing.JButton; +import javax.swing.JTextField; + +/** + * + * @author camilstaps + */ +public class MandelbrotWindow { + + private final DrawView drawView; + + private final String INITIAL_CENTER_X = "0", + INITIAL_CENTER_Y = "0", + INITIAL_SCALE = "100", + INITIAL_REPETITIONS = "100"; + + private final JTextField field_centerX = new JTextField(INITIAL_CENTER_X, 6); + private final JTextField field_centerY = new JTextField(INITIAL_CENTER_Y, 6); + private final JTextField field_scale = new JTextField(INITIAL_SCALE, 6); + private final JTextField field_repetitions = new JTextField(INITIAL_REPETITIONS, 6); + private final JButton button_redraw = new JButton("Redraw"); + + private MandelbrotWindow() { + FractalModel fm = new FractalModel(); + drawView = new DrawView(fm); + + ZoomFrame frame = new ZoomFrame("Mandelbrot", drawView); + } + + public static void main(String[] args) { + MandelbrotWindow mw = new MandelbrotWindow(); + } + +} diff --git a/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/ZoomFrame.java b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/ZoomFrame.java new file mode 100644 index 0000000..38d16fc --- /dev/null +++ b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/ZoomFrame.java @@ -0,0 +1,67 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Camil Staps <info@camilstaps.nl> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.camilstaps.mandelbrot; + +import java.awt.Color; +import java.awt.Graphics; +import javax.swing.JFrame; + +/** + * A frame in which zooming is possible + * @author Camil Staps, s4498062 + */ +public class ZoomFrame extends JFrame { + + private Graphics graphics; + + private final DrawView drawView; + + public ZoomFrame(String s, DrawView drawView) { + super(s); + + this.drawView = drawView; + + setSize(drawView.getWidth(), drawView.getHeight()); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setResizable(false); + setLocationRelativeTo(null); + setVisible(true); + + add(drawView); + } + + /** + * Semi-singleton construction for graphics + * @return + */ + private Graphics getSafeGraphics() { + if (graphics == null) { + graphics = getGraphics(); + graphics.setXORMode(Color.white); + } + + return graphics; + } + +} |