#!ruby -Ks # -*- mode: ruby; encoding: sjis -*- # Last updated: <2014/05/29 06:24:33 +0900> require 'dxruby' # 与えられた多角形で塗りつぶしをするクラス # # @note 以下のページを参考にしました。 # 多角形塗りつぶし(1) # http://azskyetc.client.jp/paintprog/031_polygon1.html # class PolyFill # 塗り潰しをする # # @param [Object] img Imageオブジェクト # @param [Array] np 頂点座標配列 ((x,y), (x,y), ...)の形で入っている。 # @param [Array] f0col 塗り潰しに使う色配列 # @param [Array] f1col 塗り潰しに使う色配列 # @param [Boolean] clip_enable trueなら画面サイズを超えた部分の描画をしない # def PolyFill.fill(img, np, f0col, f1col, clip_enable = true) return if np.size < 3 # y座標の最小値と最大値を求める ymin = ymax = np[0][1] np.each do |p| ymin = p[1] if ymin > p[1] ymax = p[1] if ymax < p[1] end if clip_enable ymin = 0 if ymin < 0 ymax = Window.height if ymax > Window.height end if clip_enable # 1ラインずつスキャンしていく ymin.step(ymax, 1.0) do |y| xlst = PolyFill.get_intersection_point(y.to_f, np) # 交点のx座標を求める next if xlst.empty? # 交点が無い next if xlst.size % 2 != 0 # 交点数が奇数 i = 0 while i < xlst.size x0, x1 = xlst[i], xlst[i+1] unless x1 < 0 or x0 > Window.width img.line(x0, y, x1, y, f0col) end i += 2 end end else ymin.step(ymax, 1.0) do |y| xlst = PolyFill.get_intersection_point(y.to_f, np) next if xlst.empty? or xlst.size % 2 != 0 i = 0 while i < xlst.size img.line(xlst[i], y, xlst[i+1], y, f0col) i += 2 end end end end # 与えられた頂点座標配列を元にして交点リストを求める # # @param [Number] y スキャンするy座標 # @param [Array] lst 頂点座標配列 # @return [Array] 交点のx座標を配列で返す # def PolyFill.get_intersection_point(y, lst) xlst = [] len = lst.size len.times do |i| x1, y1 = lst[i] x2, y2 = lst[(i + 1) % len] next if y1 == y2 # 水平線なら処理しない # yが、現在の辺の終点と、次辺の始点であり、 # 両辺が上方向、または下方向の場合は交点から除外 if y == y2 y3 = lst[(i + 2) % len][1] next if (y2 - y1 < 0 and y3 - y2 < 0) next if (y2 - y1 > 0 and y3 - y2 > 0) end # yが下方向になるように入れ替え if y1 > y2 x1, x2 = x2, x1 y1, y2 = y2, y1 end if y1 <= y and y <= y2 # 交点を追加 x = ((y - y1) * (x2 - x1)).to_f / (y2 - y1) + x1 xlst.push(x) end end # 交点を小さい順にソートして返す return xlst.sort end end if $0 == __FILE__ # ---------------------------------------- # 動作テスト img = Image.new(640, 480) lst = [ [200, 30], [300, 130], [350, 230], [300, 330], [200, 230], [50, 330], [100, 130], [200, 30] ] f0col = [255, 0, 255, 0] f1col = [255, 255, 0, 0] Window.loop do break if Input.keyPush?(K_ESCAPE) lst[4] = Input.mousePosX, Input.mousePosY img.clear PolyFill.fill(img, lst, f0col, f1col, false) Window.draw(0, 0, img) end end