import static util.Common.bw1;
import static util.Common.cos360;
import static util.Common.hsb360;
import static util.Common.sin360;
import static util.SVGUtil.finish;
import static util.SVGUtil.line;
import static util.SVGUtil.noFill;
import static util.SVGUtil.pageHeight;
import static util.SVGUtil.pageWidth;
import static util.SVGUtil.popMatrix;
import static util.SVGUtil.pushMatrix;
import static util.SVGUtil.rect;
import static util.SVGUtil.rulers;
import static util.SVGUtil.start;
import static util.SVGUtil.stroke;
import static util.SVGUtil.strokeOpacity;
import static util.SVGUtil.strokeWeight;
import static util.SVGUtil.translate;

public class ManyTrees {
	private static double startX, startY, width, height;
	private static int cols, rows;

	private static void CardSpec(double sx, double sy, double dx, double dy, int c, int r) {
		startX = sx; startY = sy; width = dx; height = dy;
		cols = c; rows = r;
		// sx + dx * (cols-1) + xs = 294
		// sy + dy * (rows-1) * sy = 210
	}
	
	private static void CardSpec(double sx, double sy, int c, int r) {
		CardSpec(sx, sy, (pageWidth() - sx * 2) / c , (pageHeight() - sy * 2) / r, c, r);
	}
	
	private static void drawFrame() {
		strokeWeight(0.1);
		stroke(bw1(0));
		noFill();
		rect(0, 0, width, height);
	}
	
    /* 位置     縮小率    角度  */   
    private static double[][] branches = { { 1,      0.7,       11}    // 幹
                                          , { 0.45,   0.5,      -80}    // 左の枝
                                          , { 0.55,   0.45,      75} }; // 右の枝
    
//    private static double[][] branches = { { 1,      0.7,      -11}    // 幹
//                                           { 0.45,   0.4,      -60}    // 左の枝
//                                           { 0.55,   0.45,      70} }; // 右の枝
        
    public static void generate(double ratio, int d, double x, double y, double len, double angle) {
        double x1, y1;

        if (d<=0) return;
        int color = hsb360(ratio*360 + d*7.5, 100, 100);     // ★　色相
        stroke(color);
        x1 = x + len * cos360(angle);
        y1 = y + len * sin360(angle);
        line(x, y, x1, y1);
            
        for (double[] branch : branches) {
            double r = branch[0];
            generate(ratio, d-1, x * (1 - r) + x1 * r, 
                     y * (1 - r) + y1 * r, 
                     len * branch[1], angle + branch[2]);
        }
    }

	private static void drawCard(int n, int i, int j, double ratio) {
		
		strokeOpacity(1);
//		drawFrame();			// デバッグ用
		noFill();
		pushMatrix();
		translate(width/3, 0);
		strokeWeight(1);
		strokeOpacity(0.5);
		branches[0][2] = 20 * ratio - 10;
		generate(ratio, 5 /* 再帰の深さ */, 0, 30, 12, -60);
		popMatrix();
	}

    
    public static void main(String[] args) {
		int i, j, n=0;
		double x; 
		
        start();
        rulers();                                          	 // 折りの目安線
            
        strokeWeight(0.5);
        noFill();
            
//		CardSpec(20, 28, 4, 3);    // A4 縦 3 x 横 4 の場合
		CardSpec(20, 28, 5, 4);    // A4 縦 4 x 横 5 の場合
//		CardSpec(20, 28, 6, 5);    // A4 縦 5 x 横 6 の場合
		

		x = startX;
		for (i=0; i<cols; i++) {
			double y = startY;
			for (j=0; j<rows; j++, n++) {
				pushMatrix();
				translate(x, y);
				drawCard(n, i, j, (double)n/(cols*rows));
				popMatrix();
				y += height;
			}
			x += width;
		}
        
        finish();
        return;
    }
}
