LoginSignup
10
1

More than 3 years have passed since last update.

ABCLでマンデルブロ集合

Last updated at Posted at 2019-12-01

この記事は、 Lisp Advent Calendar 2019の2日目の記事です。

ABCLでマンデルブロ集合

ABCL(Armed Bear Common Lisp)でマンデルブロ集合を表示させてみました。

ABCL(Armed Bear Common Lisp)はJavaで作られたCommonLispです。そのため、Javaが動く環境ならばどこでも動きます。また、Javaの豊富なライブラリを利用することができます。JavaのSwingを使ってマンデルブロ集合を描画してみました。

Mandelbrot_001.png
Mandelbrot_004.png
Mandelbrot_007.png
Mandelbrot_010.png
Mandelbrot_013.png
Mandelbrot_016.png
Mandelbrot_019.png

jnewでJavaのインスタンスの作成、jcallでメソッドの呼び出し、jstaticでクラスメソッドの呼び出し、jfieldでフィールドの参照ができます。詳細はソースを見てください。

test/Mandelbrot.lisp
; Mandelbrot Set
; (load "test/Mandelbrot.lisp")

; Java> new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
(defun createImage (w h)
    (jnew "java.awt.image.BufferedImage" 
        w h (jfield "java.awt.image.BufferedImage" "TYPE_4BYTE_ABGR")))

; Java> image.setRGB(x, y, rgb);
(defun putPixel (image x y rgb)
    (jcall "setRGB" image x y rgb))

; Java> g.setColor(color);
; Java> g.fillRect(x1, y1, x2, y2);
(defun fillRect (g x1 y1 x2 y2 color)
    (progn
        (jcall "setColor" g color)
        (jcall "fillRect" g x1 y1 x2 y2)))

; Java> Color.HSBtoRGB(h, s, b);
(defun convertHSBtoRGB (h s b)
    (jstatic "HSBtoRGB" "java.awt.Color" h s b))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; マンデルブロ集合の漸化式
; z[n+1] = z[n]^2 + c
(defun f (x y a b)
    (cons
        (+ (- (* x x) (* y y)) a)
        (+ (* 2 x y) b)))

; 発散するか? 絶対値が2以上になったか?
(defun isDiverge (x y)
    (> (+ (* x x) (* y y)) 4.0))

; 点(a,b)の発散するまでの回数を計算する。発散しない場合は-1を返す。
(defun calc (a b maxCount)
    (block exit
        (let* ((zx 0) (zy 0) (i 0))
            (loop
                (if (> i maxCount) (return-from exit -1))
                (if (isDiverge zx zy) (return-from exit i))
                (setq zz (f zx zy a b))
                (setq zx (car zz))
                (setq zy (cdr zz))
                (setq i (+ i 1))))))

; 計算した回数により色分けする。
(defun toRgb (count)
    (if (= count -1)
        (convertHSBtoRGB 0 0 0)     ; 黒
        (convertHSBtoRGB (* (mod count 1000) 0.002) 1.0 1.0))) ; グラデーション


; 指定された点を打つ
(defun drawMandelbrot1 (image a0 b0 zoom maxCount x y)
    (setq a (+ a0 (* (- x 100) zoom)))
    (setq b (+ b0 (* (- y 100) zoom)))
    (setq count (calc a b maxCount))
    (setq rgb (toRgb count))
    (putPixel image x y rgb))

; 画像に描画する
(defun drawMandelbrot (image a0 b0 zoom maxCount)
    (dotimes (y 200)
        (dotimes (x 200)
            (drawMandelbrot1 image a0 b0 zoom maxCount x y))))


; メイン
(let ((frame (jnew "javax.swing.JFrame" "Mandelbrot set"))
    (image (createImage 200 200)))
    (progn
        (jcall "add" frame (jnew "javax.swing.JLabel" (jnew "javax.swing.ImageIcon" image)))
        (jcall "pack" frame)
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.02d0 100)   ; Mandelbrot_001.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.01d0 100)   ; Mandelbrot_002.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.005d0 100)  ; Mandelbrot_003.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.002d0 1000) ; Mandelbrot_004.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.001d0 1000) ; Mandelbrot_005.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.0005d0 1000)    ; Mandelbrot_006.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.0002d0 1000)    ; Mandelbrot_007.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.0001d0 1000)    ; Mandelbrot_008.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.00005d0 1000)   ; Mandelbrot_009.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.00002d0 1000)   ; Mandelbrot_010.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.00001d0 1000)   ; Mandelbrot_011.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.000005d0 1000)  ; Mandelbrot_012.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.000002d0 1000)  ; Mandelbrot_013.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.000001d0 1000)  ; Mandelbrot_014.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.0000005d0 1000) ; Mandelbrot_015.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.0000002d0 1000) ; Mandelbrot_016.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.0000001d0 1000) ; Mandelbrot_017.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.00000005d0 1000)    ; Mandelbrot_018.png
;       (drawMandelbrot image -0.745428d0 -0.113009d0 0.00000002d0 2000)    ; Mandelbrot_019.png
        (drawMandelbrot image -0.745428d0 -0.113009d0 0.00000001d0 2000)    ; Mandelbrot_020.png
        (jcall "setVisible" frame T)))

実行方法は以下のとおり。実行には数秒~数十秒かかります。

C:\devel\lisp\abcl-bin-1.6.0>java -jar abcl.jar
Armed Bear Common Lisp 1.6.0
Java 10.0.1 Oracle Corporation
Java HotSpot(TM) 64-Bit Server VM
Low-level initialization completed in 0.23 seconds.
Startup completed in 4.251 seconds.
Type ":help" for a list of available commands.
CL-USER(1): (load "test/Mandelbrot.lisp")
T
CL-USER(2): (exit)

C:\devel\lisp\abcl-bin-1.6.0>

既知のツッコミ

  • CommonLispでは複素数が使えます。知らなかったので、実部と虚部に分解して計算しました。
  • デフォルトで浮動小数点は単精度だったので、数値の末尾にd0をつけて倍精度にしています。*read-default-float-format*で指定する方法もあります。

ではでは

10
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
1