2015年9月11日金曜日

【Ruby】 離散ボロノイ図の描画

Ruby落書きシリーズ。
今回はなんちゃって離散ボロノイ図の描画(描画は完全にいつものやつ)です。全然厳密ではないので、実行結果を見て楽しむぐらいしかできません。



ソースコード

voronoi.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class Voronoi
  POINT_TYPE = {
    :nomal => 0,
    :generator => 1,
    :border => 2
  }
 
  def initialize(i, j, generators)
    @i_size, @j_size = i, j
    @generators = generators
 
    @points = Array.new(@i_size) do
      Array.new(@j_size) { POINT_TYPE[:nomal] }
    end
    @generators.each do |i, j|
      @points[i][j] = POINT_TYPE[:generator]
    end
  end
 
  def exec
    @i_size.times.to_a.product(@j_size.times.to_a) do |i, j|
      @generators.map do |gi, gj|
        Math.sqrt( ((i-gi)**2) + ((j-gj)**2) )
      end
      .sort.tap do |ary|
        if (ary[0] - ary[1]).abs < 0.9
          @points[i][j] = POINT_TYPE[:border]
          puts self
          printf "\e[#{@i_size + 1}A"; STDOUT.flush; #sleep 0.1
        end
      end
    end
    puts self
 
  rescue Interrupt
    exit 0
  end
 
  def to_s
    "\n" << @points.map do |line|
      "  " << line.map do |point|
        case point
        when POINT_TYPE[:nomal] then "\e[47m  \e[0m"
        when POINT_TYPE[:generator] then "\e[41m  \e[0m"
        when POINT_TYPE[:border] then "\e[46m  \e[0m"
        end
      end.join("")
    end.join("\n")
  end
end
 
 
generators = [
  [8, 2], [6, 26], [30, 20], [35, 5], [20, 10], [20, 33]
]
voronoi = Voronoi.new(40, 40, generators)
voronoi.exec


実行結果

赤が母点、青が境界を表しています。楽しい。

図1 voronoi.rb 実行結果


おわりに

今やりたいことでボロノイ図が必要だったのですが、正しい点が求められているか確認するため境界線だけわかればよかったので、そのようなコードを書いてみました。とは言え図1のようでは線が粗いので、全く同じ処理でマス目を10等分した版をgnuplotで出力してみました(図2)。ちゃんと線に見えるのでとりあえずこれでいいかなという感じです。(ちゃんとしたボロノイ図もいつかやってみたい)

図2 gnuplotの出力結果

0 件のコメント:

コメントを投稿