フラクタルな図形

SICP の Picture Language を使って有名どころのフラクタル図形を書いてみました。

準備

任意角度の回転手続 rotate と並行移動の手続 shift、 原点からの拡大/縮小の scale, さらに比率を x 軸, y 軸それぞれに 与えることのできる scale2 を作ります。

(define (rotate painter t)
  (let ((s (sin t))
        (c (cos t)))
    (transform-painter painter
                       (make-vect  0.0 0.0)
                       (make-vect    c   s)
                       (make-vect (- s) c))))

(define (shift painter s)
  (transform-painter painter
                     s
                     (add-vect (make-vect 1.0 0.0) s)
                     (add-vect (make-vect 0.0 1.0) s)))

(define (scale painter r)
  (transform-painter painter
                     (make-vect 0.0 0.0)
                     (make-vect  r  0.0)
                     (make-vect 0.0  r )))

(define (scale2 painter x y)
  (transform-painter painter
                     (make-vect 0.0 0.0)
                     (make-vect  x  0.0)
                     (make-vect 0.0  y )))

(/ 1 (sqrt 2))(/ 1 (sqrt 3)) はよく出てくるので、あらかじめ適当な名前をつけておきます.

(define ir2  (/ 1 (sqrt 2)))
(define ir3  (/ 1 (sqrt 3)))
(define pi/6 (/ pi 6))

もとの SICP では最初に与えられた frame からはみ出さないような変換しかなかったけど, これらの変換はそうとは限りません. できあがった図形がきちんと画板に収まるように, 最後に shiftscale で調整します.

(define d10 (dragon simple-segment 10))
(define k08 (koch   simple-segment  8))
(define l12 (levy   simple-segment 12))

(draw-painter (shift (scale d10 0.6) (make-vect 0.25 0.60))
              400 400 "dragon10.png")

(draw-painter (shift k08             (make-vect 0.00 0.50))
              400 400 "koch08.png")

(draw-painter (shift (scale l12 0.5) (make-vect 0.25 0.65))
              400 400 "levy12.png")
draw-painter は描画する画板(ウィンドウやビットマップなど) の情報と それに合わせた枠(frame)を painter に渡して実際に描画を行ないます.

それではお絵書きをお楽しみ下さい.

Koch 曲線

(define (koch painter n)
  (if (= n 0)
      painter
      (let ((f1 (scale (rotate (scale2 painter 1 -1) pi/6) ir3))
            (f2 (shift (scale (rotate (shift (scale2 painter 1 -1)  
                                             (make-vect -1.0 0.0))  
                                      (- pi/6))
                              ir3)
                       (make-vect 1.0 0.0))))
        (koch (compose-painter f1 f2) (- n 1)))))

Levy 曲線

(define (levy painter n)
  (if (= n 0)
      painter
      (let ((f1 (scale (rotate painter (- pi/4)) ir2))
            (f2 (shift (scale (rotate (shift painter 
                                             (make-vect -1.0 0.0))
                                      pi/4)
                              ir2)
                       (make-vect 1.0 0.0))))
        (levy (compose-painter f1 f2) (- n 1)))))

Dragon 曲線

(define (dragon painter n)
  (if (= n 0)
      painter
      (let ((f1 (scale (rotate painter (- pi/4)) ir2))
            (f2 (shift (scale (rotate (scale2 painter -1 -1) pi/4) ir2)
                       (make-vect 1.0 0.0))))
        (dragon (compose-painter f1 f2) (- n 1)))))

おまけ

skimu@mac.com