package spiro;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.imageio.stream.FileImageOutputStream;

public class Spir {
	static final int NBP = 4500, BORDER = 2, SIZE = 400, CENTER = SIZE / 2,
			Z_F = CENTER - BORDER;
	static final double C = Math.PI / NBP;

	final int[] xpoints = new int[NBP + 1], ypoints = new int[NBP + 1];
	final double d, s, zf;
	final double[] fs;
	final String defaultFilename;

	public Spir(int p, int q) {
		this(p, q, 1);
	}

	private static int gcd(int a, int b) {
		if (b == 0) {
			return a;
		}
		return gcd(b, a % b);
	}

	public Spir(int p, int q, double... fs) {
		if (!(p > q)) {
			throw new IllegalArgumentException("!p>q");
		}
		int gcd = gcd(p, q);
		this.fs = fs;
		d = 1 - (double) p / q;
		s = 2 * C * q / gcd;
		zf = Math.abs(d) + 1; // fs[fs.length - 1];
		StringBuilder sb = new StringBuilder();
		sb.append("out").append(p).append("-").append(q);
		for (double f : fs) {
			if (f > 1 || f < 0) {
				throw new IllegalArgumentException("f>1 || f<0");
			}
			sb.append("-").append(f);
		}
		sb.append(".png");
		defaultFilename = sb.toString();
	}

	@Override
	public String toString() {
		return defaultFilename;
	}

	public Spir draw(Graphics g, Color... cs) {
		for (double f : fs) {
			for (int t = 0; t <= NBP; t++) {
				xpoints[t] = (int) (Z_F * x_t(s * t, f) + CENTER);
				ypoints[t] = (int) (Z_F * y_t(s * t, f) + CENTER);
			}
			int i = 0;
			for (Color c : cs) {
				g.setColor(c);
				int from = (i * (NBP - 1)) / cs.length, to = ((i + 1) * (NBP - 1))
						/ cs.length;
				for (int k = from; k <= to; k++) {
					g.drawLine(xpoints[k], ypoints[k], xpoints[k + 1],
							ypoints[k + 1]);
				}
				i++;
			}
		}
		return this;
	}

	public static void main(String[] args) throws FileNotFoundException,
			IOException {
		BufferedImage bimage = new BufferedImage(SIZE, SIZE,
				BufferedImage.TYPE_INT_RGB);
		ImageIO.write(bimage, "png", new FileImageOutputStream(new File(
				draw3(bimage.createGraphics()))));
	}

	public static String draw1(Graphics g) {
		g.setColor(new Color(250, 250, 250));
		g.fillRect(0, 0, SIZE, SIZE);
		Spir sp = new Spir(105, 52, 0.72).draw(g, new Color(200, 50, 120),
				new Color(200, 120, 50), new Color(50, 120, 200));
		return sp.toString();
	}

	public static String draw2(Graphics g) {
		g.setColor(new Color(240, 240, 240));
		g.fillRect(0, 0, SIZE, SIZE);
		return new Spir(96, 60, .6, .7, .8, .9).draw(g, new Color(240, 50, 70))
				.toString();
	}

	public static String draw3(Graphics g) {
		g.setColor(new Color(245, 245, 235));
		g.fillRect(0, 0, SIZE, SIZE);
		return new Spir(96, 64, .1, .8, .14, .22, .28, .34, .4, .5, .56, .62,
				.68, .74, .8, .86, .92).draw(g, new Color(150, 150, 150))
				.toString();
	}

	public double x_t(double t, double f) {
		return (d * Math.sin(t) - f * Math.sin(d * t)) / zf;
	}

	public double y_t(double t, double f) {
		return (d * Math.cos(t) - f * Math.cos(d * t)) / zf;
	}

}


syntax highlighted by Code2HTML, v. 0.9.1