平面充填のもう一つの形 --ペンローズタイル--

平面充填といえばこの話を避けて通ることはできないでしょう。イギリスの物理学者、ロジャー・ペンローズが提示した、平面充填のパターンで、繰り返しに周期性を持たない非常にレアものです。




調べてみると、ペンローズタイル作成のプログラムはlispで書かれたものがなかなかの出来で、これをF#に移植してみました。



module Penrose

open System
open System.Drawing
open System.Drawing.Imaging

let xm = 1024
let ym = 768
let gl = (1.0 + Math.Sqrt(5.0)) / 2.0   // 黄金比

let OutBitmap = new Bitmap(xm, ym, PixelFormat.Format24bppRgb)
let g = Graphics.FromImage(OutBitmap)
g.Clear(Color.White)

let rot_point (x1, y1) (x2, y2) r n =
  let x = (x2 - x1) * n
  let y = (y2 - y1) * n
  let r = r * (-1.0) * Math.PI
  (x * Math.Cos(r) - y * Math.Sin(r) + x1,
   x * Math.Sin(r) + y * Math.Cos(r) + y1)

let center (x1, y1) (x2, y2) =
  ((x2 - x1) / 2.0 + x1, (y2 - y1) / 2.0 + y1)

let draw_point (x1, y1) (x2, y2) c =
  let ix1 = int x1
  let ix2 = int x2
  let iy1 = int y1
  let iy2 = int y2
  if ix1 <= xm + 100 && iy1 <= ym + 100 &&
     ix1 >= -100 && iy1 >= -100 &&
     ix2 <= xm + 100 && iy2 <= ym + 100 &&
     ix2 >= -100 && iy2 >= -100 then
       g.DrawLine(c, ix1, iy1, ix2, iy2)

let rec draw_list l c =
  match l with
  | [] -> ()
  | h :: [] -> ()
  | p1 :: p2 :: t ->
    draw_point p1 p2 c
    draw_list (p2 :: t) c

let rec make_kite a b n =
  let c = rot_point a b 0.2 1.0
  let d = rot_point a b 0.4 1.0
  if n = 0 then
    draw_list [a; b; c; d; a] Pens.Black
//    draw_list [center a b; center c d] Pens.Red
//    draw_list [center b c; center d a] Pens.Red
  else
    kite_deflation a b c d (n - 1)
and
  kite_deflation a b c d n =
    let e = rot_point b c 0.4 1.0
    let f = rot_point d c -0.4 1.0
    make_dart a e n
    make_dart a f n
    make_kite b c n
    make_kite d f n
and
  make_dart a c n =
    let b = rot_point c a 0.6 1.0
    let d = rot_point c a -0.6 1.0
    if n = 0 then
      draw_list [a;b;c;d;a] Pens.Black
//      draw_list [center a b; center c d] Pens.Red
//      draw_list [center b c; center d a] Pens.Red
    else
      dart_deflation a b c d (n - 1)
and
  dart_deflation a b c d n =
    let e = rot_point a c -0.2 1.0
    let f = rot_point a c 0.2 1.0
    make_kite a e n
    make_dart b e n
    make_dart d f n

let kite_dart a b c d n t =
  let x = (a, b)
  let y = (c, d)
  if t = 0 then
    make_dart x y n
  else
    make_kite x (rot_point x y -0.2 1.0) n

kite_dart -1000.0 200.0 2000.0 400.0 10 0

OutBitmap.Save(@".\Penrose.png", ImageFormat.Png)

g.Dispose()


(執筆中)
最終更新:2013年06月26日 10:28
添付ファイル