require 'RMagick' class Amida class AmidaError < RuntimeError; end class BadBranchError < AmidaError; end class BadIndexError < AmidaError; end def initialize(size=2) @size = size @branch = {} @keys = nil end attr_reader :size def add_branch(x, y) raise(BadBranchError) if x >= @size-1 || x < 0 raise(BadBranchError) if y > 1.0 || y < 0.0 while @branch.include? y y += 0.01 end @branch[y] = x @keys = @branch.keys.sort end def setup_branch (@size-1).times do |x| (@size / 2).times do add_branch(x, rand * 0.7 + 0.3) end end end def each @keys.each do |key| yield(@branch[key], key) end end def trace(idx = 0) raise(BadIndexError) if idx >= @size || idx < 0 curr = idx y = 0.0 yield(curr, y) if block_given? self.each do |v, k| if curr == v curr = curr + 1 yield(curr, k) if block_given? elsif curr == v + 1 curr = curr - 1 yield(curr, k) if block_given? end end yield(curr, 1.0) if block_given? return curr end end class AmidaMagick def initialize(width=512, height=512) @width = width @height = height end attr_reader :width, :height def canvas Magick::Image.new(@width, @height) end def draw_field(amida) size = amida.size draw = Magick::Draw.new draw.stroke('black') draw.stroke_width(2) y0 = ay_to_my(0) y1 = ay_to_my(1) size.times do |ax| x = ax_to_mx(ax, size) draw.line(x, y0, x, y1) end amida.each do |ax, ay| x0 = ax_to_mx(ax, size) x1 = ax_to_mx(ax + 1, size) y = ay_to_my(ay) draw.line(x0, y, x1, y) end draw end def draw_entry(amida, idx = 0) size = amida.size draw = Magick::Draw.new draw.stroke('red') draw.stroke_width(4) ary = [] last_x = nil amida.trace(idx) do |ax, ay| x = ax_to_mx(ax, size) y = ay_to_my(ay) if last_x ary << last_x ary << ay_to_my(ay) end ary << x ary << y last_x = x end draw.fill_opacity(0) draw.polyline(*ary) draw end def add_branch(amida, x, y) x = mx_to_ax(x, amida.size) y = my_to_ay(y) begin amida.add_branch(x, y) return [x, y] rescue Amida::AmidaError return nil end end private def entry_x(size) a = 0.5 / size (0...size).collect do |n| ((a + 1.0 / size * n) * @width).to_i end end def amida_x_to_magick_x(ax, size) a = 0.5 / size ((a + 1.0 / size * ax) * @width).to_i end alias ax_to_mx amida_x_to_magick_x def magick_x_to_amida_x(mx, size) ((size * mx) / @width.to_f - 0.5).to_i end alias mx_to_ax magick_x_to_amida_x def amida_y_to_magick_y(ay) ((ay * 0.9 + 0.05) * @height).to_i end alias ay_to_my amida_y_to_magick_y def magick_y_to_amida_y(my) (my / @height.to_f - 0.05) / 0.9 end alias my_to_ay magick_y_to_amida_y end