Ruby練習四日目(離散ボロノイ図)
離散ボロノイ図を全探索法を使って作成してみる。全探索法とは、すべての離散点においてどの母点にもっとも近いかを計算する方法。一番単純な方法かつ、計算量の多い方法。
require "digest/md5" require "cairo" # # ボロノイ図を描画する(全探索法) # class VoronoiDiagram def initialize(width, height) @width = width @height = height @context = Cairo::Context.new( Cairo::ImageSurface.new(@width, @height) ) end #=== ボロノイ図を作成 def draw(kernel_points) # 離散点の初期化 @dp = Array.new(@height) { Array.new(@width) { nil } } # # 各離散点から最も距離が近い母点の添字を記録する # @height.times { |y| @width.times { |x| min_dist = Float::MAX kernel_points.each_with_index { |point, i| dist = distance([x, y], point) if (dist < min_dist) min_dist = dist @dp[y][x] = i end } } } # # 描画 # @context.set_source_rgb(1, 1, 1) # 色:白 @context.rectangle(0, 0, @width, @height) # 領域全てをパスで囲む @context.fill # パスの内側を塗りつぶす set_colors(kernel_points) # 離散点を描画 @dp.each_with_index { |line, y| line.each_with_index { |cell, x| @context.set_source_rgb( @colors[cell][0], @colors[cell][1], @colors[cell][2] ) @context.rectangle(x, y, 1, 1) @context.fill } } # 母点を描画 @context.set_source_rgb(0, 0, 0) kernel_points.each { |point| @context.circle(point[0], point[1], 1) @context.fill } @context.target.write_to_png("voronoi.png") end #=== 領域の色を決定 def set_colors(points) @colors = [] points.each { |point| r = Digest::MD5.hexdigest(point[0].to_s).to_i(16) % 101 g = Digest::MD5.hexdigest(point[1].to_s).to_i(16) % 101 b = Digest::MD5.hexdigest(point.to_s).to_i(16) % 101 @colors << [r / 100.0, g / 100.0, b / 100.0] } end #=== 二点間の距離を求める def distance(point1, point2) dx = point2[0] - point1[0] dy = point2[1] - point1[1] Math.sqrt(dx * dx + dy * dy) end end # テスト points = DATA.readlines.map { |item| item.chomp.split(/,/).map { |i| i.to_i } } voronoi = VoronoiDiagram.new(180, 180) voronoi.draw(points) __END__ 10,12 10,137 91,99 90,28 123,120 160,78 170,170