第8章 8.1 自己相似図形 【リスト8-1】 アフィン変換等のクラス定義(ファイル名をaffinTran.pyとする) import math class affine:#アフィン変換 def __init__(self,Nxx=1, Nxy=0, Nxo=0, Nyx=0, Nyy=1, Nyo=0): self.xx = Nxx; self.yy = Nyy self.xy = Nxy; self.yx = Nyx self.xo = Nxo; self.yo = Nyo def scale(self, a, b=0):#スケール if b==0: return affine(self.xx * a, self.xy * a, self.xo * a, self.yx * a, self.yy * a, self.yo * a) else : return affine(self.xx * a, self.xy * a, self.xo * a, self.yx * b, self.yy * b, self.yo * b) def shift(self, a, b):#移動 return affine(self.xx, self.xy, self.xo + a, self.yx, self.yy, self.yo + b) def rotate(self, theta):#回転 ct = math.cos(theta); st = math.sin(theta); return affine(self.xx * ct - self.yx * st, self.xy * ct - self.yy * st, self.xo * ct - self.yo * st, self.yx * ct + self.xx * st, self.yy * ct + self.xy * st, self.yo * ct + self.xo * st) def __mul__(self, m):#乗算の定義 return affine(self.xx * m.xx + self.yx * m.xy, self.xy * m.xx + self.yy * m.xy, self.xo * m.xx + self.yo * m.xy + m.xo, self.xx * m.yx + self.yx * m.yy , self.xy * m.yx + self.yy * m.yy , self.xo * m.yx + self.yo * m.yy + m.yo) def det(): return self.xx*self.yy - self.xy*self.yx class coordinate:#座標変換 def __init__(self,x=0, y=0, Left=-0.5,Right=1.5,Bottom=-1,Top=1.5): self.x=x; self.y=y; self.left=Left;self.right=Right self.bottom=Bottom;self.top=Top def transformed(self, p, m): return coordinate(p.x * m.xx + p.y * m.xy + m.xo, p.x * m.yx + p.y * m.yy + m.yo) def scXY(self,SC,X0=0,Y0=0): w=[0 for i in range(2)] w[0]=int(SC*(self.x-self.left)/(self.right-self.left)+0.5+X0) w[1]=int(SC*(self.y-self.top)/(self.bottom-self.top)+0.5+Y0) #print(w[0],w[1], self.x, self.y,self.left,self.top) return w def colorValue(DT):#カラーのRGB値の範囲に収める ii=int(255*DT) if ii<0: return 0 if ii>255: return 255 return ii 【リスト8-2】 アフィン変換による簡単な例題 from tkinter import * import math from affinTran import * Nmax=8; SC=200; X0=-40; Y0=50 f1=affine(1/2, 0.0, 0, 0.0, 1/2, 0) f2=affine(1/2, 0.0, 1, 0.0, 1/2, 0) f3=affine(1/2, 0.0, 1/2, 0.0, 1/2, 1.0) origin=coordinate() def drawTran(t): global origin, canvas, SC, X0, Y0 w =coordinate().transformed(origin,t).scXY(SC, X0, Y0) #canvas.create_rectangle(w[0], w[1],w[0]+5, w[1]+5,fill="red") canvas.create_rectangle(w[0], w[1],w[0], w[1],fill="#FF0000",outline="") def trans(n,t): global f1,f2, f3, Nmax if n>Nmax: drawTran(t) else : trans(n+1, f1 * t) trans(n+1, f2 * t) trans(n+1, f3 * t) def paint(canvas): trans(0,affine()) root=Tk();root.title("Similarity Transformation") canvas=Canvas(root, width=220,height=198,bg="white") canvas.pack() paint(canvas) root.update() root.mainloop() 8.2 おなじみのフラクタル 【リスト8-3】 コッホ曲線 from tkinter import * import math from affinTran import * #■データ設定 Nmax=10; SC=400; X0=-90; Y0=-120 m6=math.pi/6; s3=1/math.sqrt(3) f1=affine().scale(1,-1).rotate(m6).scale(s3) f2=affine().shift(-1, 0).rotate(m6).scale(1, -1).scale(s3).shift(1, 0) #---------データ設定ここまで #■座標変換設定 origin=coordinate(0,0) #■アフィン行列表示関数 def printf(pstr, f): print(pstr) print(" %12.4f, %12.4f, %12.4f" % (f.xx, f.xy, f.xo)) print(" %12.4f, %12.4f, %12.4f" % (f.yx, f.yy, f.yo)) #■アフィン行列表示 printf("f1", f1) printf("f2", f2) #---------アフィン行列表示ここまで #■点の描画 def drawTran(t, r, g, b): global origin, canvas, SC, X0, Y0 w =coordinate().transformed(origin,t).scXY(SC, X0, Y0) C="#%02X%02X%02X" % (colorValue(r), colorValue(g), colorValue(b)) canvas.create_rectangle(w[0], w[1],w[0], w[1],fill=C,outline="") #■縮小変換 def trans(n, t, r, g, b): global f1,f2, Nmax if n>Nmax: drawTran(t, r, g, b) else : m=math.pow(2, -n) trans(n+1, f1 * t, r+m, g, b) trans(n+1, f2 * t, r, g, b+m) def paint(canvas): trans(0,affine(), 0,0,0) #■メイン処理 root=Tk();root.title("Similarity Transformation") canvas=Canvas(root, width=220,height=198,bg="white"); canvas.pack() paint(canvas); root.update() root.mainloop() 【リスト8-4】 (リスト8-3のデータ設定部分だけを入れ換えます) Nmax=13; SC=100; X0=60; Y0=80 p4=math.pi / 4; s2=1/math.sqrt(2) f1=affine().rotate(p4).scale(s2) f2=affine().shift(1, 0).rotate(p4).scale(s2).shift(1, 0) 【リスト8-5】 (リスト8-3のデータ設定部分だけを入れ換えます) Nmax=14; SC=100; X0=40; Y0=80 p4=math.pi / 4; s2=1/math.sqrt(2) f1=affine().rotate(p4).scale(s2) f2=affine().shift(-1,-1).rotate(-p4).scale(s2).shift(2.0, 1.0) 【リスト8-6】 (リスト8-3のデータ設定/再帰呼出し部分を入れ換え, f3表示部分を追加します) Nmax=7; SC=200; X0=-40; Y0=40 s3=math.sqrt(3)/2 f1=affine().scale(1/2) f2=affine().scale(1/2).shift(1, 0) f3=affine().scale(1/2).shift(1/2, s3) (f3表示部分:追加) printf("f3", f3) (再帰呼出し) m=r+math.pow(2, -n) trans(n+1, f1 * t, r, g, b) trans(n+1, f2 * t, r, g, b+m) trans(n+1, f3 * t, r, g+m, b) 【リスト8-7】 (リスト8-3のデータ設定/再帰呼出し部分を入れ換え, f3表示部分を追加します) Nmax=4; SC=100; X0=10; Y0=100 f1=affine().scale(1/3); f2= f1.shift(1,0); f3= f1.shift(2,0) f4=f1.shift(0,1); f5=f1.shift(2,1) f6=f1.shift(0,2); f7=f1.shift(1,2); f8=f1.shift(2,2) (f3~f8表示部分:追加) printf("f3", f3); printf("f4", f4) printf("f5", f5); printf("f6", f6) printf("f7", f7); printf("f8", f8) (再帰呼出し) m=math.pow(2, -n) trans(n+1, f1 * t, r+m, g , b ) trans(n+1, f2 * t, r , g+m, b ) trans(n+1, f3 * t, r , g , b+m) trans(n+1, f4 * t, r , g+m, b+m) trans(n+1, f5 * t, r+m, g+m, b ) trans(n+1, f6 * t, r+m, g , b+m) trans(n+1, f7 * t, r , g , b+m) trans(n+1, f8 * t, r , g+m, b ) (canvas定義部分) canvas(root, width=220,height=198,bg="black") 8.3 特徴的なフラクタル   【リスト8-8】 葉模様(その1) from tkinter import * import math from affinTran import * #■データ設定部分 Nmax=13; SC=350; X0=-60; Y0=-100 f1=affine().scale(1/math.sqrt(2)).rotate(math.pi / 8) f2=affine().shift(-1, 0).scale(1,-1).scale(2/3).shift(1, 0) #■座標変換定義 origin=coordinate() #■アフィン行列表示関数 def printf(pstr, f): print(pstr) print(" %12.4f, %12.4f, %12.4f" % (f.xx, f.xy, f.xo)) print(" %12.4f, %12.4f, %12.4f" % (f.yx, f.yy, f.yo)) #■アフィン変換行列表示 printf("f1", f1) printf("f2", f2) #■点の描画 def drawTran(t, r, g, b): global origin, canvas, SC, X0, Y0 w =coordinate().transformed(origin,t).scXY(SC, X0, Y0) C="#%02X%02X%02X" % (colorValue(r), colorValue(g), colorValue(b)) canvas.create_rectangle(w[0], w[1],w[0], w[1],fill=C,outline="") #■縮小変換による描画 def trans(n, t, r, g, b): global f1,f2, Nmax if n>Nmax: drawTran(t, r, g, b) else :#再帰呼出し部 m=math.pow(2, -n) trans(n+1, f1 * t, r+m, g , b) trans(n+1, f2 * t, r , g+m, b) #■描画メイン def paint(canvas): trans(0,affine(), 0,0,0) #■メイン処理 root=Tk();root.title("Similarity Transformation") canvas=Canvas(root, width=220,height=198,bg="black"); canvas.pack() paint(canvas) root.update();root.mainloop() 【リスト8-9】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax =13; SC=400; X0=-85; Y0=-150 f1=affine().scale(1/math.sqrt(3)).rotate(math.pi / 8) f2=affine().shift(-1, 0).scale(1,-1).scale(2/3).shift(1, 0) 【リスト8-10】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=13; SC=400; X0=-90; Y0=-150 f1=affine().scale(1,-1).scale(1/math.sqrt(3)).rotate(math.pi / 8) f2=affine().shift(-1, 0).scale(1,-1).scale(2/3).shift(1, 0) 【リスト8-11】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=13; SC=300; X0=-10; Y0=-90 f1=affine().scale(1/math.sqrt(2)).rotate(math.pi /3) f2=affine().shift(-1, -1).scale(1,-1).scale(2/3).shift(1, -1) 【リスト8-12】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=13; SC=350; X0=-50; Y0=-120 f1=affine().scale(1/2).rotate(math.pi /3) f2=affine().shift(-1, -1).scale(1,-1).scale(0.85).shift(1, -1) 【リスト8-13】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=13; SC=300; X0=-20; Y0=-80 f1=affine().scale(0.7).rotate(math.pi /6) f2=affine().shift(-1, -1).scale(1,-1).scale(0.75).shift(1, -1) 【リスト8-14】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=13; SC=150; X0=-100; Y0=20 f1=affine( 0.5, 0.3, 0.5, 0.0, -0.6, 0.2) f2=affine( 0.6, 0.5, 1.0, 0.4, -0.6, 0.0) 【リスト8-15】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=12; SC=100; X0=130; Y0=50 f1=affine( 0.45, 0.66, -0.5, 0.66, -0.45, -0.5) f2=affine(-0.45, 0.50, 0.5, -0.20, -0.45, 0.5) 【リスト8-16】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=14; SC=120; X0=50; Y0=80 f1=affine( 0.67, -0.5, 0.5, 0.5, 0.67, 0.5) f2=affine(-0.25, 0.5, 0.5, -0.5, -0.25, 0.5) 【リスト8-17】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=12; SC=150; X0=40; Y0=20 f1=affine(0.45, 0.5, -0.1, 0.5, -0.45, -0.5) f2=affine(0.45, 0.5, 0.1, 0.5, -0.45, 0.5) 8.4 その他のフラクタル 【リスト8-18】 (データ設定部分のみ。他は【リスト8-8】と同じ) f1=affine(0.45, 0.0, 0.0, 0.0, -0.5, 0.0) f2=affine(0.45, 0.0, 0.5, 0.0, -0.5, 0.5) 【リスト8-19】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=12; SC=150; X0=80; Y0=20 f1=affine( 0.45, -0.5, 0, -0.45, -0.5, 0.00) f2=affine( 0.45, 0.5, 0, -0.45, 0.5, 0.75) 【リスト8-20】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=12; SC=300; X0=0; Y0=0 f1=affine(0.6, 0.0, 0.0, 0.0, 0.6, 0.0) f2=affine(0.5, -0.5, 0.5, 0.5, 0.5, 0.5) 【リスト8-21】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=12; SC=250; X0=0; Y0=10 f1=affine( 0.5, 0.3, 0, -0.3, 0.5, 0) f2=affine( 0.5, -0.5, 0.5, 0.5, 0.5, 0.5) 【リスト8-22】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=12; SC=300; X0=10; Y0=-50 f1=affine(0.45, 0.5, 0.0, -0.5, 0.45, 0.0) f2=affine(0.45, 0.5, 0.0, -0.5, 0.45, 0.5) 【リスト8-23】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=12; SC=300; X0=10; Y0=-70 f1=affine( 0.67, 0.5, 0.0, -0.5, 0.67, 0.0) f2=affine(-0.25, 0.5, 0.5, -0.5, -0.25, 0.5) 【リスト8-24】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=14; SC=70; X0=80; Y0=80 f1=affine(0.8, -0.5, 0.2, 0.5, 0.8, 0.2) f2=affine(0.6, 0.4, 0.8, -0.4, 0.6, 0.2) 【リスト8-25】 (データ設定部分のみ。他は【リスト8-8】と同じ) Nmax=12; SC=150; X0=-50; Y0=10 f1=affine( 0.9, 0.4, 0.5, -0.2, 0.5, 0.1) f2=affine( 0.4, -0.4, 0.5, 0.3, 0.5, 0.0) 【リスト8-26】 (データ設定と再帰呼出し部のみ。他は【リスト8-8】と同じ) (データ設定) Nmax=12; SC=150; X0=-50; Y0=10 f1=affine( 0.9, 0.4, 0.5, -0.2, 0.5, 0.1) f2=affine( 0.4, -0.4, 0.5, 0.3, 0.5, 0.0) (再帰呼出し部) m=math.pow(2, -n)/2 trans(n+1, f1 * t, r , g+m, b) trans(n+1, f2 * t, r, g , b) trans(n+1, f3 * t, r+m, g , b) trans(n+1, f4 * t, r+m, g +m, b) 【リスト8-27】 (データ設定のみ。再帰呼出し部は【リスト8-26】と同じ。他は【リスト8-8】と同じ) (データ設定) Nmax=12; SC=150; X0=-50; Y0=10 f1=affine( 0.9, 0.4, 0.5, -0.2, 0.5, 0.1) f2=affine( 0.4, -0.4, 0.5, 0.3, 0.5, 0.0) 【リスト8-28】 (データ設定のみ。再帰呼出し部は【リスト8-26】と同じ。他は【リスト8-8】と同じ) (データ設定) Nmax=6; SC=500; X0=-150; Y0=-100 f1=affine( 0.36, 0.36, 0.4, -0.36, 0.36, 0.4) f2=affine( 0.8, 0.0, 0.10, 0.0, 0.8, 0.04) f3=affine( 0.36,-0.36, 0.3, 0.36, 0.36, 0.08) f4=affine( 0.5, 0.0, 0.25, 0.0, 0.5, 0.4) 【リスト8-29】 (データ設定と再帰呼出し部のみ。他は【リスト8-8】と同じ) (データ設定) Nmax=5; SC=200; X0=-10; Y0=-20 s2=math.sqrt(2)/2; f1=affine().scale(1/3) f2=f1.shift(1,0); f3=f1.shift(0.5,s2); f4=f1.shift(0.5,-s2) (再帰呼出し部) m=math.pow(2, -n) trans(n+1, f1 * t, r+m, g, b) trans(n+1, f2 * t, r, g+m, b) trans(n+1, f3 * t, r, g, b+m) trans(n+1, f4 * t, r, g+m, b+m) 【リスト8-30】 (データ設定と再帰呼出し部のみ。他は【リスト8-8】と同じ) (データ設定) Nmax=5; SC=400; X0=-90; Y0=-60 f1=affine().scale(1/3).shift(1/3,1/3) f2=f1.shift(0,1/3); f3=f1.shift(0,-1/3) f4=f1.shift(1/3,0); f5=f1.shift(-1/3,0) (再帰呼出し部) m=math.pow(2, -n) trans(n+1, f1 * t, r+m, g , b ) trans(n+1, f2 * t, r , g+m, b ) trans(n+1, f3 * t, r , g , b+m) trans(n+1, f4 * t, r , g+m, b+m) trans(n+1, f5 * t, r+m, g+m, b ) 【リスト8-31】 (データ設定と再帰呼出し部のみ。他は【リスト8-8】と同じ) (データ設定) Nmax=5; SC=200; X0=60; Y0=60 f1=affine( 0.05, 0.0, 0.0, 0.0, 0.6, 0.0) f2=affine( 0.05, 0.0, 0.0, 0.0, -0.5, 1.0) f3=affine( 0.46, -0.32, 0.0, 0.39, 0.38, 0.6) f4=affine( 0.47, -0.15, 0.0, 0.17, 0.42, 1.1) f5=affine( 0.43, 0.28, 0.0, -0.25, 0.45, 1.0) f6=affine( 0.42, 0.26, 0.0, -0.35, 0.31, 0.7) (再帰呼出し部) m=math.pow(2, -n)/2 trans(n+1, f1 * t, r , g+m, b) trans(n+1, f2 * t, r+m, g+m, b) trans(n+1, f3 * t, r+m, g+m, b) trans(n+1, f4 * t, r , g+m, b) trans(n+1, f5 * t, r , g+m, b) trans(n+1, f6 * t, r+m, g+m, b)