LoginSignup
5
9

More than 5 years have passed since last update.

Playgroundでマンデルブロ集合とジュリア集合を描いてみた

Last updated at Posted at 2015-11-21

Playgroundでマンデルブロ集合とジュリア集合を描いてみた

リポジトリ

動機

Playgroundを使ってプロトタイプして時に、いろいろ調べていて見つけたPlaygroundの紹介記事でマンデルブロ集合のデモをしていた。

演算子オーバーロード、PlaygroundのAnimation確認等、いろいろ試したいことがあって、ちょうど良い題材だった。

フラクタル図形を描いたり、複素数でぐにゅぐにょしたかった。

マンデルブロ集合(Mandelbrot Set)

マンデルブロ集合の定義

 z_{k}, c \in \mathbb{C} \\
    \begin{cases}
    z_{0} = 0 \\
    z_{k+1} = z_{k}^{2} + c 
    \end{cases}

とした時、$k$ を大きくしても $ \infty $ に発散しない( $\lim_{k \rightarrow \infty } |z_{k}| = \infty $ とならないような)$c$ の集合をマンデルブロ集合といい、複素平面を見てみるとフラクタル図形となっている。

マンデルブロ集合の計算方法

適当に$k$をインクリメントしていき、$N$ 回反復して、
発散しない$c$ をマンデルブロ集合と判断する。
$ |z| > 2 $となれば$\infty$ に発散することが保証されているので、その時点で反復を打ち切って、マンデルブロ集合の要素ではないと判断する。

また、マンデルブロ集合の要素か否かを求までのはやさ(反復回数)で色分けをしたり、漸化式をいろいろ変えてやってアニメーションするといい感じになる。

例えば、$ z_{k+1} = z_{k}^{n} + c $ として $ n $ をいろいろ変えるとこんな感じ

MandelbrotSet.gif

ジュリア集合(Julia Set)

マンデルブロ集合と似ているが、

 z_{k}, c \in \mathbb{C} \\
    z_{k+1} = z_{k}^{2} + c 

$ \lim_{k \rightarrow \infty } |z_{k}| = \infty $ とならないような$ z_{0} $ の集合がジュリア集合。

計算方法とかもマンデルブロ集合とほぼ同じ。
これもいろいろ漸化式を変えてみると面白い。

JuliaSet.gif

もう少し厳密な定義等はググってください。

コーディング

元ネタ記事においてあるhttp://developer.apple.com/swift/blog/downloads/Mandelbrot.zipがベースなので詳細は省略します。上のリンクのものは、Xcode6.3の時のものなのでXcode7.xだとそのままでは動かせないと思います。

図形の描画

複素平面の座標系(下方向が虚数軸の負)とビューの座標系(下方向がy軸の正)を変換するメソッドを作っとく。図を書いてごにょごにょすればこんな感じになっている。

public func viewCoordToComplexCoord(x x: Double, y: Double, rect: CGRect, rectScale: Double = 1.0) -> Complex {
        let Co = self.topLeft, Cn = self.bottomRight - Co
        let W = Double(rect.size.width) * rectScale, H = Double(rect.size.height) * rectScale
        let cx = Re(Co) + x * Re(Cn)/W
        let cy = Im(Co) + y * Im(Cn)/H
        return Complex(cx, cy)
}

UIViewを継承し、drawRectでフレームの適当な間隔の座標をとってきて、漸化式を計算し集合に含まれるかどうかを判断しUIColor.set()で色をつけて、UIBezierPath(rect:).fill()で塗りつぶす。

func drawJuliaSet(rect : CGRect) {
    let width = Double(rect.size.width), height = Double(rect.size.height)
    for x in 0.stride(through: width, by: self.block) {
        for y in 0.stride(through: height, by: self.block) {
            let z0 = self.complexRect.viewCoordToComplexCoord(x: x, y: y, rect: rect, rectScale: self.rectScale)
            //反復回数に応じたUIColor
            self.computeJuliaSetPoint(z0).set()
            UIBezierPath(rect: CGRect(x: x, y: y, width: self.block, height: self.block)).fill()
        }
    }
}

Playgroundでのアニメーションの確認

最近変わったみたいですが、XCPlaygroundPage.currentPage.liveViewにビューを設定するとタイムラインに表示されるようになります。
UIImageViewをanimated gifみたいにしたい場合は、UIImageViewanimationImagesUIImageを入れて,startAnimating()すれば良いです。

import XCPlayground
//...
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
let iv = UIImageView(frame: rect)
XCPlaygroundPage.currentPage.liveView = iv
iv.animationImages = imgs
iv.animationDuration = 1.0
iv.animationRepeatCount = 0
iv.startAnimating()

タイムラインを表示するには、Xcodeの[View][Assistant Editor]で表示します。(右上のベン図みたいなアイコンのボタンでもいい)。Contents.swiftを表示している状態で右側のUtility Areaを見るとShow Timelineというチェックボックスがあるのでチェックする。
Assistant Editorの表示をTimelineにすればXCPlaygroundPage.currentPage.liveViewに設定されているViewのアニメーションを確認できる。

screenshot.png

Animationが目的じゃなきゃパラメータを変えてループさせるだけで、右側のビューで見えるのでliveViewは不要かもね。

それにしても、やっぱりフレームをでかくすると遅いな...

Xcode7.1.1
➜  ~  swift --version
Apple Swift version 2.1 (swiftlang-700.1.101.6 clang-700.1.76)
Target: x86_64-apple-darwin15.0.0

参考

5
9
1

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
5
9