Processing: サトクリフ五角形サンプルのリファクタリング
マット・ピアソン著『ジェネラティブ・アート Processingによる実践ガイド』「Chapter 8 フラクタル」に出てくる「サトクリフ五角形」のサンプルコードがどうも冗長なのでリファクタリングしてみた。特に、数学的に無意味な条件分岐を整理したら随分すっきりした。
サトクリフ五角形
int _maxlevels = 5; float _strutFactor = 0.2; void setup() { size(800, 800); //オリジナルはsize(1000, 1000); smooth(); FractalRoot pentagon = new FractalRoot(); pentagon.drawShape(); } class PointObj { float x, y; PointObj(float ex, float ey) { x = ex; y = ey; } } class FractalRoot { Branch rootBranch; FractalRoot() { float centerX = width/2; float centerY = height/2; PointObj[] points = new PointObj[5]; int radius = 400; int apex = 0; for (int angle = 0; angle < 360; angle += 72) { float x = centerX + (radius * cos(radians(angle))); float y = centerY + (radius * sin(radians(angle))); points[apex] = new PointObj(x, y); apex++; } rootBranch = new Branch(0, 0, points); } void drawShape() { rootBranch.drawMe(); } } class Branch { int level, num; PointObj[] outerPoints = {}; PointObj[] midPoints = {}; PointObj[] projPoints = {}; Branch[] myBranches = {}; Branch(int lev, int n, PointObj[] points) { level = lev; num = n; outerPoints = points; midPoints = calcMidPoints(); projPoints = calcStrutPoints(); if ((level + 1) < _maxlevels) { Branch childBranch = new Branch(level + 1, 0, projPoints); myBranches = (Branch[])append(myBranches, childBranch); for (int apex = 0; apex < outerPoints.length; apex++) { int nextApex = apex - 1; if (nextApex < 0) { nextApex += outerPoints.length; } PointObj[] newPoints = { projPoints[apex], midPoints[apex], outerPoints[apex], midPoints[nextApex], projPoints[nextApex] }; childBranch = new Branch(level + 1, apex + 1, newPoints); myBranches = (Branch[])append(myBranches, childBranch); } } } void drawMe() { strokeWeight(5 - level); drawOuter(); strokeWeight(0.5); drawMid(); drawBranch(); } void drawOuter() { for (int apex = 0; apex < outerPoints.length; apex++) { int nextApex = apex + 1; if (nextApex == outerPoints.length) { nextApex = 0; } line(outerPoints[apex].x, outerPoints[apex].y, outerPoints[nextApex].x, outerPoints[nextApex].y); } } void drawMid() { for (int apex = 0; apex < midPoints.length; apex++) { line(midPoints[apex].x, midPoints[apex].y, projPoints[apex].x, projPoints[apex].y); } } void drawBranch() { for (int apex = 0; apex < myBranches.length; apex++) { myBranches[apex].drawMe(); } } PointObj[] calcMidPoints() { PointObj[] points = new PointObj[outerPoints.length]; for (int apex = 0; apex < outerPoints.length; apex++) { int nextApex = apex + 1; if (nextApex == outerPoints.length) { nextApex = 0; } PointObj midPoint = calcMidPoint(outerPoints[apex], outerPoints[nextApex]); points[apex] = midPoint; } return points; } PointObj calcMidPoint(PointObj point1, PointObj point2) { float mx, my; mx = calcMid(point1.x, point2.x); my = calcMid(point1.y, point2.y); return new PointObj(mx, my); } float calcMid(float a, float b) { return a + ((b - a) / 2); } PointObj[] calcStrutPoints() { PointObj[] points = new PointObj[midPoints.length]; for (int point = 0; point < midPoints.length; point++) { int nextPoint = point + 3; if (nextPoint >= midPoints.length) { nextPoint -= midPoints.length; } PointObj strPoint = calcProjPoint(midPoints[point], outerPoints[nextPoint]); points[point] = strPoint; } return points; } PointObj calcProjPoint(PointObj mp, PointObj op) { float px, py; px = mp.x - ((mp.x - op.x) * _strutFactor); py = mp.y - ((mp.y - op.y) * _strutFactor); return new PointObj(px, py); } }