import java.io.*; public class Mandel { static class Complex { final double real, imag; Complex(double r, double i) { real = r; imag = i; } Complex add(Complex y) { return new Complex(real + y.real,imag + y.imag); } Complex mul(Complex y) { return new Complex(real * y.real - imag * y.imag, real * y.imag + imag * y.real); } double absq() { return real * real + imag * imag; } } static class HSV { double h, s, v; HSV(double h, double s, double v) { this.h = h; this.s = s; this.v = v; } int hi() { return (int)Math.floor(h / 60) % 6; } double f() { return h / 60 - hi(); } double p() { return (1 - s) * v; } double q() { return (1 - f() * s) * v; } double t() { return (1 - ((1 - f()) * s)) * v; } byte[] makeRGB(double r, double g, double b) { byte[] ret = new byte[3]; ret[0] = (byte)(r * 255); ret[1] = (byte)(g * 255); ret[2] = (byte)(b * 255); return ret; } byte[] toRGB() { int h = hi(); switch(h) { case 0: return makeRGB(v,t(),p()); case 1: return makeRGB(q(),v,p()); case 2: return makeRGB(p(),v,t()); case 3: return makeRGB(p(),q(),v); case 4: return makeRGB(t(),p(),v); default: return makeRGB(v,p(),q()); } } } static final int width = 640; static final int height = 480; static final int maxColor = 360; static final int maxIterations = 40; static final double zoomFact = 0.8; static final double center = -0.65; static final double xInc = width / (200000 * zoomFact); static final double yInc = height / (150000 * zoomFact); static final double sat = 0.85; static final double val = 0.85; static byte[][] makeColorMap(int nbCols) { byte[][] out = new byte[nbCols][]; for(int i = 0; i < nbCols; i++) out[i] = new HSV((360.0 * i) / (nbCols + 1),sat,val).toRGB(); return out; } static byte[][] colorMap = makeColorMap(Math.min(maxIterations,maxColor)); static Complex c(int i, int j) { return new Complex(xInc * i + center - xInc * width / 2, yInc * j - yInc * height / 2); } static int pixel(Complex c) { Complex z = new Complex(0.0,0.0); for(int i = maxIterations; i >= 0; i--) { z = z.mul(z).add(c); if(z.absq() >= 4.0) return i; } return -1; } static byte[] black = new byte[] { 0,0,0 }; static byte[] color(int iterations) { if(iterations == -1) return black; else return colorMap[iterations % colorMap.length]; } static void render(OutputStream out) throws IOException { for(int j = 0; j < height; j++) for(int i = 0; i < width; i++) out.write(color(pixel(c(i,j)))); } static void writePPMHeader(OutputStream out) throws IOException { out.write("P6\n".getBytes("ASCII")); out.write(Integer.toString(width).getBytes("ASCII")); out.write(" ".getBytes("ASCII")); out.write(Integer.toString(height).getBytes("ASCII")); out.write("\n255\n".getBytes("ASCII")); } static void run() throws IOException { BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream("out.ppm")); try { writePPMHeader(out); render(out); } finally { out.close(); } } public static void main(String[] args) throws IOException { for(int i = 0; i < 20; i++) { long start = System.currentTimeMillis(); run(); System.out.println(System.currentTimeMillis() - start); } } }