ruby+svgでフラクタル

幾何なんて久しぶりだ。

フラクタル図形?をsvgで書いてみる

コッホ曲線

rubyのmatrixが意外に使いやすいことがわかった。
てか、行列とか幾何とかすっかり忘れてるよ。
復習のために一応書いておく

2点\normalsize a(x_{a},y_{b}), b(x_{b},y_{b})の3分割点c,dの座標はそれぞれ
\normalsize(x_{c},y_{c})=(\frac{2x_{a}+x_{b}}{3},\frac{2y_{a}+y_{b}}{3}), (x_{d},y_{d})=(\frac{x_{a}+2x_{b}}{3},\frac{y_{a}+2y_{b}}{3})

点eは点dを点cを中心に反時計回りに60°つまりπ/3回転したもの
だから、点dを-c分だけ平行移動、π/3回転、c分平行移動することを行列で表すと

\normalsize\left(\begin{array}{c}x_{e}\\y_{e}\\1\end{array}\right)=\left(\begin{array}{ccc}1&0&x_{c}\\0&1&y_{c}\\0&0&1\end{array}\right)\left( \begin{array}{ccc}cos(\frac{\pi}{3}) & -sin(\frac{\pi}{3}) & 0 \\ sin(\frac{\pi}{3}) & cos(\frac{\pi}{3}) & 0 \\ 0 & 0 & 1 \end{array} \right)\left(\begin{array}{ccc}1&0&-x_{c}\\0&1&-y_{c}\\0&0&1\end{array}\right)\left(\begin{array}{c}x_{d}\\y_{d}\\1\end{array}\right)

展開した方が良さそうな気がしたが面倒なのでそのままrubyに埋め込むことにする

実行が面倒なのでcgiで(svgだけほしいときには を抽出すればいい)


#!/usr/bin/ruby
require 'matrix'
puts <<HEAD
content-type: text/xml

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>svg koch</title>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1000" height="1000">
HEAD

def line(a,b)
  %Q!<line x1="#{a[0]}" y1="#{a[1]}" x2="#{b[0]}" y2="#{b[1]}" stroke="blue" stroke-width="1"/>!
end

def koch(a,b,n)
  c=Vector[(a[0]*2+b[0])/3,(a[1]*2+b[1])/3,1]
  d=Vector[(a[0]+b[0]*2)/3,(a[1]+b[1]*2)/3,1]
  e=Matrix[[1,0,c[0]],
           [0,1,c[1]],
           [0,0,  1]] *
    Matrix[[Math.cos(Math::PI/3),-Math.sin(Math::PI/3),0],
           [Math.sin(Math::PI/3), Math.cos(Math::PI/3),0],
           [0                   ,0                    ,1]] * 
    Matrix[[1,0,-c[0]],
           [0,1,-c[1]],
           [0,0,   1]] * d
  if n>0
    koch(a,c,n-1)
    koch(c,e,n-1)
    koch(e,d,n-1)
    koch(d,b,n-1)
  else
    puts line(a,c)
    puts line(c,e)
    puts line(e,d)
    puts line(d,b)
  end
end

koch(Vector[100,100,1],Vector[900,100,1],5)

puts <<TAIL
</svg>
</body>
</html>
TAIL

ドラゴンカーブ

コッホ曲線とほぼ同じなのだが、再帰する際に a->c と b->c で行う点が違う。c->bにすると45°のコッホ崩れが現れる。

\normalsize\left(\begin{array}{c}x_{c}\\y_{c}\\1\end{array}\right)=\left(\begin{array}{ccc}1&0&x_{a}\\0&1&y_{a}\\0&0&1\end{array}\right)\left(\begin{array}{ccc}\frac{1}{\sqrt{2}}&0&0\\0&\frac{1}{\sqrt{2}}&0\\0&0&1\end{array}\right)\left( \begin{array}{ccc}cos(\frac{\pi}{4}) & -sin(\frac{\pi}{4}) & 0 \\ sin(\frac{\pi}{4}) & cos(\frac{\pi}{4}) & 0 \\ 0 & 0 & 1 \end{array} \right)\left(\begin{array}{ccc}1&0&-x_{a}\\0&1&-y_{a}\\0&0&1\end{array}\right)\left(\begin{array}{c}x_{b}\\y_{b}\\1\end{array}\right)


#!/usr/bin/ruby
require 'matrix'
puts <<HEAD
content-type: text/xml

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>svg dragon</title>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1000" height="1000">
HEAD

def line(a,b)
  %Q!<line x1="#{a[0]}" y1="#{a[1]}" x2="#{b[0]}" y2="#{b[1]}" stroke="blue" stroke-width="1"/>!
end

def dragon(a,b,n)
  c=Matrix[[1,0,a[0]],
           [0,1,a[1]],
           [0,0,  1]] *
    Matrix[[1/Math.sqrt(2),0             ,0],
           [0             ,1/Math.sqrt(2),0],
           [0             ,0             ,1]] *
    Matrix[[Math.cos(Math::PI/4),-Math.sin(Math::PI/4),0],
           [Math.sin(Math::PI/4), Math.cos(Math::PI/4),0],
           [0                    ,0                   ,1]] *
    Matrix[[1,0,-a[0]],
           [0,1,-a[1]],
           [0,0,   1]] * b
  if n>0
    dragon(a,c,n-1)
    dragon(b,c,n-1)
  else
    puts line(a,c)
    puts line(b,c)
  end
end

dragon(Vector[200,300,1],Vector[800,300,1],14)

puts <<TAIL
</svg>
</body>
</html>
TAIL