diff options
Diffstat (limited to 'Week15 Mandelbrot/src/com')
6 files changed, 499 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..4d73434 --- /dev/null +++ b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/DrawView.java @@ -0,0 +1,167 @@ +/* + * 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.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..106c967 --- /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(MandelbrotFractal.Point p, int repetitions) { +        return MandelbrotFractal.mandelNumber(p, repetitions); +    } +     +    public int getMandelNumber(double x, double y, int repetitions) { +        return MandelbrotFractal.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..c65d99d --- /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 MandelbrotFractal fractal; +     +    public MandelbrotController(MandelbrotFractal 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..e0c0520 --- /dev/null +++ b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/MandelbrotFractal.java @@ -0,0 +1,121 @@ +/* + * 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.util.HashMap; +import java.util.Map; + +/** + * Class for calculating Mandelbrot numbers + * By remembering seen numbers, we can significantly decrease calculation time + *  + * @author Camil Staps + */ +public class MandelbrotFractal { +     +    /** +     * Storage for previously calculated numbers +     */ +    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..225347a --- /dev/null +++ b/Week15 Mandelbrot/src/com/camilstaps/mandelbrot/MandelbrotWindow.java @@ -0,0 +1,59 @@ +/* + * 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 javax.swing.JButton; +import javax.swing.JTextField; + +/** + * Solutions to week 15 + * @author Camil Staps + */ +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; +    } +     +} | 
